SeaBIOS is an open source implementation of a 16-bit X86 BIOS. It can run in an emulator or natively on X86 hardware with the use of coreboot. With SeaBIOS's help, we can boot some OSes that require 16-bit BIOS services like Windows/DOS.
As U-Boot, we have to manually create a table where SeaBIOS gets system information (eg: E820) from. The table unfortunately has to follow the coreboot table format as SeaBIOS currently supports booting as a coreboot payload. No U-Boot native support there.
Booting SeaBIOS is done via U-Boot's bootelf command.
This is the initial attempt to support booting SeaBIOS from U-Boot. If the basic concept is good, I can spend time working on follow-on patches to enable BIOS tables as well as graphics support. One issue is that U-Boot x86 does not has a ROM file system like coreboot. This brings difficulities to pass PCI option ROM to SeaBIOS, if we don't modify SeaBIOS's source codes. Maybe we should promote CBFS in U-Boot x86?
This is tested on an Intel Crown Bay board with VGA card, booting SeaBIOS then chain loading a GRUB on a USB drive, then Linux kernel finally.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
---
arch/x86/Kconfig | 10 ++++++++++ arch/x86/include/asm/tables.h | 29 +++++++++++++++++++++++++++++ arch/x86/lib/tables.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 5e42d7d..b432ff8 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -401,6 +401,16 @@ config PCIE_ECAM_SIZE so a default 0x10000000 size covers all of the 256 buses which is the maximum number of PCI buses as defined by the PCI specification.
+config SEABIOS + bool "Support booting SeaBIOS" + help + SeaBIOS is an open source implementation of a 16-bit X86 BIOS. + It can run in an emulator or natively on X86 hardware with the use + of coreboot/U-Boot. By turning on this option, U-Boot prepares + all the configuration tables that are necessary to boot SeaBIOS. + + Check http://www.seabios.org/SeaBIOS for details. + source "arch/x86/lib/efi/Kconfig"
endmenu diff --git a/arch/x86/include/asm/tables.h b/arch/x86/include/asm/tables.h index 0aa6d9b..a083cac 100644 --- a/arch/x86/include/asm/tables.h +++ b/arch/x86/include/asm/tables.h @@ -7,6 +7,32 @@ #ifndef _X86_TABLES_H_ #define _X86_TABLES_H_
+#ifdef CONFIG_SEABIOS + +#define CB_TAG_MEMORY 1 + +struct cb_header { + u8 signature[4]; + u32 header_bytes; + u32 header_checksum; + u32 table_bytes; + u32 table_checksum; + u32 table_entries; +}; + +struct cb_memory_range { + u64 start; + u64 size; + u32 type; +}; + +struct cb_memory { + u32 tag; + u32 size; + struct cb_memory_range map[0]; +}; +#endif + /* * All x86 tables happen to like the address range from 0xf0000 to 0x100000. * We use 0xf0000 as the starting address to store those tables, including @@ -14,6 +40,9 @@ */ #define ROM_TABLE_ADDR 0xf0000
+/* SeaBIOS expects coreboot tables at address range 0x0000-0x1000 */ +#define CB_TABLE_ADDR 0x800 + /** * table_compute_checksum() - Compute a table checksum * diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c index f15b2e2..5849b2f 100644 --- a/arch/x86/lib/tables.c +++ b/arch/x86/lib/tables.c @@ -9,6 +9,7 @@ #include <asm/mpspec.h> #include <asm/tables.h> #include <asm/acpi_table.h> +#include <asm/e820.h>
u8 table_compute_checksum(void *v, int len) { @@ -36,6 +37,41 @@ void table_fill_string(char *dest, const char *src, size_t n, char pad) dest[i] = pad; }
+#ifdef CONFIG_SEABIOS +static u32 write_cb_tables(u32 addr) +{ + struct cb_header *cbh = (struct cb_header *)addr; + struct cb_memory *mem; + struct cb_memory_range *map; + struct e820entry entry[32]; + int num, i; + + memset(cbh, 0, sizeof(struct cb_header)); + strncpy((char *)cbh->signature, "LBIO", 4); + cbh->header_bytes = sizeof(struct cb_header); + + /* populate memory map table */ + mem = (struct cb_memory *)(cbh + 1); + mem->tag = CB_TAG_MEMORY; + map = mem->map; + num = install_e820_map(32, entry); + for (i = 0; i < num; i++) { + map->start = entry[i].addr; + map->size = entry[i].size; + map->type = entry[i].type; + map++; + } + mem->size = num * sizeof(struct cb_memory_range) + 8; + + cbh->table_bytes = mem->size; + cbh->table_checksum = compute_ip_checksum(mem, cbh->table_bytes); + cbh->table_entries = 1; + cbh->header_checksum = compute_ip_checksum(cbh, cbh->header_bytes); + + return (u32)map; +} +#endif + void write_tables(void) { u32 __maybe_unused rom_table_end = ROM_TABLE_ADDR; @@ -56,4 +92,7 @@ void write_tables(void) rom_table_end = write_acpi_tables(rom_table_end); rom_table_end = ALIGN(rom_table_end, 1024); #endif +#ifdef CONFIG_SEABIOS + write_cb_tables(CB_TABLE_ADDR); +#endif }