]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: BSD-3-Clause |
63f559cd GB |
2 | /* |
3 | * This file is part of the libpayload project. | |
4 | * | |
5 | * Copyright (C) 2008 Advanced Micro Devices, Inc. | |
6 | * Copyright (C) 2009 coresystems GmbH | |
63f559cd GB |
7 | */ |
8 | ||
d678a59d | 9 | #include <common.h> |
e35b6497 | 10 | #include <asm/cb_sysinfo.h> |
1058ab37 SG |
11 | #include <init.h> |
12 | #include <mapmem.h> | |
13 | #include <net.h> | |
401d1c4f | 14 | #include <asm/global_data.h> |
63f559cd | 15 | |
9ef16867 SG |
16 | DECLARE_GLOBAL_DATA_PTR; |
17 | ||
93c1735f SR |
18 | /* |
19 | * This needs to be in the .data section so that it's copied over during | |
20 | * relocation. By default it's put in the .bss section which is simply filled | |
21 | * with zeroes when transitioning from "ROM", which is really RAM, to other | |
22 | * RAM. | |
23 | */ | |
236f2ec4 | 24 | struct sysinfo_t lib_sysinfo __section(".data"); |
93c1735f | 25 | |
63f559cd GB |
26 | /* |
27 | * Some of this is x86 specific, and the rest of it is generic. Right now, | |
28 | * since we only support x86, we'll avoid trying to make lots of infrastructure | |
29 | * we don't need. If in the future, we want to use coreboot on some other | |
30 | * architecture, then take out the generic parsing code and move it elsewhere. | |
31 | */ | |
32 | ||
33 | /* === Parsing code === */ | |
1058ab37 | 34 | /* This is the generic parsing code */ |
63f559cd GB |
35 | |
36 | static void cb_parse_memory(unsigned char *ptr, struct sysinfo_t *info) | |
37 | { | |
38 | struct cb_memory *mem = (struct cb_memory *)ptr; | |
39 | int count = MEM_RANGE_COUNT(mem); | |
40 | int i; | |
41 | ||
42 | if (count > SYSINFO_MAX_MEM_RANGES) | |
43 | count = SYSINFO_MAX_MEM_RANGES; | |
44 | ||
45 | info->n_memranges = 0; | |
46 | ||
47 | for (i = 0; i < count; i++) { | |
48 | struct cb_memory_range *range = | |
49 | (struct cb_memory_range *)MEM_RANGE_PTR(mem, i); | |
50 | ||
51 | info->memrange[info->n_memranges].base = | |
52 | UNPACK_CB64(range->start); | |
53 | ||
54 | info->memrange[info->n_memranges].size = | |
55 | UNPACK_CB64(range->size); | |
56 | ||
57 | info->memrange[info->n_memranges].type = range->type; | |
58 | ||
59 | info->n_memranges++; | |
60 | } | |
61 | } | |
62 | ||
63 | static void cb_parse_serial(unsigned char *ptr, struct sysinfo_t *info) | |
64 | { | |
65 | struct cb_serial *ser = (struct cb_serial *)ptr; | |
1058ab37 | 66 | |
402ed004 | 67 | info->serial = ser; |
63f559cd GB |
68 | } |
69 | ||
1058ab37 SG |
70 | static void cb_parse_vboot_handoff(unsigned char *ptr, struct sysinfo_t *info) |
71 | { | |
72 | struct lb_range *vbho = (struct lb_range *)ptr; | |
73 | ||
74 | info->vboot_handoff = (void *)(uintptr_t)vbho->range_start; | |
75 | info->vboot_handoff_size = vbho->range_size; | |
76 | } | |
77 | ||
402ed004 | 78 | static void cb_parse_vbnv(unsigned char *ptr, struct sysinfo_t *info) |
63f559cd | 79 | { |
1058ab37 | 80 | struct lb_range *vbnv = (struct lb_range *)ptr; |
402ed004 | 81 | |
1058ab37 SG |
82 | info->vbnv_start = vbnv->range_start; |
83 | info->vbnv_size = vbnv->range_size; | |
63f559cd GB |
84 | } |
85 | ||
53942b96 CG |
86 | static void cb_parse_cbmem_entry(unsigned char *ptr, struct sysinfo_t *info) |
87 | { | |
88 | struct cb_cbmem_entry *entry = (struct cb_cbmem_entry *)ptr; | |
89 | ||
90 | if (entry->id != CBMEM_ID_SMBIOS) | |
91 | return; | |
92 | ||
93 | info->smbios_start = entry->address; | |
94 | info->smbios_size = entry->entry_size; | |
95 | } | |
96 | ||
402ed004 | 97 | static void cb_parse_gpios(unsigned char *ptr, struct sysinfo_t *info) |
63f559cd | 98 | { |
402ed004 SG |
99 | int i; |
100 | struct cb_gpios *gpios = (struct cb_gpios *)ptr; | |
101 | ||
102 | info->num_gpios = (gpios->count < SYSINFO_MAX_GPIOS) ? | |
103 | (gpios->count) : SYSINFO_MAX_GPIOS; | |
104 | ||
105 | for (i = 0; i < info->num_gpios; i++) | |
106 | info->gpios[i] = gpios->gpios[i]; | |
107 | } | |
108 | ||
109 | static void cb_parse_vdat(unsigned char *ptr, struct sysinfo_t *info) | |
110 | { | |
1058ab37 SG |
111 | struct lb_range *vdat = (struct lb_range *)ptr; |
112 | ||
113 | info->vdat_addr = map_sysmem(vdat->range_start, vdat->range_size); | |
114 | info->vdat_size = vdat->range_size; | |
115 | } | |
116 | ||
117 | static void cb_parse_mac_addresses(unsigned char *ptr, | |
118 | struct sysinfo_t *info) | |
119 | { | |
120 | struct cb_macs *macs = (struct cb_macs *)ptr; | |
121 | int i; | |
122 | ||
123 | info->num_macs = (macs->count < ARRAY_SIZE(info->macs)) ? | |
124 | macs->count : ARRAY_SIZE(info->macs); | |
125 | ||
126 | for (i = 0; i < info->num_macs; i++) | |
127 | info->macs[i] = macs->mac_addrs[i]; | |
128 | } | |
129 | ||
130 | static void cb_parse_tstamp(void *ptr, struct sysinfo_t *info) | |
131 | { | |
132 | struct cb_cbmem_tab *const cbmem = ptr; | |
133 | ||
134 | info->tstamp_table = map_sysmem(cbmem->cbmem_tab, 0); | |
135 | } | |
136 | ||
137 | static void cb_parse_cbmem_cons(void *ptr, struct sysinfo_t *info) | |
138 | { | |
139 | struct cb_cbmem_tab *const cbmem = ptr; | |
140 | ||
141 | info->cbmem_cons = map_sysmem(cbmem->cbmem_tab, 0); | |
142 | } | |
143 | ||
144 | static void cb_parse_acpi_gnvs(unsigned char *ptr, struct sysinfo_t *info) | |
145 | { | |
146 | struct cb_cbmem_tab *const cbmem = (struct cb_cbmem_tab *)ptr; | |
402ed004 | 147 | |
1058ab37 | 148 | info->acpi_gnvs = map_sysmem(cbmem->cbmem_tab, 0); |
402ed004 SG |
149 | } |
150 | ||
1058ab37 | 151 | static void cb_parse_board_id(unsigned char *ptr, struct sysinfo_t *info) |
402ed004 | 152 | { |
1058ab37 SG |
153 | struct cb_board_id *const cbbid = (struct cb_board_id *)ptr; |
154 | ||
155 | info->board_id = cbbid->board_id; | |
402ed004 SG |
156 | } |
157 | ||
1058ab37 | 158 | static void cb_parse_ram_code(unsigned char *ptr, struct sysinfo_t *info) |
402ed004 | 159 | { |
1058ab37 SG |
160 | struct cb_ram_code *const ram_code = (struct cb_ram_code *)ptr; |
161 | ||
162 | info->ram_code = ram_code->ram_code; | |
63f559cd GB |
163 | } |
164 | ||
1058ab37 | 165 | static void cb_parse_optiontable(void *ptr, struct sysinfo_t *info) |
63f559cd | 166 | { |
1058ab37 SG |
167 | /* ptr points to a coreboot table entry and is already virtual */ |
168 | info->option_table = ptr; | |
169 | } | |
170 | ||
171 | static void cb_parse_checksum(void *ptr, struct sysinfo_t *info) | |
172 | { | |
173 | struct cb_cmos_checksum *cmos_cksum = ptr; | |
174 | ||
175 | info->cmos_range_start = cmos_cksum->range_start; | |
176 | info->cmos_range_end = cmos_cksum->range_end; | |
177 | info->cmos_checksum_location = cmos_cksum->location; | |
178 | } | |
179 | ||
180 | static void cb_parse_framebuffer(void *ptr, struct sysinfo_t *info) | |
181 | { | |
182 | /* ptr points to a coreboot table entry and is already virtual */ | |
183 | info->framebuffer = ptr; | |
63f559cd GB |
184 | } |
185 | ||
402ed004 SG |
186 | static void cb_parse_string(unsigned char *ptr, char **info) |
187 | { | |
188 | *info = (char *)((struct cb_string *)ptr)->string; | |
189 | } | |
190 | ||
1058ab37 SG |
191 | static void cb_parse_wifi_calibration(void *ptr, struct sysinfo_t *info) |
192 | { | |
193 | struct cb_cbmem_tab *const cbmem = (struct cb_cbmem_tab *)ptr; | |
194 | ||
195 | info->wifi_calibration = map_sysmem(cbmem->cbmem_tab, 0); | |
196 | } | |
197 | ||
198 | static void cb_parse_ramoops(void *ptr, struct sysinfo_t *info) | |
199 | { | |
200 | struct lb_range *ramoops = (struct lb_range *)ptr; | |
201 | ||
202 | info->ramoops_buffer = ramoops->range_start; | |
203 | info->ramoops_buffer_size = ramoops->range_size; | |
204 | } | |
205 | ||
206 | static void cb_parse_mtc(void *ptr, struct sysinfo_t *info) | |
207 | { | |
208 | struct lb_range *mtc = (struct lb_range *)ptr; | |
209 | ||
210 | info->mtc_start = mtc->range_start; | |
211 | info->mtc_size = mtc->range_size; | |
212 | } | |
213 | ||
214 | static void cb_parse_spi_flash(void *ptr, struct sysinfo_t *info) | |
215 | { | |
216 | struct cb_spi_flash *flash = (struct cb_spi_flash *)ptr; | |
217 | ||
218 | info->spi_flash.size = flash->flash_size; | |
219 | info->spi_flash.sector_size = flash->sector_size; | |
220 | info->spi_flash.erase_cmd = flash->erase_cmd; | |
221 | } | |
222 | ||
223 | static void cb_parse_boot_media_params(unsigned char *ptr, | |
224 | struct sysinfo_t *info) | |
225 | { | |
226 | struct cb_boot_media_params *const bmp = | |
227 | (struct cb_boot_media_params *)ptr; | |
228 | ||
229 | info->fmap_offset = bmp->fmap_offset; | |
230 | info->cbfs_offset = bmp->cbfs_offset; | |
231 | info->cbfs_size = bmp->cbfs_size; | |
232 | info->boot_media_size = bmp->boot_media_size; | |
233 | } | |
234 | ||
235 | static void cb_parse_vpd(void *ptr, struct sysinfo_t *info) | |
236 | { | |
237 | struct cb_cbmem_tab *const cbmem = (struct cb_cbmem_tab *)ptr; | |
238 | ||
239 | info->chromeos_vpd = map_sysmem(cbmem->cbmem_tab, 0); | |
240 | } | |
241 | ||
242 | static void cb_parse_tsc_info(void *ptr, struct sysinfo_t *info) | |
243 | { | |
244 | const struct cb_tsc_info *tsc_info = ptr; | |
245 | ||
246 | if (tsc_info->freq_khz == 0) | |
247 | return; | |
248 | ||
249 | /* Honor the TSC frequency passed to the payload */ | |
250 | info->cpu_khz = tsc_info->freq_khz; | |
251 | } | |
252 | ||
253 | static void cb_parse_x86_rom_var_mtrr(void *ptr, struct sysinfo_t *info) | |
254 | { | |
255 | struct cb_x86_rom_mtrr *rom_mtrr = ptr; | |
256 | ||
257 | info->x86_rom_var_mtrr_index = rom_mtrr->index; | |
258 | } | |
259 | ||
260 | static void cb_parse_mrc_cache(void *ptr, struct sysinfo_t *info) | |
261 | { | |
262 | struct cb_cbmem_tab *const cbmem = (struct cb_cbmem_tab *)ptr; | |
263 | ||
264 | info->mrc_cache = map_sysmem(cbmem->cbmem_tab, 0); | |
265 | } | |
266 | ||
368fd564 SG |
267 | static void cb_parse_acpi_rsdp(void *ptr, struct sysinfo_t *info) |
268 | { | |
269 | struct cb_cbmem_tab *const cbmem = (struct cb_cbmem_tab *)ptr; | |
270 | ||
271 | info->rsdp = map_sysmem(cbmem->cbmem_tab, 0); | |
272 | } | |
273 | ||
b52e9f0c CG |
274 | __weak void cb_parse_unhandled(u32 tag, unsigned char *ptr) |
275 | { | |
276 | } | |
277 | ||
63f559cd GB |
278 | static int cb_parse_header(void *addr, int len, struct sysinfo_t *info) |
279 | { | |
33139a0b | 280 | unsigned char *ptr = addr; |
63f559cd | 281 | struct cb_header *header; |
63f559cd GB |
282 | int i; |
283 | ||
33139a0b | 284 | header = (struct cb_header *)ptr; |
63f559cd GB |
285 | if (!header->table_bytes) |
286 | return 0; | |
287 | ||
1058ab37 | 288 | /* Make sure the checksums match */ |
b18c68d8 | 289 | if (!ip_checksum_ok(header, sizeof(*header))) |
63f559cd GB |
290 | return -1; |
291 | ||
b18c68d8 SG |
292 | if (compute_ip_checksum(ptr + sizeof(*header), header->table_bytes) != |
293 | header->table_checksum) | |
63f559cd GB |
294 | return -1; |
295 | ||
1058ab37 SG |
296 | info->header = header; |
297 | ||
298 | /* | |
299 | * Board straps represented by numerical values are small numbers. | |
300 | * Preset them to an invalid value in case the firmware does not | |
301 | * supply the info. | |
302 | */ | |
303 | info->board_id = ~0; | |
304 | info->ram_code = ~0; | |
305 | ||
306 | /* Now, walk the tables */ | |
63f559cd GB |
307 | ptr += header->header_bytes; |
308 | ||
1058ab37 | 309 | /* Inintialize some fields to sentinel values */ |
402ed004 SG |
310 | info->vbnv_start = info->vbnv_size = (uint32_t)(-1); |
311 | ||
63f559cd GB |
312 | for (i = 0; i < header->table_entries; i++) { |
313 | struct cb_record *rec = (struct cb_record *)ptr; | |
314 | ||
1058ab37 | 315 | /* We only care about a few tags here (maybe more later) */ |
63f559cd GB |
316 | switch (rec->tag) { |
317 | case CB_TAG_FORWARD: | |
318 | return cb_parse_header( | |
319 | (void *)(unsigned long) | |
320 | ((struct cb_forward *)rec)->forward, | |
321 | len, info); | |
322 | continue; | |
323 | case CB_TAG_MEMORY: | |
324 | cb_parse_memory(ptr, info); | |
325 | break; | |
326 | case CB_TAG_SERIAL: | |
327 | cb_parse_serial(ptr, info); | |
328 | break; | |
402ed004 | 329 | case CB_TAG_VERSION: |
1058ab37 | 330 | cb_parse_string(ptr, &info->cb_version); |
402ed004 SG |
331 | break; |
332 | case CB_TAG_EXTRA_VERSION: | |
333 | cb_parse_string(ptr, &info->extra_version); | |
334 | break; | |
335 | case CB_TAG_BUILD: | |
336 | cb_parse_string(ptr, &info->build); | |
337 | break; | |
338 | case CB_TAG_COMPILE_TIME: | |
339 | cb_parse_string(ptr, &info->compile_time); | |
340 | break; | |
341 | case CB_TAG_COMPILE_BY: | |
342 | cb_parse_string(ptr, &info->compile_by); | |
343 | break; | |
344 | case CB_TAG_COMPILE_HOST: | |
345 | cb_parse_string(ptr, &info->compile_host); | |
346 | break; | |
347 | case CB_TAG_COMPILE_DOMAIN: | |
348 | cb_parse_string(ptr, &info->compile_domain); | |
349 | break; | |
350 | case CB_TAG_COMPILER: | |
351 | cb_parse_string(ptr, &info->compiler); | |
352 | break; | |
353 | case CB_TAG_LINKER: | |
354 | cb_parse_string(ptr, &info->linker); | |
63f559cd | 355 | break; |
402ed004 SG |
356 | case CB_TAG_ASSEMBLER: |
357 | cb_parse_string(ptr, &info->assembler); | |
63f559cd | 358 | break; |
1058ab37 SG |
359 | case CB_TAG_CMOS_OPTION_TABLE: |
360 | cb_parse_optiontable(ptr, info); | |
361 | break; | |
362 | case CB_TAG_OPTION_CHECKSUM: | |
363 | cb_parse_checksum(ptr, info); | |
364 | break; | |
63f559cd GB |
365 | /* |
366 | * FIXME we should warn on serial if coreboot set up a | |
367 | * framebuffer buf the payload does not know about it. | |
368 | */ | |
369 | case CB_TAG_FRAMEBUFFER: | |
370 | cb_parse_framebuffer(ptr, info); | |
371 | break; | |
1058ab37 SG |
372 | case CB_TAG_MAINBOARD: |
373 | info->mainboard = (struct cb_mainboard *)ptr; | |
374 | break; | |
402ed004 SG |
375 | case CB_TAG_GPIO: |
376 | cb_parse_gpios(ptr, info); | |
377 | break; | |
378 | case CB_TAG_VDAT: | |
379 | cb_parse_vdat(ptr, info); | |
380 | break; | |
1058ab37 SG |
381 | case CB_TAG_VBNV: |
382 | cb_parse_vbnv(ptr, info); | |
383 | break; | |
384 | case CB_TAG_VBOOT_HANDOFF: | |
385 | cb_parse_vboot_handoff(ptr, info); | |
386 | break; | |
387 | case CB_TAG_MAC_ADDRS: | |
388 | cb_parse_mac_addresses(ptr, info); | |
389 | break; | |
390 | case CB_TAG_SERIALNO: | |
391 | cb_parse_string(ptr, &info->serialno); | |
392 | break; | |
402ed004 SG |
393 | case CB_TAG_TIMESTAMPS: |
394 | cb_parse_tstamp(ptr, info); | |
395 | break; | |
396 | case CB_TAG_CBMEM_CONSOLE: | |
397 | cb_parse_cbmem_cons(ptr, info); | |
398 | break; | |
1058ab37 SG |
399 | case CB_TAG_ACPI_GNVS: |
400 | cb_parse_acpi_gnvs(ptr, info); | |
402ed004 | 401 | break; |
53942b96 CG |
402 | case CB_TAG_CBMEM_ENTRY: |
403 | cb_parse_cbmem_entry(ptr, info); | |
404 | break; | |
1058ab37 SG |
405 | case CB_TAG_BOARD_ID: |
406 | cb_parse_board_id(ptr, info); | |
407 | break; | |
408 | case CB_TAG_RAM_CODE: | |
409 | cb_parse_ram_code(ptr, info); | |
410 | break; | |
411 | case CB_TAG_WIFI_CALIBRATION: | |
412 | cb_parse_wifi_calibration(ptr, info); | |
413 | break; | |
414 | case CB_TAG_RAM_OOPS: | |
415 | cb_parse_ramoops(ptr, info); | |
416 | break; | |
417 | case CB_TAG_SPI_FLASH: | |
418 | cb_parse_spi_flash(ptr, info); | |
419 | break; | |
420 | case CB_TAG_MTC: | |
421 | cb_parse_mtc(ptr, info); | |
422 | break; | |
423 | case CB_TAG_BOOT_MEDIA_PARAMS: | |
424 | cb_parse_boot_media_params(ptr, info); | |
425 | break; | |
426 | case CB_TAG_TSC_INFO: | |
427 | cb_parse_tsc_info(ptr, info); | |
428 | break; | |
429 | case CB_TAG_VPD: | |
430 | cb_parse_vpd(ptr, info); | |
431 | break; | |
432 | case CB_TAG_X86_ROM_MTRR: | |
433 | cb_parse_x86_rom_var_mtrr(rec, info); | |
434 | break; | |
435 | case CB_TAG_MRC_CACHE: | |
436 | cb_parse_mrc_cache(rec, info); | |
437 | break; | |
368fd564 SG |
438 | case CB_TAG_ACPI_RSDP: |
439 | cb_parse_acpi_rsdp(rec, info); | |
440 | break; | |
b52e9f0c | 441 | default: |
2f5210b7 SG |
442 | if (info->unimpl_count < SYSINFO_MAX_UNIMPL) |
443 | info->unimpl[info->unimpl_count++] = rec->tag; | |
b52e9f0c CG |
444 | cb_parse_unhandled(rec->tag, ptr); |
445 | break; | |
63f559cd GB |
446 | } |
447 | ||
448 | ptr += rec->size; | |
449 | } | |
db971a75 SG |
450 | info->table_size += (void *)ptr - (void *)header; |
451 | info->rec_count += header->table_entries; | |
63f559cd GB |
452 | |
453 | return 1; | |
454 | } | |
455 | ||
456 | /* == Architecture specific == */ | |
1058ab37 | 457 | /* This is the x86 specific stuff */ |
63f559cd | 458 | |
63f559cd GB |
459 | int get_coreboot_info(struct sysinfo_t *info) |
460 | { | |
33139a0b SG |
461 | long addr; |
462 | int ret; | |
63f559cd | 463 | |
33139a0b SG |
464 | addr = locate_coreboot_table(); |
465 | if (addr < 0) | |
466 | return addr; | |
db971a75 SG |
467 | info->table_size = 0; |
468 | info->rec_count = 0; | |
33139a0b | 469 | ret = cb_parse_header((void *)addr, 0x1000, info); |
9ef16867 SG |
470 | if (!ret) |
471 | return -ENOENT; | |
472 | gd->arch.coreboot_table = addr; | |
368fd564 | 473 | gd_set_acpi_start(map_to_sysmem(info->rsdp)); |
93543309 | 474 | gd_set_smbios_start(info->smbios_start); |
9ef16867 | 475 | gd->flags |= GD_FLG_SKIP_LL_INIT; |
63f559cd | 476 | |
9ef16867 | 477 | return 0; |
63f559cd | 478 | } |
1058ab37 SG |
479 | |
480 | const struct sysinfo_t *cb_get_sysinfo(void) | |
481 | { | |
482 | if (!ll_boot_init()) | |
483 | return &lib_sysinfo; | |
484 | ||
485 | return NULL; | |
486 | } |