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