1 /** 2 * Describes utility functions for parsing CPER into JSON IR. 3 * 4 * Author: Lawrence.Tang@arm.com 5 **/ 6 7 #include <stdio.h> 8 #include "json.h" 9 #include "edk/Cper.h" 10 #include "cper-utils.h" 11 12 //The available severity types for CPER. 13 const char* CPER_SEVERITY_TYPES[4] = {"Recoverable", "Fatal", "Corrected", "Informational"}; 14 15 //Converts the given generic CPER error status to JSON IR. 16 json_object* cper_generic_error_status_to_ir(EFI_GENERIC_ERROR_STATUS* error_status) 17 { 18 json_object* error_status_ir = json_object_new_object(); 19 20 //Error type. 21 json_object_object_add(error_status_ir, "errorType", integer_to_readable_pair_with_desc(error_status->Type, 18, 22 CPER_GENERIC_ERROR_TYPES_KEYS, 23 CPER_GENERIC_ERROR_TYPES_VALUES, 24 CPER_GENERIC_ERROR_TYPES_DESCRIPTIONS, 25 "Unknown (Reserved)")); 26 27 //Boolean bit fields. 28 json_object_object_add(error_status_ir, "addressSignal", json_object_new_boolean(error_status->AddressSignal)); 29 json_object_object_add(error_status_ir, "controlSignal", json_object_new_boolean(error_status->ControlSignal)); 30 json_object_object_add(error_status_ir, "dataSignal", json_object_new_boolean(error_status->DataSignal)); 31 json_object_object_add(error_status_ir, "detectedByResponder", json_object_new_boolean(error_status->DetectedByResponder)); 32 json_object_object_add(error_status_ir, "detectedByRequester", json_object_new_boolean(error_status->DetectedByRequester)); 33 json_object_object_add(error_status_ir, "firstError", json_object_new_boolean(error_status->FirstError)); 34 json_object_object_add(error_status_ir, "overflowDroppedLogs", json_object_new_boolean(error_status->OverflowNotLogged)); 35 36 return error_status_ir; 37 } 38 39 //Converts a single uniform struct of UINT64s into intermediate JSON IR format, given names for each field in byte order. 40 json_object* uniform_struct64_to_ir(UINT64* start, int len, const char* names[]) 41 { 42 json_object* result = json_object_new_object(); 43 44 UINT64* cur = start; 45 for (int i=0; i<len; i++) 46 { 47 json_object_object_add(result, names[i], json_object_new_uint64(*cur)); 48 cur++; 49 } 50 51 return result; 52 } 53 54 //Converts a single uniform struct of UINT32s into intermediate JSON IR format, given names for each field in byte order. 55 json_object* uniform_struct_to_ir(UINT32* start, int len, const char* names[]) 56 { 57 json_object* result = json_object_new_object(); 58 59 UINT32* cur = start; 60 for (int i=0; i<len; i++) 61 { 62 json_object_object_add(result, names[i], json_object_new_uint64(*cur)); 63 cur++; 64 } 65 66 return result; 67 } 68 69 //Converts a single object containing UINT32s into a uniform struct. 70 void ir_to_uniform_struct64(json_object* ir, UINT64* start, int len, const char* names[]) 71 { 72 UINT64* cur = start; 73 for (int i=0; i<len; i++) 74 { 75 *cur = json_object_get_uint64(json_object_object_get(ir, names[i])); 76 cur++; 77 } 78 } 79 80 //Converts a single object containing UINT32s into a uniform struct. 81 void ir_to_uniform_struct(json_object* ir, UINT32* start, int len, const char* names[]) 82 { 83 UINT32* cur = start; 84 for (int i=0; i<len; i++) 85 { 86 *cur = (UINT32)json_object_get_uint64(json_object_object_get(ir, names[i])); 87 cur++; 88 } 89 } 90 91 //Converts a single integer value to an object containing a value, and a readable name if possible. 92 json_object* integer_to_readable_pair(UINT64 value, int len, int keys[], const char* values[], const char* default_value) 93 { 94 json_object* result = json_object_new_object(); 95 json_object_object_add(result, "value", json_object_new_uint64(value)); 96 97 //Search for human readable name, add. 98 const char* name = default_value; 99 for (int i=0; i<len; i++) 100 { 101 if (keys[i] == value) 102 name = values[i]; 103 } 104 105 json_object_object_add(result, "name", json_object_new_string(name)); 106 return result; 107 } 108 109 //Converts a single integer value to an object containing a value, readable name and description if possible. 110 json_object* integer_to_readable_pair_with_desc(int value, int len, int keys[], const char* values[], 111 const char* descriptions[], const char* default_value) 112 { 113 json_object* result = json_object_new_object(); 114 json_object_object_add(result, "value", json_object_new_int(value)); 115 116 //Search for human readable name, add. 117 const char* name = default_value; 118 for (int i=0; i<len; i++) 119 { 120 if (keys[i] == value) 121 { 122 name = values[i]; 123 json_object_object_add(result, "description", json_object_new_string(descriptions[i])); 124 } 125 } 126 127 json_object_object_add(result, "name", json_object_new_string(name)); 128 return result; 129 } 130 131 //Returns a single UINT64 value from the given readable pair object. 132 //Assumes the integer value is held in the "value" field. 133 UINT64 readable_pair_to_integer(json_object* pair) 134 { 135 return json_object_get_uint64(json_object_object_get(pair, "value")); 136 } 137 138 //Converts the given 64 bit bitfield to IR, assuming bit 0 starts on the left. 139 json_object* bitfield_to_ir(UINT64 bitfield, int num_fields, const char* names[]) 140 { 141 json_object* result = json_object_new_object(); 142 for (int i=0; i<num_fields; i++) 143 { 144 json_object_object_add(result, names[i], json_object_new_boolean((bitfield >> i) & 0b1)); 145 } 146 147 return result; 148 } 149 150 //Converts the given IR bitfield into a standard UINT64 bitfield, with fields beginning from bit 0. 151 UINT64 ir_to_bitfield(json_object* ir, int num_fields, const char* names[]) 152 { 153 UINT64 result = 0x0; 154 for (int i=0; i<num_fields; i++) 155 { 156 if (json_object_get_boolean(json_object_object_get(ir, names[i]))) 157 result |= (0x1 << i); 158 } 159 160 return result; 161 } 162 163 //Converts the given UINT64 array into a JSON IR array, given the length. 164 json_object* uint64_array_to_ir_array(UINT64* array, int len) 165 { 166 json_object* array_ir = json_object_new_array(); 167 for (int i=0; i<len; i++) 168 json_object_array_add(array_ir, json_object_new_uint64(array[i])); 169 return array_ir; 170 } 171 172 //Converts a single UINT16 revision number into JSON IR representation. 173 json_object* revision_to_ir(UINT16 revision) 174 { 175 json_object* revision_info = json_object_new_object(); 176 json_object_object_add(revision_info, "major", json_object_new_int(revision >> 8)); 177 json_object_object_add(revision_info, "minor", json_object_new_int(revision & 0xFF)); 178 return revision_info; 179 } 180 181 //Returns the appropriate string for the given integer severity. 182 const char* severity_to_string(UINT8 severity) 183 { 184 return severity < 4 ? CPER_SEVERITY_TYPES[severity] : "Unknown"; 185 } 186 187 //Converts a single EFI timestamp to string, at the given output. 188 //Output must be at least TIMESTAMP_LENGTH bytes long. 189 void timestamp_to_string(char* out, EFI_ERROR_TIME_STAMP* timestamp) 190 { 191 sprintf(out, "%02d%02d-%02d-%02dT%02d:%02d:%02d.000", 192 timestamp->Century, 193 timestamp->Year, 194 timestamp->Month, 195 timestamp->Day, 196 timestamp->Hours, 197 timestamp->Minutes, 198 timestamp->Seconds); 199 } 200 201 //Converts a single timestamp string to an EFI timestamp. 202 void string_to_timestamp(EFI_ERROR_TIME_STAMP* out, const char* timestamp) 203 { 204 //Ignore invalid timestamps. 205 if (timestamp == NULL) 206 return; 207 208 sscanf(timestamp, "%02hhd%02hhd-%02hhd-%02hhdT%02hhd:%02hhd:%02hhd.000", 209 &out->Century, 210 &out->Year, 211 &out->Month, 212 &out->Day, 213 &out->Hours, 214 &out->Minutes, 215 &out->Seconds); 216 } 217 218 //Helper function to convert an EDK EFI GUID into a string for intermediate use. 219 void guid_to_string(char* out, EFI_GUID* guid) 220 { 221 sprintf(out, "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x", 222 guid->Data1, 223 guid->Data2, 224 guid->Data3, 225 guid->Data4[0], 226 guid->Data4[1], 227 guid->Data4[2], 228 guid->Data4[3], 229 guid->Data4[4], 230 guid->Data4[5], 231 guid->Data4[6], 232 guid->Data4[7]); 233 } 234 235 //Helper function to convert a string into an EDK EFI GUID. 236 void string_to_guid(EFI_GUID* out, const char* guid) 237 { 238 //Ignore invalid GUIDs. 239 if (guid == NULL) 240 return; 241 242 sscanf(guid, "%08x-%04hx-%04hx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", 243 &out->Data1, 244 &out->Data2, 245 &out->Data3, 246 out->Data4, 247 out->Data4 + 1, 248 out->Data4 + 2, 249 out->Data4 + 3, 250 out->Data4 + 4, 251 out->Data4 + 5, 252 out->Data4 + 6, 253 out->Data4 + 7); 254 } 255 256 //Returns one if two EFI GUIDs are equal, zero otherwise. 257 int guid_equal(EFI_GUID* a, EFI_GUID* b) 258 { 259 //Check top base 3 components. 260 if (a->Data1 != b->Data1 261 || a->Data2 != b->Data2 262 || a->Data3 != b->Data3) 263 { 264 return 0; 265 } 266 267 //Check Data4 array for equality. 268 for (int i=0; i<8; i++) 269 { 270 if (a->Data4[i] != b->Data4[i]) 271 return 0; 272 } 273 274 return 1; 275 } 276 277 //Converts the given BCD byte to a standard integer. 278 int bcd_to_int(UINT8 bcd) 279 { 280 return ((bcd & 0xF0) >> 4) * 10 + (bcd & 0x0F); 281 }