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