|  | /** | 
|  | * Functions for generating psuedo-random CPER IA32/x64 sections. | 
|  | * | 
|  | * Author: Lawrence.Tang@arm.com | 
|  | **/ | 
|  |  | 
|  | #include <stdlib.h> | 
|  | #include <string.h> | 
|  | #include <stdio.h> | 
|  | #include "../../edk/Cper.h" | 
|  | #include "../gen-utils.h" | 
|  | #include "gen-sections.h" | 
|  | #define IA32X64_ERROR_STRUCTURE_SIZE 64 | 
|  |  | 
|  | void* generate_ia32x64_error_structure(); | 
|  | size_t generate_ia32x64_context_structure(void** location); | 
|  |  | 
|  | //Generates a single psuedo-random IA32/x64 section, saving the resulting address to the given | 
|  | //location. Returns the size of the newly created section. | 
|  | size_t generate_section_ia32x64(void** location) | 
|  | { | 
|  | //Set up for generation of error/context structures. | 
|  | UINT16 error_structure_num = rand() % 5; | 
|  | UINT16 context_structure_num = rand() % 5; | 
|  | void* error_structures[error_structure_num]; | 
|  | void* context_structures[context_structure_num]; | 
|  | size_t context_structure_lengths[context_structure_num]; | 
|  |  | 
|  | //Generate the structures. | 
|  | for (int i=0; i<error_structure_num; i++) | 
|  | error_structures[i] = generate_ia32x64_error_structure(); | 
|  | for (int i=0; i<context_structure_num; i++) | 
|  | context_structure_lengths[i] = generate_ia32x64_context_structure(context_structures + i); | 
|  |  | 
|  | //Create a valid IA32/x64 section. | 
|  | size_t total_len = 64 + (IA32X64_ERROR_STRUCTURE_SIZE * error_structure_num); | 
|  | for (int i=0; i<context_structure_num; i++) | 
|  | total_len += context_structure_lengths[i]; | 
|  | UINT8* section = generate_random_bytes(total_len); | 
|  |  | 
|  | //Null extend the end of the CPUID in the header. | 
|  | for (int i=0; i<16; i++) | 
|  | *(section + 48 + i) = 0x0; | 
|  |  | 
|  | //Set header information. | 
|  | UINT64* validation = (UINT64*)section; | 
|  | *validation &= 0b11; | 
|  | *validation |= error_structure_num << 2; | 
|  | *validation |= context_structure_num << 8; | 
|  |  | 
|  | //Copy in structures, free resources. | 
|  | UINT8* cur_pos = section + 64; | 
|  | for (int i=0; i<error_structure_num; i++) | 
|  | { | 
|  | memcpy(cur_pos, error_structures[i], IA32X64_ERROR_STRUCTURE_SIZE); | 
|  | free(error_structures[i]); | 
|  | cur_pos += IA32X64_ERROR_STRUCTURE_SIZE; | 
|  | } | 
|  | for (int i=0; i<context_structure_num; i++) | 
|  | { | 
|  | memcpy(cur_pos, context_structures[i], context_structure_lengths[i]); | 
|  | free(context_structures[i]); | 
|  | cur_pos += context_structure_lengths[i]; | 
|  | } | 
|  |  | 
|  | //Set return values, exist. | 
|  | *location = section; | 
|  | return total_len; | 
|  | } | 
|  |  | 
|  | //Generates a single IA32/x64 error structure. Must later be freed. | 
|  | void* generate_ia32x64_error_structure() | 
|  | { | 
|  | UINT8* error_structure = generate_random_bytes(IA32X64_ERROR_STRUCTURE_SIZE); | 
|  |  | 
|  | //Set error structure reserved space to zero. | 
|  | UINT64* validation = (UINT64*)(error_structure + 16); | 
|  | *validation &= 0x1F; | 
|  |  | 
|  | //Create a random type of error structure. | 
|  | EFI_GUID* guid = (EFI_GUID*)error_structure; | 
|  | UINT64* check_info = (UINT64*)(error_structure + 24); | 
|  | int error_structure_type = rand() % 4; | 
|  | switch (error_structure_type) | 
|  | { | 
|  | //Cache | 
|  | case 0: | 
|  | memcpy(guid, &gEfiIa32x64ErrorTypeCacheCheckGuid, sizeof(EFI_GUID)); | 
|  |  | 
|  | //Set reserved space to zero. | 
|  | *check_info &= ~0xFF00; | 
|  | *check_info &= 0x3FFFFFFF; | 
|  | break; | 
|  |  | 
|  | //TLB | 
|  | case 1: | 
|  | memcpy(guid, &gEfiIa32x64ErrorTypeTlbCheckGuid, sizeof(EFI_GUID)); | 
|  |  | 
|  | //Set reserved space to zero. | 
|  | *check_info &= ~0xFF00; | 
|  | *check_info &= 0x3FFFFFFF; | 
|  | break; | 
|  |  | 
|  | //Bus | 
|  | case 2: | 
|  | memcpy(guid, &gEfiIa32x64ErrorTypeBusCheckGuid, sizeof(EFI_GUID)); | 
|  |  | 
|  | //Set reserved space to zero. | 
|  | *check_info &= ~0xF800; | 
|  | *check_info &= 0x7FFFFFFFF; | 
|  | break; | 
|  |  | 
|  | //MS | 
|  | case 3: | 
|  | memcpy(guid, &gEfiIa32x64ErrorTypeMsCheckGuid, sizeof(EFI_GUID)); | 
|  |  | 
|  | //Set reserved space to zero. | 
|  | *check_info &= ~0xFFE0; | 
|  | *check_info &= 0xFFFFFF; | 
|  | break; | 
|  | } | 
|  |  | 
|  | return error_structure; | 
|  | } | 
|  |  | 
|  | //Generates a single IA32/x64 context structure. Must later be freed. | 
|  | size_t generate_ia32x64_context_structure(void** location) | 
|  | { | 
|  | //Initial length is 16 bytes. Add extra based on type. | 
|  | int reg_type = rand() % 8; | 
|  | int reg_size = 0; | 
|  |  | 
|  | //Set register size. | 
|  | if (reg_type == 2) | 
|  | reg_size = 92; //IA32 registers. | 
|  | if (reg_type == 3) | 
|  | reg_size = 244; //x64 registers. | 
|  | else | 
|  | reg_size = (rand() % 5) * 32; //Not table defined. | 
|  |  | 
|  | //Create structure randomly. | 
|  | int total_size = 16 + reg_size; | 
|  | UINT16* context_structure = (UINT16*)generate_random_bytes(total_size); | 
|  |  | 
|  | //Set header information. | 
|  | *(context_structure) = reg_type; | 
|  | *(context_structure + 1) = reg_size; | 
|  | printf("set reg size to %d (for type %d).\n", reg_size, reg_type); | 
|  |  | 
|  | //Set return values and exit. | 
|  | *location = context_structure; | 
|  | return total_size; | 
|  | } |