[U-Boot] [RFC PATCH] x86: Support booting SeaBIOS

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 }

Hi Bin,
On 29 September 2015 at 11:17, Bin Meng bmeng.cn@gmail.com wrote:
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.
Looks good to me. I think it is OK to use CBFS if needed - are you thinking of an option to build u-boot.rom as a CBFS filesystem?
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);
memcpy()?
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);
ARRAY_SIZE(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;
What is 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 } -- 1.8.2.1
Regards, Simon

Hi Simon,
On Sat, Oct 3, 2015 at 10:29 PM, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 29 September 2015 at 11:17, Bin Meng bmeng.cn@gmail.com wrote:
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.
Looks good to me. I think it is OK to use CBFS if needed - are you thinking of an option to build u-boot.rom as a CBFS filesystem?
If using CBFS, that means we may have to abandon ifdtool? Or maybe mixed usage of both tools?
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);
memcpy()?
Yes.
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);
ARRAY_SIZE(entry)
Yes
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;
What is 8?
It's sizeof(struct cb_memory) - sizeof(struct cb_memory_range)
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 } --
Regards, Bin

Hi Bin,
On 10 October 2015 at 02:57, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Sat, Oct 3, 2015 at 10:29 PM, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 29 September 2015 at 11:17, Bin Meng bmeng.cn@gmail.com wrote:
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.
Looks good to me. I think it is OK to use CBFS if needed - are you thinking of an option to build u-boot.rom as a CBFS filesystem?
If using CBFS, that means we may have to abandon ifdtool? Or maybe mixed usage of both tools?
So far I'm not sure of the best approach. At present we have the ROM offsets stored mostly in Kconfig, with the MRC area in the SPI flash device tree node. The environment is also in Kconfig.
What sort of option ROMs do you want to support? What other options does seabios provide?
What does SEA stand for?
[snip]
Regards, Simon

Hi Simon,
On Mon, Oct 19, 2015 at 10:51 AM, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 10 October 2015 at 02:57, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Sat, Oct 3, 2015 at 10:29 PM, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 29 September 2015 at 11:17, Bin Meng bmeng.cn@gmail.com wrote:
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.
Looks good to me. I think it is OK to use CBFS if needed - are you thinking of an option to build u-boot.rom as a CBFS filesystem?
If using CBFS, that means we may have to abandon ifdtool? Or maybe mixed usage of both tools?
So far I'm not sure of the best approach. At present we have the ROM offsets stored mostly in Kconfig, with the MRC area in the SPI flash device tree node. The environment is also in Kconfig.
What sort of option ROMs do you want to support? What other options does seabios provide?
I believe SeaBIOS can run any kind of PCI option ROMs, but I have never tested other than vgabios. Also per coreboot's documentation, booting Windows needs SeaBIOS.
What does SEA stand for?
I guess it's because most of SeaBIOS's source codes are written in 'C', thus a 'C' BIOS.
Regards, Bin
participants (2)
-
Bin Meng
-
Simon Glass