From d6b606cfb1e283d3973b357f450a3a6a30fa4a41 Mon Sep 17 00:00:00 2001 From: Roy Hopkins Date: Wed, 10 Jan 2024 13:13:31 +0000 Subject: [PATCH] igvmbld: Extend verbose mode to show guest memory and igvm params In order to help validate and debug issues around allocation of guest physical address ranges, and to ensure it matches the expectations of coconut SVSM, it is useful to see what is generated by the IGVM file builder. This commit extends the verbose output from the tool to show the purpose and the range for each block of guest physical memory defined by the generated IGVM file as well as giving a detailed summary of the contents of the IGVM parameter block. Signed-off-by: Roy Hopkins --- igvmbld/igvmbld.c | 89 +++++++++++++++++++++++++++++++--------------- igvmbld/igvmbld.h | 4 +-- igvmbld/igvmcopy.c | 6 ++-- 3 files changed, 66 insertions(+), 33 deletions(-) diff --git a/igvmbld/igvmbld.c b/igvmbld/igvmbld.c index 881d918d6..91fa8bbf3 100644 --- a/igvmbld/igvmbld.c +++ b/igvmbld/igvmbld.c @@ -78,10 +78,15 @@ static uint32_t crc32b_finish() { return ~_crc; } -void construct_parameter_page(uint32_t address, ParameterPageIndex index) +void construct_parameter_page(uint32_t address, ParameterPageIndex index, const char *description) { PARAM_PAGE *param_page; + if (is_verbose) + { + printf("%08X-%08X: \"%s\" parameter page\n", address, address + 0x1000, description); + } + param_page = malloc(sizeof(PARAM_PAGE)); param_page->address = address; param_page->index = index; @@ -126,13 +131,21 @@ DATA_OBJ *allocate_data_object(uint64_t address, uint32_t size, uint32_t data_si return data_object; } -DATA_OBJ *construct_empty_data_object(uint64_t address, uint32_t size) +DATA_OBJ *construct_empty_data_object(uint64_t address, uint32_t size, const char *description) { + if (is_verbose) + { + printf("%08lX-%08lX: \"%s\" empty data\n", address, address + size, description); + } return insert_data_object(allocate_data_object(address, size, 0)); } -DATA_OBJ *construct_mem_data_object(uint64_t address, uint32_t size) +DATA_OBJ *construct_mem_data_object(uint64_t address, uint32_t size, const char *description) { + if (is_verbose) + { + printf("%08lX-%08lX: \"%s\" mem data\n", address, address + size, description); + } return insert_data_object(allocate_data_object(address, size, size)); } @@ -162,7 +175,7 @@ DATA_OBJ *construct_file_data_object( file_size = ftell(file); - data_obj = construct_mem_data_object(address, file_size); + data_obj = construct_mem_data_object(address, file_size, file_name); if (fseek(file, 0, SEEK_SET) != 0) { @@ -854,21 +867,41 @@ static void print_fw_metadata(IgvmParamBlock *igvm_parameter_block) { uint32_t i; - printf("Firmware configuration\n======================\n"); - printf(" start: %X\n", igvm_parameter_block->firmware.start); - printf(" size: %X\n", igvm_parameter_block->firmware.size); - printf(" secrets_page: %X\n", igvm_parameter_block->firmware.secrets_page); - printf(" caa_page: %X\n", igvm_parameter_block->firmware.caa_page); - printf(" cpuid_page: %X\n", igvm_parameter_block->firmware.cpuid_page); - printf(" reset_addr: %X\n", igvm_parameter_block->firmware.reset_addr); - printf(" prevalidated_count: %X\n", igvm_parameter_block->firmware.prevalidated_count); + printf(" firmware:\n"); + printf(" start: 0x%X\n", igvm_parameter_block->firmware.start); + printf(" size: 0x%X\n", igvm_parameter_block->firmware.size); + printf(" secrets_page: 0x%X\n", igvm_parameter_block->firmware.secrets_page); + printf(" caa_page: 0x%X\n", igvm_parameter_block->firmware.caa_page); + printf(" cpuid_page: 0x%X\n", igvm_parameter_block->firmware.cpuid_page); + printf(" reset_addr: 0x%X\n", igvm_parameter_block->firmware.reset_addr); + printf(" prevalidated_count: 0x%X\n", igvm_parameter_block->firmware.prevalidated_count); for (i = 0; i < igvm_parameter_block->firmware.prevalidated_count; ++i) { - printf(" prevalidated[%d].base: %X\n", i, igvm_parameter_block->firmware.prevalidated[i].base); - printf(" prevalidated[%d].size: %X\n", i, igvm_parameter_block->firmware.prevalidated[i].size); + printf(" prevalidated[%d].base: 0x%X\n", i, igvm_parameter_block->firmware.prevalidated[i].base); + printf(" prevalidated[%d].size: 0x%X\n", i, igvm_parameter_block->firmware.prevalidated[i].size); } } +static void print_param_block(IgvmParamBlock *igvm_parameter_block) +{ + printf("\nigvm_parameter_block:\n"); + printf(" param_area_size: 0x%X\n", igvm_parameter_block->param_area_size); + printf(" param_page_offset: 0x%X\n", igvm_parameter_block->param_page_offset); + printf(" memory_map_offset: 0x%X\n", igvm_parameter_block->memory_map_offset); + printf(" guest_context_offset: 0x%X\n", igvm_parameter_block->guest_context_offset); + printf(" cpuid_page: 0x%X\n", igvm_parameter_block->cpuid_page); + printf(" secrets_page: 0x%X\n", igvm_parameter_block->secrets_page); + printf(" debug_serial_port: 0x%X\n", igvm_parameter_block->debug_serial_port); + printf(" _reserved[3]: %02X%02X%02X\n", igvm_parameter_block->_reserved[0], + igvm_parameter_block->_reserved[1], + igvm_parameter_block->_reserved[2]); + print_fw_metadata(igvm_parameter_block); + printf(" kernel_reserved_size: 0x%X\n", igvm_parameter_block->kernel_reserved_size); + printf(" kernel_size: 0x%X\n", igvm_parameter_block->kernel_size); + printf(" kernel_base: 0x%lX\n", igvm_parameter_block->kernel_base); + printf(" vtom: 0x%lX\n", igvm_parameter_block->vtom); +} + int main(int argc, const char *argv[]) { uint32_t address; @@ -909,11 +942,11 @@ int main(int argc, const char *argv[]) // nnnnn-9EFFF: zero-filled (must be pre-validated) // 9F000-9FFFF: CPUID page // A0000-nnnnn: kernel and filesystem - construct_empty_data_object(0x00000, 0xF000); + construct_empty_data_object(0x00000, 0xF000, "Low memory"); // Construct a page containing an initial stack. This is the page // immediately below 64K, where stage 2 is loaded. - initial_stack = construct_mem_data_object(0xF000, PAGE_SIZE); + initial_stack = construct_mem_data_object(0xF000, PAGE_SIZE, "Initial stack"); // Construct a data object for the stage 2 image. Stage 2 is always // loaded at 64K. @@ -932,10 +965,10 @@ int main(int argc, const char *argv[]) } else if (stage2_top < 0x9F000) { - construct_empty_data_object(stage2_top, 0x9F000 - stage2_top); + construct_empty_data_object(stage2_top, 0x9F000 - stage2_top, "Stage 2 free space"); } - cpuid_page = construct_mem_data_object(0x9F000, 0x1000); + cpuid_page = construct_mem_data_object(0x9F000, 0x1000, "CPUID page"); cpuid_page->page_type = IgvmPageType_Cpuid; fill_cpuid_page((SNP_CPUID_PAGE *)cpuid_page->data); @@ -1012,25 +1045,25 @@ int main(int argc, const char *argv[]) // Allocate a page to hold the secrets page. This is not considered part // of the IGVM data. - secrets_page = construct_empty_data_object(address, PAGE_SIZE); + secrets_page = construct_empty_data_object(address, PAGE_SIZE, "Secrets page"); secrets_page->page_type = IgvmPageType_Secrets; address += PAGE_SIZE; // Construct a data object for the IGVM parameter block. stage2_stack->igvm_param_block = address; - igvm_parameter_object = construct_mem_data_object(address, sizeof(IgvmParamBlock)); + igvm_parameter_object = construct_mem_data_object(address, sizeof(IgvmParamBlock), "IGVM Parameter Block"); igvm_parameter_block = (IgvmParamBlock *)igvm_parameter_object->data; memset(igvm_parameter_block, 0, sizeof(IgvmParamBlock)); address += PAGE_SIZE; // Reserve a parameter page to hold IGVM parameters. igvm_parameter_block->param_page_offset = address - (uint32_t)igvm_parameter_object->address; - construct_parameter_page(address, parameter_page_general); + construct_parameter_page(address, parameter_page_general, "General parameters"); address += PAGE_SIZE; // Reserve a parameter page to hold the memory map. igvm_parameter_block->memory_map_offset = address - (uint32_t)igvm_parameter_object->address; - construct_parameter_page(address, parameter_page_memory_map); + construct_parameter_page(address, parameter_page_memory_map, "Memory map"); address += PAGE_SIZE; // If the firmware has supplied a guest context page, then assign it an address now. @@ -1106,11 +1139,6 @@ int main(int argc, const char *argv[]) // metadata from it. If the firmware is not OVMF then this function has // no effect. parse_ovmf_metadata(fw_filename, igvm_parameter_block); - - if (is_verbose) - { - print_fw_metadata(igvm_parameter_block); - } } // Generate a header to describe the memory that will be used as the @@ -1119,7 +1147,7 @@ int main(int argc, const char *argv[]) generate_required_memory_header(igvm_parameter_block); // Generate the initial VMSA. - vmsa_data = construct_mem_data_object(vmsa_address, PAGE_SIZE); + vmsa_data = construct_mem_data_object(vmsa_address, PAGE_SIZE, "VMSA"); vmsa_data->data_type = IGVM_VHT_VP_CONTEXT; generate_initial_vmsa(vmsa_data->data); @@ -1133,6 +1161,11 @@ int main(int argc, const char *argv[]) // data. assign_file_data(); + if (is_verbose) + { + print_param_block(igvm_parameter_block); + } + // Finally, generate the output file. err = generate_igvm_file(output_filename); if (err != 0) diff --git a/igvmbld/igvmbld.h b/igvmbld/igvmbld.h index f405eb39b..be7e87d3e 100644 --- a/igvmbld/igvmbld.h +++ b/igvmbld/igvmbld.h @@ -86,8 +86,8 @@ IGVM_VHS *allocate_var_headers( uint32_t header_size, int count); -DATA_OBJ *construct_empty_data_object(uint64_t address, uint32_t size); -DATA_OBJ *construct_mem_data_object(uint64_t address, uint32_t size); +DATA_OBJ *construct_empty_data_object(uint64_t address, uint32_t size, const char *description); +DATA_OBJ *construct_mem_data_object(uint64_t address, uint32_t size, const char *description); int read_hyperv_igvm_file(const char *file_name, FirmwareIgvmInfo *fw_info); diff --git a/igvmbld/igvmcopy.c b/igvmbld/igvmcopy.c index d863c083c..2bd29cb4d 100644 --- a/igvmbld/igvmcopy.c +++ b/igvmbld/igvmcopy.c @@ -345,7 +345,7 @@ int read_hyperv_igvm_file(const char *file_name, FirmwareIgvmInfo *fw_info) // the SVSM. if (page_data.FileOffset == 0) { - data_obj = construct_empty_data_object(page_data.GPA, PAGE_SIZE); + data_obj = construct_empty_data_object(page_data.GPA, PAGE_SIZE, file_name); data_obj->page_type = page_data.DataType; } else @@ -354,7 +354,7 @@ int read_hyperv_igvm_file(const char *file_name, FirmwareIgvmInfo *fw_info) { goto ReadError; } - data_obj = construct_mem_data_object(page_data.GPA, PAGE_SIZE); + data_obj = construct_mem_data_object(page_data.GPA, PAGE_SIZE, file_name); data_obj->page_type = page_data.DataType; if (0 != fseek(file, page_data.FileOffset, SEEK_SET)) @@ -426,7 +426,7 @@ int read_hyperv_igvm_file(const char *file_name, FirmwareIgvmInfo *fw_info) // in the VP context object here is not relevant, because the // SVSM IGVM headers expect the guest context to be part of // the IGVM parameter area. - data_obj = construct_mem_data_object(0, PAGE_SIZE); + data_obj = construct_mem_data_object(0, PAGE_SIZE, file_name); guest_context = data_obj->data; memset(guest_context, 0, PAGE_SIZE); fill_guest_context(guest_context, vmsa);