/* SPDX-License-Identifier: GPL-2.0-only */ #include #include #include #include #include #include #define MMA_TEST_METADATA_FILENAME "mma_test_metadata.bin" #define MMA_TEST_NAME_TAG "MMA_TEST_NAME" #define MMA_TEST_PARAM_TAG "MMA_TEST_PARAM" #define TEST_NAME_MAX_SIZE 30 #define TEST_PARAM_MAX_SIZE 100 #define MMA_DATA_SIGNATURE (('M' << 0) | ('M' << 8) | \ ('A' << 16) | ('D' << 24)) struct mma_data_container { uint32_t mma_signature; /* "MMAD" */ uint8_t mma_data[0]; /* Variable size, platform/run time dependent. */ } __packed; /* * Format of the MMA test metadata file, stored under CBFS * MMA_TEST_NAME=xxxxxx.efi;MMA_TEST_PARAM=xxxxxx.bin; */ /* Returns index in haystack after 'LABEL=' * string is found, < 0 on error. */ static int find_label(const char *haystack, size_t haystack_sz, const char *label) { size_t label_sz; size_t i; size_t search_sz; label_sz = strlen(label); if (label_sz + 1 >= haystack_sz) return -1; /* Handle '=' follow label. i.e. LABEL= */ search_sz = haystack_sz - label_sz - 1; for (i = 0; i < search_sz; i++) { if (!strncmp(&haystack[i], label, label_sz)) break; } if (i == search_sz) return -1; if (haystack[i + label_sz] != '=') return -1; return i + label_sz + 1; } /* * Fill in value in dest field located by LABEL=. * Returns 0 on success, < 0 on error. */ static int label_value(const char *haystack, size_t haystack_sz, const char *label, char *dest, size_t dest_sz) { size_t val_begin; size_t val_end; size_t val_sz; int val_index; memset(dest, 0, dest_sz); /* Allow for NULL termination. */ dest_sz--; val_index = find_label(haystack, haystack_sz, label); if (val_index < 0) return -1; val_begin = val_index; val_end = val_begin; val_sz = 0; for (val_end = val_begin; val_end < haystack_sz; val_end++) { if (haystack[val_end] == ';') { val_sz = val_end - val_begin; break; } } if (val_end == haystack_sz) return -1; if (dest_sz < val_sz) return -1; memcpy(dest, &haystack[val_begin], val_sz); return 0; } int mma_map_param(struct mma_config_param *mma_cfg) { void *mma_test_metadata; size_t mma_test_metadata_file_len; char test_filename[TEST_NAME_MAX_SIZE], test_param_filename[TEST_PARAM_MAX_SIZE]; bool metadata_parse_flag = true; printk(BIOS_DEBUG, "MMA: Entry %s\n", __func__); mma_test_metadata = cbfs_ro_map(MMA_TEST_METADATA_FILENAME, &mma_test_metadata_file_len); if (!mma_test_metadata) { printk(BIOS_DEBUG, "MMA: Failed to map %s\n", MMA_TEST_METADATA_FILENAME); return -1; } if (label_value(mma_test_metadata, mma_test_metadata_file_len, MMA_TEST_NAME_TAG, test_filename, TEST_NAME_MAX_SIZE)) { printk(BIOS_DEBUG, "MMA: Failed to get %s\n", MMA_TEST_NAME_TAG); metadata_parse_flag = false; } if (metadata_parse_flag && label_value(mma_test_metadata, mma_test_metadata_file_len, MMA_TEST_PARAM_TAG, test_param_filename, TEST_PARAM_MAX_SIZE)) { printk(BIOS_DEBUG, "MMA: Failed to get %s\n", MMA_TEST_PARAM_TAG); metadata_parse_flag = false; } cbfs_unmap(mma_test_metadata); if (!metadata_parse_flag) return -1; printk(BIOS_DEBUG, "MMA: Got MMA_TEST_NAME=%s MMA_TEST_PARAM=%s\n", test_filename, test_param_filename); mma_cfg->test_content = cbfs_ro_map(test_filename, &mma_cfg->test_content_size); if (!mma_cfg->test_content) { printk(BIOS_DEBUG, "MMA: Failed to map %s\n", test_filename); return -1; } mma_cfg->test_param = cbfs_ro_map(test_param_filename, &mma_cfg->test_param_size); if (!mma_cfg->test_param) { printk(BIOS_DEBUG, "MMA: Failed to map %s\n", test_param); return -1; } printk(BIOS_DEBUG, "MMA: %s exit success\n", __func__); return 0; } static void save_mma_results_data(void *unused) { const void *mma_hob; size_t mma_hob_size; struct mma_data_container *mma_data; size_t mma_data_size; printk(BIOS_DEBUG, "MMA: Entry %s\n", __func__); if (fsp_locate_mma_results(&mma_hob, &mma_hob_size)) { printk(BIOS_DEBUG, "MMA: results data Hob not present\n"); return; } mma_data_size = ALIGN(mma_hob_size, 16) + sizeof(struct mma_data_container); mma_data = cbmem_add(CBMEM_ID_MMA_DATA, mma_data_size); if (mma_data == NULL) { printk(BIOS_DEBUG, "MMA: CBMEM was not available to save the MMA data.\n"); return; } /*clear the mma_data before coping the actual data */ memset(mma_data, 0, mma_data_size); printk(BIOS_DEBUG, "MMA: copy MMA data to CBMEM(src %p, dest %p, %u bytes)\n", mma_hob, mma_data, mma_hob_size); mma_data->mma_signature = MMA_DATA_SIGNATURE; memcpy(mma_data->mma_data, mma_hob, mma_hob_size); printk(BIOS_DEBUG, "MMA: %s exit successfully\n", __func__); } BOOT_STATE_INIT_ENTRY(BS_WRITE_TABLES, BS_ON_ENTRY, save_mma_results_data, NULL);