1 /*
2 * HVM ROMBIOS support.
3 *
4 * Leendert van Doorn, leendert@watson.ibm.com
5 * Copyright (c) 2005, International Business Machines Corporation.
6 * Copyright (c) 2006, Keir Fraser, XenSource Inc.
7 * Copyright (c) 2011, Citrix Inc.
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms and conditions of the GNU General Public License,
11 * version 2, as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * this program; If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "config.h"
23
24 #include "../rombios/config.h"
25
26 #include "smbios_types.h"
27 #include "pci_regs.h"
28 #include "util.h"
29 #include "hypercall.h"
30 #include "option_rom.h"
31
32 #include <libacpi.h>
33 #include <xen/hvm/params.h>
34
35 #define ROM_INCLUDE_ROMBIOS
36 #define ROM_INCLUDE_VGABIOS
37 #define ROM_INCLUDE_ETHERBOOT
38 #include "roms.inc"
39
40 #define ROMBIOS_BEGIN 0x000F0000
41 #define ROMBIOS_SIZE 0x00010000
42 #define ROMBIOS_MAXOFFSET 0x0000FFFF
43 #define ROMBIOS_END (ROMBIOS_BEGIN + ROMBIOS_SIZE)
44
rombios_setup_e820(void)45 static void rombios_setup_e820(void)
46 {
47 /*
48 * 0x9E000-0x09F000: Stack.
49 * 0x9FC00-0x0A0000: Extended BIOS Data Area (EBDA).
50 * ...
51 * 0xE0000-0x0F0000: PC-specific area. We place various tables here.
52 * 0xF0000-0x100000: System BIOS.
53 */
54 *E820_NR = build_e820_table(E820, 0x9E000, 0xE0000);
55 dump_e820_table(E820, *E820_NR);
56 }
57
rombios_setup_bios_info(void)58 static void rombios_setup_bios_info(void)
59 {
60 struct rombios_info *info;
61
62 info = (struct rombios_info *)BIOS_INFO_PHYSICAL_ADDRESS;
63 memset(info, 0, sizeof(*info));
64 }
65
66 static void *ipxe_module_addr;
67
rombios_load_roms(void)68 static void rombios_load_roms(void)
69 {
70 int option_rom_sz = 0, vgabios_sz = 0, etherboot_sz = 0;
71 uint32_t etherboot_phys_addr = 0, option_rom_phys_addr = 0;
72
73 switch ( virtual_vga )
74 {
75 case VGA_cirrus:
76 printf("Loading Cirrus VGABIOS ...\n");
77 memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
78 vgabios_cirrusvga, sizeof(vgabios_cirrusvga));
79 vgabios_sz = round_option_rom(sizeof(vgabios_cirrusvga));
80 break;
81 case VGA_std:
82 printf("Loading Standard VGABIOS ...\n");
83 memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
84 vgabios_stdvga, sizeof(vgabios_stdvga));
85 vgabios_sz = round_option_rom(sizeof(vgabios_stdvga));
86 break;
87 case VGA_pt:
88 printf("Loading VGABIOS of passthroughed gfx ...\n");
89 vgabios_sz = round_option_rom(
90 (*(uint8_t *)(VGABIOS_PHYSICAL_ADDRESS+2)) * 512);
91 break;
92 default:
93 printf("No emulated VGA adaptor ...\n");
94 break;
95 }
96
97 etherboot_phys_addr = VGABIOS_PHYSICAL_ADDRESS + vgabios_sz;
98 if ( etherboot_phys_addr < OPTIONROM_PHYSICAL_ADDRESS )
99 etherboot_phys_addr = OPTIONROM_PHYSICAL_ADDRESS;
100
101 if ( ipxe_module_addr )
102 {
103 etherboot_sz = scan_etherboot_nic(OPTIONROM_PHYSICAL_END,
104 etherboot_phys_addr,
105 ipxe_module_addr);
106
107 option_rom_phys_addr = etherboot_phys_addr + etherboot_sz;
108 option_rom_sz = pci_load_option_roms(OPTIONROM_PHYSICAL_END,
109 option_rom_phys_addr);
110 }
111
112 printf("Option ROMs:\n");
113 if ( vgabios_sz )
114 printf(" %05x-%05x: VGA BIOS\n",
115 VGABIOS_PHYSICAL_ADDRESS,
116 VGABIOS_PHYSICAL_ADDRESS + vgabios_sz - 1);
117 if ( etherboot_sz )
118 printf(" %05x-%05x: Etherboot ROM\n",
119 etherboot_phys_addr,
120 etherboot_phys_addr + etherboot_sz - 1);
121 if ( option_rom_sz )
122 printf(" %05x-%05x: PCI Option ROMs\n",
123 option_rom_phys_addr,
124 option_rom_phys_addr + option_rom_sz - 1);
125 }
126
rombios_load(const struct bios_config * config,void * unused_addr,uint32_t unused_size,void * ipxe_addr)127 static void rombios_load(const struct bios_config *config,
128 void *unused_addr, uint32_t unused_size,
129 void *ipxe_addr)
130 {
131 uint32_t bioshigh;
132 struct rombios_info *info;
133
134 BUILD_BUG_ON(sizeof(rombios) > 0x100000 - ROMBIOS_PHYSICAL_ADDRESS);
135
136 memcpy((void *)config->bios_address, config->image,
137 config->image_size);
138
139 bioshigh = rombios_highbios_setup();
140
141 info = (struct rombios_info *)BIOS_INFO_PHYSICAL_ADDRESS;
142 info->bios32_entry = bioshigh;
143
144 /* Stash ipxe address */
145 ipxe_module_addr = ipxe_addr;
146 }
147
148 /*
149 * find_mp_table_start - searchs through BIOS memory for '___HVMMP' signature
150 *
151 * The '___HVMMP' signature is created by the ROMBIOS and designates a chunk
152 * of space inside the ROMBIOS that is safe for us to write our MP table info
153 */
get_mp_table_start(void)154 static void *get_mp_table_start(void)
155 {
156 char *bios_mem;
157
158 for ( bios_mem = (char *)ROMBIOS_BEGIN;
159 bios_mem != (char *)ROMBIOS_END;
160 bios_mem++ )
161 {
162 if ( strncmp(bios_mem, "___HVMMP", 8) == 0 )
163 return bios_mem;
164 }
165
166 return NULL;
167 }
168
169 /* recalculate the new ROMBIOS checksum after adding MP tables */
reset_bios_checksum(void)170 static void reset_bios_checksum(void)
171 {
172 uint32_t i;
173 uint8_t checksum;
174
175 checksum = 0;
176 for ( i = 0; i < ROMBIOS_MAXOFFSET; i++ )
177 checksum += ((uint8_t *)(ROMBIOS_BEGIN))[i];
178
179 *((uint8_t *)(ROMBIOS_BEGIN + ROMBIOS_MAXOFFSET)) = -checksum;
180 }
181
rombios_acpi_build_tables(void)182 static void rombios_acpi_build_tables(void)
183 {
184 struct acpi_config config = {
185 .dsdt_anycpu = dsdt_anycpu,
186 .dsdt_anycpu_len = dsdt_anycpu_len,
187 .dsdt_15cpu = dsdt_15cpu,
188 .dsdt_15cpu_len = dsdt_15cpu_len,
189 };
190
191 hvmloader_acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
192 }
193
rombios_create_mp_tables(void)194 static void rombios_create_mp_tables(void)
195 {
196 /* Find the 'safe' place in ROMBIOS for the MP tables. */
197 void *table = get_mp_table_start();
198
199 if ( table == NULL )
200 {
201 printf("Couldn't find start point for MP tables\n");
202 return;
203 }
204
205 create_mp_tables(table);
206
207 reset_bios_checksum();
208 }
209
rombios_create_smbios_tables(void)210 static void rombios_create_smbios_tables(void)
211 {
212 hvm_write_smbios_tables(
213 SMBIOS_PHYSICAL_ADDRESS,
214 SMBIOS_PHYSICAL_ADDRESS + sizeof(struct smbios_entry_point),
215 SMBIOS_PHYSICAL_END);
216 }
217
218 struct bios_config rombios_config = {
219 .name = "ROMBIOS",
220
221 .image = rombios,
222 .image_size = sizeof(rombios),
223
224 .bios_address = ROMBIOS_PHYSICAL_ADDRESS,
225
226 .load_roms = rombios_load_roms,
227
228 .bios_load = rombios_load,
229
230 .bios_info_setup = rombios_setup_bios_info,
231 .bios_info_finish = NULL,
232
233 .e820_setup = rombios_setup_e820,
234
235 .acpi_build_tables = rombios_acpi_build_tables,
236 .create_mp_tables = rombios_create_mp_tables,
237 .create_smbios_tables = rombios_create_smbios_tables,
238 .create_pir_tables = NULL, /* embedded in ROMBIOS */
239 };
240
241 /*
242 * Local variables:
243 * mode: C
244 * c-file-style: "BSD"
245 * c-basic-offset: 4
246 * tab-width: 4
247 * indent-tabs-mode: nil
248 * End:
249 */
250