Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / seabios / src / fw / csm.c
1 // Compatibility Support Module (CSM) for UEFI / EDK-II
2 //
3 // Copyright © 2013 Intel Corporation
4 //
5 // This file may be distributed under the terms of the GNU LGPLv3 license.
6
7 #include "bregs.h"
8 #include "config.h" // CONFIG_*
9 #include "farptr.h" // MAKE_FLATPTR
10 #include "hw/pci.h"
11 #include "hw/pic.h"
12 #include "malloc.h" // csm_malloc_preinit
13 #include "memmap.h"
14 #include "output.h" // dprintf
15 #include "stacks.h" // wait_threads
16 #include "std/acpi.h" // RSDP_SIGNATURE
17 #include "std/bda.h" // struct bios_data_area_s
18 #include "std/optionrom.h" // struct rom_header
19 #include "util.h" // copy_smbios
20 #include "paravirt.h" // qemu_preinit
21
22 #define UINT8 u8
23 #define UINT16 u16
24 #define UINT32 u32
25 #include "std/LegacyBios.h"
26
27 struct rsdp_descriptor csm_rsdp VARFSEG __aligned(16);
28
29 EFI_COMPATIBILITY16_TABLE csm_compat_table VARFSEG __aligned(16) = {
30     .Signature = 0x24454649,
31     .TableChecksum = 0 /* Filled in by checkrom.py */,
32     .TableLength = sizeof(csm_compat_table),
33     .Compatibility16CallSegment = SEG_BIOS,
34     .Compatibility16CallOffset = 0 /* Filled in by checkrom.py */,
35     .OemIdStringPointer = (u32)"SeaBIOS",
36     .AcpiRsdPtrPointer = (u32)&csm_rsdp,
37 };
38
39 EFI_TO_COMPATIBILITY16_INIT_TABLE *csm_init_table;
40 EFI_TO_COMPATIBILITY16_BOOT_TABLE *csm_boot_table;
41
42 static u16 PICMask = PIC_IRQMASK_DEFAULT;
43
44 extern void __csm_return(struct bregs *regs) __noreturn;
45
46 static void
47 csm_return(struct bregs *regs)
48 {
49     u32 rommax = rom_get_max();
50     extern u8 final_readonly_start[];
51
52     dprintf(3, "handle_csm returning AX=%04x\n", regs->ax);
53
54     csm_compat_table.UmaAddress = rommax;
55     csm_compat_table.UmaSize = (u32)final_readonly_start - rommax;
56
57     PICMask = pic_irqmask_read();
58     __csm_return(regs);
59 }
60
61 static void
62 csm_maininit(struct bregs *regs)
63 {
64     interface_init();
65     pci_probe_devices();
66
67     csm_compat_table.PnPInstallationCheckSegment = SEG_BIOS;
68     csm_compat_table.PnPInstallationCheckOffset = get_pnp_offset();
69
70     regs->ax = 0;
71
72     csm_return(regs);
73 }
74
75 /* Legacy16InitializeYourself */
76 static void
77 handle_csm_0000(struct bregs *regs)
78 {
79     qemu_preinit();
80
81     dprintf(3, "Legacy16InitializeYourself table %04x:%04x\n", regs->es,
82             regs->bx);
83
84     csm_init_table = MAKE_FLATPTR(regs->es, regs->bx);
85
86     dprintf(3, "BiosLessThan1MB %08x\n", csm_init_table->BiosLessThan1MB);
87     dprintf(3, "HiPmmMemory     %08x\n", csm_init_table->HiPmmMemory);
88     dprintf(3, "HiPmmMemorySize %08x\n", csm_init_table->HiPmmMemorySizeInBytes);
89     dprintf(3, "ReverseThunk    %04x:%04x\n", csm_init_table->ReverseThunkCallSegment,
90             csm_init_table->ReverseThunkCallOffset);
91     dprintf(3, "NumE820Entries  %08x\n", csm_init_table->NumberE820Entries);
92     dprintf(3, "OsMemoryAbove1M %08x\n", csm_init_table->OsMemoryAbove1Mb);
93     dprintf(3, "ThunkStart      %08x\n", csm_init_table->ThunkStart);
94     dprintf(3, "ThunkSize       %08x\n", csm_init_table->ThunkSizeInBytes);
95     dprintf(3, "LoPmmMemory     %08x\n", csm_init_table->LowPmmMemory);
96     dprintf(3, "LoPmmMemorySize %08x\n", csm_init_table->LowPmmMemorySizeInBytes);
97
98     csm_malloc_preinit(csm_init_table->LowPmmMemory,
99                        csm_init_table->LowPmmMemorySizeInBytes,
100                        csm_init_table->HiPmmMemory,
101                        csm_init_table->HiPmmMemorySizeInBytes);
102     reloc_preinit(csm_maininit, regs);
103 }
104
105 /* Legacy16UpdateBbs */
106 static void
107 handle_csm_0001(struct bregs *regs)
108 {
109     if (!CONFIG_BOOT) {
110         regs->ax = 1;
111         return;
112     }
113
114     dprintf(3, "Legacy16UpdateBbs table %04x:%04x\n", regs->es, regs->bx);
115
116     csm_boot_table = MAKE_FLATPTR(regs->es, regs->bx);
117     dprintf(3, "MajorVersion %04x\n", csm_boot_table->MajorVersion);
118     dprintf(3, "MinorVersion %04x\n", csm_boot_table->MinorVersion);
119     dprintf(3, "AcpiTable %08x\n", csm_boot_table->AcpiTable);
120     dprintf(3, "SmbiosTable %08x\n", csm_boot_table->SmbiosTable);
121     dprintf(3, "SmbiosTableLength %08x\n", csm_boot_table->SmbiosTableLength);
122 //    dprintf(3, "SioData %08x\n", csm_boot_table->SioData);
123     dprintf(3, "DevicePathType %04x\n", csm_boot_table->DevicePathType);
124     dprintf(3, "PciIrqMask %04x\n", csm_boot_table->PciIrqMask);
125     dprintf(3, "NumberE820Entries %08x\n", csm_boot_table->NumberE820Entries);
126 //    dprintf(3, "HddInfo %08x\n", csm_boot_table->HddInfo);
127     dprintf(3, "NumberBbsEntries %08x\n", csm_boot_table->NumberBbsEntries);
128     dprintf(3, "BBsTable %08x\n", csm_boot_table->BbsTable);
129     dprintf(3, "SmmTable %08x\n", csm_boot_table->SmmTable);
130     dprintf(3, "OsMemoryAbove1Mb %08x\n", csm_boot_table->OsMemoryAbove1Mb);
131     dprintf(3, "UnconventionalDeviceTable %08x\n", csm_boot_table->UnconventionalDeviceTable);
132
133     regs->ax = 0;
134 }
135
136 /* PrepareToBoot */
137 static void
138 handle_csm_0002(struct bregs *regs)
139 {
140     if (!CONFIG_BOOT) {
141         regs->ax = 1;
142         return;
143     }
144
145     dprintf(3, "PrepareToBoot table %04x:%04x\n", regs->es, regs->bx);
146
147     struct e820entry *p = (void *)csm_compat_table.E820Pointer;
148     int i;
149     for (i=0; i < csm_compat_table.E820Length / sizeof(struct e820entry); i++)
150         add_e820(p[i].start, p[i].size, p[i].type);
151
152     if (csm_init_table->HiPmmMemorySizeInBytes > BUILD_MAX_HIGHTABLE) {
153         u32 hi_pmm_end = csm_init_table->HiPmmMemory + csm_init_table->HiPmmMemorySizeInBytes;
154         add_e820(hi_pmm_end - BUILD_MAX_HIGHTABLE, BUILD_MAX_HIGHTABLE, E820_RESERVED);
155     }
156
157     // For PCIBIOS 1ab10e
158     if (csm_compat_table.IrqRoutingTablePointer &&
159         csm_compat_table.IrqRoutingTableLength) {
160         PirAddr = (void *)csm_compat_table.IrqRoutingTablePointer;
161         dprintf(3, "CSM PIRQ table at %p\n", PirAddr);
162     }
163
164     // For find_resume_vector()... and find_acpi_features()
165     if (csm_rsdp.signature == RSDP_SIGNATURE) {
166         RsdpAddr = &csm_rsdp;
167         dprintf(3, "CSM ACPI RSDP at %p\n", RsdpAddr);
168
169         find_acpi_features();
170     }
171
172     // SMBIOS table needs to be copied into the f-seg
173     // XX: OVMF doesn't seem to set SmbiosTableLength so don't check it
174     if (csm_boot_table->SmbiosTable && !SMBiosAddr)
175         copy_smbios((void *)csm_boot_table->SmbiosTable);
176
177     // MPTABLE is just there; we don't care where.
178
179     // EFI may have reinitialised the video using its *own* driver.
180     enable_vga_console();
181
182     // EFI fills this in for us. Zero it for now...
183     struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0);
184     bda->hdcount = 0;
185
186     mathcp_setup();
187     timer_setup();
188     clock_setup();
189     device_hardware_setup();
190     wait_threads();
191     interactive_bootmenu();
192
193     prepareboot();
194
195     regs->ax = 0;
196 }
197
198 /* Boot */
199 static void
200 handle_csm_0003(struct bregs *regs)
201 {
202     if (!CONFIG_BOOT) {
203         regs->ax = 1;
204         return;
205     }
206
207     dprintf(3, "Boot\n");
208
209     startBoot();
210
211     regs->ax = 1;
212 }
213
214 /* Legacy16DispatchOprom */
215 static void
216 handle_csm_0005(struct bregs *regs)
217 {
218     EFI_DISPATCH_OPROM_TABLE *table = MAKE_FLATPTR(regs->es, regs->bx);
219     struct rom_header *rom;
220     u16 bdf;
221
222     if (!CONFIG_OPTIONROMS) {
223         regs->ax = 1;
224         return;
225     }
226
227     dprintf(3, "Legacy16DispatchOprom rom %p\n", table);
228
229     dprintf(3, "OpromSegment   %04x\n", table->OpromSegment);
230     dprintf(3, "RuntimeSegment %04x\n", table->RuntimeSegment);
231     dprintf(3, "PnPInstallationCheck %04x:%04x\n",
232             table->PnPInstallationCheckSegment,
233             table->PnPInstallationCheckOffset);
234     dprintf(3, "RuntimeSegment %04x\n", table->RuntimeSegment);
235
236     rom = MAKE_FLATPTR(table->OpromSegment, 0);
237     bdf = pci_bus_devfn_to_bdf(table->PciBus, table->PciDeviceFunction);
238
239     rom_reserve(rom->size * 512);
240
241     // XX PnP seg/ofs should never be other than default
242     callrom(rom, bdf);
243
244     rom_confirm(rom->size * 512);
245
246     regs->bx = 0; // FIXME
247     regs->ax = 0;
248 }
249
250 /* Legacy16GetTableAddress */
251 static void
252 handle_csm_0006(struct bregs *regs)
253 {
254     u16 size = regs->cx;
255     u16 align = regs->dx;
256     u16 region = regs->bx; // (1 for F000 seg, 2 for E000 seg, 0 for either)
257     void *chunk = NULL;
258
259     if (!region)
260         region = 3;
261
262     dprintf(3, "Legacy16GetTableAddress size %x align %x region %d\n",
263         size, align, region);
264
265     if (region & 2)
266         chunk = _malloc(&ZoneLow, size, align);
267     if (!chunk && (region & 1))
268         chunk = _malloc(&ZoneFSeg, size, align);
269
270     dprintf(3, "Legacy16GetTableAddress size %x align %x region %d yields %p\n",
271         size, align, region, chunk);
272     if (chunk) {
273         regs->ds = FLATPTR_TO_SEG(chunk);
274         regs->bx = FLATPTR_TO_OFFSET(chunk);
275         regs->ax = 0;
276     } else {
277         regs->ax = 1;
278     }
279 }
280
281 void VISIBLE32INIT
282 handle_csm(struct bregs *regs)
283 {
284     ASSERT32FLAT();
285
286     if (!CONFIG_CSM)
287         return;
288
289     dprintf(3, "handle_csm regs %p AX=%04x\n", regs, regs->ax);
290
291     pic_irqmask_write(PICMask);
292
293     switch(regs->ax) {
294     case 0000: handle_csm_0000(regs); break;
295     case 0001: handle_csm_0001(regs); break;
296     case 0002: handle_csm_0002(regs); break;
297     case 0003: handle_csm_0003(regs); break;
298 //    case 0004: handle_csm_0004(regs); break;
299     case 0005: handle_csm_0005(regs); break;
300     case 0006: handle_csm_0006(regs); break;
301 //    case 0007: handle_csm_0007(regs); break;
302 //    case 0008: hamdle_csm_0008(regs); break;
303     default: regs->al = 1;
304     }
305
306     csm_return(regs);
307 }
308
309 int csm_bootprio_ata(struct pci_device *pci, int chanid, int slave)
310 {
311     if (!csm_boot_table)
312         return -1;
313     BBS_TABLE *bbs = (void *)csm_boot_table->BbsTable;
314     int index = 1 + (chanid * 2) + slave;
315     dprintf(3, "CSM bootprio for ATA%d,%d (index %d) is %d\n", chanid, slave,
316             index, bbs[index].BootPriority);
317     return bbs[index].BootPriority;
318 }
319
320 int csm_bootprio_fdc(struct pci_device *pci, int port, int fdid)
321 {
322     if (!csm_boot_table)
323         return -1;
324     BBS_TABLE *bbs = (void *)csm_boot_table->BbsTable;
325     dprintf(3, "CSM bootprio for FDC is %d\n", bbs[0].BootPriority);
326     return bbs[0].BootPriority;
327 }
328
329 int csm_bootprio_pci(struct pci_device *pci)
330 {
331     if (!csm_boot_table)
332         return -1;
333     BBS_TABLE *bbs = (void *)csm_boot_table->BbsTable;
334     int i;
335
336     for (i = 5; i < csm_boot_table->NumberBbsEntries; i++) {
337         if (pci->bdf == pci_to_bdf(bbs[i].Bus, bbs[i].Device, bbs[i].Function)) {
338             dprintf(3, "CSM bootprio for PCI(%d,%d,%d) is %d\n", bbs[i].Bus,
339                     bbs[i].Device, bbs[i].Function, bbs[i].BootPriority);
340             return bbs[i].BootPriority;
341         }
342     }
343     return -1;
344 }