soc/intel/broadwell: decouple PEI memory struct from coreboot header

Recent changes to field lengths in include/memory_info.h resulted in
a mismatch between the memory_info struct the MRC blob writes to and
the struct used by coreboot to parse out data for the SMBIOS tables.
This mismatch caused type 17 SMBIOS tables to be filled incorrectly.

The solution used here is to define the memory_info struct as expected
by MRC in the pei_data header, and manually copy the data field by field
into the coreboot memory_info struct, observing the more restrictive
lengths for the two structs.

Test: build/boot google/lulu, verify SMBIOS type 17 tables correctly
populated.

Change-Id: I932b7b41ae1e3fd364d056a8c91f7ed5d25dbafc
Signed-off-by: Matt DeVillier <matt.devillier@gmail.com>
Reviewed-on: https://review.coreboot.org/26598
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Nico Huber <nico.h@gmx.de>
diff --git a/src/soc/intel/broadwell/romstage/raminit.c b/src/soc/intel/broadwell/romstage/raminit.c
index 665dad2..54db3d1 100644
--- a/src/soc/intel/broadwell/romstage/raminit.c
+++ b/src/soc/intel/broadwell/romstage/raminit.c
@@ -21,6 +21,7 @@
 #include <console/console.h>
 #include <device/pci_def.h>
 #include <lib.h>
+#include <memory_info.h>
 #include <mrc_cache.h>
 #include <string.h>
 #if IS_ENABLED(CONFIG_EC_GOOGLE_CHROMEEC)
@@ -121,6 +122,29 @@
 
 	printk(BIOS_DEBUG, "create cbmem for dimm information\n");
 	mem_info = cbmem_add(CBMEM_ID_MEMINFO, sizeof(struct memory_info));
-	memcpy(mem_info, &pei_data->meminfo, sizeof(struct memory_info));
-
+	memset(mem_info, 0, sizeof(*mem_info));
+	/* Translate pei_memory_info struct data into memory_info struct */
+	mem_info->dimm_cnt = pei_data->meminfo.dimm_cnt;
+	for (int i = 0; i < MIN(DIMM_INFO_TOTAL, PEI_DIMM_INFO_TOTAL); i++) {
+		struct dimm_info *dimm = &mem_info->dimm[i];
+		const struct pei_dimm_info *pei_dimm =
+			&pei_data->meminfo.dimm[i];
+		dimm->dimm_size = pei_dimm->dimm_size;
+		dimm->ddr_type = pei_dimm->ddr_type;
+		dimm->ddr_frequency = pei_dimm->ddr_frequency;
+		dimm->rank_per_dimm = pei_dimm->rank_per_dimm;
+		dimm->channel_num = pei_dimm->channel_num;
+		dimm->dimm_num = pei_dimm->dimm_num;
+		dimm->bank_locator = pei_dimm->bank_locator;
+		memcpy(&dimm->serial, &pei_dimm->serial,
+			MIN(sizeof(dimm->serial), sizeof(pei_dimm->serial)));
+		memcpy(&dimm->module_part_number,
+			&pei_dimm->module_part_number,
+			MIN(sizeof(dimm->module_part_number),
+			sizeof(pei_dimm->module_part_number)));
+		dimm->module_part_number[DIMM_INFO_PART_NUMBER_SIZE - 1] = '\0';
+		dimm->mod_id =  pei_dimm->mod_id;
+		dimm->mod_type = pei_dimm->mod_type;
+		dimm->bus_width = pei_dimm->bus_width;
+	}
 }