1 /** 2 * Functions for generating pseudo-random CPER ARM processor sections. 3 * 4 * Author: Lawrence.Tang@arm.com 5 **/ 6 7 #include <stdlib.h> 8 #include <stdio.h> 9 #include <string.h> 10 #include <libcper/BaseTypes.h> 11 #include <libcper/generator/gen-utils.h> 12 #include <libcper/generator/sections/gen-section.h> 13 #define ARM_ERROR_INFO_SIZE 32 14 15 void *generate_arm_error_info(GEN_VALID_BITS_TEST_TYPE validBitsType); 16 size_t generate_arm_context_info(void **location); 17 18 //Generates a single pseudo-random ARM processor section, saving the resulting address to the given 19 //location. Returns the size of the newly created section. 20 size_t generate_section_arm(void **location, 21 GEN_VALID_BITS_TEST_TYPE validBitsType) 22 { 23 //Set up for generation of error/context structures. 24 UINT16 error_structure_num = cper_rand() % 4 + 1; //Must be at least 1. 25 UINT16 context_structure_num = cper_rand() % 3 + 1; 26 void *error_structures[error_structure_num]; 27 void *context_structures[context_structure_num]; 28 size_t context_structure_lengths[context_structure_num]; 29 30 //Generate the structures. 31 for (int i = 0; i < error_structure_num; i++) { 32 error_structures[i] = generate_arm_error_info(validBitsType); 33 } 34 for (int i = 0; i < context_structure_num; i++) { 35 context_structure_lengths[i] = 36 generate_arm_context_info(context_structures + i); 37 } 38 39 //Determine a random amount of vendor specific info. 40 size_t vendor_info_len = cper_rand() % 16 + 4; 41 42 //Create the section as a whole. 43 size_t total_len = 40 + (error_structure_num * ARM_ERROR_INFO_SIZE); 44 for (int i = 0; i < context_structure_num; i++) { 45 total_len += context_structure_lengths[i]; 46 } 47 total_len += vendor_info_len; 48 UINT8 *section = generate_random_bytes(total_len); 49 50 //Set header information. 51 UINT16 *info_nums = (UINT16 *)(section + 4); 52 *info_nums = error_structure_num; 53 *(info_nums + 1) = context_structure_num; 54 UINT32 *section_length = (UINT32 *)(section + 8); 55 *section_length = total_len; 56 57 //Error affinity. 58 *(section + 12) = cper_rand() % 4; 59 60 //Reserved zero bytes. 61 UINT32 *validation = (UINT32 *)section; 62 *validation &= 0xF; 63 if (validBitsType == ALL_VALID) { 64 *validation = 0xF; 65 } else if (validBitsType == SOME_VALID) { 66 *validation = 0xA; 67 } 68 UINT32 *running_state = (UINT32 *)(section + 32); 69 *running_state &= 0x1; 70 memset(section + 13, 0, 3); 71 72 //Copy in the sections/context structures, free resources. 73 UINT8 *cur_pos = section + 40; 74 for (int i = 0; i < error_structure_num; i++) { 75 memcpy(cur_pos, error_structures[i], ARM_ERROR_INFO_SIZE); 76 free(error_structures[i]); 77 cur_pos += ARM_ERROR_INFO_SIZE; 78 } 79 for (int i = 0; i < context_structure_num; i++) { 80 memcpy(cur_pos, context_structures[i], 81 context_structure_lengths[i]); 82 free(context_structures[i]); 83 cur_pos += context_structure_lengths[i]; 84 } 85 86 //vendor specific 87 for (size_t i = 0; i < vendor_info_len; i++) { 88 //Ensure only printable ascii is used so we don't 89 // fail base64E 90 *cur_pos = cper_rand() % (0x7f - 0x20) + 0x20; 91 cur_pos += 1; 92 } 93 94 //Set return values and exit. 95 *location = section; 96 return total_len; 97 } 98 99 //Generates a single pseudo-random ARM error info structure. Must be later freed. 100 void *generate_arm_error_info(GEN_VALID_BITS_TEST_TYPE validBitsType) 101 { 102 UINT8 *error_info = generate_random_bytes(ARM_ERROR_INFO_SIZE); 103 104 //Version (zero for revision of table referenced), length. 105 *error_info = 0; 106 *(error_info + 1) = ARM_ERROR_INFO_SIZE; 107 108 //Type of error. 109 UINT8 error_type = cper_rand() % 3; 110 *(error_info + 4) = error_type; 111 112 //Reserved bits for error information. 113 UINT16 *validation = (UINT16 *)(error_info + 2); 114 *validation &= 0x1F; 115 if (validBitsType == ALL_VALID) { 116 *validation = 0x1F; 117 } else if (validBitsType == SOME_VALID) { 118 *validation = 0x15; 119 } 120 121 //Make sure reserved bits are zero according with the type. 122 UINT64 *error_subinfo = (UINT64 *)(error_info + 8); 123 switch (error_type) { 124 //Cache/TLB 125 case 0: 126 case 1: 127 *error_subinfo &= 0xFFFFFFF; 128 //Reserved bits for cache/tlb. 129 UINT16 *val_cache = (UINT16 *)(error_info + 8); 130 if (validBitsType == ALL_VALID) { 131 *val_cache = 0x7F; 132 } else if (validBitsType == SOME_VALID) { 133 *val_cache = 0x55; 134 } 135 break; 136 137 //Bus 138 case 2: 139 *error_subinfo &= 0xFFFFFFFFFFF; 140 UINT16 *val_bus = (UINT16 *)(error_info + 8); 141 if (validBitsType == ALL_VALID) { 142 *val_bus = 0xFFF; 143 } else if (validBitsType == SOME_VALID) { 144 *val_bus = 0x555; 145 } 146 147 break; 148 149 //Microarch/other. 150 default: 151 break; 152 } 153 154 //flags 155 UINT8 *flags = (UINT8 *)(error_info + 7); 156 *flags &= 0xF; 157 158 return error_info; 159 } 160 161 //Generates a single pseudo-random ARM context info structure. Must be later freed. 162 size_t generate_arm_context_info(void **location) 163 { 164 //Initial length is 8 bytes. Add extra based on type. 165 UINT16 reg_type = cper_rand() % 9; 166 UINT32 reg_size = 0; 167 168 //Set register size. 169 switch (reg_type) { 170 //AARCH32 GPR, AARCH32 EL2 171 case 0: 172 case 2: 173 reg_size = 64; 174 break; 175 176 //AARCH32 EL1 177 case 1: 178 reg_size = 96; 179 break; 180 181 //AARCH32 EL3 182 case 3: 183 reg_size = 8; 184 break; 185 186 //AARCH64 GPR 187 case 4: 188 reg_size = 256; 189 break; 190 191 //AARCH64 EL1 192 case 5: 193 reg_size = 136; 194 break; 195 196 //AARCH64 EL2 197 case 6: 198 reg_size = 120; 199 break; 200 201 //AARCH64 EL3 202 case 7: 203 reg_size = 80; 204 break; 205 206 //Misc. single register. 207 case 8: 208 reg_size = 10; 209 break; 210 } 211 212 //Create context structure randomly. 213 int total_size = 8 + reg_size; 214 UINT16 *context_info = (UINT16 *)generate_random_bytes(total_size); 215 216 //UEFI spec is not clear about bit 15 in the 217 // reg type 8 section. This sets it to 0 to 218 // avoid confusion for now. 219 if (reg_type == 8) { 220 UINT8 *reg_decode = (UINT8 *)context_info; 221 *(reg_decode + 9) &= 0x7F; 222 } 223 224 //Set header information. 225 *(context_info + 1) = reg_type; 226 *((UINT32 *)(context_info + 2)) = reg_size; 227 228 //Set return values and exit. 229 *location = context_info; 230 return total_size; 231 } 232