vendorcode/amd/genoa: Parse APOB for DRAM layout

Use the xPRF call to report holes in memory to report those regions as
reserved.

Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Change-Id: If89b08a31a9b9f8e7d2959d1bc45e91763fe565b
Reviewed-on: https://review.coreboot.org/c/coreboot/+/78922
Reviewed-by: Matt DeVillier <matt.devillier@amd.corp-partner.google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/src/vendorcode/amd/opensil/genoa_poc/Makefile.inc b/src/vendorcode/amd/opensil/genoa_poc/Makefile.inc
index cccb006..b09299b 100644
--- a/src/vendorcode/amd/opensil/genoa_poc/Makefile.inc
+++ b/src/vendorcode/amd/opensil/genoa_poc/Makefile.inc
@@ -8,6 +8,7 @@
 romstage-y += opensil_console.c
 romstage-y += romstage.c
 
+ramstage-y += memmap.c
 ramstage-y += opensil_console.c
 ramstage-y += ramstage.c
 
diff --git a/src/vendorcode/amd/opensil/genoa_poc/memmap.c b/src/vendorcode/amd/opensil/genoa_poc/memmap.c
new file mode 100644
index 0000000..4e5b457
--- /dev/null
+++ b/src/vendorcode/amd/opensil/genoa_poc/memmap.c
@@ -0,0 +1,150 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <bootstate.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <SilCommon.h>
+#include <Sil-api.h> // needed above ApobCmn.h
+#include <ApobCmn.h>
+#include <device/device.h>
+#include <xPRF-api.h>
+#include <cpu/amd/mtrr.h>
+#include <cbmem.h>
+#include <amdblocks/memmap.h>
+
+#include "opensil.h"
+
+static const char *hole_info_type(MEMORY_HOLE_TYPES type)
+{
+	const struct hole_type {
+		MEMORY_HOLE_TYPES type;
+		const char *string;
+	} types[] = {
+		{UMA, "UMA"},
+		{MMIO, "MMIO"},
+		{PrivilegedDRAM, "PrivilegedDRAM"},
+		{Reserved1TbRemap, "Reserved1TbRemap"},
+		{ReservedSLink, "ReservedSLink"},
+		{ReservedSLinkAlignment, "ReservedSLinkAlignment"},
+		{ReservedDrtm, "ReservedDrtm"},
+		{ReservedCvip, "ReservedCvip"},
+		{ReservedSmuFeatures, "ReservedSmuFeatures"},
+		{ReservedFwtpm, "ReservedFwtpm"},
+		{ReservedMpioC20, "ReservedMpioC20"},
+		{ReservedNbif, "ReservedNbif"},
+		{ReservedCxl, "ReservedCxl"},
+		{ReservedCxlAlignment, "ReservedCxlAlignment"},
+		{ReservedCpuTmr, "ReservedCpuTmr"},
+		{ReservedRasEinj, "ReservedRasEinj"},
+		{MaxMemoryHoleTypes, "MaxMemoryHoleTypes"},
+	};
+
+	int i;
+	for (i = 0; i < ARRAY_SIZE(types); i++)
+		if (type == types[i].type)
+			break;
+	if (i == ARRAY_SIZE(types))
+		return "Unknown type";
+	return types[i].string;
+}
+
+static uint64_t top_of_mem;
+static uint32_t n_holes;
+static MEMORY_HOLE_DESCRIPTOR *hole_info;
+
+static void get_hole_info(void)
+{
+	static bool done;
+	if (done)
+		return;
+        SIL_STATUS status = xPrfGetSystemMemoryMap(&n_holes, &top_of_mem, (void **)&hole_info);
+	SIL_STATUS_report("xPrfGetSystemMemoryMap", status);
+	// Make sure hole_info does not get initialized to something odd by xPRF on failure
+	if (status != SilPass)
+		hole_info = NULL;
+	done = true;
+}
+
+
+static void print_memory_holes(void *unused)
+{
+	get_hole_info();
+	if (hole_info == NULL)
+		return;
+
+	printk(BIOS_DEBUG, "APOB: top of memory 0x%016llx\n", top_of_mem);
+	printk(BIOS_DEBUG, "The following holes are reported in APOB\n");
+	for (int hole = 0; hole < n_holes; hole++) {
+		printk(BIOS_DEBUG, "  Base: 0x%016llx, Size: 0x%016llx, Type: %02d:%s\n",
+		       hole_info[hole].Base, hole_info[hole].Size, hole_info[hole].Type,
+		       hole_info_type(hole_info[hole].Type));
+	}
+}
+
+BOOT_STATE_INIT_ENTRY(BS_DEV_RESOURCES, BS_ON_ENTRY, print_memory_holes, NULL);
+
+// This assumes holes are allocated
+int add_opensil_memmap(struct device *dev, int idx)
+{
+	ram_from_to(dev, idx++, 0, 0xa0000);
+	mmio_from_to(dev, idx++, 0xa0000, 0xc0000); // legacy VGA
+	reserved_ram_from_to(dev, idx++, 0xc0000, 1 * MiB); // Option ROM
+
+	uint32_t mem_usable = (uintptr_t)cbmem_top();
+	uintptr_t early_reserved_dram_start, early_reserved_dram_end;
+	const struct memmap_early_dram *e = memmap_get_early_dram_usage();
+
+	early_reserved_dram_start = e->base;
+	early_reserved_dram_end = e->base + e->size;
+
+	// 1MB - bottom of DRAM reserved for early coreboot usage
+	ram_from_to(dev, idx++, 1 * MiB, early_reserved_dram_start);
+
+	// DRAM reserved for early coreboot usage
+	reserved_ram_from_to(dev, idx++, early_reserved_dram_start,
+			     early_reserved_dram_end);
+
+	// top of DRAM consumed early - low top usable RAM
+	// cbmem_top() accounts for low UMA and TSEG if they are used.
+	ram_from_to(dev, idx++, early_reserved_dram_end,
+		    mem_usable);
+
+	// Account for UMA and TSEG
+	const uint32_t top_mem = ALIGN_DOWN(rdmsr(TOP_MEM).lo, 1 * MiB);
+	if (mem_usable != top_mem)
+		reserved_ram_from_to(dev, idx++, mem_usable, top_mem);
+
+	mmconf_resource(dev, idx++);
+
+	// Check if we're done
+	if (top_of_mem <= 0x100000000)
+		return idx;
+
+	// Holes in upper DRAM
+	// This assumes all the holes in upper DRAM are continuous
+	get_hole_info();
+	if (hole_info == NULL)
+		return idx;
+	uint64_t lowest_upper_hole_base = top_of_mem;
+	uint64_t highest_upper_hole_end = 0x100000000;
+	for (int hole = 0; hole < n_holes; hole++) {
+		if (hole_info[hole].Type == MMIO)
+			continue;
+		if (hole_info[hole].Base < 0x100000000)
+			continue;
+		lowest_upper_hole_base = MIN(lowest_upper_hole_base, hole_info[hole].Base);
+		highest_upper_hole_end = MAX(highest_upper_hole_end, hole_info[hole].Base + hole_info[hole].Size);
+		if (hole_info[hole].Type == UMA)
+			mmio_range(dev, idx++, hole_info[hole].Base, hole_info[hole].Size);
+		else
+			reserved_ram_range(dev, idx++, hole_info[hole].Base, hole_info[hole].Size);
+	}
+
+	ram_from_to(dev, idx++, 0x100000000, lowest_upper_hole_base);
+
+	// Do we need this?
+	if (top_of_mem > highest_upper_hole_end)
+		ram_from_to(dev, idx++, highest_upper_hole_end, top_of_mem);
+
+	return idx;
+}
diff --git a/src/vendorcode/amd/opensil/genoa_poc/opensil.h b/src/vendorcode/amd/opensil/genoa_poc/opensil.h
new file mode 100644
index 0000000..ecde809
--- /dev/null
+++ b/src/vendorcode/amd/opensil/genoa_poc/opensil.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _OPENSIL_H_
+#define _OPENSIL_H_
+
+#include <acpi/acpi.h>
+
+void SIL_STATUS_report(const char *function, const int status);
+// Add the memory map to dev, starting at index idx, returns last use idx
+int add_opensil_memmap(struct device *dev, int idx);
+// Fill in FADT from opensil
+void opensil_fill_fadt(acpi_fadt_t *fadt);
+
+#endif
diff --git a/src/vendorcode/amd/opensil/genoa_poc/ramstage.c b/src/vendorcode/amd/opensil/genoa_poc/ramstage.c
index d9c8add..ab55199 100644
--- a/src/vendorcode/amd/opensil/genoa_poc/ramstage.c
+++ b/src/vendorcode/amd/opensil/genoa_poc/ramstage.c
@@ -11,8 +11,9 @@
 #include <soc/soc_chip.h>
 #include <xSIM-api.h>
 #include "opensil_console.h"
+#include "opensil.h"
 
-static void SIL_STATUS_report(const char *function, const int status)
+void SIL_STATUS_report(const char *function, const int status)
 {
 	const int log_level = status == SilPass ? BIOS_DEBUG : BIOS_ERR;
 	const char *error_string = "Unkown error";