aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2013-01-25 19:46:25 -0600
committerKevin O'Connor <kevin@koconnor.net>2013-02-07 20:00:05 -0500
commit118469aa784698953e16287f235bb272f5b4ee46 (patch)
tree06f597d784bc7e24726a1f99fd48ff9cd2bb46e9 /src
parenta3c48f51576b970ba339f4713fb5b319fa31da10 (diff)
downloadseabios-118469aa784698953e16287f235bb272f5b4ee46.tar.gz
Add CSM support
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Diffstat (limited to 'src')
-rw-r--r--src/Kconfig6
-rw-r--r--src/boot.c7
-rw-r--r--src/csm.c299
-rw-r--r--src/csm.h18
-rw-r--r--src/pmm.c19
-rw-r--r--src/romlayout.S50
-rw-r--r--src/util.h2
7 files changed, 401 insertions, 0 deletions
diff --git a/src/Kconfig b/src/Kconfig
index 0b112edd..55396c65 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -18,6 +18,12 @@ choice
help
Configure as QEMU bios.
+ config CSM
+ bool "Build as Compatibilty Support Module for EFI BIOS"
+ help
+ Configure to be used by EFI firmware as Compatibility Support
+ module (CSM) to provide legacy BIOS services.
+
endchoice
config XEN
diff --git a/src/boot.c b/src/boot.c
index 3bafa5a0..85d5051b 100644
--- a/src/boot.c
+++ b/src/boot.c
@@ -14,6 +14,7 @@
#include "paravirt.h" // qemu_cfg_show_boot_menu
#include "pci.h" // pci_bdf_to_*
#include "usb.h" // struct usbdevice_s
+#include "csm.h" // csm_bootprio_*
/****************************************************************
@@ -120,6 +121,8 @@ build_pci_path(char *buf, int max, const char *devname, struct pci_device *pci)
int bootprio_find_pci_device(struct pci_device *pci)
{
+ if (CONFIG_CSM)
+ return csm_bootprio_pci(pci);
if (!CONFIG_BOOTORDER)
return -1;
// Find pci device - for example: /pci@i0cf8/ethernet@5
@@ -144,6 +147,8 @@ int bootprio_find_scsi_device(struct pci_device *pci, int target, int lun)
int bootprio_find_ata_device(struct pci_device *pci, int chanid, int slave)
{
+ if (CONFIG_CSM)
+ return csm_bootprio_ata(pci, chanid, slave);
if (!CONFIG_BOOTORDER)
return -1;
if (!pci)
@@ -158,6 +163,8 @@ int bootprio_find_ata_device(struct pci_device *pci, int chanid, int slave)
int bootprio_find_fdc_device(struct pci_device *pci, int port, int fdid)
{
+ if (CONFIG_CSM)
+ return csm_bootprio_fdc(pci, port, fdid);
if (!CONFIG_BOOTORDER)
return -1;
if (!pci)
diff --git a/src/csm.c b/src/csm.c
new file mode 100644
index 00000000..169b608d
--- /dev/null
+++ b/src/csm.c
@@ -0,0 +1,299 @@
+// Compatibility Support Module (CSM) for UEFI / EDK-II
+//
+// Copyright © 2013 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"
+#include "optionroms.h"
+#include "pci.h"
+#include "memmap.h"
+#include "biosvar.h"
+#include "post.h"
+#include "acpi.h"
+#include "boot.h"
+#include "smbios.h"
+#include "pic.h"
+
+struct rsdp_descriptor VAR32FLATVISIBLE __aligned(16) csm_rsdp;
+
+EFI_COMPATIBILITY16_TABLE csm_compat_table VAR32FLATVISIBLE __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",
+ .AcpiRsdPtrPointer = (u32)&csm_rsdp,
+};
+
+
+EFI_TO_COMPATIBILITY16_INIT_TABLE *csm_init_table;
+EFI_TO_COMPATIBILITY16_BOOT_TABLE *csm_boot_table;
+
+extern void csm_return(struct bregs *regs) __noreturn;
+
+static void
+csm_maininit(struct bregs *regs)
+{
+ interface_init();
+ pci_probe_devices();
+
+ csm_compat_table.PnPInstallationCheckSegment = SEG_BIOS;
+ csm_compat_table.PnPInstallationCheckOffset = get_pnp_offset();
+
+ regs->ax = 0;
+
+ // Return directly to UEFI instead of unwinding stack.
+ pic_save_mask();
+ dprintf(3, "csm_maininit fast returning AX=%04x\n", regs->ax);
+ csm_return(regs);
+}
+
+/* Legacy16InitializeYourself */
+static 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);
+
+ csm_malloc_preinit(csm_init_table->LowPmmMemory,
+ csm_init_table->LowPmmMemorySizeInBytes,
+ csm_init_table->HiPmmMemory,
+ csm_init_table->HiPmmMemorySizeInBytes);
+ reloc_preinit(csm_maininit, regs);
+}
+
+/* Legacy16UpdateBbs */
+static 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;
+}
+
+/* PrepareToBoot */
+static void
+handle_csm_0002(struct bregs *regs)
+{
+ dprintf(3, "PrepareToBoot table %04x:%04x\n", regs->es, regs->bx);
+
+ struct e820entry *p = (void *)csm_compat_table.E820Pointer;
+ int i;
+ for (i=0; i < csm_compat_table.E820Length / sizeof(struct e820entry); i++)
+ add_e820(p[i].start, p[i].size, p[i].type);
+
+ if (csm_init_table->HiPmmMemorySizeInBytes > CONFIG_MAX_HIGHTABLE) {
+ u32 hi_pmm_end = csm_init_table->HiPmmMemory + csm_init_table->HiPmmMemorySizeInBytes;
+ add_e820(hi_pmm_end - CONFIG_MAX_HIGHTABLE, CONFIG_MAX_HIGHTABLE, E820_RESERVED);
+ }
+
+ // For PCIBIOS 1ab10e
+ if (csm_compat_table.IrqRoutingTablePointer &&
+ csm_compat_table.IrqRoutingTableLength) {
+ PirAddr = (void *)csm_compat_table.IrqRoutingTablePointer;
+ dprintf(3, "CSM PIRQ table at %p\n", PirAddr);
+ }
+
+ // For find_resume_vector()... and find_pmtimer()
+ if (csm_rsdp.signature == RSDP_SIGNATURE) {
+ RsdpAddr = &csm_rsdp;
+ dprintf(3, "CSM ACPI RSDP at %p\n", RsdpAddr);
+ }
+
+ // SMBIOS table needs to be copied into the f-seg
+ // XX: OVMF doesn't seem to set SmbiosTableLength so don't check it
+ if (csm_boot_table->SmbiosTable && !SMBiosAddr)
+ copy_smbios((void *)csm_boot_table->SmbiosTable);
+
+ // MPTABLE is just there; we don't care where.
+
+ // EFI may have reinitialised the video using its *own* driver.
+ enable_vga_console();
+
+ // EFI fills this in for us. Zero it for now...
+ struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0);
+ bda->hdcount = 0;
+
+ timer_setup();
+ device_hardware_setup();
+ wait_threads();
+ interactive_bootmenu();
+
+ prepareboot();
+
+ regs->ax = 0;
+}
+
+/* Boot */
+static void
+handle_csm_0003(struct bregs *regs)
+{
+ dprintf(3, "Boot\n");
+
+ startBoot();
+
+ regs->ax = 1;
+}
+
+/* Legacy16DispatchOprom */
+static void
+handle_csm_0005(struct bregs *regs)
+{
+ EFI_DISPATCH_OPROM_TABLE *table = MAKE_FLATPTR(regs->es, regs->bx);
+ struct rom_header *rom;
+ u16 bdf;
+
+ dprintf(3, "Legacy16DispatchOprom rom %p\n", table);
+
+ dprintf(3, "OpromSegment %04x\n", table->OpromSegment);
+ dprintf(3, "RuntimeSegment %04x\n", table->RuntimeSegment);
+ dprintf(3, "PnPInstallationCheck %04x:%04x\n",
+ table->PnPInstallationCheckSegment,
+ table->PnPInstallationCheckOffset);
+ dprintf(3, "RuntimeSegment %04x\n", table->RuntimeSegment);
+
+ rom = MAKE_FLATPTR(table->OpromSegment, 0);
+ bdf = pci_bus_devfn_to_bdf(table->PciBus, table->PciDeviceFunction);
+
+ rom_confirm(rom->size * 512);
+
+ // XX PnP seg/ofs should never be other than default
+ callrom(rom, bdf);
+
+ regs->bx = 0; // FIXME
+ regs->ax = 0;
+}
+
+/* Legacy16GetTableAddress */
+static 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 = NULL;
+
+ if (!region)
+ region = 3;
+
+ dprintf(3, "Legacy16GetTableAddress size %x align %x region %d\n",
+ size, align, region);
+
+ if (region & 2)
+ chunk = pmm_malloc(&ZoneLow, PMM_DEFAULT_HANDLE, size, align);
+ if (!chunk && (region & 1))
+ 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 VISIBLE32INIT
+handle_csm(struct bregs *regs)
+{
+ ASSERT32FLAT();
+
+ if (!CONFIG_CSM)
+ return;
+
+ dprintf(3, "handle_csm16 regs %p AX=%04x\n", regs, regs->ax);
+
+ pic_restore_mask();
+
+ 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;
+ }
+
+ pic_save_mask();
+
+ dprintf(3, "handle_csm16 returning AX=%04x\n", regs->ax);
+}
+
+int csm_bootprio_ata(struct pci_device *pci, int chanid, int slave)
+{
+ if (!csm_boot_table)
+ return -1;
+ BBS_TABLE *bbs = (void *)csm_boot_table->BbsTable;
+ int index = 1 + (chanid * 2) + slave;
+ dprintf(3, "CSM bootprio for ATA%d,%d (index %d) is %d\n", chanid, slave,
+ index, bbs[index].BootPriority);
+ return bbs[index].BootPriority;
+}
+
+int csm_bootprio_fdc(struct pci_device *pci, int port, int fdid)
+{
+ if (!csm_boot_table)
+ return -1;
+ BBS_TABLE *bbs = (void *)csm_boot_table->BbsTable;
+ dprintf(3, "CSM bootprio for FDC is %d\n", bbs[0].BootPriority);
+ return bbs[0].BootPriority;
+}
+
+int csm_bootprio_pci(struct pci_device *pci)
+{
+ if (!csm_boot_table)
+ return -1;
+ BBS_TABLE *bbs = (void *)csm_boot_table->BbsTable;
+ int i;
+
+ for (i = 5; i < csm_boot_table->NumberBbsEntries; i++) {
+ if (pci->bdf == pci_to_bdf(bbs[i].Bus, bbs[i].Device, bbs[i].Function)) {
+ dprintf(3, "CSM bootprio for PCI(%d,%d,%d) is %d\n", bbs[i].Bus,
+ bbs[i].Device, bbs[i].Function, bbs[i].BootPriority);
+ return bbs[i].BootPriority;
+ }
+ }
+ return -1;
+}
diff --git a/src/csm.h b/src/csm.h
new file mode 100644
index 00000000..77e5bf05
--- /dev/null
+++ b/src/csm.h
@@ -0,0 +1,18 @@
+#ifndef __CSM_H
+#define __CSM_H
+
+#include "types.h"
+#include "pci.h"
+
+#define UINT8 u8
+#define UINT16 u16
+#define UINT32 u32
+
+// csm.c
+int csm_bootprio_fdc(struct pci_device *pci, int port, int fdid);
+int csm_bootprio_ata(struct pci_device *pci, int chanid, int slave);
+int csm_bootprio_pci(struct pci_device *pci);
+
+#include "LegacyBios.h"
+
+#endif // __CSM_H
diff --git a/src/pmm.c b/src/pmm.c
index 6092ea23..b3aa5279 100644
--- a/src/pmm.c
+++ b/src/pmm.c
@@ -256,6 +256,25 @@ malloc_preinit(void)
}
}
+void
+csm_malloc_preinit(u32 low_pmm, u32 low_pmm_size, u32 hi_pmm, u32 hi_pmm_size)
+{
+ ASSERT32FLAT();
+
+ if (hi_pmm_size > CONFIG_MAX_HIGHTABLE) {
+ void *hi_pmm_end = (void *)hi_pmm + hi_pmm_size;
+ addSpace(&ZoneTmpHigh, (void *)hi_pmm, hi_pmm_end - CONFIG_MAX_HIGHTABLE);
+ addSpace(&ZoneHigh, hi_pmm_end - CONFIG_MAX_HIGHTABLE, hi_pmm_end);
+ } else {
+ addSpace(&ZoneTmpHigh, (void *)hi_pmm, (void *)hi_pmm + hi_pmm_size);
+ }
+ addSpace(&ZoneTmpLow, (void *)low_pmm, (void *)low_pmm + low_pmm_size);
+ addSpace(&ZoneFSeg, BiosTableSpace, &BiosTableSpace[CONFIG_MAX_BIOSTABLE]);
+ extern u8 final_datalow_start[];
+ addSpace(&ZoneLow, datalow_base + OPROM_HEADER_RESERVE, final_datalow_start);
+ RomBase = findLast(&ZoneLow);
+}
+
// Update pointers after code relocation.
void
malloc_fixupreloc_init(void)
diff --git a/src/romlayout.S b/src/romlayout.S
index 81252771..cbe6b1c6 100644
--- a/src/romlayout.S
+++ b/src/romlayout.S
@@ -384,6 +384,56 @@ entry_elf:
.code16gcc
+ EXPORTFUNC entry_csm
+entry_csm:
+ // Backup register state
+ pushfw
+ cli
+ cld
+ pushl %eax // dummy
+ PUSHBREGS
+
+ // Backup stack location and convert to a "flat pointer"
+ movl %ss, %ebx
+ movw %bx, BREGS_code+2(%esp) // Store %ss in bregs->code.seg
+ shll $4, %ebx
+ addl %esp, %ebx
+
+ // Change to BUILD_STACK_ADDR stack
+ xorl %eax, %eax
+ movw %ax, %ss
+ movl $BUILD_STACK_ADDR, %esp
+
+ // Jump to 32bit mode and call handle_csm(bregs)
+ movl $(1f + BUILD_BIOS_ADDR), %edx
+ jmp transition32
+ .code32
+1: movl %ebx, %eax
+ calll _cfunc32flat_handle_csm - BUILD_BIOS_ADDR
+ movl $2f, %edx
+ jmp transition16big
+
+ .global csm_return
+csm_return:
+ movl %eax, %ebx
+ movl $2f, %edx
+ jmp transition16big
+ .code16gcc
+
+ // Switch back to original stack
+2: movzwl BREGS_code+2(%ebx), %eax
+ movl %eax, %ecx
+ shll $4, %ecx
+ subl %ecx, %ebx
+ movl %eax, %ss
+ movl %ebx, %esp
+
+ // Restore register state and return.
+ POPBREGS
+ addw $4, %sp // pop dummy
+ popfw
+ lretw
+
/****************************************************************
* Interrupt entry points
diff --git a/src/util.h b/src/util.h
index 84915edf..f486c85f 100644
--- a/src/util.h
+++ b/src/util.h
@@ -368,6 +368,8 @@ u32 rom_get_top(void);
u32 rom_get_last(void);
struct rom_header *rom_reserve(u32 size);
int rom_confirm(u32 size);
+void csm_malloc_preinit(u32 low_pmm, u32 low_pmm_size, u32 hi_pmm,
+ u32 hi_pmm_size);
void malloc_preinit(void);
void malloc_fixupreloc_init(void);
void malloc_prepboot(void);