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 integer value to an object containing a value, and a readable name if possible. 70 json_object* integer_to_readable_pair(UINT64 value, int len, int keys[], const char* values[], const char* default_value) 71 { 72 json_object* result = json_object_new_object(); 73 json_object_object_add(result, "value", json_object_new_uint64(value)); 74 75 //Search for human readable name, add. 76 const char* name = default_value; 77 for (int i=0; i<len; i++) 78 { 79 if (keys[i] == value) 80 name = values[i]; 81 } 82 83 json_object_object_add(result, "name", json_object_new_string(name)); 84 return result; 85 } 86 87 //Converts a single integer value to an object containing a value, readable name and description if possible. 88 json_object* integer_to_readable_pair_with_desc(int value, int len, int keys[], const char* values[], 89 const char* descriptions[], const char* default_value) 90 { 91 json_object* result = json_object_new_object(); 92 json_object_object_add(result, "value", json_object_new_int(value)); 93 94 //Search for human readable name, add. 95 const char* name = default_value; 96 for (int i=0; i<len; i++) 97 { 98 if (keys[i] == value) 99 { 100 name = values[i]; 101 json_object_object_add(result, "description", json_object_new_string(descriptions[i])); 102 } 103 } 104 105 json_object_object_add(result, "name", json_object_new_string(name)); 106 return result; 107 } 108 109 //Returns a single UINT64 value from the given readable pair object. 110 //Assumes the integer value is held in the "value" field. 111 UINT64 readable_pair_to_integer(json_object* pair) 112 { 113 return json_object_get_uint64(json_object_object_get(pair, "value")); 114 } 115 116 //Converts the given 64 bit bitfield to IR, assuming bit 0 starts on the left. 117 json_object* bitfield_to_ir(UINT64 bitfield, int num_fields, const char* names[]) 118 { 119 json_object* result = json_object_new_object(); 120 for (int i=0; i<num_fields; i++) 121 { 122 json_object_object_add(result, names[i], json_object_new_boolean((bitfield >> i) & 0b1)); 123 } 124 125 return result; 126 } 127 128 //Converts the given IR bitfield into a standard UINT64 bitfield, with fields beginning from bit 0. 129 UINT64 ir_to_bitfield(json_object* ir, int num_fields, const char* names[]) 130 { 131 UINT64 result = 0x0; 132 for (int i=0; i<num_fields; i++) 133 { 134 if (json_object_get_boolean(json_object_object_get(ir, names[i]))) 135 result |= (0x1 << i); 136 } 137 138 return result; 139 } 140 141 //Converts the given UINT64 array into a JSON IR array, given the length. 142 json_object* uint64_array_to_ir_array(UINT64* array, int len) 143 { 144 json_object* array_ir = json_object_new_array(); 145 for (int i=0; i<len; i++) 146 json_object_array_add(array_ir, json_object_new_uint64(array[i])); 147 return array_ir; 148 } 149 150 //Converts a single UINT16 revision number into JSON IR representation. 151 json_object* revision_to_ir(UINT16 revision) 152 { 153 json_object* revision_info = json_object_new_object(); 154 json_object_object_add(revision_info, "major", json_object_new_int(revision >> 8)); 155 json_object_object_add(revision_info, "minor", json_object_new_int(revision & 0xFF)); 156 return revision_info; 157 } 158 159 //Returns the appropriate string for the given integer severity. 160 const char* severity_to_string(UINT8 severity) 161 { 162 return severity < 4 ? CPER_SEVERITY_TYPES[severity] : "Unknown"; 163 } 164 165 //Converts a single EFI timestamp to string, at the given output. 166 //Output must be at least TIMESTAMP_LENGTH bytes long. 167 void timestamp_to_string(char* out, EFI_ERROR_TIME_STAMP* timestamp) 168 { 169 sprintf(out, "%02d%02d-%02d-%02dT%02d:%02d:%02d.000", 170 timestamp->Century, 171 timestamp->Year, 172 timestamp->Month, 173 timestamp->Day, 174 timestamp->Hours, 175 timestamp->Minutes, 176 timestamp->Seconds); 177 } 178 179 //Converts a single timestamp string to an EFI timestamp. 180 void string_to_timestamp(EFI_ERROR_TIME_STAMP* out, const char* timestamp) 181 { 182 //Ignore invalid timestamps. 183 if (timestamp == NULL) 184 return; 185 186 sscanf(timestamp, "%02hhd%02hhd-%02hhd-%02hhdT%02hhd:%02hhd:%02hhd.000", 187 &out->Century, 188 &out->Year, 189 &out->Month, 190 &out->Day, 191 &out->Hours, 192 &out->Minutes, 193 &out->Seconds); 194 } 195 196 //Helper function to convert an EDK EFI GUID into a string for intermediate use. 197 void guid_to_string(char* out, EFI_GUID* guid) 198 { 199 sprintf(out, "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x", 200 guid->Data1, 201 guid->Data2, 202 guid->Data3, 203 guid->Data4[0], 204 guid->Data4[1], 205 guid->Data4[2], 206 guid->Data4[3], 207 guid->Data4[4], 208 guid->Data4[5], 209 guid->Data4[6], 210 guid->Data4[7]); 211 } 212 213 //Helper function to convert a string into an EDK EFI GUID. 214 void string_to_guid(EFI_GUID* out, const char* guid) 215 { 216 //Ignore invalid GUIDs. 217 if (guid == NULL) 218 return; 219 220 sscanf(guid, "%08x-%04hx-%04hx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", 221 &out->Data1, 222 &out->Data2, 223 &out->Data3, 224 out->Data4, 225 out->Data4 + 1, 226 out->Data4 + 2, 227 out->Data4 + 3, 228 out->Data4 + 4, 229 out->Data4 + 5, 230 out->Data4 + 6, 231 out->Data4 + 7); 232 } 233 234 //Returns one if two EFI GUIDs are equal, zero otherwise. 235 int guid_equal(EFI_GUID* a, EFI_GUID* b) 236 { 237 //Check top base 3 components. 238 if (a->Data1 != b->Data1 239 || a->Data2 != b->Data2 240 || a->Data3 != b->Data3) 241 { 242 return 0; 243 } 244 245 //Check Data4 array for equality. 246 for (int i=0; i<8; i++) 247 { 248 if (a->Data4[i] != b->Data4[i]) 249 return 0; 250 } 251 252 return 1; 253 } 254 255 //Converts the given BCD byte to a standard integer. 256 int bcd_to_int(UINT8 bcd) 257 { 258 return ((bcd & 0xF0) >> 4) * 10 + (bcd & 0x0F); 259 }