coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
tables.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <console/console.h>
4 #include <bootmem.h>
5 #include <boot/tables.h>
6 #include <boot/coreboot_tables.h>
7 #include <arch/pirq_routing.h>
8 #include <arch/smp/mpspec.h>
9 #include <acpi/acpi.h>
10 #include <commonlib/helpers.h>
11 #include <string.h>
12 #include <cbmem.h>
13 #include <smbios.h>
14 
15 static unsigned long write_pirq_table(unsigned long rom_table_end)
16 {
17  unsigned long high_table_pointer;
18 
19 #define MAX_PIRQ_TABLE_SIZE (4 * 1024)
20  post_code(0x9a);
21 
22  /* This table must be between 0x0f0000 and 0x100000 */
23  rom_table_end = write_pirq_routing_table(rom_table_end);
24  rom_table_end = ALIGN_UP(rom_table_end, 1024);
25 
26  /* And add a high table version for those payloads that
27  * want to live in the F segment
28  */
29  high_table_pointer = (unsigned long)cbmem_add(CBMEM_ID_PIRQ,
31  if (high_table_pointer) {
32  unsigned long new_high_table_pointer;
33  new_high_table_pointer =
34  write_pirq_routing_table(high_table_pointer);
35  // FIXME make pirq table code intelligent enough to know how
36  // much space it's going to need.
37  if (new_high_table_pointer > (high_table_pointer
39  printk(BIOS_ERR, "Increase PIRQ size.\n");
40  printk(BIOS_DEBUG, "PIRQ table: %ld bytes.\n",
41  new_high_table_pointer - high_table_pointer);
42  }
43 
44  return rom_table_end;
45 }
46 
47 static unsigned long write_mptable(unsigned long rom_table_end)
48 {
49  unsigned long high_table_pointer;
50 
51 #define MAX_MP_TABLE_SIZE (4 * 1024)
52  post_code(0x9b);
53 
54  /* The smp table must be in 0-1K, 639K-640K, or 960K-1M */
55  rom_table_end = write_smp_table(rom_table_end);
56  rom_table_end = ALIGN_UP(rom_table_end, 1024);
57 
58  high_table_pointer = (unsigned long)cbmem_add(CBMEM_ID_MPTABLE,
60  if (high_table_pointer) {
61  unsigned long new_high_table_pointer;
62  new_high_table_pointer = write_smp_table(high_table_pointer);
63  // FIXME make mp table code intelligent enough to know how
64  // much space it's going to need.
65  if (new_high_table_pointer > (high_table_pointer
67  printk(BIOS_ERR, "Increase MP table size.\n");
68 
69  printk(BIOS_DEBUG, "MP table: %ld bytes.\n",
70  new_high_table_pointer - high_table_pointer);
71  }
72 
73  return rom_table_end;
74 }
75 
76 static unsigned long write_acpi_table(unsigned long rom_table_end)
77 {
78  unsigned long high_table_pointer;
79  const size_t max_acpi_size = CONFIG_MAX_ACPI_TABLE_SIZE_KB * KiB;
80 
81  post_code(0x9c);
82 
83  /* Write ACPI tables to F segment and high tables area */
84 
85  /* Ok, this is a bit hacky still, because some day we want to have this
86  * completely dynamic. But right now we are setting fixed sizes.
87  * It's probably still better than the old high_table_base code because
88  * now at least we know when we have an overflow in the area.
89  *
90  * We want to use 1MB - 64K for Resume backup. We use 512B for TOC and
91  * 512 byte for GDT, 4K for PIRQ and 4K for MP table and 8KB for the
92  * coreboot table. This leaves us with 47KB for all of ACPI. Let's see
93  * how far we get.
94  */
95  high_table_pointer = (unsigned long)cbmem_add(CBMEM_ID_ACPI,
96  max_acpi_size);
97  if (high_table_pointer) {
98  unsigned long acpi_start = high_table_pointer;
99  unsigned long new_high_table_pointer;
100 
101  rom_table_end = ALIGN_UP(rom_table_end, 16);
102  new_high_table_pointer = write_acpi_tables(high_table_pointer);
103  if (new_high_table_pointer > (high_table_pointer
104  + max_acpi_size))
105  printk(BIOS_ERR, "Increase ACPI size\n");
106  printk(BIOS_DEBUG, "ACPI tables: %ld bytes.\n",
107  new_high_table_pointer - high_table_pointer);
108 
109  /* Now we need to create a low table copy of the RSDP. */
110 
111  /* First we look for the high table RSDP */
112  while (acpi_start < new_high_table_pointer) {
113  if (memcmp(((acpi_rsdp_t *)acpi_start)->signature,
114  RSDP_SIG, 8) == 0)
115  break;
116  acpi_start++;
117  }
118 
119  /* Now, if we found the RSDP, we take the RSDT and XSDT pointer
120  * from it in order to write the low RSDP
121  */
122  if (acpi_start < new_high_table_pointer) {
123  acpi_rsdp_t *low_rsdp = (acpi_rsdp_t *)rom_table_end,
124  *high_rsdp = (acpi_rsdp_t *)acpi_start;
125 
126  /* Technically rsdp length varies but coreboot always
127  writes longest size available. */
128  memcpy(low_rsdp, high_rsdp, sizeof(acpi_rsdp_t));
129  } else {
130  printk(BIOS_ERR, "Didn't find RSDP in high table.\n");
131  }
132  rom_table_end = ALIGN_UP(rom_table_end + sizeof(acpi_rsdp_t), 16);
133  } else {
134  rom_table_end = write_acpi_tables(rom_table_end);
135  rom_table_end = ALIGN_UP(rom_table_end, 1024);
136  }
137 
138  return rom_table_end;
139 }
140 
141 static unsigned long write_smbios_table(unsigned long rom_table_end)
142 {
143  unsigned long high_table_pointer;
144 
145 #define MAX_SMBIOS_SIZE (4 * KiB)
146 
147  high_table_pointer = (unsigned long)cbmem_add(CBMEM_ID_SMBIOS,
149  if (high_table_pointer) {
150  unsigned long new_high_table_pointer;
151 
152  new_high_table_pointer =
153  smbios_write_tables(high_table_pointer);
154  rom_table_end = ALIGN_UP(rom_table_end, 16);
155  memcpy((void *)rom_table_end, (void *)high_table_pointer,
156  sizeof(struct smbios_entry));
157  rom_table_end += sizeof(struct smbios_entry);
158 
159  if (new_high_table_pointer > (high_table_pointer
160  + MAX_SMBIOS_SIZE))
161  printk(BIOS_ERR, "Increase SMBIOS size\n");
162  printk(BIOS_DEBUG, "SMBIOS tables: %ld bytes.\n",
163  new_high_table_pointer - high_table_pointer);
164  } else {
165  unsigned long new_rom_table_end;
166 
167  new_rom_table_end = smbios_write_tables(rom_table_end);
168  printk(BIOS_DEBUG, "SMBIOS size %ld bytes\n", new_rom_table_end
169  - rom_table_end);
170  rom_table_end = ALIGN_UP(new_rom_table_end, 16);
171  }
172 
173  return rom_table_end;
174 }
175 
176 /* Start forwarding table at 0x500, so we don't run into conflicts with the BDA
177  * in case our data structures grow beyond 0x400. Only GDT
178  * and the coreboot table use low_tables.
179  */
180 #define FORWARDING_TABLE_ADDR ((uintptr_t)0x500)
182 
183 void arch_write_tables(uintptr_t coreboot_table)
184 {
185  size_t sz;
186  unsigned long rom_table_end = 0xf0000;
187 
188  /* This table must be between 0x0f0000 and 0x100000 */
189  if (CONFIG(GENERATE_PIRQ_TABLE))
190  rom_table_end = write_pirq_table(rom_table_end);
191 
192  /* The smp table must be in 0-1K, 639K-640K, or 960K-1M */
193  if (CONFIG(GENERATE_MP_TABLE))
194  rom_table_end = write_mptable(rom_table_end);
195 
196  if (CONFIG(HAVE_ACPI_TABLES))
197  rom_table_end = write_acpi_table(rom_table_end);
198 
199  if (CONFIG(GENERATE_SMBIOS_TABLES))
200  rom_table_end = write_smbios_table(rom_table_end);
201 
203 
204  forwarding_table += sz;
205  /* Align up to page boundary for historical consistency. */
207 
208  /* Tell static analysis we know value is left unused. */
209  (void)rom_table_end;
210 }
211 
213 {
214  /* Memory from 0 through the forwarding_table is reserved. */
215  const uintptr_t base = 0;
216 
218 }
unsigned long write_acpi_tables(unsigned long start)
Definition: acpi.c:1592
void arch_write_tables(uintptr_t coreboot_table)
Definition: tables.c:8
void bootmem_arch_add_ranges(void)
Definition: tables.c:12
void * memcpy(void *dest, const void *src, size_t n)
Definition: memcpy.c:7
unsigned long smbios_write_tables(unsigned long current)
Definition: smbios.c:1290
#define MAX_PIRQ_TABLE_SIZE
static unsigned long write_pirq_table(unsigned long rom_table_end)
Definition: tables.c:15
static unsigned long write_mptable(unsigned long rom_table_end)
Definition: tables.c:47
static unsigned long write_smbios_table(unsigned long rom_table_end)
Definition: tables.c:141
#define MAX_SMBIOS_SIZE
static unsigned long write_acpi_table(unsigned long rom_table_end)
Definition: tables.c:76
static uintptr_t forwarding_table
Definition: tables.c:181
#define FORWARDING_TABLE_ADDR
Definition: tables.c:180
#define MAX_MP_TABLE_SIZE
@ BM_MEM_TABLE
Definition: bootmem.h:31
void bootmem_add_range(uint64_t start, uint64_t size, const enum bootmem_type tag)
Definition: bootmem.c:88
#define KiB
Definition: helpers.h:75
#define ALIGN_UP(x, a)
Definition: helpers.h:17
void * cbmem_add(u32 id, u64 size)
Definition: imd_cbmem.c:144
#define CBMEM_ID_MPTABLE
Definition: cbmem_id.h:36
#define CBMEM_ID_ACPI
Definition: cbmem_id.h:6
#define CBMEM_ID_SMBIOS
Definition: cbmem_id.h:54
#define CBMEM_ID_PIRQ
Definition: cbmem_id.h:42
#define printk(level,...)
Definition: stdlib.h:16
@ CONFIG
Definition: dsi_common.h:201
#define RSDP_SIG
Definition: acpi.h:56
size_t write_coreboot_forwarding_table(uintptr_t entry, uintptr_t target)
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
unsigned long write_smp_table(unsigned long addr)
Definition: mpspec.c:530
unsigned long write_pirq_routing_table(unsigned long start)
Definition: irq_tables.c:28
#define post_code(value)
Definition: post_code.h:12
uintptr_t base
Definition: uart.c:17
unsigned long uintptr_t
Definition: stdint.h:21
int memcmp(const void *s1, const void *s2, size_t n)
Definition: memcmp.c:3
Definition: acpi.h:82
Definition: smbios.h:259
typedef void(X86APIP X86EMU_intrFuncs)(int num)