1 // Compatibility Support Module (CSM) for UEFI / EDK-II
3 // Copyright © 2013 Intel Corporation
5 // This file may be distributed under the terms of the GNU LGPLv3 license.
8 #include "config.h" // CONFIG_*
9 #include "farptr.h" // MAKE_FLATPTR
12 #include "malloc.h" // csm_malloc_preinit
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
25 #include "std/LegacyBios.h"
27 struct rsdp_descriptor csm_rsdp VARFSEG __aligned(16);
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,
39 EFI_TO_COMPATIBILITY16_INIT_TABLE *csm_init_table;
40 EFI_TO_COMPATIBILITY16_BOOT_TABLE *csm_boot_table;
42 static u16 PICMask = PIC_IRQMASK_DEFAULT;
44 extern void __csm_return(struct bregs *regs) __noreturn;
47 csm_return(struct bregs *regs)
49 u32 rommax = rom_get_max();
50 extern u8 final_readonly_start[];
52 dprintf(3, "handle_csm returning AX=%04x\n", regs->ax);
54 csm_compat_table.UmaAddress = rommax;
55 csm_compat_table.UmaSize = (u32)final_readonly_start - rommax;
57 PICMask = pic_irqmask_read();
62 csm_maininit(struct bregs *regs)
67 csm_compat_table.PnPInstallationCheckSegment = SEG_BIOS;
68 csm_compat_table.PnPInstallationCheckOffset = get_pnp_offset();
75 /* Legacy16InitializeYourself */
77 handle_csm_0000(struct bregs *regs)
81 dprintf(3, "Legacy16InitializeYourself table %04x:%04x\n", regs->es,
84 csm_init_table = MAKE_FLATPTR(regs->es, regs->bx);
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);
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);
105 /* Legacy16UpdateBbs */
107 handle_csm_0001(struct bregs *regs)
114 dprintf(3, "Legacy16UpdateBbs table %04x:%04x\n", regs->es, regs->bx);
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);
138 handle_csm_0002(struct bregs *regs)
145 dprintf(3, "PrepareToBoot table %04x:%04x\n", regs->es, regs->bx);
147 struct e820entry *p = (void *)csm_compat_table.E820Pointer;
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);
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);
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);
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);
169 find_acpi_features();
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);
177 // MPTABLE is just there; we don't care where.
179 // EFI may have reinitialised the video using its *own* driver.
180 enable_vga_console();
182 // EFI fills this in for us. Zero it for now...
183 struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0);
189 device_hardware_setup();
191 interactive_bootmenu();
200 handle_csm_0003(struct bregs *regs)
207 dprintf(3, "Boot\n");
214 /* Legacy16DispatchOprom */
216 handle_csm_0005(struct bregs *regs)
218 EFI_DISPATCH_OPROM_TABLE *table = MAKE_FLATPTR(regs->es, regs->bx);
219 struct rom_header *rom;
222 if (!CONFIG_OPTIONROMS) {
227 dprintf(3, "Legacy16DispatchOprom rom %p\n", table);
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);
236 rom = MAKE_FLATPTR(table->OpromSegment, 0);
237 bdf = pci_bus_devfn_to_bdf(table->PciBus, table->PciDeviceFunction);
239 rom_reserve(rom->size * 512);
241 // XX PnP seg/ofs should never be other than default
244 rom_confirm(rom->size * 512);
246 regs->bx = 0; // FIXME
250 /* Legacy16GetTableAddress */
252 handle_csm_0006(struct bregs *regs)
255 u16 align = regs->dx;
256 u16 region = regs->bx; // (1 for F000 seg, 2 for E000 seg, 0 for either)
262 dprintf(3, "Legacy16GetTableAddress size %x align %x region %d\n",
263 size, align, region);
266 chunk = _malloc(&ZoneLow, size, align);
267 if (!chunk && (region & 1))
268 chunk = _malloc(&ZoneFSeg, size, align);
270 dprintf(3, "Legacy16GetTableAddress size %x align %x region %d yields %p\n",
271 size, align, region, chunk);
273 regs->ds = FLATPTR_TO_SEG(chunk);
274 regs->bx = FLATPTR_TO_OFFSET(chunk);
282 handle_csm(struct bregs *regs)
289 dprintf(3, "handle_csm regs %p AX=%04x\n", regs, regs->ax);
291 pic_irqmask_write(PICMask);
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;
309 int csm_bootprio_ata(struct pci_device *pci, int chanid, int slave)
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;
320 int csm_bootprio_fdc(struct pci_device *pci, int port, int fdid)
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;
329 int csm_bootprio_pci(struct pci_device *pci)
333 BBS_TABLE *bbs = (void *)csm_boot_table->BbsTable;
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;