From: Ross Philipson Date: Tue, 13 Jan 2009 16:51:25 +0000 (-0500) Subject: SMBIOS pass-through functionality for HVM loader X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=6226a140117ed504ad293b79a4c2ecfccea79e1e;p=xenclient%2Fxen.git SMBIOS pass-through functionality for HVM loader System SMBIOS is passed in to HVM loader via the hvm_table_info page and is read and loaded into the virtual SMBIOS. Changes to be committed: modified: tools/firmware/hvmloader/smbios.c modified: tools/firmware/hvmloader/util.c modified: tools/firmware/hvmloader/util.h modified: xen/include/public/hvm/hvm_info_table.h --- diff --git a/tools/firmware/hvmloader/smbios.c b/tools/firmware/hvmloader/smbios.c index 7b3b64a..2649b8c 100644 --- a/tools/firmware/hvmloader/smbios.c +++ b/tools/firmware/hvmloader/smbios.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "smbios_types.h" #include "util.h" #include "hypercall.h" @@ -35,6 +36,8 @@ write_smbios_tables(void *start, uint8_t uuid[16], char *xen_version, uint32_t xen_major_version, uint32_t xen_minor_version); +static struct hvm_smtable_header * +get_sminfo_by_type(struct hvm_sminfo_table *pa_sm, uint8_t type); static void get_cpu_manufacturer(char *buf, int len); static void @@ -69,6 +72,26 @@ smbios_type_32_init(void *start); static void * smbios_type_127_init(void *start); +static struct hvm_smtable_header * +get_sminfo_by_type(struct hvm_sminfo_table *pa_sm, uint8_t type) +{ + struct hvm_smtable_header *header = (struct hvm_smtable_header*)((uint8_t*)pa_sm + sizeof(struct hvm_sminfo_table)); + uint32_t count; + uint8_t *ptr; + + for (count = 0; count < pa_sm->sm_count; count++) { + if (header->sm_length == 0) { + printf("Invalid SMINFO tables passed to HVM loader."); + return NULL; + } + ptr = ((uint8_t*)header + sizeof(struct hvm_smtable_header)); + if (ptr[0] == type) + return header; + header = (struct hvm_smtable_header*)(ptr + header->sm_length); + } + return NULL; +} + static void get_cpu_manufacturer(char *buf, int len) { @@ -130,6 +153,8 @@ write_smbios_tables(void *start, } do_struct(smbios_type_32_init(p)); + /* NOTE: future enhancement - vendor specific structures (range 128 - 256) would be + processed and added here */ do_struct(smbios_type_127_init(p)); #undef do_struct @@ -293,9 +318,34 @@ static void * smbios_type_0_init(void *start, const char *xen_version, uint32_t xen_major_version, uint32_t xen_minor_version) { - struct smbios_type_0 *p = (struct smbios_type_0 *)start; static const char *smbios_release_date = __SMBIOS_DATE__; + struct smbios_type_0 *p = (struct smbios_type_0 *)start; + struct hvm_sminfo_table *pa_sm; + struct hvm_smtable_header *header; + + /* if passed a struct, use it */ + pa_sm = get_hvm_sminfo_table(); + while (pa_sm != NULL) { + header = get_sminfo_by_type(pa_sm, 0); + if (header == NULL) + break; + if (header->sm_length < sizeof(struct smbios_type_0)) + break; + memcpy(start, ((uint8_t*)header + sizeof(struct hvm_smtable_header)), header->sm_length); + + /* fix up some bits */ + p->header.handle = 0; + p->starting_address_segment = 0xe800; + p->rom_size = 0; + p->characteristics[0] = 0x80; /* PCI is supported */ + p->characteristics[2] = 0x08; /* EDD is supported */ + p->characteristics_extension_bytes[1] = 0x04; /* Enable Targeted Content Distribution. */ + + printf("***RJP*** COPIED IN TYPE 0 - length: %d (0x%x)\n", header->sm_length, header->sm_length); /* TODO REMOVE */ + return (start + header->sm_length); + } + /* fall back to building our own */ memset(p, 0, sizeof(*p)); p->header.type = 0; @@ -347,7 +397,27 @@ smbios_type_1_init(void *start, const char *xen_version, char uuid_str[37]; struct smbios_type_1 *p = (struct smbios_type_1 *)start; int next = 5; + struct hvm_sminfo_table *pa_sm; + struct hvm_smtable_header *header; + + /* if passed a struct, use it */ + pa_sm = get_hvm_sminfo_table(); + while (pa_sm != NULL) { + header = get_sminfo_by_type(pa_sm, 1); + if (header == NULL) + break; + if (header->sm_length < sizeof(struct smbios_type_1)) + break; + memcpy(start, ((uint8_t*)header + sizeof(struct hvm_smtable_header)), header->sm_length); + + /* fix up some bits */ + p->header.handle = 0x100; + + printf("***RJP*** COPIED IN TYPE 1 - length: %d (0x%x)\n", header->sm_length, header->sm_length); /* TODO REMOVE */ + return (start + header->sm_length); + } + /* fall back to building our own */ memset(p, 0, sizeof(*p)); p->header.type = 1; @@ -412,7 +482,27 @@ static void * smbios_type_3_init(void *start) { struct smbios_type_3 *p = (struct smbios_type_3 *)start; - + struct hvm_sminfo_table *pa_sm; + struct hvm_smtable_header *header; + + /* if passed a struct, use it */ + pa_sm = get_hvm_sminfo_table(); + while (pa_sm != NULL) { + header = get_sminfo_by_type(pa_sm, 3); + if (header == NULL) + break; + if (header->sm_length < sizeof(struct smbios_type_3)) + break; + memcpy(start, ((uint8_t*)header + sizeof(struct hvm_smtable_header)), header->sm_length); + + /* fix up some bits */ + p->header.handle = 0x300; + + printf("***RJP*** COPIED IN TYPE 3 - length: %d (0x%x)\n", header->sm_length, header->sm_length); /* TODO REMOVE */ + return (start + header->sm_length); + } + + /* fall back to building our own */ memset(p, 0, sizeof(*p)); p->header.type = 3; @@ -503,6 +593,27 @@ smbios_type_11_init(void *start) { struct smbios_type_11 *p = (struct smbios_type_11 *)start; int i = 0; + struct hvm_sminfo_table *pa_sm; + struct hvm_smtable_header *header; + + /* if passed a struct, use it */ + pa_sm = get_hvm_sminfo_table(); + while (pa_sm != NULL) { + header = get_sminfo_by_type(pa_sm, 11); + if (header == NULL) + break; + if (header->sm_length < sizeof(struct smbios_type_11)) + break; + memcpy(start, ((uint8_t*)header + sizeof(struct hvm_smtable_header)), header->sm_length); + + /* fix up some bits */ + p->header.handle = 0xB00; + + printf("***RJP*** COPIED IN TYPE 11 - length: %d (0x%x)\n", header->sm_length, header->sm_length); /* TODO REMOVE */ + return (start + header->sm_length); + } + + /* fall back to building our own */ if ( oem_strings_array[0] == NULL ) return start; /* no OEM strings to add */ diff --git a/tools/firmware/hvmloader/util.c b/tools/firmware/hvmloader/util.c index fe33b0f..6a29d6b 100644 --- a/tools/firmware/hvmloader/util.c +++ b/tools/firmware/hvmloader/util.c @@ -647,6 +647,55 @@ uint16_t get_cpu_mhz(void) return cpu_mhz; } +static int validate_hvm_sminfo(struct hvm_sminfo_table *t) +{ + char signature[] = "SM INFO"; + uint8_t *ptr = (uint8_t *)t; + uint8_t sum = 0; + uint32_t length; + int i; + + if ( (t->total_length == 0) && (t->sm_count == 0) ) { + printf("Empty hvm smbios info table\n"); + } + + /* strncmp(t->signature, "SM INFO", 7) */ + for ( i = 0; i < 7; i++ ) + { + if ( signature[i] != t->signature[i] ) + { + printf("Bad hvm smbios info signature\n"); + return 0; + } + } + + length = sizeof(struct hvm_sminfo_table) + t->total_length; + for ( i = 0; i < length; i++ ) + sum += ptr[i]; + + return (sum == 0); +} + +struct hvm_sminfo_table *get_hvm_sminfo_table(void) +{ + static struct hvm_sminfo_table *table = NULL; + static int validated = 0; + struct hvm_sminfo_table *t; + + if ( validated ) + return table; + + t = (struct hvm_sminfo_table *)HVM_SMINFO_PADDR; + + if ( validate_hvm_sminfo(t) ) + table = t; + else + printf("Bad or missing hvm smbios info table\n"); + validated = 1; + + return table; +} + /* * Local variables: * mode: C diff --git a/tools/firmware/hvmloader/util.h b/tools/firmware/hvmloader/util.h index 81f0e4f..cd8ede9 100644 --- a/tools/firmware/hvmloader/util.h +++ b/tools/firmware/hvmloader/util.h @@ -107,6 +107,9 @@ int get_vcpu_nr(void); int get_acpi_enabled(void); int get_apic_mode(void); +/* HVM-build SMBIOS info. */ +struct hvm_sminfo_table *get_hvm_sminfo_table(void); + /* String and memory functions */ int strcmp(const char *cs, const char *ct); int strncmp(const char *s1, const char *s2, uint32_t n); diff --git a/xen/include/public/hvm/hvm_info_table.h b/xen/include/public/hvm/hvm_info_table.h index dfe34db..ddeca54 100644 --- a/xen/include/public/hvm/hvm_info_table.h +++ b/xen/include/public/hvm/hvm_info_table.h @@ -28,6 +28,10 @@ #define HVM_INFO_PFN 0x09F #define HVM_INFO_OFFSET 0x800 #define HVM_INFO_PADDR ((HVM_INFO_PFN << 12) + HVM_INFO_OFFSET) +#define HVM_SMINFO_OFFSET 0x0 +#define HVM_SMINFO_PADDR ((HVM_INFO_PFN << 12) + HVM_SMINFO_OFFSET) +#define HVM_SMINFO_MAX 0x800 + struct hvm_info_table { char signature[8]; /* "HVM INFO" */ @@ -38,4 +42,15 @@ struct hvm_info_table { uint32_t nr_vcpus; }; +struct hvm_sminfo_table { + char signature[7]; /* "SM INFO" */ + uint8_t checksum; + uint32_t total_length; /* beginning after this stucture */ + uint32_t sm_count; +}; + +struct hvm_smtable_header { + uint32_t sm_length; /* beginning after this stucture, includes fixed table, string list, and terminator */ +}; + #endif /* __XEN_PUBLIC_HVM_HVM_INFO_TABLE_H__ */