1// SPDX-License-Identifier: BSD-3-Clause
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
7 */
8
9#include <common.h>
10#include <asm/cb_sysinfo.h>
11#include <init.h>
12#include <mapmem.h>
13#include <net.h>
14#include <asm/global_data.h>
15
16DECLARE_GLOBAL_DATA_PTR;
17
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 */
24struct sysinfo_t lib_sysinfo __section(".data");
25
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 === */
34/* This is the generic parsing code */
35
36static 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
63static void cb_parse_serial(unsigned char *ptr, struct sysinfo_t *info)
64{
65	struct cb_serial *ser = (struct cb_serial *)ptr;
66
67	info->serial = ser;
68}
69
70static 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
78static void cb_parse_vbnv(unsigned char *ptr, struct sysinfo_t *info)
79{
80	struct lb_range *vbnv = (struct lb_range *)ptr;
81
82	info->vbnv_start = vbnv->range_start;
83	info->vbnv_size = vbnv->range_size;
84}
85
86static 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
97static void cb_parse_gpios(unsigned char *ptr, struct sysinfo_t *info)
98{
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
109static void cb_parse_vdat(unsigned char *ptr, struct sysinfo_t *info)
110{
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
117static 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
130static 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
137static 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
144static 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;
147
148	info->acpi_gnvs = map_sysmem(cbmem->cbmem_tab, 0);
149}
150
151static void cb_parse_board_id(unsigned char *ptr, struct sysinfo_t *info)
152{
153	struct cb_board_id *const cbbid = (struct cb_board_id *)ptr;
154
155	info->board_id = cbbid->board_id;
156}
157
158static void cb_parse_ram_code(unsigned char *ptr, struct sysinfo_t *info)
159{
160	struct cb_ram_code *const ram_code = (struct cb_ram_code *)ptr;
161
162	info->ram_code = ram_code->ram_code;
163}
164
165static void cb_parse_optiontable(void *ptr, struct sysinfo_t *info)
166{
167	/* ptr points to a coreboot table entry and is already virtual */
168	info->option_table = ptr;
169}
170
171static 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
180static 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;
184}
185
186static void cb_parse_string(unsigned char *ptr, char **info)
187{
188	*info = (char *)((struct cb_string *)ptr)->string;
189}
190
191static 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
198static 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
206static 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
214static 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
223static 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
235static 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
242static 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
253static 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
260static 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
267static 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
274__weak void cb_parse_unhandled(u32 tag, unsigned char *ptr)
275{
276}
277
278static int cb_parse_header(void *addr, int len, struct sysinfo_t *info)
279{
280	unsigned char *ptr = addr;
281	struct cb_header *header;
282	int i;
283
284	header = (struct cb_header *)ptr;
285	if (!header->table_bytes)
286		return 0;
287
288	/* Make sure the checksums match */
289	if (!ip_checksum_ok(header, sizeof(*header)))
290		return -1;
291
292	if (compute_ip_checksum(ptr + sizeof(*header), header->table_bytes) !=
293	    header->table_checksum)
294		return -1;
295
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 */
307	ptr += header->header_bytes;
308
309	/* Inintialize some fields to sentinel values */
310	info->vbnv_start = info->vbnv_size = (uint32_t)(-1);
311
312	for (i = 0; i < header->table_entries; i++) {
313		struct cb_record *rec = (struct cb_record *)ptr;
314
315		/* We only care about a few tags here (maybe more later) */
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;
329		case CB_TAG_VERSION:
330			cb_parse_string(ptr, &info->cb_version);
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);
355			break;
356		case CB_TAG_ASSEMBLER:
357			cb_parse_string(ptr, &info->assembler);
358			break;
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;
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;
372		case CB_TAG_MAINBOARD:
373			info->mainboard = (struct cb_mainboard *)ptr;
374			break;
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;
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;
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;
399		case CB_TAG_ACPI_GNVS:
400			cb_parse_acpi_gnvs(ptr, info);
401			break;
402		case CB_TAG_CBMEM_ENTRY:
403			cb_parse_cbmem_entry(ptr, info);
404			break;
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;
438		case CB_TAG_ACPI_RSDP:
439			cb_parse_acpi_rsdp(rec, info);
440			break;
441		default:
442			if (info->unimpl_count < SYSINFO_MAX_UNIMPL)
443				info->unimpl[info->unimpl_count++] = rec->tag;
444			cb_parse_unhandled(rec->tag, ptr);
445			break;
446		}
447
448		ptr += rec->size;
449	}
450	info->table_size += (void *)ptr - (void *)header;
451	info->rec_count += header->table_entries;
452
453	return 1;
454}
455
456/* == Architecture specific == */
457/* This is the x86 specific stuff */
458
459int get_coreboot_info(struct sysinfo_t *info)
460{
461	long addr;
462	int ret;
463
464	addr = locate_coreboot_table();
465	if (addr < 0)
466		return addr;
467	info->table_size = 0;
468	info->rec_count = 0;
469	ret = cb_parse_header((void *)addr, 0x1000, info);
470	if (!ret)
471		return -ENOENT;
472	gd->arch.coreboot_table = addr;
473	gd_set_acpi_start(map_to_sysmem(info->rsdp));
474	gd_set_smbios_start(info->smbios_start);
475	gd->flags |= GD_FLG_SKIP_LL_INIT;
476
477	return 0;
478}
479
480const struct sysinfo_t *cb_get_sysinfo(void)
481{
482	if (!ll_boot_init())
483		return &lib_sysinfo;
484
485	return NULL;
486}
487