summaryrefslogtreecommitdiff
path: root/src/soc/intel/common/basecode/ramtop/ramtop.c
blob: 203d3437c7a8a95d4aa154efe1b14ce47fbd92f0 (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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/* SPDX-License-Identifier: GPL-2.0-or-later */

#include <commonlib/bsd/ipchksum.h>
#include <console/console.h>
#include <cpu/cpu.h>
#include <cpu/x86/mtrr.h>
#include <fsp/util.h>
#include <intelbasecode/ramtop.h>
#include <pc80/mc146818rtc.h>
#include <stdint.h>

/* We need a region in CMOS to store the RAMTOP address */

#define RAMTOP_SIGNATURE   0x504F5452 /* 'RTOP' */

/*
 * Address of the ramtop byte in CMOS. Should be reserved
 * in mainboards' cmos.layout and not covered by checksum.
 */

#if CONFIG(USE_OPTION_TABLE)
#include "option_table.h"

#ifndef CMOS_VSTART_ramtop
#error "The `ramtop` CMOS entry is missing, please add it to your cmos.layout."
#endif

#if CMOS_VSTART_ramtop % 8 != 0
#error "The `ramtop` CMOS entry needs to be byte aligned, check your cmos.layout."
#endif	// CMOS_VSTART_ramtop % 8 != 0

#if CMOS_VLEN_ramtop != (10 * 8)
#error "The `ramtop` CMOS entry needs to be 10 bytes long, check your cmos.layout."
#endif	// CMOS_VLEN_ramtop != (10 * 8)

#else
#define CMOS_VSTART_ramtop 800
#endif	// CONFIG(USE_OPTION_TABLE)

struct ramtop_table {
	uint32_t signature;
	uint32_t addr;
	size_t size;
	uint16_t checksum;
} __packed;

/* Read and validate ramtop_table structure from CMOS */
static int ramtop_cmos_read(struct ramtop_table *ramtop)
{
	u8 i, *p;
	u16 csum;

	for (p = (u8 *)ramtop, i = 0; i < sizeof(*ramtop); i++, p++)
		*p = cmos_read((CMOS_VSTART_ramtop / 8) + i);

	/* Verify signature */
	if (ramtop->signature != RAMTOP_SIGNATURE) {
		printk(BIOS_DEBUG, "ramtop_table invalid signature\n");
		return -1;
	}

	/* Verify RAMTOP size */
	if (ramtop->size == 0) {
		printk(BIOS_DEBUG, "ramtop_table holds invalid size\n");
		return -1;
	}

	/* Verify checksum over signature and counter only */
	csum = ipchksum(ramtop, offsetof(struct ramtop_table, checksum));

	if (csum != ramtop->checksum) {
		printk(BIOS_DEBUG, "ramtop_table checksum mismatch\n");
		return -1;
	}

	return 0;
}

/* Write ramtop_table structure to CMOS */
static void ramtop_cmos_write(struct ramtop_table *ramtop)
{
	u8 i, *p;

	/* Checksum over signature and counter only */
	ramtop->checksum = ipchksum(ramtop, offsetof(struct ramtop_table, checksum));

	for (p = (u8 *)ramtop, i = 0; i < sizeof(*ramtop); i++, p++)
		cmos_write(*p, (CMOS_VSTART_ramtop / 8) + i);
}

/*
 * RAMTOP range:
 *
 *  This defines the memory range covered by RAMTOP, which extends from
 *  cbmem_top down to FSP TOLUM. This range includes essential components:
 *
 * +---------------------------+ TOLUM / top_of_ram / cbmem_top
 * | CBMEM Root                |
 * +---------------------------+
 * | FSP Reserved Memory       |
 * +---------------------------+
 * | various CBMEM entries     |
 * +---------------------------+ top_of_stack (8 byte aligned)
 * | stack (CBMEM entry)       |
 * +---------------------------+ FSP TOLUM
 * |                           |
 * +---------------------------+ 0
*/
static size_t calculate_ramtop_size(uint32_t addr)
{
	struct range_entry fsp_mem;
	uint32_t fsp_reserve_base;
	fsp_find_reserved_memory(&fsp_mem);

	fsp_reserve_base = range_entry_base(&fsp_mem);
	size_t ramtop_size = ALIGN_UP(addr - fsp_reserve_base, 4 * MiB);

	return ramtop_size;
}

/* Update the RAMTOP if required based on the input top_of_ram address */
void update_ramtop(uint32_t addr)
{
	struct ramtop_table ramtop;

	/* Read and update ramtop (if required) */
	if (ramtop_cmos_read(&ramtop) < 0) {
		/* Structure invalid, re-initialize */
		ramtop.signature = RAMTOP_SIGNATURE;
		ramtop.addr = 0;
		ramtop.size = 0;
	}

	size_t size = calculate_ramtop_size(addr);

	/* Update ramtop if required */
	if ((ramtop.addr == addr) && (ramtop.size == size))
		return;

	ramtop.addr = addr;
	ramtop.size = size;

	/* Write the new top_of_ram address to CMOS */
	ramtop_cmos_write(&ramtop);

	printk(BIOS_DEBUG, "Updated the RAMTOP address (0x%x) with size (0x%zx) into CMOS\n",
			 ramtop.addr, ramtop.size);
}

uint32_t get_ramtop_addr(void)
{
	struct ramtop_table ramtop;

	if (ramtop_cmos_read(&ramtop) < 0)
		return 0;

	return ramtop.addr;
}

static uint32_t get_ramtop_size(void)
{
	struct ramtop_table ramtop;

	if (ramtop_cmos_read(&ramtop) < 0)
		return 0;

	return ramtop.size;
}

/* Early caching of top_of_ram region */
void early_ramtop_enable_cache_range(void)
{
	uint32_t ramtop = get_ramtop_addr();
	if (!ramtop)
		return;

	int mtrr = get_free_var_mtrr();
	if (mtrr == -1) {
		printk(BIOS_WARNING, "ramtop_table update failure due to no free MTRR available!\n");
		return;
	}

	size_t ramtop_size = get_ramtop_size();
	if (!ramtop_size)
		return;

	/*
	 *  INTEL RECOMMENDATION: Early Ramtop Caching Configuration
	 *
	 *  Configuring the Early Caching Ramtop range as Write-Back (WB) before
	 *  memory initialization is NOT RECOMMENDED. Speculative execution within
	 *  this WB range can lead to issues. WB configuration should be applied
	 *  to this range ONLY AFTER memory initialization is complete.
	 *
	 *  To enable Ramtop caching before memory initialization, use Write-Combining
	 *  (WC) instead of Write-Back (WB).
	 */
	set_var_mtrr(mtrr, ramtop - ramtop_size, ramtop_size, MTRR_TYPE_WRCOMB);
}