This change allows seabios to load bootorder not only from CBFS but also from the NVRAM as well, making use of coreboot's cmos.layout.
Tested on QEMU Q35 >From 055a831ed9872b99bf6d060c70b495e286ded1ba Mon Sep 17 00:00:00 2001 From: Timothy Kenno Handojo <timken...@mailbox.org> Date: Thu, 31 Oct 2024 08:11:38 +0700 Subject: [PATCH] boot: Allow setting bootorder from CMOS entry The original bootorder from CBFS remains, but takes lower priority. Signed-off-by: Timothy Kenno Handojo <timken...@mailbox.org> --- Makefile | 2 +- src/boot.c | 9 +++- src/nvram.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/nvram.h | 37 +++++++++++++++ 4 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 src/nvram.c create mode 100644 src/nvram.h diff --git a/Makefile b/Makefile index d3341870..48f0b9ac 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,7 @@ SRC32FLAT=$(SRCBOTH) post.c e820map.c malloc.c romfile.c x86.c \ fw/mtrr.c fw/xen.c fw/acpi.c fw/mptable.c fw/pirtable.c \ fw/smbios.c fw/romfile_loader.c fw/dsdt_parser.c hw/virtio-ring.c \ hw/virtio-pci.c hw/virtio-mmio.c hw/virtio-blk.c hw/virtio-scsi.c \ - hw/tpm_drivers.c hw/nvme.c sha256.c sha512.c + hw/tpm_drivers.c hw/nvme.c sha256.c sha512.c nvram.c SRC32SEG=string.c output.c pcibios.c apm.c stacks.c hw/pci.c hw/serialio.c DIRS=src src/hw src/fw vgasrc diff --git a/src/boot.c b/src/boot.c index 1effd802..0689d7de 100644 --- a/src/boot.c +++ b/src/boot.c @@ -21,6 +21,8 @@ #include "string.h" // memset #include "util.h" // irqtimer_calc #include "tcgbios.h" // tpm_* +#include "nvram.h" // get_nvram_bootorder + /**************************************************************** * Helper search functions @@ -250,8 +252,13 @@ loadBootOrder(void) { if (!CONFIG_BOOTORDER) return; + char *f = NULL; + + f = get_nvram_bootorder(); + + if (!f) + f = romfile_loadfile("bootorder", NULL); - char *f = romfile_loadfile("bootorder", NULL); if (!f) return; diff --git a/src/nvram.c b/src/nvram.c new file mode 100644 index 00000000..0634cf9c --- /dev/null +++ b/src/nvram.c @@ -0,0 +1,130 @@ +#include "nvram.h" +#include "string.h" // memcmp, strlen +#include "malloc.h" // malloc_low +#include "x86.h" // inb, outb +#include "output.h" // dprintf +#include "util.h" // cb_header, find_cb_table, find_cb_subtable + +#define CB_TAG_CMOS_OPTION_TABLE 0x00c8 +#define CB_TAG_OPTION 0x00c9 +#define CB_TAG_OPTION_CHECKSUM 0x00cc + + +u8 nvram_read(u8 addr){ + u16 rtc_port = addr < 128 ? RTC_PORT_STANDARD : RTC_PORT_EXTENDED; + + outb(addr, rtc_port); + return inb(rtc_port + 1); +} + +void nvram_write(u8 val, u8 addr) +{ + u16 rtc_port = addr < 128 ? RTC_PORT_STANDARD : RTC_PORT_EXTENDED; + + outb(addr, rtc_port); + outb(val, rtc_port + 1); +} + +struct nvram_accessor { + u8 (*read)(u8 reg); + void (*write)(u8 val, u8 reg); +}; + +struct nvram_accessor *use_nvram = &(struct nvram_accessor) { + nvram_read, + nvram_write +}; + +static struct cb_cmos_entries *lookup_cmos_entry(struct cb_cmos_option_table *option_table, const char *name) +{ + struct cb_cmos_entries *cmos_entry, *next; + int len = name ? strlen(name) : 0; + + /* CMOS entries are located right after the option table */ + cmos_entry = (struct cb_cmos_entries*)((unsigned char *)option_table + option_table->header_length); + while (cmos_entry) { + if (memcmp((const char*)cmos_entry->name, name, len) == 0) + return cmos_entry; + next = (struct cb_cmos_entries*)((unsigned char *)cmos_entry + cmos_entry->size); + cmos_entry = (next->tag == CB_TAG_OPTION) ? next : NULL; + } + + dprintf(1, "ERROR: No such CMOS option (%s)\n", name); + return NULL; +} + +static int get_cmos_value(const struct nvram_accessor *nvram, u32 bitnum, u32 len, void *valptr) +{ + u8 *value = valptr; + int offs = 0; + u32 addr, bit; + u8 reg8; + + /* Convert to byte borders */ + addr=(bitnum / 8); + bit=(bitnum % 8); + + /* Handle single byte or less */ + if(len <= 8) { + reg8 = nvram->read(addr); + reg8 >>= bit; + value[0] = reg8 & ((1 << len) -1); + return 0; + } + + /* When handling more than a byte, copy whole bytes */ + while (len > 0) { + len -= 8; + value[offs++]=nvram->read(addr++); + } + + return 0; +} + +int options_checksum_valid(const struct nvram_accessor *nvram, struct cb_cmos_checksum *option_checksum) +{ + int i; + int checksum_location = option_checksum->location / 8; + u16 checksum = 0, checksum_old; + + for(i = option_checksum->range_start; i <= option_checksum->range_end; i++) { + checksum += nvram->read(i); + } + + checksum_old = ((nvram->read(checksum_location)<<8) | nvram->read(checksum_location+1)); + + return (checksum_old == checksum); +} + +void *get_nvram_bootorder() +{ + const char *name = "bootorder"; + struct cb_header *cbh = find_cb_table(); + + if (!cbh) + return NULL; + struct cb_cmos_option_table *option_table = find_cb_subtable(cbh, CB_TAG_CMOS_OPTION_TABLE); + struct cb_cmos_checksum *option_checksum = find_cb_subtable(cbh, CB_TAG_OPTION_CHECKSUM); + if (option_table == NULL) { + dprintf(1, "Could not find coreboot option table.\n"); + return NULL; + } + + struct cb_cmos_entries *cmos_entry = lookup_cmos_entry(option_table, name); + + if (!cmos_entry) + return NULL; + int cmos_length = cmos_entry->length; + + /* extra byte to ensure 0-terminated strings */ + void *buf = malloc_low(cmos_length+1); + memset(buf, 0, cmos_length+1); + + if(!options_checksum_valid(use_nvram, option_checksum)) { + dprintf(1, "Invalid option checksum.\n"); + return NULL; + } + get_cmos_value(use_nvram, cmos_entry->bit, cmos_entry->length, buf); + + return buf; +} diff --git a/src/nvram.h b/src/nvram.h new file mode 100644 index 00000000..4c9d559e --- /dev/null +++ b/src/nvram.h @@ -0,0 +1,37 @@ +#ifndef __NVRAM_H +#define __NVRAM_H + +#include "types.h" // u32, u8 + +#define RTC_PORT_STANDARD 0x70 +#define RTC_PORT_EXTENDED 0x72 + +struct cb_cmos_option_table { + u32 tag; + u32 size; + u32 header_length; +}; + +#define CB_CMOS_MAX_NAME_LENGTH 32 +struct cb_cmos_entries { + u32 tag; + u32 size; + u32 bit; + u32 length; + u32 config; + u32 config_id; + u8 name[CB_CMOS_MAX_NAME_LENGTH]; +}; + +struct cb_cmos_checksum { + u32 tag; + u32 size; + u32 range_start; + u32 range_end; + u32 location; + u32 type; +}; + +void *get_nvram_bootorder(); + +#endif \ No newline at end of file -- 2.39.5 _______________________________________________ SeaBIOS mailing list -- seabios@seabios.org To unsubscribe send an email to seabios-le...@seabios.org