Not particularly functional, but it's a start...
Build with CONFIG_CSM enabled (and CONFIG_RELOCATE_INIT disabled) and drop the resulting bios.bin into OvmfPkg/Csm/Csm16/Csm16.bin in your EDK-II build tree, then build with 'build -D CSM_ENABLE'.
You'll see it initialise SeaBIOS as a CSM as it's starting up, and then crash in a storm of what Qemu's debug log says is 'hardware INT=0x68'... which I suppose is what I have to debug next...
Signed-off-by: David Woodhouse David.Woodhouse@intel.com --- Makefile | 2 +- src/Kconfig | 7 +++ src/csm.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/post.c | 3 ++ src/romlayout.S | 7 +++ src/shadow.c | 6 +-- 6 files changed, 163 insertions(+), 4 deletions(-) create mode 100644 src/csm.c
diff --git a/Makefile b/Makefile index f28d86c..cb8ecdf 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SRCBOTH=misc.c stacks.c pmm.c output.c util.c block.c floppy.c ata.c mouse.c \ pnpbios.c pirtable.c vgahooks.c ramdisk.c pcibios.c blockcmd.c \ usb.c usb-uhci.c usb-ohci.c usb-ehci.c usb-hid.c usb-msc.c \ virtio-ring.c virtio-pci.c virtio-blk.c virtio-scsi.c apm.c ahci.c \ - usb-uas.c lsi-scsi.c esp-scsi.c megasas.c + usb-uas.c lsi-scsi.c esp-scsi.c megasas.c csm.c SRC16=$(SRCBOTH) system.c disk.c font.c SRC32FLAT=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \ acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \ diff --git a/src/Kconfig b/src/Kconfig index 0b112ed..f35b0f5 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -27,6 +27,13 @@ endchoice help Configure to be used by xen hvmloader, for a HVM guest.
+ config CSM + bool "Build as Compatibilty Support Module for EFI BIOS" + default n + help + Configure to be used by EFI firmware as Compatibility Support + module (CSM) to provide legacy BIOS services. + config THREADS bool "Parallelize hardware init" default y diff --git a/src/csm.c b/src/csm.c new file mode 100644 index 0000000..7ff173b --- /dev/null +++ b/src/csm.c @@ -0,0 +1,142 @@ +// CSM table generation (for providing legacy BIOS support to EFI) +// +// Copyright © 2012 Intel Corporation +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "config.h" // CONFIG_* +#include "csm.h" +#include "util.h" // checksum +#include "bregs.h" + + +#if CONFIG_CSM +extern void entry_csm16(void); +EFI_COMPATIBILITY16_TABLE csm_compat_table VAR16EXPORT __aligned(16) = { + .Signature = 0x24454649, + .TableChecksum = 0 /* Filled in by checkrom.py */, + .TableLength = sizeof(csm_compat_table), + .Compatibility16CallSegment = SEG_BIOS, + .Compatibility16CallOffset = 0 /* Filled in by checkrom.py */, + .OemIdStringPointer = (u32)"SeaBIOS", +}; +#endif + +extern void handle_post(void); +extern void _cfunc32flat_handle_csm16(struct bregs *); + +EFI_TO_COMPATIBILITY16_INIT_TABLE *csm_init_table; +EFI_TO_COMPATIBILITY16_BOOT_TABLE *csm_boot_table; + +/* Legacy16InitializeYourself */ +void handle_csm_0000(struct bregs *regs) +{ + dprintf(3, "Legacy16InitializeYourself table %04x:%04x\n", regs->es, + regs->bx); + + csm_init_table = MAKE_FLATPTR(regs->es, regs->bx); + + dprintf(3, "BiosLessThan1MB %08x\n", csm_init_table->BiosLessThan1MB); + dprintf(3, "HiPmmMemory %08x\n", csm_init_table->HiPmmMemory); + dprintf(3, "HiPmmMemorySize %08x\n", csm_init_table->HiPmmMemorySizeInBytes); + dprintf(3, "ReverseThunk %04x:%04x\n", csm_init_table->ReverseThunkCallSegment, + csm_init_table->ReverseThunkCallOffset); + dprintf(3, "NumE820Entries %08x\n", csm_init_table->NumberE820Entries); + dprintf(3, "OsMemoryAbove1M %08x\n", csm_init_table->OsMemoryAbove1Mb); + dprintf(3, "ThunkStart %08x\n", csm_init_table->ThunkStart); + dprintf(3, "ThunkSize %08x\n", csm_init_table->ThunkSizeInBytes); + dprintf(3, "LoPmmMemory %08x\n", csm_init_table->LowPmmMemory); + dprintf(3, "LoPmmMemorySize %08x\n", csm_init_table->LowPmmMemorySizeInBytes); + + handle_post(); + regs->ax = 0; +} + +/* Legacy16UpdateBbs */ +void handle_csm_0001(struct bregs *regs) +{ + dprintf(3, "Legacy16UpdateBbs table %04x:%04x\n", regs->es, regs->bx); + + csm_boot_table = MAKE_FLATPTR(regs->es, regs->bx); + dprintf(3, "MajorVersion %04x\n", csm_boot_table->MajorVersion); + dprintf(3, "MinorVersion %04x\n", csm_boot_table->MinorVersion); + dprintf(3, "AcpiTable %08x\n", csm_boot_table->AcpiTable); + dprintf(3, "SmbiosTable %08x\n", csm_boot_table->SmbiosTable); + dprintf(3, "SmbiosTableLength %08x\n", csm_boot_table->SmbiosTableLength); +// dprintf(3, "SioData %08x\n", csm_boot_table->SioData); + dprintf(3, "DevicePathType %04x\n", csm_boot_table->DevicePathType); + dprintf(3, "PciIrqMask %04x\n", csm_boot_table->PciIrqMask); + dprintf(3, "NumberE820Entries %08x\n", csm_boot_table->NumberE820Entries); +// dprintf(3, "HddInfo %08x\n", csm_boot_table->HddInfo); + dprintf(3, "NumberBbsEntries %08x\n", csm_boot_table->NumberBbsEntries); + dprintf(3, "BBsTable %08x\n", csm_boot_table->BbsTable); + dprintf(3, "SmmTable %08x\n", csm_boot_table->SmmTable); + dprintf(3, "OsMemoryAbove1Mb %08x\n", csm_boot_table->OsMemoryAbove1Mb); + dprintf(3, "UnconventionalDeviceTable %08x\n", csm_boot_table->UnconventionalDeviceTable); + + regs->ax = 0; +} + +/* Legacy16DispatchOprom */ +void handle_csm_0005(struct bregs *regs) +{ + EFI_DISPATCH_OPROM_TABLE *rom = MAKE_FLATPTR(regs->es, regs->bx); + + dprintf(3, "Legacy16DispatchOprom rom %p\n", rom); + + dprintf(3, "OpromSegment %04x\n", rom->OpromSegment); + dprintf(3, "RuntimeSegment %04x\n", rom->RuntimeSegment); + + /* FIXME: Actually do it! */ + + regs->ax = 0; +} + +/* Legacy16GetTableAddress */ +void handle_csm_0006(struct bregs *regs) +{ + u16 size = regs->cx; + u16 align = regs->dx; + u16 region = regs->bx; // (1 for F000 seg, 2 for E000 seg, 0 for either) + void *chunk; + + /* FIXME: I don't know if we can allocate in the E000 segment at all. */ + dprintf(3, "Legacy16GetTableAddress size %x align %x region %d\n", + size, align, region); + chunk = pmm_malloc(&ZoneFSeg, PMM_DEFAULT_HANDLE, size, align); + dprintf(3, "Legacy16GetTableAddress size %x align %x region %d yields %p\n", + size, align, region, chunk); + if (chunk) { + regs->ds = FLATPTR_TO_SEG(chunk); + regs->bx = FLATPTR_TO_OFFSET(chunk); + regs->ax = 0; + } else { + regs->ax = 1; + } +} + +void __VISIBLE +handle_csm16(struct bregs *regs) +{ + if (MODESEGMENT) { + void *flatptr = MAKE_FLATPTR(GET_SEG(SS), regs); + call32(_cfunc32flat_handle_csm16, (u32)flatptr, 0); + return; + } + dprintf(3, "handle_csm16 AX=%04x\n", regs->ax); + + switch(regs->ax) { + case 0000: handle_csm_0000(regs); break; + case 0001: handle_csm_0001(regs); break; +// case 0002: handle_csm_0002(regs); break; +// case 0003: handle_csm_0003(regs); break; +// case 0004: handle_csm_0004(regs); break; + case 0005: handle_csm_0005(regs); break; + case 0006: handle_csm_0006(regs); break; +// case 0007: handle_csm_0007(regs); break; +// case 0008: hamdle_csm_0008(regs); break; + default: regs->al = 1; + } + + dprintf(3, "handle_csm16 returning AX=%04x\n", regs->ax); +} diff --git a/src/post.c b/src/post.c index f3b56b8..dc07e8b 100644 --- a/src/post.c +++ b/src/post.c @@ -225,6 +225,9 @@ maininit(void) init_ivt(); init_bda();
+ if (CONFIG_CSM) + return; + // Init base pc hardware. pic_setup(); timer_setup(); diff --git a/src/romlayout.S b/src/romlayout.S index 8125277..f1a276e 100644 --- a/src/romlayout.S +++ b/src/romlayout.S @@ -468,6 +468,13 @@ irqentryarg: DECL_IRQ_ENTRY hwpic1 DECL_IRQ_ENTRY hwpic2
+#if CONFIG_CSM + EXPORTFUNC entry_csm16 +entry_csm16: + ENTRY_ARG handle_csm16 + iretw +#endif + // int 18/19 are special - they reset stack and call into 32bit mode. DECLFUNC entry_19 entry_19: diff --git a/src/shadow.c b/src/shadow.c index a2195da..881d5a6 100644 --- a/src/shadow.c +++ b/src/shadow.c @@ -119,7 +119,7 @@ static const struct pci_device_id dram_controller_make_readonly_tbl[] = { void make_bios_writable(void) { - if (CONFIG_COREBOOT || usingXen()) + if (CONFIG_COREBOOT || CONFIG_CSM || usingXen()) return;
dprintf(3, "enabling shadow ram\n"); @@ -148,7 +148,7 @@ make_bios_writable(void) void make_bios_readonly(void) { - if (CONFIG_COREBOOT || usingXen()) + if (CONFIG_COREBOOT || CONFIG_CSM || usingXen()) return;
dprintf(3, "locking shadow ram\n"); @@ -161,7 +161,7 @@ make_bios_readonly(void) void qemu_prep_reset(void) { - if (CONFIG_COREBOOT) + if (CONFIG_COREBOOT || CONFIG_CSM ) return; // QEMU doesn't map 0xc0000-0xfffff back to the original rom on a // reset, so do that manually before invoking a hard reset.