From 94d3b1b5d1fc30bd7b63af9d07cb8db89a5f4868 Mon Sep 17 00:00:00 2001 From: "kaihuan.pkh" Date: Mon, 18 Nov 2019 20:08:36 +0800 Subject: support smbios alloc buffer in fseg memory and fill it with smbios anchor and tables which read from the fw_cfg, then check type0 table and rebuild it if it's not exist. mainly inspired by the seabios, and borrowed some code from it. Reviewed-by: Ben Luo Signed-off-by: kaihuan.pkh --- Makefile | 2 +- README | 1 - include/smbios.h | 1 + include/string.h | 2 + main.c | 3 +- smbios.c | 174 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ string.c | 8 +++ tables.c | 7 --- 8 files changed, 188 insertions(+), 10 deletions(-) create mode 100644 include/smbios.h create mode 100644 smbios.c diff --git a/Makefile b/Makefile index adbf1b3..b5970a8 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ obj-y = code16.o entry.o main.o string.o printf.o cstart.o fw_cfg.o obj-y += linuxboot.o malloc.o tables.o hwsetup.o pci.o code32seg.o -obj-y += mptable.o +obj-y += mptable.o smbios.o all-y = bios.bin all: $(all-y) diff --git a/README b/README index 7f45a06..e04e984 100644 --- a/README +++ b/README @@ -44,5 +44,4 @@ Usage TODO ==== -* SMBIOS tables * Add the possibility to configure out PIC and PCI bridge initialization diff --git a/include/smbios.h b/include/smbios.h new file mode 100644 index 0000000..ec033ce --- /dev/null +++ b/include/smbios.h @@ -0,0 +1 @@ +void extract_smbios(void); diff --git a/include/string.h b/include/string.h index d1bb037..cf9fde9 100644 --- a/include/string.h +++ b/include/string.h @@ -2,6 +2,7 @@ #define BIOS_STRING_H #include +#include unsigned long strlen(const char *buf); char *strcat(char *dest, const char *src); @@ -12,6 +13,7 @@ char *strstr(const char *s1, const char *s2); int memcmp(const void *s1, const void *s2, size_t n); void *memmove(void *dest, const void *src, size_t n); void *memchr(const void *s, int c, size_t n); +uint8_t csum8(uint8_t *buf, uint32_t len); static inline void *memset(void *s, int c, size_t n) { diff --git a/main.c b/main.c index ea67f3c..afa2200 100644 --- a/main.c +++ b/main.c @@ -7,6 +7,7 @@ #include "fw_cfg.h" #include "pci.h" #include "benchmark.h" +#include "smbios.h" static void set_realmode_int(int vec, void *p) { @@ -98,7 +99,7 @@ int __attribute__ ((section (".text.startup"))) main(void) extract_acpi(); extract_e820(); setup_mptable(); - // extract_smbios(); + extract_smbios(); boot_from_fwcfg(); panic(); } diff --git a/smbios.c b/smbios.c new file mode 100644 index 0000000..1ed98b6 --- /dev/null +++ b/smbios.c @@ -0,0 +1,174 @@ +#include +#include "smbios.h" +#include "string.h" +#include "fw_cfg.h" + +#define VERSION "0.1" +#define BIOS_NAME "qboot" +#define BIOS_DATE "11/11/2019" + +struct smbios_entry_point { + uint32_t signature; + uint8_t checksum; + uint8_t length; + uint8_t smbios_major_version; + uint8_t smbios_minor_version; + uint16_t max_structure_size; + uint8_t entry_point_revision; + uint8_t formatted_area[5]; + char intermediate_anchor_string[5]; + uint8_t intermediate_checksum; + uint16_t structure_table_length; + uint32_t structure_table_address; + uint16_t number_of_structures; + uint8_t smbios_bcd_revision; +} __attribute__((packed)); + +struct smbios_structure_header { + uint8_t type; + uint8_t length; + uint16_t handle; +} __attribute__((packed)); + +struct smbios_type_0 { + struct smbios_structure_header header; + uint8_t vendor_str; + uint8_t bios_version_str; + uint16_t bios_starting_address_segment; + uint8_t bios_release_date_str; + uint8_t bios_rom_size; + uint8_t bios_characteristics[8]; + uint8_t bios_characteristics_extension_bytes[2]; + uint8_t system_bios_major_release; + uint8_t system_bios_minor_release; + uint8_t embedded_controller_major_release; + uint8_t embedded_controller_minor_release; +} __attribute__((packed)); + +#define set_str_field_or_skip(type, field, value) \ + do { \ + int size = (value != NULL) ? strlen(value) + 1 : 0; \ + if (size > 1) { \ + memcpy(end, value, size); \ + end += size; \ + p->field = ++str_index; \ + } else { \ + p->field = 0; \ + } \ + } while (0) + +static void smbios_new_type_0(void *start, const char *vendor, + const char *version, const char *date) +{ + struct smbios_type_0 *p = (struct smbios_type_0 *)start; + char *end = (char *)start + sizeof(struct smbios_type_0); + int str_index = 0; + + p->header.type = 0; + p->header.length = sizeof(struct smbios_type_0); + p->header.handle = 0; + + set_str_field_or_skip(0, vendor_str, vendor); + set_str_field_or_skip(0, bios_version_str, version); + p->bios_starting_address_segment = 0xe800; + set_str_field_or_skip(0, bios_release_date_str, date); + + p->bios_rom_size = 0; /* FIXME */ + + /* BIOS characteristics not supported */ + memset(p->bios_characteristics, 0, 8); + p->bios_characteristics[0] = 0x08; + + /* Enable targeted content distribution (needed for SVVP) */ + p->bios_characteristics_extension_bytes[0] = 0; + p->bios_characteristics_extension_bytes[1] = 4; + + p->system_bios_major_release = 0; + p->system_bios_minor_release = 0; + p->embedded_controller_major_release = 0xFF; + p->embedded_controller_minor_release = 0xFF; + + *end = 0; + end++; + if (!str_index) { + *end = 0; + end++; + } +} + +static struct smbios_structure_header *smbios_next(struct smbios_entry_point *ep, + struct smbios_structure_header *hdr) +{ + if (!ep) + return NULL; + void *start = (void *)ep->structure_table_address; + void *end = start + ep->structure_table_length; + void *ptr; + + if (hdr == NULL) + ptr = start; + else { + ptr = hdr; + if (ptr + sizeof(*hdr) > end) + return NULL; + ptr += hdr->length + 2; + while (ptr < end && + (*(uint8_t*)(ptr-1) != '\0' || *(uint8_t*)(ptr-2) != '\0')) + ptr++; + } + hdr = ptr; + if (ptr >= end || ptr + sizeof(*hdr) >= end || ptr + hdr->length >= end) + return NULL; + return hdr; +} + +void extract_smbios(void) +{ + int id; + struct smbios_entry_point *ep; + uint8_t *qtables; + uint16_t qtables_length; + struct smbios_structure_header *table_header = NULL; + int need_t0 = 1; + uint16_t t0_len = sizeof(struct smbios_type_0) + strlen(BIOS_NAME) + + strlen(VERSION) + strlen(BIOS_DATE) + 4; + + id = fw_cfg_file_id("etc/smbios/smbios-anchor"); + if (id == -1 || (sizeof(*ep) != fw_cfg_file_size(id))) + return ; + /* malloc_fseg is 16-byte alignment default */ + if (!(ep = malloc_fseg(sizeof(*ep)))) + return; + fw_cfg_read_file(id, ep, sizeof(*ep)); + + qtables_length = ep->structure_table_length; + id = fw_cfg_file_id("etc/smbios/smbios-tables"); + if (id == -1 || qtables_length != fw_cfg_file_size(id)) + return ; + if (!(qtables = malloc_fseg(qtables_length + t0_len))) + return ; + qtables += t0_len; + fw_cfg_read_file(id, qtables, qtables_length); + + ep->structure_table_address = (uint32_t) qtables; + ep->structure_table_length = qtables_length; + + while ((table_header = smbios_next(ep, table_header))) { + if (table_header->type == 0) { + need_t0 = 0; + break; + } + } + + if (need_t0) { + smbios_new_type_0(qtables - t0_len, BIOS_NAME, VERSION, BIOS_DATE); + ep->number_of_structures++; + ep->structure_table_address -= t0_len; + ep->structure_table_length += t0_len; + if (t0_len > ep->max_structure_size) + ep->max_structure_size = t0_len; + } + + ep->checksum -= csum8((void *) ep, 0x10); + ep->intermediate_checksum -= csum8((void *) ep + 0x10, ep->length - 0x10); +} diff --git a/string.c b/string.c index 8d1cb7a..e3ebfa7 100644 --- a/string.c +++ b/string.c @@ -132,3 +132,11 @@ long atol(const char *ptr) return acc; } + +uint8_t csum8(uint8_t *buf, uint32_t len) +{ + uint32_t s = 0; + while (len-- > 0) + s += *buf++; + return s; +} diff --git a/tables.c b/tables.c index 9493691..9934a91 100644 --- a/tables.c +++ b/tables.c @@ -107,13 +107,6 @@ static void do_ptr(char *dest, char *src, uint32_t offset, uint8_t size) memcpy(q, &data.b, size); } -static inline uint8_t csum8(uint8_t *buf, uint32_t len) -{ - uint32_t s = 0; - while (len-- > 0) - s += *buf++; - return s; -} static void do_checksum(char *file, uint32_t offset, uint32_t start, uint32_t len) { uint8_t *p; -- cgit v1.1