| resolve memory device roll over reporting issues with >32G guests (Bill Rieske) |
| |
| The field within the Memory Device type 17 is only a word with the MSB being |
| used to report MB/KB. Thereby, a guest with 32G and greater would report |
| incorrect memory device information rolling over to 0. |
| |
| This presents more than one memory device and associated memory structures |
| if the memory is larger than 16G |
| |
| Signed-off-by: Bill Rieske <brieske@novell.com> |
| Signed-off-by: Avi Kivity <avi@redhat.com> |
| Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> |
| |
| Index: bochs/bios/rombios32.c |
| =================================================================== |
| --- bochs.orig/bios/rombios32.c |
| +++ bochs/bios/rombios32.c |
| @@ -381,6 +381,17 @@ int vsnprintf(char *buf, int buflen, con |
| return buf - buf0; |
| } |
| |
| +int snprintf(char * buf, size_t size, const char *fmt, ...) |
| +{ |
| + va_list args; |
| + int i; |
| + |
| + va_start(args, fmt); |
| + i=vsnprintf(buf,size,fmt,args); |
| + va_end(args); |
| + return i; |
| +} |
| + |
| void bios_printf(int flags, const char *fmt, ...) |
| { |
| va_list ap; |
| @@ -2039,7 +2050,7 @@ smbios_type_4_init(void *start, unsigned |
| |
| /* Type 16 -- Physical Memory Array */ |
| static void * |
| -smbios_type_16_init(void *start, uint32_t memsize) |
| +smbios_type_16_init(void *start, uint32_t memsize, int nr_mem_devs) |
| { |
| struct smbios_type_16 *p = (struct smbios_type_16*)start; |
| |
| @@ -2052,7 +2063,7 @@ smbios_type_16_init(void *start, uint32_ |
| p->error_correction = 0x01; /* other */ |
| p->maximum_capacity = memsize * 1024; |
| p->memory_error_information_handle = 0xfffe; /* none provided */ |
| - p->number_of_memory_devices = 1; |
| + p->number_of_memory_devices = nr_mem_devs; |
| |
| start += sizeof(struct smbios_type_16); |
| *((uint16_t *)start) = 0; |
| @@ -2062,20 +2073,19 @@ smbios_type_16_init(void *start, uint32_ |
| |
| /* Type 17 -- Memory Device */ |
| static void * |
| -smbios_type_17_init(void *start, uint32_t memory_size_mb) |
| +smbios_type_17_init(void *start, uint32_t memory_size_mb, int instance) |
| { |
| struct smbios_type_17 *p = (struct smbios_type_17 *)start; |
| |
| p->header.type = 17; |
| p->header.length = sizeof(struct smbios_type_17); |
| - p->header.handle = 0x1100; |
| + p->header.handle = 0x1100 + instance; |
| |
| p->physical_memory_array_handle = 0x1000; |
| p->total_width = 64; |
| p->data_width = 64; |
| - /* truncate memory_size_mb to 16 bits and clear most significant |
| - bit [indicates size in MB] */ |
| - p->size = (uint16_t) memory_size_mb & 0x7fff; |
| +/* TODO: should assert in case something is wrong ASSERT((memory_size_mb & ~0x7fff) == 0); */ |
| + p->size = memory_size_mb; |
| p->form_factor = 0x09; /* DIMM */ |
| p->device_set = 0; |
| p->device_locator_str = 1; |
| @@ -2084,8 +2094,8 @@ smbios_type_17_init(void *start, uint32_ |
| p->type_detail = 0; |
| |
| start += sizeof(struct smbios_type_17); |
| - memcpy((char *)start, "DIMM 1", 7); |
| - start += 7; |
| + snprintf(start, 8, "DIMM %d", instance); |
| + start += strlen(start) + 1; |
| *((uint8_t *)start) = 0; |
| |
| return start+1; |
| @@ -2093,16 +2103,16 @@ smbios_type_17_init(void *start, uint32_ |
| |
| /* Type 19 -- Memory Array Mapped Address */ |
| static void * |
| -smbios_type_19_init(void *start, uint32_t memory_size_mb) |
| +smbios_type_19_init(void *start, uint32_t memory_size_mb, int instance) |
| { |
| struct smbios_type_19 *p = (struct smbios_type_19 *)start; |
| |
| p->header.type = 19; |
| p->header.length = sizeof(struct smbios_type_19); |
| - p->header.handle = 0x1300; |
| + p->header.handle = 0x1300 + instance; |
| |
| - p->starting_address = 0; |
| - p->ending_address = (memory_size_mb * 1024) - 1; |
| + p->starting_address = instance << 24; |
| + p->ending_address = p->starting_address + (memory_size_mb << 10) - 1; |
| p->memory_array_handle = 0x1000; |
| p->partition_width = 1; |
| |
| @@ -2114,18 +2124,18 @@ smbios_type_19_init(void *start, uint32_ |
| |
| /* Type 20 -- Memory Device Mapped Address */ |
| static void * |
| -smbios_type_20_init(void *start, uint32_t memory_size_mb) |
| +smbios_type_20_init(void *start, uint32_t memory_size_mb, int instance) |
| { |
| struct smbios_type_20 *p = (struct smbios_type_20 *)start; |
| |
| p->header.type = 20; |
| p->header.length = sizeof(struct smbios_type_20); |
| - p->header.handle = 0x1400; |
| + p->header.handle = 0x1400 + instance; |
| |
| - p->starting_address = 0; |
| - p->ending_address = (memory_size_mb * 1024) - 1; |
| - p->memory_device_handle = 0x1100; |
| - p->memory_array_mapped_address_handle = 0x1300; |
| + p->starting_address = instance << 24; |
| + p->ending_address = p->starting_address + (memory_size_mb << 10) - 1; |
| + p->memory_device_handle = 0x1100 + instance; |
| + p->memory_array_mapped_address_handle = 0x1300 + instance; |
| p->partition_row_position = 1; |
| p->interleave_position = 0; |
| p->interleaved_data_depth = 0; |
| @@ -2176,6 +2186,7 @@ void smbios_init(void) |
| char *start, *p, *q; |
| int memsize = (ram_end == ram_size) ? ram_size / (1024 * 1024) : |
| (ram_end - (1ull << 32) + ram_size) / (1024 * 1024); |
| + int i, nr_mem_devs; |
| |
| #ifdef BX_USE_EBDA_TABLES |
| ebda_cur_addr = align(ebda_cur_addr, 16); |
| @@ -2187,23 +2198,32 @@ void smbios_init(void) |
| |
| p = (char *)start + sizeof(struct smbios_entry_point); |
| |
| -#define add_struct(fn) { \ |
| +#define add_struct(fn) do{ \ |
| q = (fn); \ |
| nr_structs++; \ |
| if ((q - p) > max_struct_size) \ |
| max_struct_size = q - p; \ |
| p = q; \ |
| -} |
| +}while (0) |
| |
| add_struct(smbios_type_0_init(p)); |
| add_struct(smbios_type_1_init(p)); |
| add_struct(smbios_type_3_init(p)); |
| for (cpu_num = 1; cpu_num <= smp_cpus; cpu_num++) |
| add_struct(smbios_type_4_init(p, cpu_num)); |
| - add_struct(smbios_type_16_init(p, memsize)); |
| - add_struct(smbios_type_17_init(p, memsize)); |
| - add_struct(smbios_type_19_init(p, ram_end / (1024 * 1024))); |
| - add_struct(smbios_type_20_init(p, ram_end / (1024 * 1024))); |
| + |
| + /* Each 'memory device' covers up to 16GB of address space. */ |
| + nr_mem_devs = (memsize + 0x3fff) >> 14; |
| + add_struct(smbios_type_16_init(p, memsize, nr_mem_devs)); |
| + for ( i = 0; i < nr_mem_devs; i++ ) |
| + { |
| + uint32_t dev_memsize = ((i == (nr_mem_devs - 1)) |
| + ? (memsize & 0x3fff) : 0x4000); |
| + add_struct(smbios_type_17_init(p, dev_memsize, i)); |
| + add_struct(smbios_type_19_init(p, dev_memsize, i)); |
| + add_struct(smbios_type_20_init(p, dev_memsize, i)); |
| + } |
| + |
| add_struct(smbios_type_32_init(p)); |
| add_struct(smbios_type_127_init(p)); |
| |
| |
| |