1*02c801a5SLawrence Tang /** 2*02c801a5SLawrence Tang * A user-space application for generating psuedo-random specification compliant CPER records. 3*02c801a5SLawrence Tang * 4*02c801a5SLawrence Tang * Author: Lawrence.Tang@arm.com 5*02c801a5SLawrence Tang **/ 6*02c801a5SLawrence Tang 7*02c801a5SLawrence Tang #include <stdio.h> 8*02c801a5SLawrence Tang #include <stdlib.h> 9*02c801a5SLawrence Tang #include <string.h> 10*02c801a5SLawrence Tang #include "../edk/Cper.h" 11*02c801a5SLawrence Tang #include "gen-utils.h" 12*02c801a5SLawrence Tang #include "sections/gen-section-generic.h" 13*02c801a5SLawrence Tang #include "sections/gen-section-ia32x64.h" 14*02c801a5SLawrence Tang 15*02c801a5SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR* generate_section_descriptor(char* type, size_t* lengths, int index); 16*02c801a5SLawrence Tang size_t generate_section(void** location, char* type); 17*02c801a5SLawrence Tang void print_help(); 18*02c801a5SLawrence Tang 19*02c801a5SLawrence Tang int main(int argc, char* argv[]) 20*02c801a5SLawrence Tang { 21*02c801a5SLawrence Tang //If help requested, print help. 22*02c801a5SLawrence Tang if (argc == 2 && strcmp(argv[1], "--help") == 0) 23*02c801a5SLawrence Tang { 24*02c801a5SLawrence Tang print_help(); 25*02c801a5SLawrence Tang return 0; 26*02c801a5SLawrence Tang } 27*02c801a5SLawrence Tang 28*02c801a5SLawrence Tang //Ensure the minimum number of arguments. 29*02c801a5SLawrence Tang if (argc < 5) 30*02c801a5SLawrence Tang { 31*02c801a5SLawrence Tang printf("Insufficient number of arguments. See 'cper-generate --help' for command information.\n"); 32*02c801a5SLawrence Tang return -1; 33*02c801a5SLawrence Tang } 34*02c801a5SLawrence Tang 35*02c801a5SLawrence Tang //Initialise randomiser. 36*02c801a5SLawrence Tang init_random(); 37*02c801a5SLawrence Tang 38*02c801a5SLawrence Tang //Generate the sections. Type names start from argv[4]. 39*02c801a5SLawrence Tang UINT16 num_sections = argc - 4; 40*02c801a5SLawrence Tang void* sections[num_sections]; 41*02c801a5SLawrence Tang size_t section_lengths[num_sections]; 42*02c801a5SLawrence Tang for (int i=0; i<num_sections; i++) 43*02c801a5SLawrence Tang { 44*02c801a5SLawrence Tang section_lengths[i] = generate_section(sections + i, argv[4 + i]); 45*02c801a5SLawrence Tang if (section_lengths[i] == 0) 46*02c801a5SLawrence Tang { 47*02c801a5SLawrence Tang //Error encountered, exit. 48*02c801a5SLawrence Tang return -1; 49*02c801a5SLawrence Tang } 50*02c801a5SLawrence Tang } 51*02c801a5SLawrence Tang 52*02c801a5SLawrence Tang //Generate the header given the number of sections. 53*02c801a5SLawrence Tang EFI_COMMON_ERROR_RECORD_HEADER* header = 54*02c801a5SLawrence Tang (EFI_COMMON_ERROR_RECORD_HEADER*)calloc(1, sizeof(EFI_COMMON_ERROR_RECORD_HEADER)); 55*02c801a5SLawrence Tang header->SignatureStart = 0x52455043; //CPER 56*02c801a5SLawrence Tang header->SectionCount = num_sections; 57*02c801a5SLawrence Tang printf("%d sections\n", num_sections); 58*02c801a5SLawrence Tang header->SignatureEnd = 0xFFFFFFFF; 59*02c801a5SLawrence Tang header->Flags = 4; //HW_ERROR_FLAGS_SIMULATED 60*02c801a5SLawrence Tang 61*02c801a5SLawrence Tang //Generate the section descriptors given the number of sections. 62*02c801a5SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR* section_descriptors[num_sections]; 63*02c801a5SLawrence Tang for (int i=0; i<num_sections; i++) 64*02c801a5SLawrence Tang section_descriptors[i] = generate_section_descriptor(argv[4 + i], section_lengths, i); 65*02c801a5SLawrence Tang 66*02c801a5SLawrence Tang //Calculate total length of structure, set in header. 67*02c801a5SLawrence Tang size_t total_len = sizeof(header); 68*02c801a5SLawrence Tang for (int i=0; i<num_sections; i++) 69*02c801a5SLawrence Tang total_len += section_lengths[i]; 70*02c801a5SLawrence Tang total_len += num_sections * sizeof(EFI_ERROR_SECTION_DESCRIPTOR); 71*02c801a5SLawrence Tang header->RecordLength = (UINT32)total_len; 72*02c801a5SLawrence Tang 73*02c801a5SLawrence Tang //Open a file handle to write output. 74*02c801a5SLawrence Tang FILE* cper_file = fopen(argv[2], "w"); 75*02c801a5SLawrence Tang if (cper_file == NULL) 76*02c801a5SLawrence Tang { 77*02c801a5SLawrence Tang printf("Could not get a handle for output file '%s', file handle returned null.\n", argv[2]); 78*02c801a5SLawrence Tang return -1; 79*02c801a5SLawrence Tang } 80*02c801a5SLawrence Tang 81*02c801a5SLawrence Tang //Write to file in order, free all resources. 82*02c801a5SLawrence Tang fwrite(header, sizeof(EFI_COMMON_ERROR_RECORD_HEADER), 1, cper_file); 83*02c801a5SLawrence Tang fflush(cper_file); 84*02c801a5SLawrence Tang free(header); 85*02c801a5SLawrence Tang for (int i=0; i<num_sections; i++) 86*02c801a5SLawrence Tang { 87*02c801a5SLawrence Tang fwrite(section_descriptors[i], sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1, cper_file); 88*02c801a5SLawrence Tang fflush(cper_file); 89*02c801a5SLawrence Tang free(section_descriptors[i]); 90*02c801a5SLawrence Tang } 91*02c801a5SLawrence Tang for (int i=0; i<num_sections; i++) 92*02c801a5SLawrence Tang { 93*02c801a5SLawrence Tang fwrite(sections[i], section_lengths[i], 1, cper_file); 94*02c801a5SLawrence Tang fflush(cper_file); 95*02c801a5SLawrence Tang free(sections[i]); 96*02c801a5SLawrence Tang } 97*02c801a5SLawrence Tang fclose(cper_file); 98*02c801a5SLawrence Tang } 99*02c801a5SLawrence Tang 100*02c801a5SLawrence Tang //Generates a single section descriptor for a section with the given properties. 101*02c801a5SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR* generate_section_descriptor(char* type, size_t* lengths, int index) 102*02c801a5SLawrence Tang { 103*02c801a5SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR* descriptor = 104*02c801a5SLawrence Tang (EFI_ERROR_SECTION_DESCRIPTOR*)generate_random_bytes(sizeof(EFI_ERROR_SECTION_DESCRIPTOR)); 105*02c801a5SLawrence Tang 106*02c801a5SLawrence Tang //Set reserved bits to zero. 107*02c801a5SLawrence Tang descriptor->SecValidMask &= 0b11; 108*02c801a5SLawrence Tang descriptor->Resv1 = 0; 109*02c801a5SLawrence Tang descriptor->SectionFlags &= 0xFF; 110*02c801a5SLawrence Tang 111*02c801a5SLawrence Tang //Set length, offset from base record. 112*02c801a5SLawrence Tang descriptor->SectionLength = (UINT32)lengths[index]; 113*02c801a5SLawrence Tang descriptor->SectionOffset = sizeof(EFI_COMMON_ERROR_RECORD_HEADER); 114*02c801a5SLawrence Tang for (int i=0; i<index; i++) 115*02c801a5SLawrence Tang descriptor->SectionOffset += lengths[i]; 116*02c801a5SLawrence Tang 117*02c801a5SLawrence Tang //Set section type GUID based on type name. 118*02c801a5SLawrence Tang if (strcmp(type, "generic") == 0) 119*02c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiProcessorGenericErrorSectionGuid, sizeof(EFI_GUID)); 120*02c801a5SLawrence Tang else if (strcmp(type, "ia32x64") == 0) 121*02c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiIa32X64ProcessorErrorSectionGuid, sizeof(EFI_GUID)); 122*02c801a5SLawrence Tang else if (strcmp(type, "ipf") == 0) 123*02c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiIpfProcessorErrorSectionGuid, sizeof(EFI_GUID)); 124*02c801a5SLawrence Tang else if (strcmp(type, "arm") == 0) 125*02c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiArmProcessorErrorSectionGuid, sizeof(EFI_GUID)); 126*02c801a5SLawrence Tang else if (strcmp(type, "memory") == 0) 127*02c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiPlatformMemoryErrorSectionGuid, sizeof(EFI_GUID)); 128*02c801a5SLawrence Tang else if (strcmp(type, "memory2") == 0) 129*02c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiPlatformMemoryError2SectionGuid, sizeof(EFI_GUID)); 130*02c801a5SLawrence Tang else if (strcmp(type, "pcie") == 0) 131*02c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiPcieErrorSectionGuid, sizeof(EFI_GUID)); 132*02c801a5SLawrence Tang else if (strcmp(type, "firmware") == 0) 133*02c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiFirmwareErrorSectionGuid, sizeof(EFI_GUID)); 134*02c801a5SLawrence Tang else if (strcmp(type, "pcibus") == 0) 135*02c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiPciBusErrorSectionGuid, sizeof(EFI_GUID)); 136*02c801a5SLawrence Tang else if (strcmp(type, "pcidev") == 0) 137*02c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiPciDevErrorSectionGuid, sizeof(EFI_GUID)); 138*02c801a5SLawrence Tang else if (strcmp(type, "dmargeneric") == 0) 139*02c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiDMArGenericErrorSectionGuid, sizeof(EFI_GUID)); 140*02c801a5SLawrence Tang else if (strcmp(type, "dmarvtd") == 0) 141*02c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiDirectedIoDMArErrorSectionGuid, sizeof(EFI_GUID)); 142*02c801a5SLawrence Tang else if (strcmp(type, "dmariommu") == 0) 143*02c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiIommuDMArErrorSectionGuid, sizeof(EFI_GUID)); 144*02c801a5SLawrence Tang else if (strcmp(type, "ccixper") == 0) 145*02c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiCcixPerLogErrorSectionGuid, sizeof(EFI_GUID)); 146*02c801a5SLawrence Tang else if (strcmp(type, "cxlprotocol") == 0) 147*02c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiCxlProtocolErrorSectionGuid, sizeof(EFI_GUID)); 148*02c801a5SLawrence Tang else if (strcmp(type, "cxlcomponent") == 0) 149*02c801a5SLawrence Tang { 150*02c801a5SLawrence Tang //Choose between the different CXL component type GUIDs. 151*02c801a5SLawrence Tang int componentType = rand() % 5; 152*02c801a5SLawrence Tang switch (componentType) 153*02c801a5SLawrence Tang { 154*02c801a5SLawrence Tang case 0: 155*02c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiCxlGeneralMediaErrorSectionGuid, sizeof(EFI_GUID)); 156*02c801a5SLawrence Tang break; 157*02c801a5SLawrence Tang case 1: 158*02c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiCxlDramEventErrorSectionGuid, sizeof(EFI_GUID)); 159*02c801a5SLawrence Tang break; 160*02c801a5SLawrence Tang case 2: 161*02c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiCxlPhysicalSwitchErrorSectionGuid, sizeof(EFI_GUID)); 162*02c801a5SLawrence Tang break; 163*02c801a5SLawrence Tang case 3: 164*02c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiCxlVirtualSwitchErrorSectionGuid, sizeof(EFI_GUID)); 165*02c801a5SLawrence Tang break; 166*02c801a5SLawrence Tang default: 167*02c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiCxlMldPortErrorSectionGuid, sizeof(EFI_GUID)); 168*02c801a5SLawrence Tang break; 169*02c801a5SLawrence Tang } 170*02c801a5SLawrence Tang } 171*02c801a5SLawrence Tang else if (strcmp(type, "unknown") != 0) 172*02c801a5SLawrence Tang { 173*02c801a5SLawrence Tang //Undefined section, show error. 174*02c801a5SLawrence Tang printf("Undefined section type '%s' provided. See 'cper-generate --help' for command information.\n", type); 175*02c801a5SLawrence Tang return 0; 176*02c801a5SLawrence Tang } 177*02c801a5SLawrence Tang 178*02c801a5SLawrence Tang return descriptor; 179*02c801a5SLawrence Tang } 180*02c801a5SLawrence Tang 181*02c801a5SLawrence Tang //Generates a single CPER section given the string type. 182*02c801a5SLawrence Tang size_t generate_section(void** location, char* type) 183*02c801a5SLawrence Tang { 184*02c801a5SLawrence Tang //The length of the section. 185*02c801a5SLawrence Tang size_t length = 0; 186*02c801a5SLawrence Tang 187*02c801a5SLawrence Tang //Switch on the type, generate accordingly. 188*02c801a5SLawrence Tang if (strcmp(type, "generic") == 0) 189*02c801a5SLawrence Tang length = generate_section_generic(location); 190*02c801a5SLawrence Tang else if (strcmp(type, "ia32x64") == 0) 191*02c801a5SLawrence Tang length = generate_section_ia32x64(location); 192*02c801a5SLawrence Tang // else if (strcmp(type, "ipf") == 0) 193*02c801a5SLawrence Tang // length = generate_section_ipf(location); 194*02c801a5SLawrence Tang // else if (strcmp(type, "arm") == 0) 195*02c801a5SLawrence Tang // length = generate_section_arm(location); 196*02c801a5SLawrence Tang // else if (strcmp(type, "memory") == 0) 197*02c801a5SLawrence Tang // length = generate_section_memory(location); 198*02c801a5SLawrence Tang // else if (strcmp(type, "memory2") == 0) 199*02c801a5SLawrence Tang // length = generate_section_memory2(location); 200*02c801a5SLawrence Tang // else if (strcmp(type, "pcie") == 0) 201*02c801a5SLawrence Tang // length = generate_section_pcie(location); 202*02c801a5SLawrence Tang // else if (strcmp(type, "firmware") == 0) 203*02c801a5SLawrence Tang // length = generate_section_firmware(location); 204*02c801a5SLawrence Tang // else if (strcmp(type, "pcibus") == 0) 205*02c801a5SLawrence Tang // length = generate_section_pci_bus(location); 206*02c801a5SLawrence Tang // else if (strcmp(type, "pcidev") == 0) 207*02c801a5SLawrence Tang // length = generate_section_pci_dev(location); 208*02c801a5SLawrence Tang // else if (strcmp(type, "dmargeneric") == 0) 209*02c801a5SLawrence Tang // length = generate_section_dmar_generic(location); 210*02c801a5SLawrence Tang // else if (strcmp(type, "dmarvtd") == 0) 211*02c801a5SLawrence Tang // length = generate_section_dmar_vtd(location); 212*02c801a5SLawrence Tang // else if (strcmp(type, "dmariommu") == 0) 213*02c801a5SLawrence Tang // length = generate_section_dmar_iommu(location); 214*02c801a5SLawrence Tang // else if (strcmp(type, "ccixper") == 0) 215*02c801a5SLawrence Tang // length = generate_section_ccix_per(location); 216*02c801a5SLawrence Tang // else if (strcmp(type, "cxlprotocol") == 0) 217*02c801a5SLawrence Tang // length = generate_section_cxl_protocol(location); 218*02c801a5SLawrence Tang // else if (strcmp(type, "cxlcomponent") == 0) 219*02c801a5SLawrence Tang // length = generate_section_cxl_component(location); 220*02c801a5SLawrence Tang // else if (strcmp(type, "unknown") == 0) 221*02c801a5SLawrence Tang // length = generate_section_unknown(location); 222*02c801a5SLawrence Tang else 223*02c801a5SLawrence Tang { 224*02c801a5SLawrence Tang //Undefined section, show error. 225*02c801a5SLawrence Tang printf("Undefined section type '%s' given to generate. See 'cper-generate --help' for command information.\n", type); 226*02c801a5SLawrence Tang return 0; 227*02c801a5SLawrence Tang } 228*02c801a5SLawrence Tang 229*02c801a5SLawrence Tang return length; 230*02c801a5SLawrence Tang } 231*02c801a5SLawrence Tang 232*02c801a5SLawrence Tang //Prints command help for this CPER generator. 233*02c801a5SLawrence Tang void print_help() 234*02c801a5SLawrence Tang { 235*02c801a5SLawrence Tang printf(":: --out cper.file --sections section1 [section2 section3 ...]\n"); 236*02c801a5SLawrence Tang printf("\tGenerates a psuedo-random CPER file with the provided section types and outputs to the given file name.\n"); 237*02c801a5SLawrence Tang printf("\tValid section type names are the following:\n"); 238*02c801a5SLawrence Tang printf("\t\t- generic\n"); 239*02c801a5SLawrence Tang printf("\t\t- ia32x64\n"); 240*02c801a5SLawrence Tang printf("\t\t- ipf\n"); 241*02c801a5SLawrence Tang printf("\t\t- arm\n"); 242*02c801a5SLawrence Tang printf("\t\t- memory\n"); 243*02c801a5SLawrence Tang printf("\t\t- memory2\n"); 244*02c801a5SLawrence Tang printf("\t\t- pcie\n"); 245*02c801a5SLawrence Tang printf("\t\t- firmware\n"); 246*02c801a5SLawrence Tang printf("\t\t- pcibus\n"); 247*02c801a5SLawrence Tang printf("\t\t- pcidev\n"); 248*02c801a5SLawrence Tang printf("\t\t- dmargeneric\n"); 249*02c801a5SLawrence Tang printf("\t\t- dmarvtd\n"); 250*02c801a5SLawrence Tang printf("\t\t- dmariommu\n"); 251*02c801a5SLawrence Tang printf("\t\t- ccixper\n"); 252*02c801a5SLawrence Tang printf("\t\t- cxlprotocol\n"); 253*02c801a5SLawrence Tang printf("\t\t- cxlcomponent\n"); 254*02c801a5SLawrence Tang printf("\t\t- unknown\n"); 255*02c801a5SLawrence Tang printf("\n:: --help\n"); 256*02c801a5SLawrence Tang printf("\tDisplays help information to the console.\n"); 257*02c801a5SLawrence Tang }