blob: 6d3df8f42529053b492222b775c008edac74b569 [file] [log] [blame]
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +01001/**
2 * Describes functions for converting IOMMU specific DMAr CPER sections from binary and JSON format
3 * into an intermediate format.
Ed Tanousfedd4572024-07-12 13:56:00 -07004 *
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +01005 * Author: Lawrence.Tang@arm.com
6 **/
7#include <stdio.h>
Lawrence Tang205dd1d2022-07-14 16:23:38 +01008#include <string.h>
Lawrence Tang5202bbb2022-08-12 14:54:36 +01009#include <json.h>
Thu Nguyene42fb482024-10-15 14:43:11 +000010#include <libcper/base64.h>
11#include <libcper/Cper.h>
12#include <libcper/cper-utils.h>
13#include <libcper/sections/cper-section-dmar-iommu.h>
Ed Tanous50b966f2025-03-11 09:06:19 -070014#include <libcper/log.h>
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -070015#include <string.h>
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +010016
17//Converts a single IOMMU specific DMAr CPER section into JSON IR.
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -070018json_object *cper_section_dmar_iommu_to_ir(const UINT8 *section, UINT32 size,
19 char **desc_string)
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +010020{
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -070021 int outstr_len = 0;
22 *desc_string = malloc(SECTION_DESC_STRING_SIZE);
23 outstr_len = snprintf(*desc_string, SECTION_DESC_STRING_SIZE,
24 "A IOMMU Specific DMAr Error occurred");
25 if (outstr_len < 0) {
26 cper_print_log(
27 "Error: Could not write to IOMMU Specific DMAr description string\n");
28 } else if (outstr_len > SECTION_DESC_STRING_SIZE) {
29 cper_print_log(
30 "Error: IOMMU Specific DMAr description string truncated\n");
31 }
32
Ed Tanous12dbd4f2025-03-08 19:05:01 -080033 if (size < sizeof(EFI_IOMMU_DMAR_ERROR_DATA)) {
34 return NULL;
35 }
36
Lawrence Tange407b4c2022-07-21 13:54:01 +010037 EFI_IOMMU_DMAR_ERROR_DATA *iommu_error =
38 (EFI_IOMMU_DMAR_ERROR_DATA *)section;
39 json_object *section_ir = json_object_new_object();
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +010040
Lawrence Tange407b4c2022-07-21 13:54:01 +010041 //Revision.
42 json_object_object_add(section_ir, "revision",
43 json_object_new_int(iommu_error->Revision));
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +010044
Lawrence Tange407b4c2022-07-21 13:54:01 +010045 //IOMMU registers.
46 json_object_object_add(section_ir, "controlRegister",
47 json_object_new_uint64(iommu_error->Control));
48 json_object_object_add(section_ir, "statusRegister",
49 json_object_new_uint64(iommu_error->Status));
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +010050
Lawrence Tange407b4c2022-07-21 13:54:01 +010051 //IOMMU event log entry.
52 //The format of these entries differ widely by the type of error.
Ed Tanousa7d2cdd2024-07-15 11:07:27 -070053 int32_t encoded_len = 0;
54
55 char *encoded = base64_encode((UINT8 *)iommu_error->EventLogEntry, 16,
56 &encoded_len);
57 if (encoded == NULL) {
Ed Tanous50b966f2025-03-11 09:06:19 -070058 cper_print_log("Failed to allocate encode output buffer. \n");
Ed Tanousa7d2cdd2024-07-15 11:07:27 -070059
60 return NULL;
John Chungf8fc7052024-05-03 20:05:29 +080061 }
Ed Tanousa7d2cdd2024-07-15 11:07:27 -070062 json_object_object_add(section_ir, "eventLogEntry",
63 json_object_new_string_len(encoded,
64 encoded_len));
65 free(encoded);
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +010066
Lawrence Tange407b4c2022-07-21 13:54:01 +010067 //Device table entry (as base64).
John Chungf8fc7052024-05-03 20:05:29 +080068 encoded_len = 0;
Ed Tanousa7d2cdd2024-07-15 11:07:27 -070069
70 encoded = base64_encode((UINT8 *)iommu_error->DeviceTableEntry, 32,
71 &encoded_len);
72 if (encoded == NULL) {
Ed Tanous50b966f2025-03-11 09:06:19 -070073 cper_print_log("Failed to allocate encode output buffer. \n");
Ed Tanousa7d2cdd2024-07-15 11:07:27 -070074 return NULL;
John Chungf8fc7052024-05-03 20:05:29 +080075 }
Ed Tanousa7d2cdd2024-07-15 11:07:27 -070076 json_object_object_add(section_ir, "deviceTableEntry",
77 json_object_new_string_len(encoded,
78 encoded_len));
79 free(encoded);
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +010080
Lawrence Tange407b4c2022-07-21 13:54:01 +010081 //Page table entries.
82 json_object_object_add(section_ir, "pageTableEntry_Level6",
83 json_object_new_uint64(iommu_error->PteL6));
84 json_object_object_add(section_ir, "pageTableEntry_Level5",
85 json_object_new_uint64(iommu_error->PteL5));
86 json_object_object_add(section_ir, "pageTableEntry_Level4",
87 json_object_new_uint64(iommu_error->PteL4));
88 json_object_object_add(section_ir, "pageTableEntry_Level3",
89 json_object_new_uint64(iommu_error->PteL3));
90 json_object_object_add(section_ir, "pageTableEntry_Level2",
91 json_object_new_uint64(iommu_error->PteL2));
92 json_object_object_add(section_ir, "pageTableEntry_Level1",
93 json_object_new_uint64(iommu_error->PteL1));
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +010094
Lawrence Tange407b4c2022-07-21 13:54:01 +010095 return section_ir;
Lawrence Tang205dd1d2022-07-14 16:23:38 +010096}
97
98//Converts a single DMAR IOMMU CPER-JSON section into CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +010099void ir_section_dmar_iommu_to_cper(json_object *section, FILE *out)
Lawrence Tang205dd1d2022-07-14 16:23:38 +0100100{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100101 EFI_IOMMU_DMAR_ERROR_DATA *section_cper =
102 (EFI_IOMMU_DMAR_ERROR_DATA *)calloc(
103 1, sizeof(EFI_IOMMU_DMAR_ERROR_DATA));
Lawrence Tang205dd1d2022-07-14 16:23:38 +0100104
Lawrence Tange407b4c2022-07-21 13:54:01 +0100105 //Revision, registers.
106 section_cper->Revision = (UINT8)json_object_get_int(
107 json_object_object_get(section, "revision"));
108 section_cper->Control = json_object_get_uint64(
109 json_object_object_get(section, "controlRegister"));
110 section_cper->Status = json_object_get_uint64(
111 json_object_object_get(section, "statusRegister"));
Lawrence Tang205dd1d2022-07-14 16:23:38 +0100112
Lawrence Tange407b4c2022-07-21 13:54:01 +0100113 //IOMMU event log entry.
114 json_object *encoded = json_object_object_get(section, "eventLogEntry");
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700115 int32_t decoded_len = 0;
116
117 UINT8 *decoded = base64_decode(json_object_get_string(encoded),
118 json_object_get_string_len(encoded),
119 &decoded_len);
120 if (decoded == NULL) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700121 cper_print_log("Failed to allocate decode output buffer. \n");
John Chungf8fc7052024-05-03 20:05:29 +0800122 } else {
John Chungf8fc7052024-05-03 20:05:29 +0800123 memcpy(section_cper->EventLogEntry, decoded, decoded_len);
124 free(decoded);
125 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100126 //Device table entry.
127 encoded = json_object_object_get(section, "deviceTableEntry");
John Chungf8fc7052024-05-03 20:05:29 +0800128 decoded_len = 0;
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700129
130 decoded = base64_decode(json_object_get_string(encoded),
131 json_object_get_string_len(encoded),
132 &decoded_len);
133 if (decoded == NULL) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700134 cper_print_log("Failed to allocate decode output buffer. \n");
John Chungf8fc7052024-05-03 20:05:29 +0800135 } else {
John Chungf8fc7052024-05-03 20:05:29 +0800136 memcpy(section_cper->DeviceTableEntry, decoded, decoded_len);
137 free(decoded);
138 }
Lawrence Tang205dd1d2022-07-14 16:23:38 +0100139
Lawrence Tange407b4c2022-07-21 13:54:01 +0100140 //Page table entries.
141 section_cper->PteL1 = json_object_get_uint64(
142 json_object_object_get(section, "pageTableEntry_Level1"));
143 section_cper->PteL2 = json_object_get_uint64(
144 json_object_object_get(section, "pageTableEntry_Level2"));
145 section_cper->PteL3 = json_object_get_uint64(
146 json_object_object_get(section, "pageTableEntry_Level3"));
147 section_cper->PteL4 = json_object_get_uint64(
148 json_object_object_get(section, "pageTableEntry_Level4"));
149 section_cper->PteL5 = json_object_get_uint64(
150 json_object_object_get(section, "pageTableEntry_Level5"));
151 section_cper->PteL6 = json_object_get_uint64(
152 json_object_object_get(section, "pageTableEntry_Level6"));
Lawrence Tang205dd1d2022-07-14 16:23:38 +0100153
Lawrence Tange407b4c2022-07-21 13:54:01 +0100154 //Write to stream, free resources.
155 fwrite(section_cper, sizeof(EFI_IOMMU_DMAR_ERROR_DATA), 1, out);
156 fflush(out);
157 free(section_cper);
John Chungf8fc7052024-05-03 20:05:29 +0800158}