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