diff mbox

[v2,1/2] SMBIOS: Fix endian-ness when populating fields wider than 8-bit

Message ID 1400005030-20729-2-git-send-email-somlo@cmu.edu
State New
Headers show

Commit Message

Gabriel L. Somlo May 13, 2014, 6:17 p.m. UTC
When i386 guests are emulated on big endian hosts, make sure
fields wider than 8 bits are populated safely via cpu_to_le*().

Signed-off-by: Gabriel Somlo <somlo@cmu.edu>
---
 hw/i386/smbios.c | 91 ++++++++++++++++++++++++++++----------------------------
 1 file changed, 46 insertions(+), 45 deletions(-)

Comments

Laszlo Ersek May 13, 2014, 7:56 p.m. UTC | #1
comments below

On 05/13/14 20:17, Gabriel L. Somlo wrote:
> When i386 guests are emulated on big endian hosts, make sure
> fields wider than 8 bits are populated safely via cpu_to_le*().
> 
> Signed-off-by: Gabriel Somlo <somlo@cmu.edu>
> ---
>  hw/i386/smbios.c | 91 ++++++++++++++++++++++++++++----------------------------
>  1 file changed, 46 insertions(+), 45 deletions(-)
> 
> diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c
> index 7660718..609e921 100644
> --- a/hw/i386/smbios.c
> +++ b/hw/i386/smbios.c
> @@ -444,7 +444,7 @@ static bool smbios_skip_table(uint8_t type, bool required_table)
>                                                                            \
>          t->header.type = tbl_type;                                        \
>          t->header.length = sizeof(*t);                                    \
> -        t->header.handle = tbl_handle;                                    \
> +        t->header.handle = cpu_to_le16(tbl_handle);                       \
>      } while (0)
>  
>  #define SMBIOS_TABLE_SET_STR(tbl_type, field, value)                      \
> @@ -491,7 +491,7 @@ static void smbios_build_type_0_table(void)
>      SMBIOS_TABLE_SET_STR(0, vendor_str, type0.vendor);
>      SMBIOS_TABLE_SET_STR(0, bios_version_str, type0.version);
>  
> -    t->bios_starting_address_segment = 0xE800; /* hardcoded in SeaBIOS */
> +    t->bios_starting_address_segment = cpu_to_le16(0xE800); /* from SeaBIOS */
>  
>      SMBIOS_TABLE_SET_STR(0, bios_release_date_str, type0.date);
>  
> @@ -551,7 +551,7 @@ static void smbios_build_type_2_table(void)
>      SMBIOS_TABLE_SET_STR(2, asset_tag_number_str, type2.asset);
>      t->feature_flags = 0x01; /* Motherboard */
>      SMBIOS_TABLE_SET_STR(2, location_str, type2.location);
> -    t->chassis_handle = 0x300; /* Type 3 (System enclosure) */
> +    t->chassis_handle = cpu_to_le16(0x300); /* Type 3 (System enclosure) */
>      t->board_type = 0x0A; /* Motherboard */
>      t->contained_element_count = 0;
>  
> @@ -571,7 +571,7 @@ static void smbios_build_type_3_table(void)
>      t->power_supply_state = 0x03; /* Safe */
>      t->thermal_state = 0x03; /* Safe */
>      t->security_status = 0x02; /* Unknown */
> -    t->oem_defined = 0;
> +    t->oem_defined = cpu_to_le32(0);
>      t->height = 0;
>      t->number_of_power_cords = 0;
>      t->contained_element_count = 0;
> @@ -589,26 +589,27 @@ static void smbios_build_type_4_table(unsigned instance)
>      snprintf(sock_str, sizeof(sock_str), "%s%2x", type4.sock_pfx, instance);
>      SMBIOS_TABLE_SET_STR(4, socket_designation_str, sock_str);
>      t->processor_type = 0x03; /* CPU */
> +    t->processor_family = 0x01; /* Other */

This does something else than a cpu_to_leXX() conversion. Intended?

>      SMBIOS_TABLE_SET_STR(4, processor_manufacturer_str, type4.manufacturer);
> -    t->processor_id[0] = smbios_cpuid_version;
> -    t->processor_id[1] = smbios_cpuid_features;
> +    t->processor_id[0] = smbios_cpuid_version; /* opaque, no cpu_to_le16 */
> +    t->processor_id[1] = smbios_cpuid_features; /* opaque, no cpu_to_le16 */

My 2.7.1 smbios spec says one QWORD here (spanning both array elements).
The array elements are uint32_t, so the comments should probably say "no
cpu_to_le32". Not important.

>      SMBIOS_TABLE_SET_STR(4, processor_version_str, type4.version);
>      t->voltage = 0;
> -    t->external_clock = 0; /* Unknown */
> -    t->max_speed = 0; /* Unknown */
> -    t->current_speed = 0; /* Unknown */
> +    t->external_clock = cpu_to_le16(0); /* Unknown */
> +    t->max_speed = cpu_to_le16(0); /* Unknown */
> +    t->current_speed = cpu_to_le16(0); /* Unknown */
>      t->status = 0x41; /* Socket populated, CPU enabled */
>      t->processor_upgrade = 0x01; /* Other */
> -    t->l1_cache_handle = 0xFFFF; /* N/A */
> -    t->l2_cache_handle = 0xFFFF; /* N/A */
> -    t->l3_cache_handle = 0xFFFF; /* N/A */
> +    t->l1_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
> +    t->l2_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
> +    t->l3_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
>      SMBIOS_TABLE_SET_STR(4, serial_number_str, type4.serial);
>      SMBIOS_TABLE_SET_STR(4, asset_tag_number_str, type4.asset);
>      SMBIOS_TABLE_SET_STR(4, part_number_str, type4.part);
>      t->core_count = t->core_enabled = smp_cores;
>      t->thread_count = smp_threads;
> -    t->processor_characteristics = 0x02; /* Unknown */
> -    t->processor_family = t->processor_family2 = 0x01; /* Other */
> +    t->processor_characteristics = cpu_to_le16(0x02); /* Unknown */
> +    t->processor_family2 = cpu_to_le16(0x01); /* Other */

Ah I understand. "processor_family" is BYTE, that's why you split it off.

>  
>      SMBIOS_BUILD_TABLE_POST;
>      smbios_type4_count++;
> @@ -631,14 +632,14 @@ static void smbios_build_type_16_table(unsigned dimm_cnt)
>      t->error_correction = 0x06; /* Multi-bit ECC (for Microsoft, per SeaBIOS) */
>      size_kb = QEMU_ALIGN_UP(ram_size, ONE_KB) / ONE_KB;
>      if (size_kb < MAX_T16_STD_SZ) {
> -        t->maximum_capacity = size_kb;
> -        t->extended_maximum_capacity = 0;
> +        t->maximum_capacity = cpu_to_le32(size_kb);
> +        t->extended_maximum_capacity = cpu_to_le64(0);
>      } else {
> -        t->maximum_capacity = MAX_T16_STD_SZ;
> -        t->extended_maximum_capacity = ram_size;
> +        t->maximum_capacity = cpu_to_le32(MAX_T16_STD_SZ);
> +        t->extended_maximum_capacity = cpu_to_le64(ram_size);
>      }
> -    t->memory_error_information_handle = 0xFFFE; /* Not provided */
> -    t->number_of_memory_devices = dimm_cnt;
> +    t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */
> +    t->number_of_memory_devices = cpu_to_le16(dimm_cnt);
>  
>      SMBIOS_BUILD_TABLE_POST;
>  }
> @@ -653,18 +654,18 @@ static void smbios_build_type_17_table(unsigned instance, ram_addr_t size)
>  
>      SMBIOS_BUILD_TABLE_PRE(17, 0x1100 + instance, true); /* required */
>  
> -    t->physical_memory_array_handle = 0x1000; /* Type 16 (Phys. Mem. Array) */
> -    t->memory_error_information_handle = 0xFFFE; /* Not provided */
> -    t->total_width = 0xFFFF; /* Unknown */
> -    t->data_width = 0xFFFF; /* Unknown */
> +    t->physical_memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */
> +    t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */
> +    t->total_width = cpu_to_le16(0xFFFF); /* Unknown */
> +    t->data_width = cpu_to_le16(0xFFFF); /* Unknown */
>      size_mb = QEMU_ALIGN_UP(size, ONE_MB) / ONE_MB;
>      if (size_mb < MAX_T17_STD_SZ) {
> -        t->size = size_mb;
> -        t->extended_size = 0;
> +        t->size = cpu_to_le16(size_mb);
> +        t->extended_size = cpu_to_le32(0);
>      } else {
>          assert(size_mb < MAX_T17_EXT_SZ);
> -        t->size = MAX_T17_STD_SZ;
> -        t->extended_size = size_mb;
> +        t->size = cpu_to_le16(MAX_T17_STD_SZ);
> +        t->extended_size = cpu_to_le32(size_mb);
>      }
>      t->form_factor = 0x09; /* DIMM */
>      t->device_set = 0; /* Not in a set */
> @@ -672,17 +673,17 @@ static void smbios_build_type_17_table(unsigned instance, ram_addr_t size)
>      SMBIOS_TABLE_SET_STR(17, device_locator_str, loc_str);
>      SMBIOS_TABLE_SET_STR(17, bank_locator_str, type17.bank);
>      t->memory_type = 0x07; /* RAM */
> -    t->type_detail = 0x02; /* Other */
> -    t->speed = 0; /* Unknown */
> +    t->type_detail = cpu_to_le16(0x02); /* Other */
> +    t->speed = cpu_to_le16(0); /* Unknown */
>      SMBIOS_TABLE_SET_STR(17, manufacturer_str, type17.manufacturer);
>      SMBIOS_TABLE_SET_STR(17, serial_number_str, type17.serial);
>      SMBIOS_TABLE_SET_STR(17, asset_tag_number_str, type17.asset);
>      SMBIOS_TABLE_SET_STR(17, part_number_str, type17.part);
>      t->attributes = 0; /* Unknown */
> -    t->configured_clock_speed = 0; /* Unknown */
> -    t->minimum_voltage = 0; /* Unknown */
> -    t->maximum_voltage = 0; /* Unknown */
> -    t->configured_voltage = 0; /* Unknown */
> +    t->configured_clock_speed = cpu_to_le32(0); /* Unknown */

"Configured Memory Clock Speed" at offset 20h in Type17 is WORD in my
2.7.1 spec. Was this expanded to DWORD in 2.8? (Along with the addition
of the voltage fields?)

> +    t->minimum_voltage = cpu_to_le32(0); /* Unknown */
> +    t->maximum_voltage = cpu_to_le32(0); /* Unknown */
> +    t->configured_voltage = cpu_to_le32(0); /* Unknown */
>  
>      SMBIOS_BUILD_TABLE_POST;
>  }
> @@ -699,15 +700,15 @@ static void smbios_build_type_19_table(unsigned instance,
>      start_kb = start / ONE_KB;
>      end_kb = end / ONE_KB;
>      if (start_kb < UINT32_MAX && end_kb < UINT32_MAX) {
> -        t->starting_address = start_kb;
> -        t->ending_address = end_kb;
> -        t->extended_starting_address = t->extended_ending_address = 0;
> +        t->starting_address = cpu_to_le32(start_kb);
> +        t->ending_address = cpu_to_le32(end_kb);
> +        t->extended_starting_address = t->extended_ending_address = cpu_to_le64(0);
>      } else {
> -        t->starting_address = t->ending_address = UINT32_MAX;
> -        t->extended_starting_address = start;
> -        t->extended_ending_address = end;
> +        t->starting_address = t->ending_address = cpu_to_le32(UINT32_MAX);
> +        t->extended_starting_address = cpu_to_le64(start);
> +        t->extended_ending_address = cpu_to_le64(end);
>      }
> -    t->memory_array_handle = 0x1000; /* Type 16 (Phys. Mem. Array) */
> +    t->memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */
>      t->partition_width = 1; /* One device per row */
>  
>      SMBIOS_BUILD_TABLE_POST;
> @@ -794,14 +795,14 @@ static void smbios_entry_point_setup(void)
>      ep.smbios_bcd_revision = 0x28;
>  
>      /* set during table construction, but BIOS may override: */
> -    ep.structure_table_length = smbios_tables_len;
> -    ep.max_structure_size = smbios_table_max;
> -    ep.number_of_structures = smbios_table_cnt;
> +    ep.structure_table_length = cpu_to_le16(smbios_tables_len);
> +    ep.max_structure_size = cpu_to_le16(smbios_table_max);
> +    ep.number_of_structures = cpu_to_le16(smbios_table_cnt);
>  
>      /* BIOS must recalculate: */
>      ep.checksum = 0;
>      ep.intermediate_checksum = 0;
> -    ep.structure_table_address = 0; /* where BIOS has copied smbios_tables */
> +    ep.structure_table_address = cpu_to_le32(0);
>  }
>  
>  void smbios_get_tables(uint8_t **tables, size_t *tables_len,
> 

Thanks
Laszlo
Paolo Bonzini May 13, 2014, 8:09 p.m. UTC | #2
Il 13/05/2014 20:17, Gabriel L. Somlo ha scritto:
> -    t->processor_id[0] = smbios_cpuid_version;
> -    t->processor_id[1] = smbios_cpuid_features;
> +    t->processor_id[0] = smbios_cpuid_version; /* opaque, no cpu_to_le16 */
> +    t->processor_id[1] = smbios_cpuid_features; /* opaque, no cpu_to_le16 */

Actually I think these should be subject to cpu_to_le32.  They 
correspond to CPUID values, so they are little-endian 32-bit.

Paolo
Gabriel L. Somlo May 13, 2014, 8:21 p.m. UTC | #3
On Tue, May 13, 2014 at 10:09:45PM +0200, Paolo Bonzini wrote:
> Il 13/05/2014 20:17, Gabriel L. Somlo ha scritto:
> >-    t->processor_id[0] = smbios_cpuid_version;
> >-    t->processor_id[1] = smbios_cpuid_features;
> >+    t->processor_id[0] = smbios_cpuid_version; /* opaque, no cpu_to_le16 */
> >+    t->processor_id[1] = smbios_cpuid_features; /* opaque, no cpu_to_le16 */
> 
> Actually I think these should be subject to cpu_to_le32.  They
> correspond to CPUID values, so they are little-endian 32-bit.

Right, my comment is wrong, should be "no need for cpu_to_le32()" instead
of what I said ("no need for cpu_to_le16()")... :)

Re. why I said "opaque, no need for endianness fix" is because they're
a straight-through assignment from cpu->env.cpuid_version and 
cpu->env.features[FEAT_1_EDX], respectively. So they're not really
"numbers" which need endianness adjustment.

Did I get that wrong ? (I mean, besides the 16 vs. 32 in the comment) ?

Thanks,
--Gabriel
Laszlo Ersek May 13, 2014, 8:32 p.m. UTC | #4
On 05/13/14 22:21, Gabriel L. Somlo wrote:
> On Tue, May 13, 2014 at 10:09:45PM +0200, Paolo Bonzini wrote:
>> Il 13/05/2014 20:17, Gabriel L. Somlo ha scritto:
>>> -    t->processor_id[0] = smbios_cpuid_version;
>>> -    t->processor_id[1] = smbios_cpuid_features;
>>> +    t->processor_id[0] = smbios_cpuid_version; /* opaque, no cpu_to_le16 */
>>> +    t->processor_id[1] = smbios_cpuid_features; /* opaque, no cpu_to_le16 */
>>
>> Actually I think these should be subject to cpu_to_le32.  They
>> correspond to CPUID values, so they are little-endian 32-bit.
> 
> Right, my comment is wrong, should be "no need for cpu_to_le32()" instead
> of what I said ("no need for cpu_to_le16()")... :)
> 
> Re. why I said "opaque, no need for endianness fix" is because they're
> a straight-through assignment from cpu->env.cpuid_version and 
> cpu->env.features[FEAT_1_EDX], respectively. So they're not really
> "numbers" which need endianness adjustment.
> 
> Did I get that wrong ? (I mean, besides the 16 vs. 32 in the comment) ?

See 7.5.3.1 "x86-Class CPUs" in the spec.

> For x86 class CPUs, the field’s format depends on the processor’s
> support of the CPUID instruction. If the instruction is supported,
> the Processor ID field contains two DWORD-formatted values. The first
> (offsets 08h-0Bh) is the EAX value returned by a CPUID instruction
> with input EAX set to 1; the second (offsets 0Ch-0Fh) is the EDX
> value returned by that instruction.

I'm inclined to think that Paolo's right.

Laszlo
Paolo Bonzini May 13, 2014, 8:33 p.m. UTC | #5
Il 13/05/2014 22:21, Gabriel L. Somlo ha scritto:
>>> > >-    t->processor_id[0] = smbios_cpuid_version;
>>> > >-    t->processor_id[1] = smbios_cpuid_features;
>>> > >+    t->processor_id[0] = smbios_cpuid_version; /* opaque, no cpu_to_le16 */
>>> > >+    t->processor_id[1] = smbios_cpuid_features; /* opaque, no cpu_to_le16 */
>> >
>> > Actually I think these should be subject to cpu_to_le32.  They
>> > correspond to CPUID values, so they are little-endian 32-bit.
> Right, my comment is wrong, should be "no need for cpu_to_le32()" instead
> of what I said ("no need for cpu_to_le16()")... :)
>
> Re. why I said "opaque, no need for endianness fix" is because they're
> a straight-through assignment from cpu->env.cpuid_version and
> cpu->env.features[FEAT_1_EDX], respectively. So they're not really
> "numbers" which need endianness adjustment.
>
> Did I get that wrong ? (I mean, besides the 16 vs. 32 in the comment) ?

I think they do need cpu_to_le32.  We assign them straight from other 
32-bit integers, but still bits 0..7 should be in byte 0, bits 8..15 
should be in byte 1, etc.  So we need to convert from host CPU 
endianness to target CPU endianness.

Paolo
Gabriel L. Somlo May 13, 2014, 8:46 p.m. UTC | #6
On Tue, May 13, 2014 at 10:33:35PM +0200, Paolo Bonzini wrote:
> Il 13/05/2014 22:21, Gabriel L. Somlo ha scritto:
> >>>> >-    t->processor_id[0] = smbios_cpuid_version;
> >>>> >-    t->processor_id[1] = smbios_cpuid_features;
> >>>> >+    t->processor_id[0] = smbios_cpuid_version; /* opaque, no cpu_to_le16 */
> >>>> >+    t->processor_id[1] = smbios_cpuid_features; /* opaque, no cpu_to_le16 */
> >>>
> >>> Actually I think these should be subject to cpu_to_le32.  They
> >>> correspond to CPUID values, so they are little-endian 32-bit.
> >Right, my comment is wrong, should be "no need for cpu_to_le32()" instead
> >of what I said ("no need for cpu_to_le16()")... :)
> >
> >Re. why I said "opaque, no need for endianness fix" is because they're
> >a straight-through assignment from cpu->env.cpuid_version and
> >cpu->env.features[FEAT_1_EDX], respectively. So they're not really
> >"numbers" which need endianness adjustment.
> >
> >Did I get that wrong ? (I mean, besides the 16 vs. 32 in the comment) ?
> 
> I think they do need cpu_to_le32.  We assign them straight from
> other 32-bit integers, but still bits 0..7 should be in byte 0, bits
> 8..15 should be in byte 1, etc.  So we need to convert from host CPU
> endianness to target CPU endianness.

OK, so the host creates cpu->env.cpuid_version and
cpu->env.features[FEAT_1_EDX] in *host* format, so on
a BE host the i386 cpu values would be in BE ordrer,
and so I'd have to convert them to LE on behalf of the
x86 guest ?

OK, I'll go ahead and do that, then :)

Thanks!

--Gabriel
diff mbox

Patch

diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c
index 7660718..609e921 100644
--- a/hw/i386/smbios.c
+++ b/hw/i386/smbios.c
@@ -444,7 +444,7 @@  static bool smbios_skip_table(uint8_t type, bool required_table)
                                                                           \
         t->header.type = tbl_type;                                        \
         t->header.length = sizeof(*t);                                    \
-        t->header.handle = tbl_handle;                                    \
+        t->header.handle = cpu_to_le16(tbl_handle);                       \
     } while (0)
 
 #define SMBIOS_TABLE_SET_STR(tbl_type, field, value)                      \
@@ -491,7 +491,7 @@  static void smbios_build_type_0_table(void)
     SMBIOS_TABLE_SET_STR(0, vendor_str, type0.vendor);
     SMBIOS_TABLE_SET_STR(0, bios_version_str, type0.version);
 
-    t->bios_starting_address_segment = 0xE800; /* hardcoded in SeaBIOS */
+    t->bios_starting_address_segment = cpu_to_le16(0xE800); /* from SeaBIOS */
 
     SMBIOS_TABLE_SET_STR(0, bios_release_date_str, type0.date);
 
@@ -551,7 +551,7 @@  static void smbios_build_type_2_table(void)
     SMBIOS_TABLE_SET_STR(2, asset_tag_number_str, type2.asset);
     t->feature_flags = 0x01; /* Motherboard */
     SMBIOS_TABLE_SET_STR(2, location_str, type2.location);
-    t->chassis_handle = 0x300; /* Type 3 (System enclosure) */
+    t->chassis_handle = cpu_to_le16(0x300); /* Type 3 (System enclosure) */
     t->board_type = 0x0A; /* Motherboard */
     t->contained_element_count = 0;
 
@@ -571,7 +571,7 @@  static void smbios_build_type_3_table(void)
     t->power_supply_state = 0x03; /* Safe */
     t->thermal_state = 0x03; /* Safe */
     t->security_status = 0x02; /* Unknown */
-    t->oem_defined = 0;
+    t->oem_defined = cpu_to_le32(0);
     t->height = 0;
     t->number_of_power_cords = 0;
     t->contained_element_count = 0;
@@ -589,26 +589,27 @@  static void smbios_build_type_4_table(unsigned instance)
     snprintf(sock_str, sizeof(sock_str), "%s%2x", type4.sock_pfx, instance);
     SMBIOS_TABLE_SET_STR(4, socket_designation_str, sock_str);
     t->processor_type = 0x03; /* CPU */
+    t->processor_family = 0x01; /* Other */
     SMBIOS_TABLE_SET_STR(4, processor_manufacturer_str, type4.manufacturer);
-    t->processor_id[0] = smbios_cpuid_version;
-    t->processor_id[1] = smbios_cpuid_features;
+    t->processor_id[0] = smbios_cpuid_version; /* opaque, no cpu_to_le16 */
+    t->processor_id[1] = smbios_cpuid_features; /* opaque, no cpu_to_le16 */
     SMBIOS_TABLE_SET_STR(4, processor_version_str, type4.version);
     t->voltage = 0;
-    t->external_clock = 0; /* Unknown */
-    t->max_speed = 0; /* Unknown */
-    t->current_speed = 0; /* Unknown */
+    t->external_clock = cpu_to_le16(0); /* Unknown */
+    t->max_speed = cpu_to_le16(0); /* Unknown */
+    t->current_speed = cpu_to_le16(0); /* Unknown */
     t->status = 0x41; /* Socket populated, CPU enabled */
     t->processor_upgrade = 0x01; /* Other */
-    t->l1_cache_handle = 0xFFFF; /* N/A */
-    t->l2_cache_handle = 0xFFFF; /* N/A */
-    t->l3_cache_handle = 0xFFFF; /* N/A */
+    t->l1_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
+    t->l2_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
+    t->l3_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
     SMBIOS_TABLE_SET_STR(4, serial_number_str, type4.serial);
     SMBIOS_TABLE_SET_STR(4, asset_tag_number_str, type4.asset);
     SMBIOS_TABLE_SET_STR(4, part_number_str, type4.part);
     t->core_count = t->core_enabled = smp_cores;
     t->thread_count = smp_threads;
-    t->processor_characteristics = 0x02; /* Unknown */
-    t->processor_family = t->processor_family2 = 0x01; /* Other */
+    t->processor_characteristics = cpu_to_le16(0x02); /* Unknown */
+    t->processor_family2 = cpu_to_le16(0x01); /* Other */
 
     SMBIOS_BUILD_TABLE_POST;
     smbios_type4_count++;
@@ -631,14 +632,14 @@  static void smbios_build_type_16_table(unsigned dimm_cnt)
     t->error_correction = 0x06; /* Multi-bit ECC (for Microsoft, per SeaBIOS) */
     size_kb = QEMU_ALIGN_UP(ram_size, ONE_KB) / ONE_KB;
     if (size_kb < MAX_T16_STD_SZ) {
-        t->maximum_capacity = size_kb;
-        t->extended_maximum_capacity = 0;
+        t->maximum_capacity = cpu_to_le32(size_kb);
+        t->extended_maximum_capacity = cpu_to_le64(0);
     } else {
-        t->maximum_capacity = MAX_T16_STD_SZ;
-        t->extended_maximum_capacity = ram_size;
+        t->maximum_capacity = cpu_to_le32(MAX_T16_STD_SZ);
+        t->extended_maximum_capacity = cpu_to_le64(ram_size);
     }
-    t->memory_error_information_handle = 0xFFFE; /* Not provided */
-    t->number_of_memory_devices = dimm_cnt;
+    t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */
+    t->number_of_memory_devices = cpu_to_le16(dimm_cnt);
 
     SMBIOS_BUILD_TABLE_POST;
 }
@@ -653,18 +654,18 @@  static void smbios_build_type_17_table(unsigned instance, ram_addr_t size)
 
     SMBIOS_BUILD_TABLE_PRE(17, 0x1100 + instance, true); /* required */
 
-    t->physical_memory_array_handle = 0x1000; /* Type 16 (Phys. Mem. Array) */
-    t->memory_error_information_handle = 0xFFFE; /* Not provided */
-    t->total_width = 0xFFFF; /* Unknown */
-    t->data_width = 0xFFFF; /* Unknown */
+    t->physical_memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */
+    t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */
+    t->total_width = cpu_to_le16(0xFFFF); /* Unknown */
+    t->data_width = cpu_to_le16(0xFFFF); /* Unknown */
     size_mb = QEMU_ALIGN_UP(size, ONE_MB) / ONE_MB;
     if (size_mb < MAX_T17_STD_SZ) {
-        t->size = size_mb;
-        t->extended_size = 0;
+        t->size = cpu_to_le16(size_mb);
+        t->extended_size = cpu_to_le32(0);
     } else {
         assert(size_mb < MAX_T17_EXT_SZ);
-        t->size = MAX_T17_STD_SZ;
-        t->extended_size = size_mb;
+        t->size = cpu_to_le16(MAX_T17_STD_SZ);
+        t->extended_size = cpu_to_le32(size_mb);
     }
     t->form_factor = 0x09; /* DIMM */
     t->device_set = 0; /* Not in a set */
@@ -672,17 +673,17 @@  static void smbios_build_type_17_table(unsigned instance, ram_addr_t size)
     SMBIOS_TABLE_SET_STR(17, device_locator_str, loc_str);
     SMBIOS_TABLE_SET_STR(17, bank_locator_str, type17.bank);
     t->memory_type = 0x07; /* RAM */
-    t->type_detail = 0x02; /* Other */
-    t->speed = 0; /* Unknown */
+    t->type_detail = cpu_to_le16(0x02); /* Other */
+    t->speed = cpu_to_le16(0); /* Unknown */
     SMBIOS_TABLE_SET_STR(17, manufacturer_str, type17.manufacturer);
     SMBIOS_TABLE_SET_STR(17, serial_number_str, type17.serial);
     SMBIOS_TABLE_SET_STR(17, asset_tag_number_str, type17.asset);
     SMBIOS_TABLE_SET_STR(17, part_number_str, type17.part);
     t->attributes = 0; /* Unknown */
-    t->configured_clock_speed = 0; /* Unknown */
-    t->minimum_voltage = 0; /* Unknown */
-    t->maximum_voltage = 0; /* Unknown */
-    t->configured_voltage = 0; /* Unknown */
+    t->configured_clock_speed = cpu_to_le32(0); /* Unknown */
+    t->minimum_voltage = cpu_to_le32(0); /* Unknown */
+    t->maximum_voltage = cpu_to_le32(0); /* Unknown */
+    t->configured_voltage = cpu_to_le32(0); /* Unknown */
 
     SMBIOS_BUILD_TABLE_POST;
 }
@@ -699,15 +700,15 @@  static void smbios_build_type_19_table(unsigned instance,
     start_kb = start / ONE_KB;
     end_kb = end / ONE_KB;
     if (start_kb < UINT32_MAX && end_kb < UINT32_MAX) {
-        t->starting_address = start_kb;
-        t->ending_address = end_kb;
-        t->extended_starting_address = t->extended_ending_address = 0;
+        t->starting_address = cpu_to_le32(start_kb);
+        t->ending_address = cpu_to_le32(end_kb);
+        t->extended_starting_address = t->extended_ending_address = cpu_to_le64(0);
     } else {
-        t->starting_address = t->ending_address = UINT32_MAX;
-        t->extended_starting_address = start;
-        t->extended_ending_address = end;
+        t->starting_address = t->ending_address = cpu_to_le32(UINT32_MAX);
+        t->extended_starting_address = cpu_to_le64(start);
+        t->extended_ending_address = cpu_to_le64(end);
     }
-    t->memory_array_handle = 0x1000; /* Type 16 (Phys. Mem. Array) */
+    t->memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */
     t->partition_width = 1; /* One device per row */
 
     SMBIOS_BUILD_TABLE_POST;
@@ -794,14 +795,14 @@  static void smbios_entry_point_setup(void)
     ep.smbios_bcd_revision = 0x28;
 
     /* set during table construction, but BIOS may override: */
-    ep.structure_table_length = smbios_tables_len;
-    ep.max_structure_size = smbios_table_max;
-    ep.number_of_structures = smbios_table_cnt;
+    ep.structure_table_length = cpu_to_le16(smbios_tables_len);
+    ep.max_structure_size = cpu_to_le16(smbios_table_max);
+    ep.number_of_structures = cpu_to_le16(smbios_table_cnt);
 
     /* BIOS must recalculate: */
     ep.checksum = 0;
     ep.intermediate_checksum = 0;
-    ep.structure_table_address = 0; /* where BIOS has copied smbios_tables */
+    ep.structure_table_address = cpu_to_le32(0);
 }
 
 void smbios_get_tables(uint8_t **tables, size_t *tables_len,