xref: /aosp_15_r20/external/coreboot/payloads/libpayload/libc/coreboot.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /*
2  *
3  * Copyright (C) 2008 Advanced Micro Devices, Inc.
4  * Copyright (C) 2009 coresystems GmbH
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <libpayload-config.h>
31 #include <libpayload.h>
32 #include <commonlib/bsd/cbmem_id.h>
33 #include <coreboot_tables.h>
34 #include <stdint.h>
35 
36 /*
37  * The code in this file applies to all coreboot architectures. Some coreboot
38  * table tags are architecture specific, they are handled by their respective
39  * cb_parse_arch_specific() functions.
40  */
41 
42 /* === Parsing code === */
43 /* This is the generic parsing code. */
44 
cb_parse_memory(void * ptr,struct sysinfo_t * info)45 static void cb_parse_memory(void *ptr, struct sysinfo_t *info)
46 {
47 	struct cb_memory *mem = ptr;
48 	int count = MEM_RANGE_COUNT(mem);
49 	int i;
50 
51 	if (count > SYSINFO_MAX_MEM_RANGES)
52 		count = SYSINFO_MAX_MEM_RANGES;
53 
54 	info->n_memranges = 0;
55 
56 	for (i = 0; i < count; i++) {
57 		struct cb_memory_range *range = MEM_RANGE_PTR(mem, i);
58 
59 #if CONFIG(LP_MEMMAP_RAM_ONLY)
60 		if (range->type != CB_MEM_RAM)
61 			continue;
62 #endif
63 
64 		info->memrange[info->n_memranges].base = range->start;
65 		info->memrange[info->n_memranges].size = range->size;
66 		info->memrange[info->n_memranges].type = range->type;
67 
68 		info->n_memranges++;
69 	}
70 }
71 
cb_parse_serial(void * ptr,struct sysinfo_t * info)72 static void cb_parse_serial(void *ptr, struct sysinfo_t *info)
73 {
74 	info->cb_serial = virt_to_phys(ptr);
75 }
76 
cb_parse_vbnv(unsigned char * ptr,struct sysinfo_t * info)77 static void cb_parse_vbnv(unsigned char *ptr, struct sysinfo_t *info)
78 {
79 	struct lb_range *vbnv = (struct lb_range *)ptr;
80 
81 	info->vbnv_start = vbnv->range_start;
82 	info->vbnv_size = vbnv->range_size;
83 }
84 
cb_parse_mmc_info(unsigned char * ptr,struct sysinfo_t * info)85 static void cb_parse_mmc_info(unsigned char *ptr, struct sysinfo_t *info)
86 {
87 	struct cb_mmc_info *mmc_info = (struct cb_mmc_info *)ptr;
88 
89 	info->mmc_early_wake_status = mmc_info->early_cmd1_status;
90 }
91 
cb_parse_gpios(unsigned char * ptr,struct sysinfo_t * info)92 static void cb_parse_gpios(unsigned char *ptr, struct sysinfo_t *info)
93 {
94 	int i;
95 	struct cb_gpios *gpios = (struct cb_gpios *)ptr;
96 
97 	info->num_gpios = (gpios->count < SYSINFO_MAX_GPIOS) ?
98 				(gpios->count) : SYSINFO_MAX_GPIOS;
99 
100 	for (i = 0; i < info->num_gpios; i++)
101 		info->gpios[i] = gpios->gpios[i];
102 }
103 
cb_parse_mac_addresses(unsigned char * ptr,struct sysinfo_t * info)104 static void cb_parse_mac_addresses(unsigned char *ptr,
105 				   struct sysinfo_t *info)
106 {
107 	struct cb_macs *macs = (struct cb_macs *)ptr;
108 	int i;
109 
110 	info->num_macs = (macs->count < ARRAY_SIZE(info->macs)) ?
111 		macs->count : ARRAY_SIZE(info->macs);
112 
113 	for (i = 0; i < info->num_macs; i++)
114 		info->macs[i] = macs->mac_addrs[i];
115 }
116 
cb_parse_board_config(unsigned char * ptr,struct sysinfo_t * info)117 static void cb_parse_board_config(unsigned char *ptr, struct sysinfo_t *info)
118 {
119 	struct cb_board_config *const config = (struct cb_board_config *)ptr;
120 	info->fw_config = config->fw_config;
121 	info->board_id = config->board_id;
122 	info->ram_code = config->ram_code;
123 	info->sku_id = config->sku_id;
124 }
125 
126 #if CONFIG(LP_NVRAM)
cb_parse_optiontable(void * ptr,struct sysinfo_t * info)127 static void cb_parse_optiontable(void *ptr, struct sysinfo_t *info)
128 {
129 	/* ptr is already virtual, but we want to keep physical addresses */
130 	info->cmos_option_table = virt_to_phys(ptr);
131 }
132 
cb_parse_checksum(void * ptr,struct sysinfo_t * info)133 static void cb_parse_checksum(void *ptr, struct sysinfo_t *info)
134 {
135 	struct cb_cmos_checksum *cmos_cksum = ptr;
136 	info->cmos_range_start = cmos_cksum->range_start;
137 	info->cmos_range_end = cmos_cksum->range_end;
138 	info->cmos_checksum_location = cmos_cksum->location;
139 }
140 #endif
141 
142 #if CONFIG(LP_COREBOOT_VIDEO_CONSOLE)
cb_parse_framebuffer(void * ptr,struct sysinfo_t * info)143 static void cb_parse_framebuffer(void *ptr, struct sysinfo_t *info)
144 {
145 	info->framebuffer = *(struct cb_framebuffer *)ptr;
146 }
147 #endif
148 
cb_parse_string(const void * const ptr,uintptr_t * const info)149 static void cb_parse_string(const void *const ptr, uintptr_t *const info)
150 {
151 	/* ptr is already virtual (str->string just an offset to that),
152 	   but we want to keep physical addresses */
153 	const struct cb_string *const str = ptr;
154 	*info = virt_to_phys(str->string);
155 }
156 
cb_parse_ramoops(void * ptr,struct sysinfo_t * info)157 static void cb_parse_ramoops(void *ptr, struct sysinfo_t *info)
158 {
159 	struct lb_range *ramoops = (struct lb_range *)ptr;
160 
161 	info->ramoops_buffer = ramoops->range_start;
162 	info->ramoops_buffer_size = ramoops->range_size;
163 }
164 
cb_parse_mtc(void * ptr,struct sysinfo_t * info)165 static void cb_parse_mtc(void *ptr, struct sysinfo_t *info)
166 {
167 	struct lb_range *mtc = (struct lb_range *)ptr;
168 
169 	info->mtc_start = mtc->range_start;
170 	info->mtc_size = mtc->range_size;
171 }
172 
cb_parse_spi_flash(void * ptr,struct sysinfo_t * info)173 static void cb_parse_spi_flash(void *ptr, struct sysinfo_t *info)
174 {
175 	struct cb_spi_flash *flash = (struct cb_spi_flash *)ptr;
176 
177 	info->spi_flash.size = flash->flash_size;
178 	info->spi_flash.sector_size = flash->sector_size;
179 	info->spi_flash.erase_cmd = flash->erase_cmd;
180 
181 	if (flash->mmap_count == 0)
182 		return;
183 
184 	info->spi_flash.mmap_window_count = MIN(flash->mmap_count, SYSINFO_MAX_MMAP_WINDOWS);
185 	memcpy(info->spi_flash.mmap_table, flash->mmap_table,
186 	       info->spi_flash.mmap_window_count * sizeof(struct flash_mmap_window));
187 }
188 
cb_parse_boot_media_params(unsigned char * ptr,struct sysinfo_t * info)189 static void cb_parse_boot_media_params(unsigned char *ptr,
190 				       struct sysinfo_t *info)
191 {
192 	struct cb_boot_media_params *const bmp =
193 			(struct cb_boot_media_params *)ptr;
194 	info->fmap_offset = bmp->fmap_offset;
195 	info->cbfs_offset = bmp->cbfs_offset;
196 	info->cbfs_size = bmp->cbfs_size;
197 	info->boot_media_size = bmp->boot_media_size;
198 }
199 
200 #if CONFIG(LP_TIMER_RDTSC)
cb_parse_tsc_info(void * ptr,struct sysinfo_t * info)201 static void cb_parse_tsc_info(void *ptr, struct sysinfo_t *info)
202 {
203 	const struct cb_tsc_info *tsc_info = ptr;
204 
205 	if (tsc_info->freq_khz == 0)
206 		return;
207 
208 	/* Honor the TSC frequency passed to the payload. */
209 	info->cpu_khz = tsc_info->freq_khz;
210 }
211 #endif
212 
cb_parse_cbmem_entry(void * ptr,struct sysinfo_t * info)213 static void cb_parse_cbmem_entry(void *ptr, struct sysinfo_t *info)
214 {
215 	const struct cb_cbmem_entry *cbmem_entry = ptr;
216 
217 	if (cbmem_entry->size != sizeof(*cbmem_entry))
218 		return;
219 
220 	switch (cbmem_entry->id) {
221 	case CBMEM_ID_ACPI_CNVS:
222 		info->acpi_cnvs = cbmem_entry->address;
223 		break;
224 	case CBMEM_ID_ACPI_GNVS:
225 		info->acpi_gnvs = cbmem_entry->address;
226 		break;
227 	case CBMEM_ID_SMBIOS:
228 		info->smbios = cbmem_entry->address;
229 		break;
230 	case CBMEM_ID_CBFS_RO_MCACHE:
231 		info->cbfs_ro_mcache_offset = cbmem_entry->address;
232 		info->cbfs_ro_mcache_size = cbmem_entry->entry_size;
233 		break;
234 	case CBMEM_ID_CBFS_RW_MCACHE:
235 		info->cbfs_rw_mcache_offset = cbmem_entry->address;
236 		info->cbfs_rw_mcache_size = cbmem_entry->entry_size;
237 		break;
238 	case CBMEM_ID_CONSOLE:
239 		info->cbmem_cons = cbmem_entry->address;
240 		break;
241 	case CBMEM_ID_MRCDATA:
242 		info->mrc_cache = cbmem_entry->address;
243 		break;
244 	case CBMEM_ID_VBOOT_WORKBUF:
245 		info->vboot_workbuf = cbmem_entry->address;
246 		break;
247 	case CBMEM_ID_TIMESTAMP:
248 		info->tstamp_table = cbmem_entry->address;
249 		break;
250 	case CBMEM_ID_VPD:
251 		info->chromeos_vpd = cbmem_entry->address;
252 		break;
253 	case CBMEM_ID_FMAP:
254 		info->fmap_cache = cbmem_entry->address;
255 		break;
256 	case CBMEM_ID_WIFI_CALIBRATION:
257 		info->wifi_calibration = cbmem_entry->address;
258 		break;
259 	case CBMEM_ID_TYPE_C_INFO:
260 		info->type_c_info = cbmem_entry->address;
261 		break;
262 	case CBMEM_ID_MEM_CHIP_INFO:
263 		info->mem_chip_base = cbmem_entry->address;
264 		break;
265 	case CBMEM_ID_CSE_BP_INFO:
266 		info->cse_bp_info = cbmem_entry->address;
267 		break;
268 	case CBMEM_ID_CSE_INFO:
269 		info->cse_info = cbmem_entry->address;
270 		break;
271 	default:
272 		break;
273 	}
274 }
275 
cb_parse_pcie(void * ptr,struct sysinfo_t * info)276 static void cb_parse_pcie(void *ptr, struct sysinfo_t *info)
277 {
278 	const struct cb_pcie *pcie = ptr;
279 
280 	info->pcie_ctrl_base = pcie->ctrl_base;
281 }
282 
cb_parse_rsdp(void * ptr,struct sysinfo_t * info)283 static void cb_parse_rsdp(void *ptr, struct sysinfo_t *info)
284 {
285 	const struct cb_acpi_rsdp *cb_acpi_rsdp = ptr;
286 	info->acpi_rsdp = cb_acpi_rsdp->rsdp_pointer;
287 }
288 
cb_parse_header(void * addr,int len,struct sysinfo_t * info)289 int cb_parse_header(void *addr, int len, struct sysinfo_t *info)
290 {
291 	struct cb_header *header;
292 	unsigned char *ptr = addr;
293 	void *forward;
294 	int i;
295 
296 	for (i = 0; i < len; i += 16, ptr += 16) {
297 		header = (struct cb_header *)ptr;
298 		if (!strncmp((const char *)header->signature, "LBIO", 4))
299 			break;
300 	}
301 
302 	/* We walked the entire space and didn't find anything. */
303 	if (i >= len)
304 		return -1;
305 
306 	/* Make sure the checksums match. */
307 	if (ipchksum((u16 *) header, sizeof(*header)) != 0)
308 		return -1;
309 
310 	if (!header->table_bytes)
311 		return 0;
312 
313 	if (ipchksum((u16 *) (ptr + sizeof(*header)),
314 		     header->table_bytes) != header->table_checksum)
315 		return -1;
316 
317 	info->cb_header = virt_to_phys(header);
318 
319 	/* Initialize IDs as undefined in case they don't show up in table. */
320 	info->board_id = UNDEFINED_STRAPPING_ID;
321 	info->ram_code = UNDEFINED_STRAPPING_ID;
322 	info->sku_id = UNDEFINED_STRAPPING_ID;
323 	info->fw_config = UNDEFINED_FW_CONFIG;
324 
325 	/* Now, walk the tables. */
326 	ptr += header->header_bytes;
327 
328 	for (i = 0; i < header->table_entries; i++) {
329 		struct cb_record *rec = (struct cb_record *)ptr;
330 
331 		/* We only care about a few tags here (maybe more later). */
332 		switch (rec->tag) {
333 		case CB_TAG_FORWARD:
334 			forward = phys_to_virt((void *)(unsigned long)
335 					       ((struct cb_forward *)rec)->forward);
336 			return cb_parse_header(forward, len, info);
337 		case CB_TAG_MEMORY:
338 			cb_parse_memory(ptr, info);
339 			break;
340 		case CB_TAG_SERIAL:
341 			cb_parse_serial(ptr, info);
342 			break;
343 		case CB_TAG_VERSION:
344 			cb_parse_string(ptr, &info->cb_version);
345 			break;
346 		case CB_TAG_EXTRA_VERSION:
347 			cb_parse_string(ptr, &info->extra_version);
348 			break;
349 		case CB_TAG_BUILD:
350 			cb_parse_string(ptr, &info->build);
351 			break;
352 		case CB_TAG_COMPILE_TIME:
353 			cb_parse_string(ptr, &info->compile_time);
354 			break;
355 		case CB_TAG_COMPILE_BY:
356 			cb_parse_string(ptr, &info->compile_by);
357 			break;
358 		case CB_TAG_COMPILE_HOST:
359 			cb_parse_string(ptr, &info->compile_host);
360 			break;
361 		case CB_TAG_COMPILE_DOMAIN:
362 			cb_parse_string(ptr, &info->compile_domain);
363 			break;
364 		case CB_TAG_COMPILER:
365 			cb_parse_string(ptr, &info->compiler);
366 			break;
367 		case CB_TAG_LINKER:
368 			cb_parse_string(ptr, &info->linker);
369 			break;
370 		case CB_TAG_ASSEMBLER:
371 			cb_parse_string(ptr, &info->assembler);
372 			break;
373 #if CONFIG(LP_NVRAM)
374 		case CB_TAG_CMOS_OPTION_TABLE:
375 			cb_parse_optiontable(ptr, info);
376 			break;
377 		case CB_TAG_OPTION_CHECKSUM:
378 			cb_parse_checksum(ptr, info);
379 			break;
380 #endif
381 #if CONFIG(LP_COREBOOT_VIDEO_CONSOLE)
382 		// FIXME we should warn on serial if coreboot set up a
383 		// framebuffer buf the payload does not know about it.
384 		case CB_TAG_FRAMEBUFFER:
385 			cb_parse_framebuffer(ptr, info);
386 			break;
387 #endif
388 		case CB_TAG_MAINBOARD:
389 			info->cb_mainboard = virt_to_phys(ptr);
390 			break;
391 		case CB_TAG_GPIO:
392 			cb_parse_gpios(ptr, info);
393 			break;
394 		case CB_TAG_VBNV:
395 			cb_parse_vbnv(ptr, info);
396 			break;
397 		case CB_TAG_MAC_ADDRS:
398 			cb_parse_mac_addresses(ptr, info);
399 			break;
400 		case CB_TAG_SERIALNO:
401 			cb_parse_string(ptr, &info->serialno);
402 			break;
403 		case CB_TAG_BOARD_CONFIG:
404 			cb_parse_board_config(ptr, info);
405 			break;
406 		case CB_TAG_RAM_OOPS:
407 			cb_parse_ramoops(ptr, info);
408 			break;
409 		case CB_TAG_SPI_FLASH:
410 			cb_parse_spi_flash(ptr, info);
411 			break;
412 		case CB_TAG_MMC_INFO:
413 			cb_parse_mmc_info(ptr, info);
414 			break;
415 		case CB_TAG_MTC:
416 			cb_parse_mtc(ptr, info);
417 			break;
418 		case CB_TAG_BOOT_MEDIA_PARAMS:
419 			cb_parse_boot_media_params(ptr, info);
420 			break;
421 		case CB_TAG_CBMEM_ENTRY:
422 			cb_parse_cbmem_entry(ptr, info);
423 			break;
424 #if CONFIG(LP_TIMER_RDTSC)
425 		case CB_TAG_TSC_INFO:
426 			cb_parse_tsc_info(ptr, info);
427 			break;
428 #endif
429 		case CB_TAG_ACPI_RSDP:
430 			cb_parse_rsdp(ptr, info);
431 			break;
432 		case CB_TAG_PCIE:
433 			cb_parse_pcie(ptr, info);
434 			break;
435 		default:
436 			cb_parse_arch_specific(rec, info);
437 			break;
438 		}
439 
440 		ptr += rec->size;
441 	}
442 
443 	return 0;
444 }
445