summaryrefslogtreecommitdiffstats
path: root/src/drivers/amd/opensil/memmap.c
blob: 9b80a882ef6c3c7621eadf9a18cd9a12dcb13d9d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/* SPDX-License-Identifier: GPL-2.0-only */

#include <bootstate.h>
#include <cbmem.h>
#include <cpu/amd/mtrr.h>
#include <string.h>
#include <vendorcode/amd/opensil/opensil.h>

#include "opensil.h"

/*
 * This structure definition must align exactly with the MEMORY_HOLE_TYPES structure
 * defined in openSIL to ensure accurate casting.
 */
typedef struct {
	uint64_t base;
	uint64_t size;
	uint32_t type;
	uint32_t reserved;
} HOLE_INFO;

/* This assumes holes are allocated */
void amd_opensil_add_memmap(struct device *dev, unsigned long *idx)
{
	uint64_t top_of_mem = 0;
	uint32_t n_holes = 0;
	void *hole_info = NULL;

	/* Account for UMA and TSEG */
	const uint32_t mem_usable = cbmem_top();
	const uint32_t top_mem = ALIGN_DOWN(get_top_of_mem_below_4gb(), 1 * MiB);
	if (mem_usable != top_mem)
		reserved_ram_from_to(dev, (*idx)++, mem_usable, top_mem);

	/* Holes in upper DRAM */
	/* This assumes all the holes in upper DRAM are continuous */
	opensil_get_hole_info(&n_holes, &top_of_mem, &hole_info);
	if (hole_info == NULL)
		return;

	/* Check if we're done */
	if (top_of_mem <= 4ULL * GiB)
		return;

	HOLE_INFO *holes = (HOLE_INFO *)hole_info;

	uint64_t lowest_upper_hole_base = top_of_mem;
	uint64_t highest_upper_hole_end = 4ULL * GiB;
	for (size_t hole = 0; hole < n_holes; hole++) {
		if (!strcmp(opensil_get_hole_info_type(holes[hole].type), "MMIO"))
			continue;
		if (holes[hole].base < 4ULL * GiB)
			continue;
		lowest_upper_hole_base = MIN(lowest_upper_hole_base, holes[hole].base);
		highest_upper_hole_end = MAX(highest_upper_hole_end, holes[hole].base + holes[hole].size);
		if (!strcmp(opensil_get_hole_info_type(holes[hole].type), "UMA"))
			mmio_range(dev, (*idx)++, holes[hole].base, holes[hole].size);
		else
			reserved_ram_range(dev, (*idx)++, holes[hole].base, holes[hole].size);
	}

	ram_from_to(dev, (*idx)++, 4ULL * GiB, lowest_upper_hole_base);

	if (top_of_mem > highest_upper_hole_end)
		ram_from_to(dev, (*idx)++, highest_upper_hole_end, top_of_mem);
}

static void print_memory_holes(void *unused)
{
	uint64_t top_of_mem = 0;
	uint32_t n_holes = 0;
	void *hole_info = NULL;

	opensil_get_hole_info(&n_holes, &top_of_mem, &hole_info);
	if (hole_info == NULL)
		return;

	HOLE_INFO *holes = (HOLE_INFO *)hole_info;

	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 (size_t hole = 0; hole < n_holes; hole++) {
		printk(BIOS_DEBUG, "  Base: 0x%016llx, Size: 0x%016llx, Type: %02d:%s\n",
			holes[hole].base, holes[hole].size, holes[hole].type,
			opensil_get_hole_info_type(holes[hole].type));
	}
}

BOOT_STATE_INIT_ENTRY(BS_DEV_RESOURCES, BS_ON_ENTRY, print_memory_holes, NULL);