coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
uncore.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <cbmem.h>
4 #include <console/console.h>
5 #include <cpu/x86/lapic_def.h>
6 #include <device/pci.h>
7 #include <device/pci_ids.h>
8 #include <soc/acpi.h>
9 #include <soc/iomap.h>
10 #include <soc/pci_devs.h>
11 #include <soc/ramstage.h>
12 #include <soc/util.h>
13 #include <fsp/util.h>
15 #include <security/intel/txt/txt.h>
16 #include <stdint.h>
17 
18 struct map_entry {
20  int is_64_bit;
21  int is_limit;
22  int mask_bits;
23  const char *description;
24 };
25 
26 enum {
36  /* Must be last. */
38 };
39 
40 static struct map_entry memory_map[NUM_MAP_ENTRIES] = {
41  [TOHM_REG] = MAP_ENTRY_LIMIT_64(VTD_TOHM_CSR, 26, "TOHM"),
45  [TOLM_REG] = MAP_ENTRY_LIMIT_32(VTD_TOLM_CSR, 26, "TOLM"),
49  [TSEG_LIMIT_REG] = MAP_ENTRY_LIMIT_32(VTD_TSEG_LIMIT_CSR, 20, "TSEGMB_LIMIT"),
50 };
51 
52 static void read_map_entry(struct device *dev, struct map_entry *entry,
54 {
56  uint64_t mask;
57 
58  /* All registers are on a 1MiB granularity. */
59  mask = ((1ULL << entry->mask_bits) - 1);
60  mask = ~mask;
61 
62  value = 0;
63 
64  if (entry->is_64_bit) {
65  value = pci_read_config32(dev, entry->reg + sizeof(uint32_t));
66  value <<= 32;
67  }
68 
69  value |= (uint64_t)pci_read_config32(dev, entry->reg);
70  value &= mask;
71 
72  if (entry->is_limit)
73  value |= ~mask;
74 
75  *result = value;
76 }
77 
78 static void mc_read_map_entries(struct device *dev, uint64_t *values)
79 {
80  int i;
81  for (i = 0; i < NUM_MAP_ENTRIES; i++)
82  read_map_entry(dev, &memory_map[i], &values[i]);
83 }
84 
85 static void mc_report_map_entries(struct device *dev, uint64_t *values)
86 {
87  int i;
88  for (i = 0; i < NUM_MAP_ENTRIES; i++) {
89  printk(BIOS_DEBUG, "MC MAP: %s: 0x%llx\n",
90  memory_map[i].description, values[i]);
91  }
92 }
93 
94 static void configure_dpr(struct device *dev)
95 {
96  const uintptr_t cbmem_top_mb = ALIGN_UP((uintptr_t)cbmem_top(), MiB) / MiB;
97  union dpr_register dpr = { .raw = pci_read_config32(dev, VTD_LTDPR) };
98 
99  /* The DPR lock bit has to be set sufficiently early. It looks like
100  * it cannot be set anymore after FSP-S.
101  */
102  dpr.lock = 1;
103  dpr.epm = 1;
104  dpr.size = dpr.top - cbmem_top_mb;
105  pci_write_config32(dev, VTD_LTDPR, dpr.raw);
106 }
107 
108 /*
109  * Host Memory Map:
110  *
111  * +--------------------------+ TOCM (2 pow 46 - 1)
112  * | Reserved |
113  * +--------------------------+
114  * | MMIOH (relocatable) |
115  * +--------------------------+
116  * | PCISeg |
117  * +--------------------------+ TOHM
118  * | High DRAM Memory |
119  * +--------------------------+ 4GiB (0x100000000)
120  * +--------------------------+ 0xFFFF_FFFF
121  * | Firmware |
122  * +--------------------------+ 0xFF00_0000
123  * | Reserved |
124  * +--------------------------+ 0xFEF0_0000
125  * | Local xAPIC |
126  * +--------------------------+ 0xFEE0_0000
127  * | HPET/LT/TPM/Others |
128  * +--------------------------+ 0xFED0_0000
129  * | I/O xAPIC |
130  * +--------------------------+ 0xFEC0_0000
131  * | Reserved |
132  * +--------------------------+ 0xFEB8_0000
133  * | Reserved |
134  * +--------------------------+ 0xFEB0_0000
135  * | Reserved |
136  * +--------------------------+ 0xFE00_0000
137  * | MMIOL (relocatable) |
138  * | P2SB PCR cfg BAR | (0xfd000000 - 0xfdffffff
139  * | BAR space | [mem 0x90000000-0xfcffffff] available for PCI devices
140  * +--------------------------+ 0x9000_0000
141  * |PCIe MMCFG (relocatable) | CONFIG_ECAM_MMCONF_BASE_ADDRESS 64 or 256MB
142  * | | (0x80000000 - 0x8fffffff, 0x40000)
143  * +--------------------------+ TOLM
144  * | MEseg (relocatable) | 32, 64, 128 or 256 MB (0x78000000 - 0x7fffffff, 0x20000)
145  * +--------------------------+
146  * | Tseg (relocatable) | N x 8MB (0x70000000 - 0x77ffffff, 0x20000)
147  * +--------------------------+
148  * | DPR |
149  * +--------------------------+ cbmem_top
150  * | Reserved - CBMEM | (0x6fffe000 - 0x6fffffff, 0x2000)
151  * +--------------------------+
152  * | Reserved - FSP | (0x6fbfe000 - 0x6fffdfff, 0x400000)
153  * +--------------------------+ top_of_ram (0x6fbfdfff)
154  * | Low DRAM Memory |
155  * +--------------------------+ FFFFF (1MB)
156  * | E & F segments |
157  * +--------------------------+ E0000
158  * | C & D segments |
159  * +--------------------------+ C0000
160  * | VGA & SMM Memory |
161  * +--------------------------+ A0000
162  * | Conventional Memory |
163  * | (DOS Range) |
164  * +--------------------------+ 0
165  */
166 
167 static void mc_add_dram_resources(struct device *dev, int *res_count)
168 {
169  uint64_t base_kb;
170  uint64_t size_kb;
171  uint64_t mc_values[NUM_MAP_ENTRIES];
172  struct resource *resource;
173  int index = *res_count;
174 
175  /* Only add dram resources once. */
176  if (dev->bus->secondary != 0)
177  return;
178 
179  /* Read in the MAP registers and report their values. */
180  mc_read_map_entries(dev, &mc_values[0]);
181  mc_report_map_entries(dev, &mc_values[0]);
182 
183  /* Conventional Memory (DOS region, 0x0 to 0x9FFFF) */
184  base_kb = 0;
185  size_kb = (0xa0000 >> 10);
186  LOG_MEM_RESOURCE("legacy_ram", dev, index, base_kb, size_kb);
187  ram_resource(dev, index++, base_kb, size_kb);
188 
189  /* 1MB -> top_of_ram i.e., cbmem_top */
190  base_kb = (0x100000 >> 10);
191  size_kb = ((uintptr_t)cbmem_top() - 1 * MiB) >> 10;
192  LOG_MEM_RESOURCE("low_ram", dev, index, base_kb, size_kb);
193  ram_resource(dev, index++, base_kb, size_kb);
194 
195  /* Mark TSEG/SMM region as reserved */
196  base_kb = (mc_values[TSEG_BASE_REG] >> 10);
197  size_kb = (mc_values[TSEG_LIMIT_REG] - mc_values[TSEG_BASE_REG] + 1) >> 10;
198  LOG_MEM_RESOURCE("mmio_tseg", dev, index, base_kb, size_kb);
199  reserved_ram_resource(dev, index++, base_kb, size_kb);
200 
201  /* Reserve and set up DPR */
202  configure_dpr(dev);
203  union dpr_register dpr = { .raw = pci_read_config32(dev, VTD_LTDPR) };
204  if (dpr.size) {
205  uint64_t dpr_base_k = (dpr.top - dpr.size) << 10;
206  uint64_t dpr_size_k = dpr.size << 10;
207  reserved_ram_resource(dev, index++, dpr_base_k, dpr_size_k);
208  LOG_MEM_RESOURCE("dpr", dev, index, dpr_base_k, dpr_size_k);
209  }
210 
211  /* Mark region between TSEG - TOLM (eg. MESEG) as reserved */
212  if (mc_values[TSEG_LIMIT_REG] < mc_values[TOLM_REG]) {
213  base_kb = ((mc_values[TSEG_LIMIT_REG] + 1) >> 10);
214  size_kb = (mc_values[TOLM_REG] - mc_values[TSEG_LIMIT_REG]) >> 10;
215  LOG_MEM_RESOURCE("mmio_tolm", dev, index, base_kb, size_kb);
216  reserved_ram_resource(dev, index++, base_kb, size_kb);
217  }
218 
219  /* 4GiB -> TOHM */
220  if (mc_values[TOHM_REG] > 0x100000000) {
221  base_kb = (0x100000000 >> 10);
222  size_kb = (mc_values[TOHM_REG] - 0x100000000 + 1) >> 10;
223  LOG_MEM_RESOURCE("high_ram", dev, index, base_kb, size_kb);
224  ram_resource(dev, index++, base_kb, size_kb);
225  }
226 
227  /* add MMIO CFG resource */
228  resource = new_resource(dev, index++);
229  resource->base = (resource_t) mc_values[MMCFG_BASE_REG];
230  resource->size = (resource_t) (mc_values[MMCFG_LIMIT_REG] -
231  mc_values[MMCFG_BASE_REG] + 1);
234  LOG_MEM_RESOURCE("mmiocfg_res", dev, index-1, (resource->base >> 10),
235  (resource->size >> 10));
236 
237  /* add Local APIC resource */
238  resource = new_resource(dev, index++);
240  resource->size = 0x00001000;
243  LOG_MEM_RESOURCE("apic_res", dev, index-1, (resource->base >> 10),
244  (resource->size >> 10));
245 
246  /*
247  * Add legacy region as reserved - 0xa000 - 1MB
248  * Reserve everything between A segment and 1MB:
249  *
250  * 0xa0000 - 0xbffff: legacy VGA
251  * 0xc0000 - 0xfffff: RAM
252  */
253  base_kb = VGA_BASE_ADDRESS >> 10;
254  size_kb = VGA_BASE_SIZE >> 10;
255  LOG_MEM_RESOURCE("legacy_mmio", dev, index, base_kb, size_kb);
256  mmio_resource(dev, index++, base_kb, size_kb);
257 
258  base_kb = (0xc0000 >> 10);
259  size_kb = (0x100000 - 0xc0000) >> 10;
260  LOG_MEM_RESOURCE("legacy_write_protect", dev, index, base_kb, size_kb);
261  reserved_ram_resource(dev, index++, base_kb, size_kb);
262 
263  *res_count = index;
264 }
265 
266 static void mmapvtd_read_resources(struct device *dev)
267 {
268  int index = 0;
269 
270  /* Read standard PCI resources. */
272 
273  /* Calculate and add DRAM resources. */
274  mc_add_dram_resources(dev, &index);
275 }
276 
277 static void mmapvtd_init(struct device *dev)
278 {
279 }
280 
281 static struct device_operations mmapvtd_ops = {
283  .set_resources = pci_dev_set_resources,
284  .enable_resources = pci_dev_enable_resources,
285  .init = mmapvtd_init,
286  .ops_pci = &soc_pci_ops,
287 #if CONFIG(HAVE_ACPI_TABLES)
288  .acpi_inject_dsdt = uncore_inject_dsdt,
289 #endif
290 };
291 
292 static const unsigned short mmapvtd_ids[] = {
293  MMAP_VTD_CFG_REG_DEVID, /* Memory Map/Intel® VT-d Configuration Registers */
294  0
295 };
296 
297 static const struct pci_driver mmapvtd_driver __pci_driver = {
298  .ops = &mmapvtd_ops,
299  .vendor = PCI_VID_INTEL,
300  .devices = mmapvtd_ids
301 };
302 
303 static void vtd_read_resources(struct device *dev)
304 {
306 
307  configure_dpr(dev);
308 }
309 
310 static struct device_operations vtd_ops = {
312  .set_resources = pci_dev_set_resources,
313  .enable_resources = pci_dev_enable_resources,
314  .ops_pci = &soc_pci_ops,
315 };
316 
317 /* VTD devices on other stacks */
318 static const struct pci_driver vtd_driver __pci_driver = {
319  .ops = &vtd_ops,
320  .vendor = PCI_VID_INTEL,
322 };
323 
324 static void dmi3_init(struct device *dev)
325 {
326  if (CONFIG(INTEL_TXT) && skip_intel_txt_lockdown())
327  return;
328  /* Disable error injection */
329  pci_or_config16(dev, ERRINJCON, 1 << 0);
330 
331  /*
332  * DMIRCBAR registers are not TXT lockable, but the BAR enable
333  * bit is. TXT requires that DMIRCBAR be disabled for security.
334  */
335  pci_and_config32(dev, DMIRCBAR, ~(1 << 0));
336 }
337 
338 static struct device_operations dmi3_ops = {
340  .set_resources = pci_dev_set_resources,
341  .enable_resources = pci_dev_enable_resources,
342  .init = dmi3_init,
343  .ops_pci = &soc_pci_ops,
344 };
345 
346 static const struct pci_driver dmi3_driver __pci_driver = {
347  .ops = &dmi3_ops,
348  .vendor = PCI_VID_INTEL,
349  .device = DMI3_DEVID,
350 };
351 
352 static void iio_dfx_global_init(struct device *dev)
353 {
354  if (CONFIG(INTEL_TXT) && skip_intel_txt_lockdown())
355  return;
356 
357  uint16_t reg16;
358  pci_or_config16(dev, IIO_DFX_LCK_CTL, 0x3ff);
359  reg16 = pci_read_config16(dev, IIO_DFX_TSWCTL0);
360  reg16 &= ~(1 << 4); // allow ib mmio cfg
361  reg16 &= ~(1 << 5); // ignore acs p2p ma lpbk
362  reg16 |= (1 << 3); // me disable
363  pci_write_config16(dev, IIO_DFX_TSWCTL0, reg16);
364 }
365 
366 static const unsigned short iio_dfx_global_ids[] = {
367  0x202d,
368  0x203d,
369  0
370 };
371 
372 static struct device_operations iio_dfx_global_ops = {
374  .set_resources = pci_dev_set_resources,
375  .enable_resources = pci_dev_enable_resources,
376  .init = iio_dfx_global_init,
377  .ops_pci = &soc_pci_ops,
378 };
379 
380 static const struct pci_driver iio_dfx_global_driver __pci_driver = {
381  .ops = &iio_dfx_global_ops,
382  .vendor = PCI_VID_INTEL,
383  .devices = iio_dfx_global_ids,
384 };
pte_t value
Definition: mmu.c:91
#define MiB
Definition: helpers.h:76
#define ALIGN_UP(x, a)
Definition: helpers.h:17
void * cbmem_top(void)
Definition: imd_cbmem.c:18
#define printk(level,...)
Definition: stdlib.h:16
void uncore_inject_dsdt(const struct device *device)
Definition: soc_acpi.c:44
struct resource * new_resource(struct device *dev, unsigned int index)
See if a resource structure already exists for a given index and if not allocate one.
Definition: device_util.c:346
@ CONFIG
Definition: dsi_common.h:201
#define ram_resource(dev, idx, basek, sizek)
Definition: device.h:321
#define LOG_MEM_RESOURCE(type, dev, index, base_kb, size_kb)
Definition: device.h:281
#define mmio_resource(dev, idx, basek, sizek)
Definition: device.h:334
#define reserved_ram_resource(dev, idx, basek, sizek)
Definition: device.h:324
static __always_inline void pci_write_config32(const struct device *dev, u16 reg, u32 val)
Definition: pci_ops.h:76
static __always_inline void pci_or_config16(const struct device *dev, u16 reg, u16 ormask)
Definition: pci_ops.h:180
static __always_inline u16 pci_read_config16(const struct device *dev, u16 reg)
Definition: pci_ops.h:52
static __always_inline u32 pci_read_config32(const struct device *dev, u16 reg)
Definition: pci_ops.h:58
static __always_inline void pci_write_config16(const struct device *dev, u16 reg, u16 val)
Definition: pci_ops.h:70
static __always_inline void pci_and_config32(const struct device *dev, u16 reg, u32 andmask)
Definition: pci_ops.h:158
#define VGA_BASE_ADDRESS
Definition: iomap.h:26
#define MAP_ENTRY_LIMIT_32(reg_, mask_bits_, desc_)
Definition: iomap.h:15
#define VGA_BASE_SIZE
Definition: iomap.h:27
#define LAPIC_DEFAULT_BASE
Definition: lapic_def.h:12
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
bool skip_intel_txt_lockdown(void)
Definition: ramstage.c:359
result
Definition: mrc_cache.c:35
#define MAP_ENTRY_LIMIT_64(reg_, desc_)
Definition: northbridge.c:189
#define MAP_ENTRY_BASE_64(reg_, desc_)
Definition: northbridge.c:188
#define MAP_ENTRY_BASE_32(reg_, desc_)
Definition: northbridge.c:187
void pci_dev_enable_resources(struct device *dev)
Definition: pci_device.c:721
void pci_dev_read_resources(struct device *dev)
Definition: pci_device.c:534
void pci_dev_set_resources(struct device *dev)
Definition: pci_device.c:691
#define PCI_VID_INTEL
Definition: pci_ids.h:2157
#define IORESOURCE_RESERVE
Definition: resource.h:30
#define IORESOURCE_MEM
Definition: resource.h:10
#define IORESOURCE_STORED
Definition: resource.h:32
#define IORESOURCE_ASSIGNED
Definition: resource.h:34
u64 resource_t
Definition: resource.h:43
#define IORESOURCE_FIXED
Definition: resource.h:36
struct pci_operations soc_pci_ops
Definition: chip.c:51
static const int mask[4]
Definition: gpio.c:308
#define VTD_TOLM_CSR
Definition: pci_devs.h:104
#define VTD_MMCFG_LIMIT_CSR
Definition: pci_devs.h:109
#define ERRINJCON
Definition: pci_devs.h:167
#define VTD_TOHM_CSR
Definition: pci_devs.h:110
#define MMAP_VTD_CFG_REG_DEVID
Definition: pci_devs.h:139
#define VTD_TSEG_BASE_CSR
Definition: pci_devs.h:105
#define VTD_LTDPR
Definition: pci_devs.h:119
#define VTD_MMCFG_BASE_CSR
Definition: pci_devs.h:108
#define VTD_ME_BASE_CSR
Definition: pci_devs.h:112
#define VTD_MMIOL_CSR
Definition: pci_devs.h:111
#define IIO_DFX_TSWCTL0
Definition: pci_devs.h:183
#define MMAP_VTD_STACK_CFG_REG_DEVID
Definition: pci_devs.h:140
#define DMIRCBAR
Definition: pci_devs.h:166
#define IIO_DFX_LCK_CTL
Definition: pci_devs.h:184
#define VTD_ME_LIMIT_CSR
Definition: pci_devs.h:113
#define VTD_TSEG_LIMIT_CSR
Definition: pci_devs.h:106
#define DMI3_DEVID
Definition: pci_devs.h:165
unsigned short uint16_t
Definition: stdint.h:11
unsigned int uint32_t
Definition: stdint.h:14
unsigned long uintptr_t
Definition: stdint.h:21
unsigned long long uint64_t
Definition: stdint.h:17
uint16_t secondary
Definition: device.h:84
void(* read_resources)(struct device *dev)
Definition: device.h:39
Definition: device.h:107
DEVTREE_CONST struct bus * bus
Definition: device.h:108
Definition: northbridge.c:147
int is_64_bit
Definition: northbridge.c:149
uint32_t reg
Definition: uncore.c:19
const char * description
Definition: northbridge.c:151
int reg
Definition: northbridge.c:148
int mask_bits
Definition: uncore.c:22
int is_limit
Definition: northbridge.c:150
unsigned long flags
Definition: resource.h:49
resource_t base
Definition: resource.h:45
unsigned long index
Definition: resource.h:50
resource_t size
Definition: resource.h:46
static struct device_operations iio_dfx_global_ops
Definition: uncore.c:372
static const struct pci_driver mmapvtd_driver __pci_driver
Definition: uncore.c:297
static struct map_entry memory_map[NUM_MAP_ENTRIES]
Definition: uncore.c:40
static const unsigned short iio_dfx_global_ids[]
Definition: uncore.c:366
@ MMIOL_REG
Definition: uncore.c:28
@ ME_BASE_REG
Definition: uncore.c:32
@ TOLM_REG
Definition: uncore.c:31
@ TSEG_BASE_REG
Definition: uncore.c:34
@ NUM_MAP_ENTRIES
Definition: uncore.c:37
@ MMCFG_LIMIT_REG
Definition: uncore.c:30
@ ME_LIMIT_REG
Definition: uncore.c:33
@ TSEG_LIMIT_REG
Definition: uncore.c:35
@ TOHM_REG
Definition: uncore.c:27
@ MMCFG_BASE_REG
Definition: uncore.c:29
static void dmi3_init(struct device *dev)
Definition: uncore.c:324
static void mc_report_map_entries(struct device *dev, uint64_t *values)
Definition: uncore.c:85
static void configure_dpr(struct device *dev)
Definition: uncore.c:94
static void mc_read_map_entries(struct device *dev, uint64_t *values)
Definition: uncore.c:78
static void iio_dfx_global_init(struct device *dev)
Definition: uncore.c:352
static void vtd_read_resources(struct device *dev)
Definition: uncore.c:303
static struct device_operations vtd_ops
Definition: uncore.c:310
static void mmapvtd_read_resources(struct device *dev)
Definition: uncore.c:266
static struct device_operations dmi3_ops
Definition: uncore.c:338
static void read_map_entry(struct device *dev, struct map_entry *entry, uint64_t *result)
Definition: uncore.c:52
static void mc_add_dram_resources(struct device *dev, int *res_count)
Definition: uncore.c:167
static const unsigned short mmapvtd_ids[]
Definition: uncore.c:292
static struct device_operations mmapvtd_ops
Definition: uncore.c:281
static void mmapvtd_init(struct device *dev)
Definition: uncore.c:277
uint32_t raw
Definition: txt_register.h:174
uint32_t size
Definition: txt_register.h:170
uint32_t top
Definition: txt_register.h:172
uint32_t lock
Definition: txt_register.h:166
uint32_t epm
Definition: txt_register.h:168