xref: /aosp_15_r20/external/coreboot/tests/lib/coreboot_table-test.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <tests/test.h>
4 #include <boardid.h>
5 #include <boot/coreboot_tables.h>
6 #include <boot/tables.h>
7 #include <cbfs.h>
8 #include <cbmem.h>
9 #include <commonlib/helpers.h>
10 #include <commonlib/region.h>
11 #include <fmap_config.h>
12 #include <fw_config.h>
13 #include <stdbool.h>
14 #include <version.h>
15 
16 
17 /* Copy of lb_table_init() implementation for testing purposes */
lb_table_init(unsigned long addr)18 static struct lb_header *lb_table_init(unsigned long addr)
19 {
20 	struct lb_header *header;
21 
22 	/* 16 byte align the address */
23 	addr = ALIGN_UP(addr, 16);
24 
25 	header = (void *)addr;
26 	header->signature[0] = 'L';
27 	header->signature[1] = 'B';
28 	header->signature[2] = 'I';
29 	header->signature[3] = 'O';
30 	header->header_bytes = sizeof(*header);
31 	header->header_checksum = 0;
32 	header->table_bytes = 0;
33 	header->table_checksum = 0;
34 	header->table_entries = 0;
35 	return header;
36 }
37 
lb_first_record(struct lb_header * header)38 static struct lb_record *lb_first_record(struct lb_header *header)
39 {
40 	struct lb_record *rec;
41 	rec = (void *)(((char *)header) + sizeof(*header));
42 	return rec;
43 }
44 
45 #define LB_RECORD_FOR_EACH(record_ptr, index, header)                                          \
46 	for (index = 0, record_ptr = lb_first_record(header); index < header->table_entries;   \
47 	     record_ptr = (struct lb_record *)((uintptr_t)record_ptr + record_ptr->size),      \
48 	    index++)
49 
test_lb_add_gpios(void ** state)50 static void test_lb_add_gpios(void **state)
51 {
52 	struct lb_gpio gpios[] = {
53 		{-1, ACTIVE_HIGH, 1, "lid"},
54 		{-1, ACTIVE_HIGH, 0, "power"},
55 		{-1, ACTIVE_HIGH, 1, "oprom"},
56 		{-1, ACTIVE_HIGH, 0, "EC in RW"},
57 	};
58 	const size_t gpios_buf_size = sizeof(struct lb_gpios) + sizeof(struct lb_gpio) * 32;
59 	uint8_t gpios_buf[gpios_buf_size];
60 	struct lb_gpios *gpios_table = (struct lb_gpios *)gpios_buf;
61 	gpios_table->count = 0;
62 	gpios_table->size = 0;
63 	gpios_table->tag = LB_TAG_GPIO;
64 
65 	/* Add GPIOs an check if they have been added to the table.
66 	   GPIOs are added in the same order to the end of the table. */
67 	lb_add_gpios(gpios_table, gpios, ARRAY_SIZE(gpios));
68 	assert_int_equal(ARRAY_SIZE(gpios), gpios_table->count);
69 	assert_int_equal(sizeof(gpios), gpios_table->size);
70 	assert_memory_equal(&gpios_table->gpios[0], gpios, sizeof(gpios));
71 
72 	/* Add subset of gpios and check if they have been added correctly. */
73 	lb_add_gpios(gpios_table, &gpios[1], 2);
74 	assert_int_equal(ARRAY_SIZE(gpios) + 2, gpios_table->count);
75 	assert_int_equal(sizeof(gpios) + 2 * sizeof(gpios[0]), gpios_table->size);
76 	assert_memory_equal(&gpios_table->gpios[0], gpios, sizeof(gpios));
77 	assert_memory_equal(&gpios_table->gpios[ARRAY_SIZE(gpios)], &gpios[1],
78 			    2 * sizeof(gpios[0]));
79 }
80 
81 uint8_t tables_buffer[sizeof(struct lb_header) + 10 * KiB];
setup_test_header(void ** state)82 static int setup_test_header(void **state)
83 {
84 	*state = lb_table_init((uintptr_t)tables_buffer);
85 
86 	return 0;
87 }
88 
test_lb_new_record(void ** state)89 static void test_lb_new_record(void **state)
90 {
91 	struct lb_header *header = *state;
92 	const size_t entries = 10;
93 	int i;
94 	size_t entries_offset;
95 	size_t accumulated_size = 0;
96 	struct lb_record *curr;
97 
98 
99 	assert_int_equal(0, header->table_entries);
100 	assert_int_equal(0, header->table_bytes);
101 
102 	lb_new_record(header);
103 	assert_int_equal(1, header->table_entries);
104 	assert_int_equal(0, header->table_bytes);
105 
106 	/* Create few entries with varying sizes (but at least of sizeof(struct lb_record))
107 	   Accumulate and check size of table after each lb_new_record() call. */
108 	entries_offset = header->table_entries;
109 	accumulated_size = sizeof(struct lb_record);
110 	for (i = 0; i < entries; ++i) {
111 		curr = lb_new_record(header);
112 		curr->size = sizeof(struct lb_record) +
113 			     ALIGN_UP(((i + 2) * 7) % 32, LB_ENTRY_ALIGN);
114 
115 		assert_int_equal(entries_offset + (i + 1), header->table_entries);
116 		assert_int_equal(accumulated_size, header->table_bytes);
117 		accumulated_size += curr->size;
118 	}
119 }
120 
test_lb_add_console(void ** state)121 static void test_lb_add_console(void **state)
122 {
123 	struct lb_header *header = *state;
124 
125 	lb_add_console(LB_TAG_CONSOLE_SERIAL8250MEM, header);
126 	assert_int_equal(1, header->table_entries);
127 	/* Table bytes and checksum should be zero, because it is updated with size of previous
128 	   record or when table is closed. No previous record is present. */
129 	assert_int_equal(0, header->table_bytes);
130 	assert_int_equal(0, header->table_checksum);
131 }
132 
test_multiple_entries(void ** state)133 static void test_multiple_entries(void **state)
134 {
135 	struct lb_header *header = *state;
136 
137 	/* Add two entries */
138 	lb_add_console(LB_TAG_CONSOLE_SERIAL8250, header);
139 	lb_add_console(LB_TAG_CONSOLE_SERIAL8250MEM, header);
140 
141 	assert_int_equal(2, header->table_entries);
142 	assert_int_equal(sizeof(struct lb_console), header->table_bytes);
143 }
144 
test_write_coreboot_forwarding_table(void ** state)145 static void test_write_coreboot_forwarding_table(void **state)
146 {
147 	struct lb_header *header = *state;
148 	uint8_t forwarding_table_buffer[sizeof(struct lb_header)
149 					+ 2 * sizeof(struct lb_forward)];
150 	struct lb_header *forward_header =
151 		(struct lb_header *)ALIGN_UP((uintptr_t)forwarding_table_buffer, 16);
152 	size_t forwarding_table_size = write_coreboot_forwarding_table(
153 		(uintptr_t)forwarding_table_buffer, (uintptr_t)header);
154 	size_t expected_forwarding_table_size =
155 		ALIGN_UP((uintptr_t)forwarding_table_buffer, 16) + sizeof(struct lb_header)
156 		+ sizeof(struct lb_forward) - (uintptr_t)forwarding_table_buffer;
157 	assert_int_equal(expected_forwarding_table_size, forwarding_table_size);
158 
159 	assert_int_equal(1, forward_header->table_entries);
160 	assert_int_equal(sizeof(struct lb_forward), forward_header->table_bytes);
161 	assert_ptr_equal(header,
162 			 ((struct lb_forward *)lb_first_record(forward_header))->forward);
163 }
164 
165 /* Mocks for write_tables() */
166 const char mainboard_vendor[] = CONFIG_MAINBOARD_VENDOR;
167 const char mainboard_part_number[] = CONFIG_MAINBOARD_PART_NUMBER;
168 
169 const char coreboot_version[] = "4.13";
170 const char coreboot_extra_version[] = "abcdef";
171 const char coreboot_build[] = "Coreboot build info";
172 const unsigned int coreboot_version_timestamp = 1617191902U;
173 const unsigned int coreboot_major_revision = 4;
174 const unsigned int coreboot_minor_revision = 13;
175 
176 const char coreboot_compile_time[] = "13:58:22";
177 const char coreboot_dmi_date[] = "03/31/2021";
178 
179 const struct bcd_date coreboot_build_date = {
180 	.century = 0x20,
181 	.year = 0x20,
182 	.month = 0x03,
183 	.day = 0x31,
184 	.weekday = 0x2,
185 };
186 
187 const unsigned int asl_revision = 0x20200925;
188 
arch_write_tables(uintptr_t coreboot_table)189 void arch_write_tables(uintptr_t coreboot_table)
190 {
191 }
192 
193 static const uintptr_t ebda_base = 0xf0000;
get_coreboot_rsdp(void)194 uintptr_t get_coreboot_rsdp(void)
195 {
196 	return ebda_base;
197 }
198 
199 struct resource mock_bootmem_ranges[] = {
200 	{.base = 0x1000, .size = 0x2000, .flags = LB_MEM_RAM},
201 	{.base = 0x0000, .size = 0x4000, .flags = LB_MEM_RAM},
202 };
203 
bootmem_write_memory_table(struct lb_memory * mem)204 void bootmem_write_memory_table(struct lb_memory *mem)
205 {
206 	struct lb_memory_range *lb_r = &mem->map[0];
207 	int i;
208 
209 	/* Insert entries for testing */
210 	for (i = 0; i < ARRAY_SIZE(mock_bootmem_ranges); ++i) {
211 		struct resource *res = &mock_bootmem_ranges[i];
212 		lb_r->start = res->base;
213 		lb_r->size = res->size;
214 		lb_r->type = res->flags;
215 		lb_r++;
216 		mem->size += sizeof(struct lb_memory_range);
217 	}
218 }
219 
fill_lb_serial(struct lb_serial * serial)220 enum cb_err fill_lb_serial(struct lb_serial *serial)
221 {
222 	serial->type = LB_SERIAL_TYPE_MEMORY_MAPPED;
223 	serial->baseaddr = 0xFEDC6000;
224 	serial->baud = 115200;
225 	serial->regwidth = 1;
226 	serial->input_hertz = 115200 * 16;
227 
228 	return CB_SUCCESS;
229 }
230 
231 struct cbfs_boot_device cbfs_boot_dev = {
232 	.rdev = REGION_DEV_INIT(NULL, 0, 0x1000),
233 	.mcache = (void *)0x1000,
234 	.mcache_size = 0x1000,
235 };
236 
cbfs_get_boot_device(bool force_ro)237 const struct cbfs_boot_device *cbfs_get_boot_device(bool force_ro)
238 {
239 	return &cbfs_boot_dev;
240 }
241 
cbmem_run_init_hooks(int is_recovery)242 void cbmem_run_init_hooks(int is_recovery)
243 {
244 }
245 
246 extern uintptr_t _cbmem_top_ptr;
cbmem_top_chipset(void)247 uintptr_t cbmem_top_chipset(void)
248 {
249 	return _cbmem_top_ptr;
250 }
251 
252 #define CBMEM_SIZE (64 * KiB)
253 
teardown_write_tables_test(void ** state)254 static int teardown_write_tables_test(void **state)
255 {
256 	free(*state);
257 	_cbmem_top_ptr = 0;
258 	return 0;
259 }
260 
setup_write_tables_test(void ** state)261 static int setup_write_tables_test(void **state)
262 {
263 	/* Allocate more data to have space for alignment */
264 	void *top_ptr = malloc(CBMEM_SIZE + DYN_CBMEM_ALIGN_SIZE);
265 	int32_t *mmc_status = NULL;
266 
267 	if (!top_ptr)
268 		return -1;
269 
270 	*state = top_ptr;
271 
272 	_cbmem_top_ptr = ALIGN_UP((uintptr_t)top_ptr + CBMEM_SIZE, DYN_CBMEM_ALIGN_SIZE);
273 
274 	cbmem_initialize_empty();
275 
276 	mmc_status = cbmem_add(CBMEM_ID_MMC_STATUS, sizeof(int32_t));
277 
278 	if (mmc_status == NULL) {
279 		teardown_write_tables_test(state);
280 		return -1;
281 	}
282 
283 	*mmc_status = 0x4433AADD;
284 
285 	return 0;
286 }
287 
boot_device_ro(void)288 const struct region_device *boot_device_ro(void)
289 {
290 	return &cbfs_boot_dev.rdev;
291 }
292 
get_fmap_flash_offset(void)293 uint64_t get_fmap_flash_offset(void)
294 {
295 	return FMAP_OFFSET;
296 }
297 
298 uint32_t freq_khz = 5000 * 1000;
lb_arch_add_records(struct lb_header * header)299 void lb_arch_add_records(struct lb_header *header)
300 {
301 	struct lb_tsc_info *tsc_info;
302 
303 	tsc_info = (void *)lb_new_record(header);
304 	tsc_info->tag = LB_TAG_TSC_INFO;
305 	tsc_info->size = sizeof(*tsc_info);
306 	tsc_info->freq_khz = freq_khz;
307 }
308 
test_write_tables(void ** state)309 static void test_write_tables(void **state)
310 {
311 	void *cbtable_start;
312 	struct lb_header *header;
313 	struct lb_record *record;
314 	int32_t *mmc_status = cbmem_find(CBMEM_ID_MMC_STATUS);
315 	size_t i = 0;
316 
317 	/* Expect function to store cbtable entry in cbmem */
318 	cbtable_start = write_tables();
319 	assert_ptr_equal(cbtable_start, cbmem_find(CBMEM_ID_CBTABLE));
320 
321 	/* Expect correct lb_header at cbtable_start address */
322 	header = (struct lb_header *)cbtable_start;
323 	assert_non_null(header);
324 	assert_memory_equal("LBIO", header, 4);
325 	assert_int_equal(sizeof(*header), header->header_bytes);
326 	/* At least one entry should be present. */
327 	assert_int_not_equal(0, header->table_entries);
328 
329 	LB_RECORD_FOR_EACH(record, i, header)
330 	{
331 		switch (record->tag) {
332 		case LB_TAG_MEMORY:
333 			/* Should be the same as in bootmem_write_memory_table() */
334 			assert_int_equal(sizeof(struct lb_memory)
335 						 + ARRAY_SIZE(mock_bootmem_ranges)
336 							   * sizeof(struct lb_memory_range),
337 					 record->size);
338 
339 			const struct lb_memory *memory = (struct lb_memory *)record;
340 			const struct lb_memory_range *range;
341 			const struct resource *res;
342 			lb_uint64_t value;
343 
344 			for (int i = 0; i < ARRAY_SIZE(mock_bootmem_ranges); ++i) {
345 				res = &mock_bootmem_ranges[i];
346 				range = &memory->map[i];
347 
348 				value = res->base;
349 				assert_memory_equal(&value, &range->start,
350 						    sizeof(lb_uint64_t));
351 				value = res->size;
352 				assert_memory_equal(&value, &range->size,
353 						    sizeof(lb_uint64_t));
354 				assert_int_equal(range->type, res->flags);
355 			}
356 			break;
357 		case LB_TAG_MAINBOARD:
358 			/* Mainboard record contains its header followed
359 			   by two null-terminated strings */
360 			assert_int_equal(ALIGN_UP(sizeof(struct lb_mainboard)
361 							  + ARRAY_SIZE(mainboard_vendor)
362 							  + ARRAY_SIZE(mainboard_part_number),
363 						  LB_ENTRY_ALIGN),
364 					 record->size);
365 			break;
366 		case LB_TAG_VERSION:
367 			assert_int_equal(ALIGN_UP(sizeof(struct lb_string)
368 							  + ARRAY_SIZE(coreboot_version),
369 						  LB_ENTRY_ALIGN),
370 					 record->size);
371 			break;
372 		case LB_TAG_EXTRA_VERSION:
373 			assert_int_equal(ALIGN_UP(sizeof(struct lb_string)
374 							  + ARRAY_SIZE(coreboot_extra_version),
375 						  LB_ENTRY_ALIGN),
376 					 record->size);
377 			break;
378 		case LB_TAG_BUILD:
379 			assert_int_equal(
380 				ALIGN_UP(sizeof(struct lb_string) + ARRAY_SIZE(coreboot_build),
381 					 LB_ENTRY_ALIGN),
382 				record->size);
383 			break;
384 		case LB_TAG_COMPILE_TIME:
385 			assert_int_equal(ALIGN_UP(sizeof(struct lb_string)
386 							  + ARRAY_SIZE(coreboot_compile_time),
387 						  LB_ENTRY_ALIGN),
388 					 record->size);
389 			break;
390 		case LB_TAG_SERIAL:
391 			assert_int_equal(sizeof(struct lb_serial), record->size);
392 
393 			/* This struct have the same values as created in uart_fill_lb() */
394 			const struct lb_serial *serial = (struct lb_serial *)record;
395 			assert_int_equal(LB_SERIAL_TYPE_MEMORY_MAPPED, serial->type);
396 			assert_int_equal(0xFEDC6000, serial->baseaddr);
397 			assert_int_equal(115200, serial->baud);
398 			assert_int_equal(1, serial->regwidth);
399 			assert_int_equal(115200 * 16, serial->input_hertz);
400 			break;
401 		case LB_TAG_CONSOLE:
402 			assert_int_equal(sizeof(struct lb_console), record->size);
403 
404 			/* This struct have the same values as created in uart_fill_lb() */
405 			const struct lb_console *console = (struct lb_console *)record;
406 			assert_int_equal(LB_TAG_CONSOLE_SERIAL8250MEM, console->type);
407 			break;
408 		case LB_TAG_VERSION_TIMESTAMP:
409 			assert_int_equal(sizeof(struct lb_timestamp), record->size);
410 
411 			const struct lb_timestamp *timestamp = (struct lb_timestamp *)record;
412 			assert_int_equal(coreboot_version_timestamp, timestamp->timestamp);
413 			break;
414 		case LB_TAG_BOOT_MEDIA_PARAMS:
415 			assert_int_equal(sizeof(struct lb_boot_media_params), record->size);
416 
417 			const struct lb_boot_media_params *bmp =
418 				(struct lb_boot_media_params *)record;
419 			const struct cbfs_boot_device *cbd = cbfs_get_boot_device(false);
420 			const struct region_device *boot_dev = boot_device_ro();
421 			assert_int_equal(region_device_offset(&cbd->rdev), bmp->cbfs_offset);
422 			assert_int_equal(region_device_sz(&cbd->rdev), bmp->cbfs_size);
423 			assert_int_equal(region_device_sz(boot_dev), bmp->boot_media_size);
424 			assert_int_equal(get_fmap_flash_offset(), bmp->fmap_offset);
425 
426 			break;
427 		case LB_TAG_CBMEM_ENTRY:
428 			assert_int_equal(sizeof(struct lb_cbmem_entry), record->size);
429 
430 			const struct lb_cbmem_entry *cbmem_entry =
431 				(struct lb_cbmem_entry *)record;
432 			const LargestIntegralType expected_tags[] = {CBMEM_ID_CBTABLE,
433 								     CBMEM_ID_MMC_STATUS};
434 			assert_in_set(cbmem_entry->id, expected_tags,
435 				      ARRAY_SIZE(expected_tags));
436 			break;
437 		case LB_TAG_TSC_INFO:
438 			assert_int_equal(sizeof(struct lb_tsc_info), record->size);
439 
440 			const struct lb_tsc_info *tsc_info = (struct lb_tsc_info *)record;
441 			assert_int_equal(freq_khz, tsc_info->freq_khz);
442 			break;
443 		case LB_TAG_MMC_INFO:
444 			assert_int_equal(sizeof(struct lb_mmc_info), record->size);
445 
446 			const struct lb_mmc_info *mmc_info = (struct lb_mmc_info *)record;
447 			assert_int_equal(*mmc_status, mmc_info->early_cmd1_status);
448 			break;
449 		case LB_TAG_BOARD_CONFIG:
450 			assert_int_equal(sizeof(struct lb_board_config), record->size);
451 
452 			const struct lb_board_config *board_config =
453 				(struct lb_board_config *)record;
454 			const lb_uint64_t expected_fw_version = fw_config_get();
455 			assert_memory_equal(&expected_fw_version, &board_config->fw_config,
456 					    sizeof(lb_uint64_t));
457 			assert_int_equal(board_id(), board_config->board_id);
458 			assert_int_equal(ram_code(), board_config->ram_code);
459 			assert_int_equal(sku_id(), board_config->sku_id);
460 			break;
461 		case LB_TAG_ACPI_RSDP:
462 			assert_int_equal(sizeof(struct lb_acpi_rsdp), record->size);
463 
464 			const struct lb_acpi_rsdp *acpi_rsdp = (struct lb_acpi_rsdp *)record;
465 			assert_int_equal(ebda_base, acpi_rsdp->rsdp_pointer);
466 			break;
467 		default:
468 			fail_msg("Unexpected tag found in record. Tag ID: 0x%x", record->tag);
469 		}
470 	}
471 }
472 
main(void)473 int main(void)
474 {
475 	const struct CMUnitTest tests[] = {
476 		cmocka_unit_test(test_lb_add_gpios),
477 		cmocka_unit_test_setup(test_lb_new_record, setup_test_header),
478 		cmocka_unit_test_setup(test_lb_add_console, setup_test_header),
479 		cmocka_unit_test_setup(test_multiple_entries, setup_test_header),
480 		cmocka_unit_test_setup(test_write_coreboot_forwarding_table, setup_test_header),
481 		cmocka_unit_test_setup_teardown(test_write_tables, setup_write_tables_test,
482 						teardown_write_tables_test),
483 	};
484 
485 	return cb_run_group_tests(tests, NULL, NULL);
486 }
487