102c801a5SLawrence Tang /** 202c801a5SLawrence Tang * A user-space application for generating psuedo-random specification compliant CPER records. 302c801a5SLawrence Tang * 402c801a5SLawrence Tang * Author: Lawrence.Tang@arm.com 502c801a5SLawrence Tang **/ 602c801a5SLawrence Tang 702c801a5SLawrence Tang #include <stdio.h> 802c801a5SLawrence Tang #include <stdlib.h> 902c801a5SLawrence Tang #include <string.h> 1002c801a5SLawrence Tang #include "../edk/Cper.h" 1102c801a5SLawrence Tang #include "gen-utils.h" 1267cbed6bSLawrence Tang #include "sections/gen-sections.h" 1302c801a5SLawrence Tang 1467cbed6bSLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR* generate_section_descriptor(char* type, size_t* lengths, int index, int num_sections); 1502c801a5SLawrence Tang size_t generate_section(void** location, char* type); 1602c801a5SLawrence Tang void print_help(); 1702c801a5SLawrence Tang 1802c801a5SLawrence Tang int main(int argc, char* argv[]) 1902c801a5SLawrence Tang { 2002c801a5SLawrence Tang //If help requested, print help. 2102c801a5SLawrence Tang if (argc == 2 && strcmp(argv[1], "--help") == 0) 2202c801a5SLawrence Tang { 2302c801a5SLawrence Tang print_help(); 2402c801a5SLawrence Tang return 0; 2502c801a5SLawrence Tang } 2602c801a5SLawrence Tang 2702c801a5SLawrence Tang //Ensure the minimum number of arguments. 2802c801a5SLawrence Tang if (argc < 5) 2902c801a5SLawrence Tang { 3002c801a5SLawrence Tang printf("Insufficient number of arguments. See 'cper-generate --help' for command information.\n"); 3102c801a5SLawrence Tang return -1; 3202c801a5SLawrence Tang } 3302c801a5SLawrence Tang 3402c801a5SLawrence Tang //Initialise randomiser. 3502c801a5SLawrence Tang init_random(); 3602c801a5SLawrence Tang 3702c801a5SLawrence Tang //Generate the sections. Type names start from argv[4]. 3802c801a5SLawrence Tang UINT16 num_sections = argc - 4; 3902c801a5SLawrence Tang void* sections[num_sections]; 4002c801a5SLawrence Tang size_t section_lengths[num_sections]; 4102c801a5SLawrence Tang for (int i=0; i<num_sections; i++) 4202c801a5SLawrence Tang { 4302c801a5SLawrence Tang section_lengths[i] = generate_section(sections + i, argv[4 + i]); 4402c801a5SLawrence Tang if (section_lengths[i] == 0) 4502c801a5SLawrence Tang { 4602c801a5SLawrence Tang //Error encountered, exit. 4702c801a5SLawrence Tang return -1; 4802c801a5SLawrence Tang } 4902c801a5SLawrence Tang } 5002c801a5SLawrence Tang 5102c801a5SLawrence Tang //Generate the header given the number of sections. 5202c801a5SLawrence Tang EFI_COMMON_ERROR_RECORD_HEADER* header = 5302c801a5SLawrence Tang (EFI_COMMON_ERROR_RECORD_HEADER*)calloc(1, sizeof(EFI_COMMON_ERROR_RECORD_HEADER)); 5402c801a5SLawrence Tang header->SignatureStart = 0x52455043; //CPER 5502c801a5SLawrence Tang header->SectionCount = num_sections; 5602c801a5SLawrence Tang header->SignatureEnd = 0xFFFFFFFF; 5702c801a5SLawrence Tang header->Flags = 4; //HW_ERROR_FLAGS_SIMULATED 5867cbed6bSLawrence Tang header->RecordID = (UINT64)rand(); 5967cbed6bSLawrence Tang header->ErrorSeverity = rand() % 4; 6067cbed6bSLawrence Tang *((UINT64*)&header->TimeStamp) = (UINT64)rand(); 6167cbed6bSLawrence Tang header->ValidationBits = rand() % 0b1000; 6202c801a5SLawrence Tang 6302c801a5SLawrence Tang //Generate the section descriptors given the number of sections. 6402c801a5SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR* section_descriptors[num_sections]; 6502c801a5SLawrence Tang for (int i=0; i<num_sections; i++) 6667cbed6bSLawrence Tang section_descriptors[i] = generate_section_descriptor(argv[4 + i], section_lengths, i, num_sections); 6702c801a5SLawrence Tang 6802c801a5SLawrence Tang //Calculate total length of structure, set in header. 6967cbed6bSLawrence Tang size_t total_len = sizeof(EFI_COMMON_ERROR_RECORD_HEADER); 7002c801a5SLawrence Tang for (int i=0; i<num_sections; i++) 7102c801a5SLawrence Tang total_len += section_lengths[i]; 7202c801a5SLawrence Tang total_len += num_sections * sizeof(EFI_ERROR_SECTION_DESCRIPTOR); 7302c801a5SLawrence Tang header->RecordLength = (UINT32)total_len; 7402c801a5SLawrence Tang 7502c801a5SLawrence Tang //Open a file handle to write output. 7602c801a5SLawrence Tang FILE* cper_file = fopen(argv[2], "w"); 7702c801a5SLawrence Tang if (cper_file == NULL) 7802c801a5SLawrence Tang { 7902c801a5SLawrence Tang printf("Could not get a handle for output file '%s', file handle returned null.\n", argv[2]); 8002c801a5SLawrence Tang return -1; 8102c801a5SLawrence Tang } 8202c801a5SLawrence Tang 8302c801a5SLawrence Tang //Write to file in order, free all resources. 8402c801a5SLawrence Tang fwrite(header, sizeof(EFI_COMMON_ERROR_RECORD_HEADER), 1, cper_file); 8502c801a5SLawrence Tang fflush(cper_file); 8602c801a5SLawrence Tang free(header); 8702c801a5SLawrence Tang for (int i=0; i<num_sections; i++) 8802c801a5SLawrence Tang { 8902c801a5SLawrence Tang fwrite(section_descriptors[i], sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1, cper_file); 9002c801a5SLawrence Tang fflush(cper_file); 9102c801a5SLawrence Tang free(section_descriptors[i]); 9202c801a5SLawrence Tang } 9302c801a5SLawrence Tang for (int i=0; i<num_sections; i++) 9402c801a5SLawrence Tang { 9502c801a5SLawrence Tang fwrite(sections[i], section_lengths[i], 1, cper_file); 9602c801a5SLawrence Tang fflush(cper_file); 9702c801a5SLawrence Tang free(sections[i]); 9802c801a5SLawrence Tang } 9902c801a5SLawrence Tang fclose(cper_file); 10002c801a5SLawrence Tang } 10102c801a5SLawrence Tang 10202c801a5SLawrence Tang //Generates a single section descriptor for a section with the given properties. 10367cbed6bSLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR* generate_section_descriptor(char* type, size_t* lengths, int index, int num_sections) 10402c801a5SLawrence Tang { 10502c801a5SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR* descriptor = 10602c801a5SLawrence Tang (EFI_ERROR_SECTION_DESCRIPTOR*)generate_random_bytes(sizeof(EFI_ERROR_SECTION_DESCRIPTOR)); 10702c801a5SLawrence Tang 10802c801a5SLawrence Tang //Set reserved bits to zero. 10902c801a5SLawrence Tang descriptor->SecValidMask &= 0b11; 11002c801a5SLawrence Tang descriptor->Resv1 = 0; 11102c801a5SLawrence Tang descriptor->SectionFlags &= 0xFF; 11202c801a5SLawrence Tang 11302c801a5SLawrence Tang //Set length, offset from base record. 11402c801a5SLawrence Tang descriptor->SectionLength = (UINT32)lengths[index]; 11567cbed6bSLawrence Tang descriptor->SectionOffset = sizeof(EFI_COMMON_ERROR_RECORD_HEADER) 11667cbed6bSLawrence Tang + (num_sections * sizeof(EFI_ERROR_SECTION_DESCRIPTOR)); 11702c801a5SLawrence Tang for (int i=0; i<index; i++) 11802c801a5SLawrence Tang descriptor->SectionOffset += lengths[i]; 11902c801a5SLawrence Tang 12002c801a5SLawrence Tang //Set section type GUID based on type name. 12102c801a5SLawrence Tang if (strcmp(type, "generic") == 0) 12202c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiProcessorGenericErrorSectionGuid, sizeof(EFI_GUID)); 12302c801a5SLawrence Tang else if (strcmp(type, "ia32x64") == 0) 12402c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiIa32X64ProcessorErrorSectionGuid, sizeof(EFI_GUID)); 12502c801a5SLawrence Tang else if (strcmp(type, "ipf") == 0) 12602c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiIpfProcessorErrorSectionGuid, sizeof(EFI_GUID)); 12702c801a5SLawrence Tang else if (strcmp(type, "arm") == 0) 12802c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiArmProcessorErrorSectionGuid, sizeof(EFI_GUID)); 12902c801a5SLawrence Tang else if (strcmp(type, "memory") == 0) 13002c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiPlatformMemoryErrorSectionGuid, sizeof(EFI_GUID)); 13102c801a5SLawrence Tang else if (strcmp(type, "memory2") == 0) 13202c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiPlatformMemoryError2SectionGuid, sizeof(EFI_GUID)); 13302c801a5SLawrence Tang else if (strcmp(type, "pcie") == 0) 13402c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiPcieErrorSectionGuid, sizeof(EFI_GUID)); 13502c801a5SLawrence Tang else if (strcmp(type, "firmware") == 0) 13602c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiFirmwareErrorSectionGuid, sizeof(EFI_GUID)); 13702c801a5SLawrence Tang else if (strcmp(type, "pcibus") == 0) 13802c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiPciBusErrorSectionGuid, sizeof(EFI_GUID)); 13902c801a5SLawrence Tang else if (strcmp(type, "pcidev") == 0) 14002c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiPciDevErrorSectionGuid, sizeof(EFI_GUID)); 14102c801a5SLawrence Tang else if (strcmp(type, "dmargeneric") == 0) 14202c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiDMArGenericErrorSectionGuid, sizeof(EFI_GUID)); 14302c801a5SLawrence Tang else if (strcmp(type, "dmarvtd") == 0) 14402c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiDirectedIoDMArErrorSectionGuid, sizeof(EFI_GUID)); 14502c801a5SLawrence Tang else if (strcmp(type, "dmariommu") == 0) 14602c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiIommuDMArErrorSectionGuid, sizeof(EFI_GUID)); 14702c801a5SLawrence Tang else if (strcmp(type, "ccixper") == 0) 14802c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiCcixPerLogErrorSectionGuid, sizeof(EFI_GUID)); 14902c801a5SLawrence Tang else if (strcmp(type, "cxlprotocol") == 0) 15002c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiCxlProtocolErrorSectionGuid, sizeof(EFI_GUID)); 15102c801a5SLawrence Tang else if (strcmp(type, "cxlcomponent") == 0) 15202c801a5SLawrence Tang { 15302c801a5SLawrence Tang //Choose between the different CXL component type GUIDs. 15402c801a5SLawrence Tang int componentType = rand() % 5; 15502c801a5SLawrence Tang switch (componentType) 15602c801a5SLawrence Tang { 15702c801a5SLawrence Tang case 0: 15802c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiCxlGeneralMediaErrorSectionGuid, sizeof(EFI_GUID)); 15902c801a5SLawrence Tang break; 16002c801a5SLawrence Tang case 1: 16102c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiCxlDramEventErrorSectionGuid, sizeof(EFI_GUID)); 16202c801a5SLawrence Tang break; 16302c801a5SLawrence Tang case 2: 16402c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiCxlPhysicalSwitchErrorSectionGuid, sizeof(EFI_GUID)); 16502c801a5SLawrence Tang break; 16602c801a5SLawrence Tang case 3: 16702c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiCxlVirtualSwitchErrorSectionGuid, sizeof(EFI_GUID)); 16802c801a5SLawrence Tang break; 16902c801a5SLawrence Tang default: 17002c801a5SLawrence Tang memcpy(&descriptor->SectionType, &gEfiCxlMldPortErrorSectionGuid, sizeof(EFI_GUID)); 17102c801a5SLawrence Tang break; 17202c801a5SLawrence Tang } 17302c801a5SLawrence Tang } 17402c801a5SLawrence Tang else if (strcmp(type, "unknown") != 0) 17502c801a5SLawrence Tang { 17602c801a5SLawrence Tang //Undefined section, show error. 17702c801a5SLawrence Tang printf("Undefined section type '%s' provided. See 'cper-generate --help' for command information.\n", type); 17802c801a5SLawrence Tang return 0; 17902c801a5SLawrence Tang } 18002c801a5SLawrence Tang 18102c801a5SLawrence Tang return descriptor; 18202c801a5SLawrence Tang } 18302c801a5SLawrence Tang 18402c801a5SLawrence Tang //Generates a single CPER section given the string type. 18502c801a5SLawrence Tang size_t generate_section(void** location, char* type) 18602c801a5SLawrence Tang { 18702c801a5SLawrence Tang //The length of the section. 18802c801a5SLawrence Tang size_t length = 0; 18902c801a5SLawrence Tang 19002c801a5SLawrence Tang //Switch on the type, generate accordingly. 19102c801a5SLawrence Tang if (strcmp(type, "generic") == 0) 19202c801a5SLawrence Tang length = generate_section_generic(location); 19302c801a5SLawrence Tang else if (strcmp(type, "ia32x64") == 0) 19402c801a5SLawrence Tang length = generate_section_ia32x64(location); 19502c801a5SLawrence Tang // else if (strcmp(type, "ipf") == 0) 19602c801a5SLawrence Tang // length = generate_section_ipf(location); 19767cbed6bSLawrence Tang else if (strcmp(type, "arm") == 0) 19867cbed6bSLawrence Tang length = generate_section_arm(location); 199*de9707f9SLawrence Tang else if (strcmp(type, "memory") == 0) 200*de9707f9SLawrence Tang length = generate_section_memory(location); 201*de9707f9SLawrence Tang else if (strcmp(type, "memory2") == 0) 202*de9707f9SLawrence Tang length = generate_section_memory2(location); 203*de9707f9SLawrence Tang else if (strcmp(type, "pcie") == 0) 204*de9707f9SLawrence Tang length = generate_section_pcie(location); 205*de9707f9SLawrence Tang else if (strcmp(type, "firmware") == 0) 206*de9707f9SLawrence Tang length = generate_section_firmware(location); 207*de9707f9SLawrence Tang else if (strcmp(type, "pcibus") == 0) 208*de9707f9SLawrence Tang length = generate_section_pci_bus(location); 209*de9707f9SLawrence Tang else if (strcmp(type, "pcidev") == 0) 210*de9707f9SLawrence Tang length = generate_section_pci_dev(location); 211*de9707f9SLawrence Tang else if (strcmp(type, "dmargeneric") == 0) 212*de9707f9SLawrence Tang length = generate_section_dmar_generic(location); 213*de9707f9SLawrence Tang else if (strcmp(type, "dmarvtd") == 0) 214*de9707f9SLawrence Tang length = generate_section_dmar_vtd(location); 215*de9707f9SLawrence Tang else if (strcmp(type, "dmariommu") == 0) 216*de9707f9SLawrence Tang length = generate_section_dmar_iommu(location); 217*de9707f9SLawrence Tang else if (strcmp(type, "ccixper") == 0) 218*de9707f9SLawrence Tang length = generate_section_ccix_per(location); 219*de9707f9SLawrence Tang else if (strcmp(type, "cxlprotocol") == 0) 220*de9707f9SLawrence Tang length = generate_section_cxl_protocol(location); 221*de9707f9SLawrence Tang else if (strcmp(type, "cxlcomponent") == 0) 222*de9707f9SLawrence Tang length = generate_section_cxl_component(location); 223*de9707f9SLawrence Tang else if (strcmp(type, "unknown") == 0) 224*de9707f9SLawrence Tang length = generate_random_section(location, rand() % 256); 22502c801a5SLawrence Tang else 22602c801a5SLawrence Tang { 22702c801a5SLawrence Tang //Undefined section, show error. 22802c801a5SLawrence Tang printf("Undefined section type '%s' given to generate. See 'cper-generate --help' for command information.\n", type); 22902c801a5SLawrence Tang return 0; 23002c801a5SLawrence Tang } 23102c801a5SLawrence Tang 23202c801a5SLawrence Tang return length; 23302c801a5SLawrence Tang } 23402c801a5SLawrence Tang 23502c801a5SLawrence Tang //Prints command help for this CPER generator. 23602c801a5SLawrence Tang void print_help() 23702c801a5SLawrence Tang { 23802c801a5SLawrence Tang printf(":: --out cper.file --sections section1 [section2 section3 ...]\n"); 23902c801a5SLawrence Tang printf("\tGenerates a psuedo-random CPER file with the provided section types and outputs to the given file name.\n"); 24002c801a5SLawrence Tang printf("\tValid section type names are the following:\n"); 24102c801a5SLawrence Tang printf("\t\t- generic\n"); 24202c801a5SLawrence Tang printf("\t\t- ia32x64\n"); 24302c801a5SLawrence Tang printf("\t\t- ipf\n"); 24402c801a5SLawrence Tang printf("\t\t- arm\n"); 24502c801a5SLawrence Tang printf("\t\t- memory\n"); 24602c801a5SLawrence Tang printf("\t\t- memory2\n"); 24702c801a5SLawrence Tang printf("\t\t- pcie\n"); 24802c801a5SLawrence Tang printf("\t\t- firmware\n"); 24902c801a5SLawrence Tang printf("\t\t- pcibus\n"); 25002c801a5SLawrence Tang printf("\t\t- pcidev\n"); 25102c801a5SLawrence Tang printf("\t\t- dmargeneric\n"); 25202c801a5SLawrence Tang printf("\t\t- dmarvtd\n"); 25302c801a5SLawrence Tang printf("\t\t- dmariommu\n"); 25402c801a5SLawrence Tang printf("\t\t- ccixper\n"); 25502c801a5SLawrence Tang printf("\t\t- cxlprotocol\n"); 25602c801a5SLawrence Tang printf("\t\t- cxlcomponent\n"); 25702c801a5SLawrence Tang printf("\t\t- unknown\n"); 25802c801a5SLawrence Tang printf("\n:: --help\n"); 25902c801a5SLawrence Tang printf("\tDisplays help information to the console.\n"); 26002c801a5SLawrence Tang }