blob: edd5c2394e54cdfa12eab6a980660020eb75d54e [file] [log] [blame]
Marc Jones1587dc82017-05-15 18:55:11 -06001/*
2 * This file is part of the coreboot project.
3 *
Marshall Dawsonb6172112017-09-13 17:47:31 -06004 * Copyright (C) 2015 Intel Corp.
5 *
Marc Jones1587dc82017-05-15 18:55:11 -06006 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#define __SIMPLE_DEVICE__
17
Marshall Dawsonb6172112017-09-13 17:47:31 -060018#include <assert.h>
Marc Jones1587dc82017-05-15 18:55:11 -060019#include <stdint.h>
Marshall Dawson94ee9372017-06-15 12:18:23 -060020#include <cpu/x86/msr.h>
Elyes HAOUAS400ce552018-10-12 10:54:30 +020021#include <cpu/amd/msr.h>
Marshall Dawson94ee9372017-06-15 12:18:23 -060022#include <cpu/amd/mtrr.h>
Marc Jones1587dc82017-05-15 18:55:11 -060023#include <cbmem.h>
Marshall Dawsonf3c57a7c2018-01-29 18:08:16 -070024#include <stage_cache.h>
Marshall Dawson4b0f6fa2018-09-04 13:08:25 -060025#include <arch/bert_storage.h>
Marshall Dawsonb6172112017-09-13 17:47:31 -060026#include <soc/northbridge.h>
Marshall Dawson22f54c52017-11-29 09:30:23 -070027#include <soc/southbridge.h>
Marc Jones1587dc82017-05-15 18:55:11 -060028
29void backup_top_of_low_cacheable(uintptr_t ramtop)
30{
Marshall Dawson22f54c52017-11-29 09:30:23 -070031 biosram_write32(BIOSRAM_CBMEM_TOP, ramtop);
Marc Jones1587dc82017-05-15 18:55:11 -060032}
33
34uintptr_t restore_top_of_low_cacheable(void)
35{
Marshall Dawson22f54c52017-11-29 09:30:23 -070036 return biosram_read32(BIOSRAM_CBMEM_TOP);
Marc Jones1587dc82017-05-15 18:55:11 -060037}
Marshall Dawson94ee9372017-06-15 12:18:23 -060038
Julius Wernercd49cce2019-03-05 16:53:33 -080039#if CONFIG(ACPI_BERT)
Marshall Dawsonf0de2422018-09-10 13:28:49 -060040 #if CONFIG_SMM_TSEG_SIZE == 0x0
41 #define BERT_REGION_MAX_SIZE 0x100000
42 #else
43 /* SMM_TSEG_SIZE must stay on a boundary appropriate for its granularity */
44 #define BERT_REGION_MAX_SIZE CONFIG_SMM_TSEG_SIZE
45 #endif
Marshall Dawson4b0f6fa2018-09-04 13:08:25 -060046#else
Marshall Dawsonf0de2422018-09-10 13:28:49 -060047 #define BERT_REGION_MAX_SIZE 0
Marshall Dawson4b0f6fa2018-09-04 13:08:25 -060048#endif
49
50void bert_reserved_region(void **start, size_t *size)
51{
Julius Wernercd49cce2019-03-05 16:53:33 -080052 if (CONFIG(ACPI_BERT))
Marshall Dawson4b0f6fa2018-09-04 13:08:25 -060053 *start = cbmem_top();
54 else
55 start = NULL;
56 *size = BERT_REGION_MAX_SIZE;
57}
58
Marshall Dawson94ee9372017-06-15 12:18:23 -060059void *cbmem_top(void)
60{
61 msr_t tom = rdmsr(TOP_MEM);
62
63 if (!tom.lo)
64 return 0;
Richard Spiegel8c614f22018-10-23 14:53:23 -070065
66 /* 8MB alignment to keep MTRR usage low */
67 return (void *)ALIGN_DOWN(restore_top_of_low_cacheable()
68 - CONFIG_SMM_TSEG_SIZE
69 - BERT_REGION_MAX_SIZE, 8*MiB);
Marshall Dawsonb6172112017-09-13 17:47:31 -060070}
71
72static uintptr_t smm_region_start(void)
73{
Marshall Dawson4b0f6fa2018-09-04 13:08:25 -060074 return (uintptr_t)cbmem_top() + BERT_REGION_MAX_SIZE;
Marshall Dawsonb6172112017-09-13 17:47:31 -060075}
76
77static size_t smm_region_size(void)
78{
79 return CONFIG_SMM_TSEG_SIZE;
80}
81
Marshall Dawsonf3c57a7c2018-01-29 18:08:16 -070082void stage_cache_external_region(void **base, size_t *size)
83{
84 if (smm_subregion(SMM_SUBREGION_CACHE, base, size)) {
85 printk(BIOS_ERR, "ERROR: No cache SMM subregion.\n");
86 *base = NULL;
87 *size = 0;
88 }
89}
90
Marshall Dawsonb6172112017-09-13 17:47:31 -060091void smm_region_info(void **start, size_t *size)
92{
93 *start = (void *)smm_region_start();
94 *size = smm_region_size();
95}
96
Marshall Dawsonf3c57a7c2018-01-29 18:08:16 -070097/*
98 * For data stored in TSEG, ensure TValid is clear so R/W access can reach
99 * the DRAM when not in SMM.
100 */
101static void clear_tvalid(void)
102{
103 msr_t hwcr = rdmsr(HWCR_MSR);
Elyes HAOUAS400ce552018-10-12 10:54:30 +0200104 msr_t mask = rdmsr(SMM_MASK_MSR);
Marshall Dawsonf3c57a7c2018-01-29 18:08:16 -0700105 int tvalid = !!(mask.lo & SMM_TSEG_VALID);
106
107 if (hwcr.lo & SMM_LOCK) {
108 if (!tvalid) /* not valid but locked means still accessible */
109 return;
110
111 printk(BIOS_ERR, "Error: can't clear TValid, already locked\n");
112 return;
113 }
114
115 mask.lo &= ~SMM_TSEG_VALID;
Elyes HAOUAS400ce552018-10-12 10:54:30 +0200116 wrmsr(SMM_MASK_MSR, mask);
Marshall Dawsonf3c57a7c2018-01-29 18:08:16 -0700117}
118
Marshall Dawsonb6172112017-09-13 17:47:31 -0600119int smm_subregion(int sub, void **start, size_t *size)
120{
121 uintptr_t sub_base;
122 size_t sub_size;
123 const size_t cache_size = CONFIG_SMM_RESERVED_SIZE;
124
125 sub_base = smm_region_start();
126 sub_size = smm_region_size();
127
128 assert(sub_size > CONFIG_SMM_RESERVED_SIZE);
129
130 switch (sub) {
131 case SMM_SUBREGION_HANDLER:
132 /* Handler starts at the base of TSEG. */
133 sub_size -= cache_size;
134 break;
135 case SMM_SUBREGION_CACHE:
136 /* External cache is in the middle of TSEG. */
137 sub_base += sub_size - cache_size;
138 sub_size = cache_size;
Marshall Dawsonf3c57a7c2018-01-29 18:08:16 -0700139 clear_tvalid();
Marshall Dawsonb6172112017-09-13 17:47:31 -0600140 break;
141 default:
142 return -1;
143 }
144
145 *start = (void *)sub_base;
146 *size = sub_size;
147
148 return 0;
Marshall Dawson94ee9372017-06-15 12:18:23 -0600149}