/* SPDX-License-Identifier: GPL-2.0-only */ #include #include #include #include #define CBMEM_SIZE (32 * KiB) /* CBMEM top pointer used by implementation. */ extern uintptr_t _cbmem_top_ptr; void cbmem_run_init_hooks(int is_recovery) { } static void *get_cbmem_ptr(void) { void *cbmem_top_ptr = (void *)_cbmem_top_ptr; if (cbmem_top_ptr) return cbmem_top_ptr - CBMEM_SIZE; else return NULL; } static void clear_cbmem(void) { void *ptr = get_cbmem_ptr(); if (ptr) memset(ptr, 0, CBMEM_SIZE); } int setup_test(void **state) { void *cbmem_top_ptr = malloc(CBMEM_SIZE); if (!cbmem_top_ptr) return -1; _cbmem_top_ptr = (uintptr_t)cbmem_top_ptr + CBMEM_SIZE; clear_cbmem(); cbmem_initialize_empty(); return 0; } int teardown_test(void **state) { if (_cbmem_top_ptr && (_cbmem_top_ptr - CBMEM_SIZE)) free((void *)(_cbmem_top_ptr - CBMEM_SIZE)); _cbmem_top_ptr = 0; return 0; } /* This function is used as prog_entry of struct prog to prevent potential calls to unaccessible or incorrect addresses. */ void prog_entry_mock(void *arg) { } /* This test checks if stage_cache_add() correctly adds CBMEM_ID_STAGE_x_META and CBMEM_ID_STAGEx_CACHE entries to cbmem. stage_cache_add() must create meta entry containing load address, entry address and argument for it. It also must copy buffer pointer pointed by start pointer of prog struct to cache entry. */ void test_stage_cache_add(void **state) { const int id = 12; int arg = 0xC14; struct stage_cache *meta = NULL; uint8_t *prog_data_buf = NULL; const size_t data_sz = 4 * KiB; uint8_t *data = malloc(data_sz); struct prog prog_data = {0}; assert_non_null(data); memset(data, 0xDB, data_sz); prog_data = (struct prog)PROG_INIT(PROG_ROMSTAGE, "test_prog"); prog_set_area(&prog_data, data, data_sz); prog_set_entry(&prog_data, prog_entry_mock, &arg); stage_cache_add(id, &prog_data); meta = cbmem_find(CBMEM_ID_STAGEx_META + id); assert_non_null(meta); assert_int_equal(meta->load_addr, (uintptr_t)prog_start(&prog_data)); assert_int_equal(meta->entry_addr, (uintptr_t)prog_entry(&prog_data)); assert_int_equal(meta->arg, (uintptr_t)prog_entry_arg(&prog_data)); prog_data_buf = cbmem_find(CBMEM_ID_STAGEx_CACHE + id); assert_non_null(prog_data_buf); assert_memory_equal(data, prog_data_buf, data_sz); free(data); } /* This test checks if stage_cache_add_raw() correctly creates entry with data from provided buffer. Data should be accessible using cbmem_find() with (CBMEM_ID_STAGEx_RAW + id) parameter. */ void test_stage_cache_add_raw(void **state) { const int id = 55; const size_t data_sz = 8 * KiB; uint8_t *data = malloc(data_sz); uint8_t *data_raw = NULL; assert_non_null(data); memset(data, 0x91, data_sz); stage_cache_add_raw(id, data, data_sz); data_raw = cbmem_find(CBMEM_ID_STAGEx_RAW + id); assert_non_null(data_raw); assert_memory_equal(data_raw, data, data_sz); free(data); } /* This test checks if stage_cache_get_raw() correctly extracts base and size of previously added entry. */ void test_stage_cache_get_raw(void **state) { const int id = 23; const size_t data_sz = 3 * KiB; uint8_t *data = malloc(data_sz); size_t data_out_sz = 0; uint8_t *data_out = NULL; assert_non_null(data); memset(data, 0x3c, data_sz); stage_cache_add_raw(id, data, data_sz); stage_cache_get_raw(id, (void **)&data_out, &data_out_sz); assert_int_equal(data_sz, data_out_sz); assert_memory_equal(data, data_out, data_sz); free(data); } /* This test checks if stage_cache_load_stage() correctly loads previously added stage data and its metadata. */ void test_stage_cache_load_stage(void **state) { int id = 0xCC; struct prog prog_out = {0}; const size_t data_sz = 7 * KiB; uint8_t *data = malloc(data_sz); uint8_t *data_bak = malloc(data_sz); struct prog prog_data = {0}; int arg = 0x33224455; assert_non_null(data); assert_non_null(data_bak); memset(data, 0x45, data_sz); prog_data = (struct prog)PROG_INIT(PROG_RAMSTAGE, "test_prog"); prog_set_area(&prog_data, data, data_sz); prog_set_entry(&prog_data, prog_entry_mock, &arg); stage_cache_add(id, &prog_data); /* Copy current data to backup buffer and clear current buffer */ memcpy(data_bak, data, data_sz); memset(data, 0, data_sz); /* Load stage data. Data should be returned to the same buffer. */ stage_cache_load_stage(id, &prog_out); /* Data should be same as it was before */ assert_memory_equal(data, data_bak, data_sz); assert_int_equal(prog_start(&prog_data), prog_start(&prog_out)); assert_int_equal(prog_size(&prog_data), prog_size(&prog_out)); assert_ptr_equal(prog_entry(&prog_data), prog_entry(&prog_out)); assert_ptr_equal(prog_entry_arg(&prog_data), prog_entry_arg(&prog_out)); free(data_bak); free(data); } int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test_setup_teardown(test_stage_cache_add, setup_test, teardown_test), cmocka_unit_test_setup_teardown(test_stage_cache_add_raw, setup_test, teardown_test), cmocka_unit_test_setup_teardown(test_stage_cache_get_raw, setup_test, teardown_test), cmocka_unit_test_setup_teardown(test_stage_cache_load_stage, setup_test, teardown_test), }; return cb_run_group_tests(tests, NULL, NULL); }