Skip to content

Commit

Permalink
igvmbld: Extend verbose mode to show guest memory and igvm params
Browse files Browse the repository at this point in the history
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 <roy.hopkins@suse.com>
  • Loading branch information
roy-hopkins committed Jan 10, 2024
1 parent 02953a0 commit d6b606c
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 33 deletions.
89 changes: 61 additions & 28 deletions igvmbld/igvmbld.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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));
}

Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand All @@ -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);

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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);

Expand All @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions igvmbld/igvmbld.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
6 changes: 3 additions & 3 deletions igvmbld/igvmcopy.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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))
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit d6b606c

Please sign in to comment.