/ tests / lib / coreboot_table-test.c
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  }