coreboot_table-test.c
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 */ 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 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 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]; 82 static int setup_test_header(void **state) 83 { 84 *state = lb_table_init((uintptr_t)tables_buffer); 85 86 return 0; 87 } 88 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 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 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 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 189 void arch_write_tables(uintptr_t coreboot_table) 190 { 191 } 192 193 static const uintptr_t ebda_base = 0xf0000; 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 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 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 237 const struct cbfs_boot_device *cbfs_get_boot_device(bool force_ro) 238 { 239 return &cbfs_boot_dev; 240 } 241 242 void cbmem_run_init_hooks(int is_recovery) 243 { 244 } 245 246 extern uintptr_t _cbmem_top_ptr; 247 uintptr_t cbmem_top_chipset(void) 248 { 249 return _cbmem_top_ptr; 250 } 251 252 #define CBMEM_SIZE (64 * KiB) 253 254 static int teardown_write_tables_test(void **state) 255 { 256 free(*state); 257 _cbmem_top_ptr = 0; 258 return 0; 259 } 260 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 288 const struct region_device *boot_device_ro(void) 289 { 290 return &cbfs_boot_dev.rdev; 291 } 292 293 uint64_t get_fmap_flash_offset(void) 294 { 295 return FMAP_OFFSET; 296 } 297 298 uint32_t freq_khz = 5000 * 1000; 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 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 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 }