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>
This commit is contained in:
parent
a31b28cb23
commit
5f6cf6105c
|
@ -8,6 +8,7 @@ CPPFLAGS_romstage += -I$(opensil_dir)/Include -I$(opensil_dir)/xUSL -I$(opensil_
|
|||
romstage-y += opensil_console.c
|
||||
romstage-y += romstage.c
|
||||
|
||||
ramstage-y += memmap.c
|
||||
ramstage-y += opensil_console.c
|
||||
ramstage-y += ramstage.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;
|
||||
}
|
|
@ -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
|
|
@ -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";
|
||||
|
|
Loading…
Reference in New Issue