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(a)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.
--
1.8.0.2
--
dwmw2