diff -r 0900b1c905f1 tools/firmware/hvmloader/smbios.c
--- a/tools/firmware/hvmloader/smbios.c	Mon Feb 20 18:58:07 2012 +0000
+++ b/tools/firmware/hvmloader/smbios.c	Mon Feb 20 20:56:58 2012 -0500
@@ -49,6 +49,8 @@
 smbios_type_1_init(void *start, const char *xen_version, 
                    uint8_t uuid[16]);
 static void *
+smbios_type_2_init(void *start);
+static void *
 smbios_type_3_init(void *start);
 static void *
 smbios_type_4_init(void *start, unsigned int cpu_number,
@@ -64,8 +66,14 @@
 static void *
 smbios_type_20_init(void *start, uint32_t memory_size_mb, int instance);
 static void *
+smbios_type_22_init(void *start);
+static void *
 smbios_type_32_init(void *start);
 static void *
+smbios_type_39_init(void *start);
+static void *
+smbios_type_vendor_oem_init(void *start);
+static void *
 smbios_type_127_init(void *start);
 
 static void
@@ -85,6 +93,77 @@
         strncpy(buf, "unknown", len);
 }
 
+static struct hvm_smbios_table_header *
+get_smbios_info_by_type(struct hvm_smbios_info_table *pa_smbt, uint8_t type)
+{
+    struct hvm_smbios_table_header *header;
+    uint32_t count;
+    uint8_t *ptr;
+
+    header = (struct hvm_smbios_table_header*)
+        ((uint8_t*)pa_smbt + sizeof(struct hvm_smbios_info_table));
+
+    for ( count = 0; count < pa_smbt->count; count++ )
+    {
+        if ( (header->length > 0)&&(header->length < HVM_SMBIOS_INFO_MAX) )
+        {
+            ptr = ((uint8_t*)header + sizeof(struct hvm_smbios_table_header));
+            if ( ptr[0] == type )
+                return header;
+        }
+        else
+        {
+            printf("SMBIOS table invalid length: %d, aborting.",
+                   (int)header->length);
+            return NULL;
+        }
+
+        header = (struct hvm_smbios_table_header*)(ptr + header->length);
+    }
+
+    return NULL;
+}
+
+#define SPTARG(s, t) s, t, sizeof(struct smbios_type_##t)
+static uint32_t
+smbios_passthrough(void *start, uint8_t table, uint32_t stsize)
+{
+    struct hvm_smbios_info_table *pa_smbt;
+    struct hvm_smbios_table_header *header;
+
+    pa_smbt = get_hvm_smbios_info_table();
+    if ( pa_smbt == NULL )
+        return 0;
+
+    header = get_smbios_info_by_type(pa_smbt, table);
+    if ( header == NULL )
+        return 0;
+
+    if ( header->length < stsize )
+    {
+        printf("SMBIOS table length less than fixed minimum length, skipping.");
+        return 0;
+    }
+
+    memcpy(start,
+           ((uint8_t*)header + sizeof(struct hvm_smbios_table_header)),
+           header->length);
+
+    return header->length;
+}
+
+static uint32_t
+get_smbios_info_flags(void)
+{
+    struct hvm_smbios_info_table *pa_smbt;
+
+    pa_smbt = get_hvm_smbios_info_table();
+    if ( pa_smbt != NULL )
+        return pa_smbt->flags;
+
+    return 0;
+}
+
 static int
 write_smbios_tables(void *ep, void *start,
                     uint32_t vcpus, uint64_t memsize,
@@ -112,6 +191,7 @@
     do_struct(smbios_type_0_init(p, xen_version, xen_major_version,
                                  xen_minor_version));
     do_struct(smbios_type_1_init(p, xen_version, uuid));
+    do_struct(smbios_type_2_init(p));
     do_struct(smbios_type_3_init(p));
     for ( cpu_num = 1; cpu_num <= vcpus; cpu_num++ )
         do_struct(smbios_type_4_init(p, cpu_num, cpu_manufacturer));
@@ -130,7 +210,10 @@
         do_struct(smbios_type_20_init(p, dev_memsize, i));
     }
 
+    do_struct(smbios_type_22_init(p));
     do_struct(smbios_type_32_init(p));
+    do_struct(smbios_type_39_init(p));
+    do_struct(smbios_type_vendor_oem_init(p));
     do_struct(smbios_type_127_init(p));
 
 #undef do_struct
@@ -289,6 +372,15 @@
     struct smbios_type_0 *p = (struct smbios_type_0 *)start;
     static const char *smbios_release_date = __SMBIOS_DATE__;
     const char *s;
+    uint32_t length;
+
+    length = smbios_passthrough(SPTARG(start, 0));
+    if ( length > 0 )
+    {
+        /* Fix up, use consistent handles */
+        p->header.handle = 0;
+        return (start + length);
+    }
 
     memset(p, 0, sizeof(*p));
 
@@ -338,6 +430,15 @@
     char uuid_str[37];
     struct smbios_type_1 *p = (struct smbios_type_1 *)start;
     const char *s;
+    uint32_t length;
+
+    length = smbios_passthrough(SPTARG(start, 1));
+    if ( length > 0 )
+    {
+        /* Fix up, use consistent handles */
+        p->header.handle = 0x100;
+        return (start + length);
+    }
 
     memset(p, 0, sizeof(*p));
 
@@ -376,15 +477,88 @@
     start += strlen(s) + 1;
 
     *((uint8_t *)start) = 0;
-    
     return start+1; 
 }
 
+/* Type 2 -- System Board */
+static void *
+smbios_type_2_init(void *start)
+{
+    struct smbios_type_2 *p = (struct smbios_type_2 *)start;
+    uint8_t *bptr;
+    const char *s;
+    uint32_t length;
+
+    if ( (get_smbios_info_flags() & HVM_SMBIOS_INCLUDE_SYSTEM_BOARD) == 0 )
+        return start;
+
+    length = smbios_passthrough(SPTARG(start, 2));
+    if ( length > 0 )
+    {
+        /* Fix up, use consistent handles, set chassis handle */
+        p->header.handle = 0x200;
+
+        /* NOTE: if this code is enhanced to allow multiple instances of some tables like
+           this one, chassis info, etc. then work will have to be done to match these handles */
+        if ( p->header.length >= 13 )
+        {
+            bptr = ((uint8_t*)start) + 11;
+            if (*((uint16_t*)bptr) != 0)
+                *((uint16_t*)bptr) = 0x300; /* current chassis handle */
+        }
+
+        return (start + length);
+    }
+
+    memset(p, 0, sizeof(*p));
+
+    p->header.type = 2;
+    p->header.length = sizeof(struct smbios_type_2);
+    p->header.handle = 0x200;
+
+    p->manufacturer_str = 1;
+    p->product_name_str = 2;
+    p->version_str = 0;
+    p->serial_number_str = 0;
+
+    start += sizeof(struct smbios_type_2);
+
+    s = xenstore_read("bios-strings/board-manufacturer", "Xen");
+    strcpy((char *)start, s);
+    start += strlen(s) + 1;
+
+    s = xenstore_read("bios-strings/board-product-name", "HVM domU");
+    strcpy((char *)start, s);
+    start += strlen(s) + 1;
+
+    /* no internal defaults for this if the value is not set */
+    s = xenstore_read("bios-strings/board-serial-number", NULL);
+    if ( (s != NULL)&&(*s != '\0') )
+    {
+        strcpy((char *)start, s);
+        start += strlen(s) + 1;        
+        p->serial_number_str = 3;
+    }
+
+    *((uint8_t *)start) = 0;
+    return start+1;
+}
+
 /* Type 3 -- System Enclosure */
 static void *
 smbios_type_3_init(void *start)
 {
     struct smbios_type_3 *p = (struct smbios_type_3 *)start;
+    const char *s;
+    uint32_t length;
+
+    length = smbios_passthrough(SPTARG(start, 3));
+    if ( length > 0 )
+    {
+        /* Fix up, use consistent handles */
+        p->header.handle = 0x300;
+        return (start + length);
+    }
     
     memset(p, 0, sizeof(*p));
 
@@ -403,9 +577,20 @@
     p->security_status = 0x02; /* unknown */
 
     start += sizeof(struct smbios_type_3);
-    
-    strcpy((char *)start, "Xen");
-    start += strlen("Xen") + 1;
+
+    s = xenstore_read("bios-strings/enclosure-manufacturer", "Xen");
+    strcpy((char *)start, s);
+    start += strlen(s) + 1;
+
+    /* no internal defaults for this if the value is not set */
+    s = xenstore_read("bios-strings/enclosure-serial-number", NULL);
+    if ( (s != NULL)&&(*s != '\0') )
+    {
+        strcpy((char *)start, s);
+        start += strlen(s) + 1;        
+        p->serial_number_str = 2;
+    }
+
     *((uint8_t *)start) = 0;
     return start+1;
 }
@@ -468,6 +653,15 @@
     char path[20] = "bios-strings/oem-XX";
     const char *s;
     int i;
+    uint32_t length;
+
+    length = smbios_passthrough(SPTARG(start, 11));
+    if ( length > 0 )
+    {
+        /* Fix up, use consistent handles */
+        p->header.handle = 0xB00;
+        return (start + length);
+    }
 
     p->header.type = 11;
     p->header.length = sizeof(struct smbios_type_11);
@@ -609,6 +803,63 @@
     return start+2;
 }
 
+/* Type 22 -- Portable Battery */
+static void *
+smbios_type_22_init(void *start)
+{
+    struct smbios_type_22 *p = (struct smbios_type_22 *)start;
+    static const char *smbios_release_date = __SMBIOS_DATE__;
+    uint32_t length;
+
+    if ( (get_smbios_info_flags() & HVM_SMBIOS_INCLUDE_PORTABLE_BATTERY) == 0 )
+        return start;
+
+    length = smbios_passthrough(SPTARG(start, 22));
+    if ( length > 0 )
+    {
+        /* Fix up, use consistent handles */
+        p->header.handle = 0x1600;
+
+        return (start + length);
+    }
+
+    memset(p, 0, sizeof(*p));
+
+    p->header.type = 22;
+    p->header.length = sizeof(struct smbios_type_22);
+    p->header.handle = 0x1600;
+
+    p->location_str = 1;
+    p->manufacturer_str = 2;
+    p->manufacturer_date_str = 3;
+    p->serial_number_str = 0;
+    p->device_name_str = 4;
+    p->device_chemistry = 0x2; /* Unknown */
+    p->device_capacity = 0; /* Unknown */
+    p->device_voltage = 0; /* Unknown */
+    p->sbds_version_number = 0;
+    p->max_error = 0xff; /* Unknown */
+    p->sbds_serial_number = 0;
+    p->sbds_manufacturer_date = 0;
+    p->sbds_device_chemistry = 0;
+    p->design_capacity_multiplier = 0;
+    p->oem_specific = 0;
+
+    start += sizeof(struct smbios_type_22);
+
+    strcpy((char *)start, "Primary");
+    start += strlen("Primary") + 1;
+    strcpy((char *)start, "Xen");
+    start += strlen("Xen") + 1;
+    strcpy((char *)start, smbios_release_date);
+    start += strlen(smbios_release_date) + 1;
+    strcpy((char *)start, "XEN-VBAT");
+    start += strlen("XEN-VBAT") + 1;
+
+    *((uint8_t *)start) = 0;
+    return start+1; 
+}
+
 /* Type 32 -- System Boot Information */
 static void *
 smbios_type_32_init(void *start)
@@ -628,6 +879,75 @@
     return start+2;
 }
 
+/* Type 39 -- Power Supply */
+static void *
+smbios_type_39_init(void *start)
+{
+    struct smbios_type_39 *p = (struct smbios_type_39 *)start;
+    uint32_t length;
+
+    if ( (get_smbios_info_flags() & HVM_SMBIOS_INCLUDE_POWER_SUPPLY) == 0 )
+        return start;
+
+    /* No default values - only present if the table is passed in */
+    length = smbios_passthrough(SPTARG(start, 39));
+    if ( length == 0 )
+        return start;
+
+    /* Fix up, use consistent handles */
+    p->header.handle = 0x2700;
+
+    /* These devices are not present */
+    p->input_voltage_probe_handle = 0xFFFF;
+    p->cooling_device_handle = 0xFFFF;
+    p->input_current_probe_handle = 0xFFFF;
+
+    return (start + length);
+}
+
+static void *
+smbios_type_vendor_oem_init(void *start)
+{
+    struct hvm_smbios_info_table *pa_smbt;
+    struct hvm_smbios_table_header *header;
+    uint32_t count;
+    uint8_t *ptr;    
+
+    pa_smbt = get_hvm_smbios_info_table();
+    if ( pa_smbt == NULL )
+        return start;
+    
+    if ( (pa_smbt->flags & HVM_SMBIOS_INCLUDE_VENDOR_OEM) == 0 )
+        return start;
+
+    header = (struct hvm_smbios_table_header*)
+        ((uint8_t*)pa_smbt + sizeof(struct hvm_smbios_info_table));
+
+    for ( count = 0; count < pa_smbt->count; count++ )
+    {
+        if ( header->length != 0 )
+        {
+            ptr = ((uint8_t*)header + sizeof(struct hvm_smbios_table_header));
+            if ( ptr[0] >= SMBIOS_VENDOR_OEM_TABLE_MIN )
+            {
+                /* Vendor/OEM table, copy it in. Note the handle values cannot
+                   be changed since it is unknown what is in each of these tables
+                   but they could contain handle references to other tables. This
+                   means a slight risk of collision with the tables above but that
+                   would have to be dealt with on a case by case basis. */
+                memcpy(start, ptr, header->length);
+                start += header->length;
+            }
+        }
+        else
+            printf("Empty SMBIOS OEM table passed to HVM loader, skipping.");
+
+        header = (struct hvm_smbios_table_header*)(ptr + header->length);
+    }
+
+    return start;
+}
+
 /* Type 127 -- End of Table */
 static void *
 smbios_type_127_init(void *start)
diff -r 0900b1c905f1 tools/firmware/hvmloader/smbios_types.h
--- a/tools/firmware/hvmloader/smbios_types.h	Mon Feb 20 18:58:07 2012 +0000
+++ b/tools/firmware/hvmloader/smbios_types.h	Mon Feb 20 20:56:58 2012 -0500
@@ -28,6 +28,9 @@
 
 #include <stdint.h>
 
+#define SMBIOS_VENDOR_OEM_TABLE_MIN 128
+#define SMBIOS_VENDOR_OEM_TABLE_MAX 255
+
 /* SMBIOS entry point -- must be written to a 16-bit aligned address
    between 0xf0000 and 0xfffff. 
  */
@@ -84,6 +87,15 @@
     uint8_t family_str;
 } __attribute__ ((packed));
 
+/* SMBIOS type 2 - Base Board Information */
+struct smbios_type_2 {
+    struct smbios_structure_header header;
+    uint8_t manufacturer_str;
+    uint8_t product_name_str;
+    uint8_t version_str;
+    uint8_t serial_number_str;
+} __attribute__ ((packed));
+
 /* SMBIOS type 3 - System Enclosure */
 struct smbios_type_3 {
     struct smbios_structure_header header;
@@ -173,6 +185,26 @@
     uint8_t interleaved_data_depth;
 } __attribute__ ((packed));
 
+/* SMBIOS type 22 - Portable battery */
+struct smbios_type_22 {
+    struct smbios_structure_header header;
+    uint8_t location_str;
+    uint8_t manufacturer_str;
+    uint8_t manufacturer_date_str;
+    uint8_t serial_number_str;
+    uint8_t device_name_str;
+    uint8_t device_chemistry;
+    uint16_t device_capacity;
+    uint16_t device_voltage;
+    uint8_t sbds_version_number;
+    uint8_t max_error;
+    uint16_t sbds_serial_number;
+    uint16_t sbds_manufacturer_date;
+    uint8_t sbds_device_chemistry;
+    uint8_t design_capacity_multiplier;
+    uint32_t oem_specific;
+} __attribute__ ((packed));
+
 /* SMBIOS type 32 - System Boot Information */
 struct smbios_type_32 {
     struct smbios_structure_header header;
@@ -180,6 +212,24 @@
     uint8_t boot_status;
 } __attribute__ ((packed));
 
+/* SMBIOS type 39 - Power Supply */
+struct smbios_type_39 {
+    struct smbios_structure_header header;
+    uint8_t power_unit_group;
+    uint8_t location_str;
+    uint8_t device_name_str;
+    uint8_t manufacturer_str;
+    uint8_t serial_number_str;
+    uint8_t asset_tag_number_str;
+    uint8_t model_part_number_str;
+    uint8_t revision_level_str;
+    uint16_t max_capacity;
+    uint16_t characteristics;
+    uint16_t input_voltage_probe_handle;
+    uint16_t cooling_device_handle;
+    uint16_t input_current_probe_handle;
+} __attribute__ ((packed));
+
 /* SMBIOS type 127 -- End-of-table */
 struct smbios_type_127 {
     struct smbios_structure_header header;
