aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkaihuan.pkh <kaihuan.pkh@alibaba-inc.com>2019-11-18 20:08:36 +0800
committerPaolo Bonzini <bonzini@gnu.org>2019-11-18 15:52:42 +0100
commit94d3b1b5d1fc30bd7b63af9d07cb8db89a5f4868 (patch)
treebcf70ecfa51cb72607f497caf87d0b4050d1d3a4
parentcb1c49e0cfac99b9961d136ac0194da62c28cf64 (diff)
downloadqboot-94d3b1b5d1fc30bd7b63af9d07cb8db89a5f4868.zip
qboot-94d3b1b5d1fc30bd7b63af9d07cb8db89a5f4868.tar.gz
qboot-94d3b1b5d1fc30bd7b63af9d07cb8db89a5f4868.tar.bz2
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 <luoben@linux.alibaba.com> Signed-off-by: kaihuan.pkh <kaihuan.pkh@alibaba-inc.com>
-rw-r--r--Makefile2
-rw-r--r--README1
-rw-r--r--include/smbios.h1
-rw-r--r--include/string.h2
-rw-r--r--main.c3
-rw-r--r--smbios.c174
-rw-r--r--string.c8
-rw-r--r--tables.c7
8 files changed, 188 insertions, 10 deletions
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 <stddef.h>
+#include <inttypes.h>
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 <inttypes.h>
+#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;