]> xenbits.xen.org Git - xenclient/xen.git/commitdiff
SMBIOS pass-through functionality for HVM loader
authorRoss Philipson <ross.philipson@citrix.com>
Tue, 13 Jan 2009 16:51:25 +0000 (11:51 -0500)
committerRoss Philipson <ross.philipson@citrix.com>
Tue, 13 Jan 2009 16:51:25 +0000 (11:51 -0500)
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

tools/firmware/hvmloader/smbios.c
tools/firmware/hvmloader/util.c
tools/firmware/hvmloader/util.h
xen/include/public/hvm/hvm_info_table.h

index 7b3b64a21631d54ba096bb0a506ecbe70cf7216d..2649b8c6db11e14d257e2aaf48516b06dded068b 100644 (file)
@@ -23,6 +23,7 @@
 #include <stdint.h>
 #include <xen/xen.h>
 #include <xen/version.h>
+#include <xen/hvm/hvm_info_table.h>
 #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 */
index fe33b0f124069722687e7108425bc674942e9517..6a29d6beaf147d9db2102c2b46e11ced4e44bcf0 100644 (file)
@@ -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
index 81f0e4f4c44d3f77bebb0f5ce75c33dbcc29cd34..cd8ede9dec7cb3533c92097c4f3409800ddc09e9 100644 (file)
@@ -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);
index dfe34db1e5ca351b14cf290ad2b6d5b5758c8c3d..ddeca5494144979a02f4fa0ffc109f214d72b0d0 100644 (file)
 #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__ */