summaryrefslogtreecommitdiff
path: root/src/arch/x86
diff options
context:
space:
mode:
authorPatrick Rudolph <patrick.rudolph@9elements.com>2020-07-27 15:37:43 +0200
committerAngel Pons <th3fanbus@gmail.com>2020-07-30 22:31:24 +0000
commit5e007808cd380fe934b1a3f0c42eb79cb03787d0 (patch)
treeefb2c027acb0d018b5922e0f246db467dc4847a8 /src/arch/x86
parent95c42c3b04b1e499d756d979ef0ce2c428d9c540 (diff)
downloadcoreboot-5e007808cd380fe934b1a3f0c42eb79cb03787d0.tar.xz
smbios: Fix type 17 for Windows 10
The `GetPhysicallyInstalledSystemMemory` API call, at least on Windows 10, returns an error if SMBIOS tables are invalid. Various tools use this API call and don't operate correctly if this fails. For example, the "Intel Processor Diagnostic Tool" program is affected. Windows then guesses the physical memory size by accumulating entries from the firmware-provided memory map, which results in a total memory size that is slightly lower than the actual installed memory capacity. To fix this issue, add the handle to a type 16 entry to all type 17 entries. Add new fields to struct memory_info and fill them in Intel common code. Use the introduced variables to fill type 16 in smbios.c and provide a handle to type 17 entries. Besides keeping the current behaviour on intel/soc/common platforms, the type 16 table is also emitted on platforms that don't explicitly fill it, by using the existing fields of struct memory_info. Tested on Windows 10: The GetPhysicallyInstalledSystemMemory API call doesn't return an error anymore and the installed memory is now being reported as 8192 MiB. Change-Id: Idc3a363cbc3d0654dafd4176c4f4af9005210f42 Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com> Signed-off-by: Angel Pons <th3fanbus@gmail.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/43969 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Marcello Sylvester Bauer <sylv@sylv.io> Reviewed-by: Christian Walter <christian.walter@9elements.com> Reviewed-by: Patrick Rudolph <siro@das-labor.org>
Diffstat (limited to 'src/arch/x86')
-rw-r--r--src/arch/x86/smbios.c67
1 files changed, 63 insertions, 4 deletions
diff --git a/src/arch/x86/smbios.c b/src/arch/x86/smbios.c
index d7e87470db..47b54aa116 100644
--- a/src/arch/x86/smbios.c
+++ b/src/arch/x86/smbios.c
@@ -310,7 +310,8 @@ static void smbios_fill_dimm_serial_number(const struct dimm_info *dimm,
}
static int create_smbios_type17_for_dimm(struct dimm_info *dimm,
- unsigned long *current, int *handle)
+ unsigned long *current, int *handle,
+ int type16_handle)
{
struct smbios_type17 *t = (struct smbios_type17 *)*current;
@@ -365,6 +366,8 @@ static int create_smbios_type17_for_dimm(struct dimm_info *dimm,
t->memory_error_information_handle = 0xFFFE;
t->attributes = dimm->rank_per_dimm;
t->handle = *handle;
+ t->phys_memory_array_handle = type16_handle;
+
*handle += 1;
t->length = sizeof(struct smbios_type17) - 2;
return t->length + smbios_string_table_len(t->eos);
@@ -1063,7 +1066,53 @@ static int smbios_write_type11(unsigned long *current, int *handle)
return len;
}
-static int smbios_write_type17(unsigned long *current, int *handle)
+static int smbios_write_type16(unsigned long *current, int *handle)
+{
+ struct smbios_type16 *t = (struct smbios_type16 *)*current;
+
+ int len;
+ int i;
+
+ struct memory_info *meminfo;
+ meminfo = cbmem_find(CBMEM_ID_MEMINFO);
+ if (meminfo == NULL)
+ return 0; /* can't find mem info in cbmem */
+
+ printk(BIOS_INFO, "Create SMBIOS type 16\n");
+
+ if (meminfo->max_capacity_mib == 0 || meminfo->number_of_devices == 0) {
+ /* Fill in defaults if not provided */
+ meminfo->number_of_devices = 0;
+ meminfo->max_capacity_mib = 0;
+ for (i = 0; i < meminfo->dimm_cnt && i < ARRAY_SIZE(meminfo->dimm); i++) {
+ meminfo->max_capacity_mib += meminfo->dimm[i].dimm_size;
+ meminfo->number_of_devices += !!meminfo->dimm[i].dimm_size;
+ }
+ }
+
+ memset(t, 0, sizeof(*t));
+ t->type = SMBIOS_PHYS_MEMORY_ARRAY;
+ t->handle = *handle;
+ t->length = len = sizeof(*t) - 2;
+
+ t->location = MEMORY_ARRAY_LOCATION_SYSTEM_BOARD;
+ t->use = MEMORY_ARRAY_USE_SYSTEM;
+ t->memory_error_correction = meminfo->ecc_capable ?
+ MEMORY_ARRAY_ECC_SINGLE_BIT : MEMORY_ARRAY_ECC_NONE;
+
+ /* no error information handle available */
+ t->memory_error_information_handle = 0xFFFE;
+ t->maximum_capacity = meminfo->max_capacity_mib * (MiB / KiB);
+ t->number_of_memory_devices = meminfo->number_of_devices;
+
+ len += smbios_string_table_len(t->eos);
+
+ *current += len;
+ (*handle)++;
+ return len;
+}
+
+static int smbios_write_type17(unsigned long *current, int *handle, int type16)
{
int len = sizeof(struct smbios_type17);
int totallen = 0;
@@ -1079,7 +1128,13 @@ static int smbios_write_type17(unsigned long *current, int *handle)
i++) {
struct dimm_info *dimm;
dimm = &meminfo->dimm[i];
- len = create_smbios_type17_for_dimm(dimm, current, handle);
+ /*
+ * Windows 10 GetPhysicallyInstalledSystemMemory functions reads SMBIOS tables
+ * type 16 and type 17. The type 17 tables need to point to a type 16 table.
+ * Otherwise, the physical installed memory size is guessed from the system
+ * memory map, which results in a slightly smaller value than the actual size.
+ */
+ len = create_smbios_type17_for_dimm(dimm, current, handle, type16);
*current += len;
totallen += len;
}
@@ -1356,8 +1411,12 @@ unsigned long smbios_write_tables(unsigned long current)
if (CONFIG(ELOG))
update_max(len, max_struct_size,
elog_smbios_write_type15(&current,handle++));
- update_max(len, max_struct_size, smbios_write_type17(&current,
+
+ const int type16 = handle;
+ update_max(len, max_struct_size, smbios_write_type16(&current,
&handle));
+ update_max(len, max_struct_size, smbios_write_type17(&current,
+ &handle, type16));
update_max(len, max_struct_size, smbios_write_type19(&current,
&handle));
update_max(len, max_struct_size, smbios_write_type32(&current,