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