1db1b7ce2SLawrence Tang /**
2db1b7ce2SLawrence Tang * Describes functions for converting IOMMU specific DMAr CPER sections from binary and JSON format
3db1b7ce2SLawrence Tang * into an intermediate format.
4db1b7ce2SLawrence Tang *
5db1b7ce2SLawrence Tang * Author: Lawrence.Tang@arm.com
6db1b7ce2SLawrence Tang **/
7db1b7ce2SLawrence Tang #include <stdio.h>
8205dd1d7SLawrence Tang #include <string.h>
95202bbb4SLawrence Tang #include <json.h>
10*a7d2cdddSEd Tanous #include "base64.h"
11db1b7ce2SLawrence Tang #include "../edk/Cper.h"
12db1b7ce2SLawrence Tang #include "../cper-utils.h"
13db1b7ce2SLawrence Tang #include "cper-section-dmar-iommu.h"
14db1b7ce2SLawrence Tang
15db1b7ce2SLawrence Tang //Converts a single IOMMU specific DMAr CPER section into JSON IR.
cper_section_dmar_iommu_to_ir(void * section)16f8fc7052SJohn Chung json_object *cper_section_dmar_iommu_to_ir(void *section)
17db1b7ce2SLawrence Tang {
18e407b4c8SLawrence Tang EFI_IOMMU_DMAR_ERROR_DATA *iommu_error =
19e407b4c8SLawrence Tang (EFI_IOMMU_DMAR_ERROR_DATA *)section;
20db1b7ce2SLawrence Tang json_object *section_ir = json_object_new_object();
21db1b7ce2SLawrence Tang
22db1b7ce2SLawrence Tang //Revision.
23e407b4c8SLawrence Tang json_object_object_add(section_ir, "revision",
24e407b4c8SLawrence Tang json_object_new_int(iommu_error->Revision));
25db1b7ce2SLawrence Tang
26db1b7ce2SLawrence Tang //IOMMU registers.
27e407b4c8SLawrence Tang json_object_object_add(section_ir, "controlRegister",
28e407b4c8SLawrence Tang json_object_new_uint64(iommu_error->Control));
29e407b4c8SLawrence Tang json_object_object_add(section_ir, "statusRegister",
30e407b4c8SLawrence Tang json_object_new_uint64(iommu_error->Status));
31db1b7ce2SLawrence Tang
32db1b7ce2SLawrence Tang //IOMMU event log entry.
33ce0f82bfSLawrence Tang //The format of these entries differ widely by the type of error.
34*a7d2cdddSEd Tanous int32_t encoded_len = 0;
35*a7d2cdddSEd Tanous
36*a7d2cdddSEd Tanous char *encoded = base64_encode((UINT8 *)iommu_error->EventLogEntry, 16,
37*a7d2cdddSEd Tanous &encoded_len);
38*a7d2cdddSEd Tanous if (encoded == NULL) {
39f8fc7052SJohn Chung printf("Failed to allocate encode output buffer. \n");
40*a7d2cdddSEd Tanous
41*a7d2cdddSEd Tanous return NULL;
42*a7d2cdddSEd Tanous }
43e407b4c8SLawrence Tang json_object_object_add(section_ir, "eventLogEntry",
44f8fc7052SJohn Chung json_object_new_string_len(encoded,
45f8fc7052SJohn Chung encoded_len));
46ce0f82bfSLawrence Tang free(encoded);
47db1b7ce2SLawrence Tang
48d7e8ca34SLawrence Tang //Device table entry (as base64).
49f8fc7052SJohn Chung encoded_len = 0;
50*a7d2cdddSEd Tanous
51*a7d2cdddSEd Tanous encoded = base64_encode((UINT8 *)iommu_error->DeviceTableEntry, 32,
52*a7d2cdddSEd Tanous &encoded_len);
53*a7d2cdddSEd Tanous if (encoded == NULL) {
54f8fc7052SJohn Chung printf("Failed to allocate encode output buffer. \n");
55*a7d2cdddSEd Tanous return NULL;
56*a7d2cdddSEd Tanous }
57e407b4c8SLawrence Tang json_object_object_add(section_ir, "deviceTableEntry",
58f8fc7052SJohn Chung json_object_new_string_len(encoded,
59f8fc7052SJohn Chung encoded_len));
60d7e8ca34SLawrence Tang free(encoded);
61db1b7ce2SLawrence Tang
62db1b7ce2SLawrence Tang //Page table entries.
63e407b4c8SLawrence Tang json_object_object_add(section_ir, "pageTableEntry_Level6",
64e407b4c8SLawrence Tang json_object_new_uint64(iommu_error->PteL6));
65e407b4c8SLawrence Tang json_object_object_add(section_ir, "pageTableEntry_Level5",
66e407b4c8SLawrence Tang json_object_new_uint64(iommu_error->PteL5));
67e407b4c8SLawrence Tang json_object_object_add(section_ir, "pageTableEntry_Level4",
68e407b4c8SLawrence Tang json_object_new_uint64(iommu_error->PteL4));
69e407b4c8SLawrence Tang json_object_object_add(section_ir, "pageTableEntry_Level3",
70e407b4c8SLawrence Tang json_object_new_uint64(iommu_error->PteL3));
71e407b4c8SLawrence Tang json_object_object_add(section_ir, "pageTableEntry_Level2",
72e407b4c8SLawrence Tang json_object_new_uint64(iommu_error->PteL2));
73e407b4c8SLawrence Tang json_object_object_add(section_ir, "pageTableEntry_Level1",
74e407b4c8SLawrence Tang json_object_new_uint64(iommu_error->PteL1));
75db1b7ce2SLawrence Tang
76db1b7ce2SLawrence Tang return section_ir;
77db1b7ce2SLawrence Tang }
78205dd1d7SLawrence Tang
79205dd1d7SLawrence Tang //Converts a single DMAR IOMMU CPER-JSON section into CPER binary, outputting to the given stream.
ir_section_dmar_iommu_to_cper(json_object * section,FILE * out)80205dd1d7SLawrence Tang void ir_section_dmar_iommu_to_cper(json_object *section, FILE *out)
81205dd1d7SLawrence Tang {
82205dd1d7SLawrence Tang EFI_IOMMU_DMAR_ERROR_DATA *section_cper =
83e407b4c8SLawrence Tang (EFI_IOMMU_DMAR_ERROR_DATA *)calloc(
84e407b4c8SLawrence Tang 1, sizeof(EFI_IOMMU_DMAR_ERROR_DATA));
85205dd1d7SLawrence Tang
86205dd1d7SLawrence Tang //Revision, registers.
87e407b4c8SLawrence Tang section_cper->Revision = (UINT8)json_object_get_int(
88e407b4c8SLawrence Tang json_object_object_get(section, "revision"));
89e407b4c8SLawrence Tang section_cper->Control = json_object_get_uint64(
90e407b4c8SLawrence Tang json_object_object_get(section, "controlRegister"));
91e407b4c8SLawrence Tang section_cper->Status = json_object_get_uint64(
92e407b4c8SLawrence Tang json_object_object_get(section, "statusRegister"));
93205dd1d7SLawrence Tang
94205dd1d7SLawrence Tang //IOMMU event log entry.
95205dd1d7SLawrence Tang json_object *encoded = json_object_object_get(section, "eventLogEntry");
96*a7d2cdddSEd Tanous int32_t decoded_len = 0;
97*a7d2cdddSEd Tanous
98*a7d2cdddSEd Tanous UINT8 *decoded = base64_decode(json_object_get_string(encoded),
99*a7d2cdddSEd Tanous json_object_get_string_len(encoded),
100*a7d2cdddSEd Tanous &decoded_len);
101*a7d2cdddSEd Tanous if (decoded == NULL) {
102f8fc7052SJohn Chung printf("Failed to allocate decode output buffer. \n");
103f8fc7052SJohn Chung } else {
104f8fc7052SJohn Chung memcpy(section_cper->EventLogEntry, decoded, decoded_len);
105205dd1d7SLawrence Tang free(decoded);
106f8fc7052SJohn Chung }
107205dd1d7SLawrence Tang //Device table entry.
108205dd1d7SLawrence Tang encoded = json_object_object_get(section, "deviceTableEntry");
109f8fc7052SJohn Chung decoded_len = 0;
110*a7d2cdddSEd Tanous
111*a7d2cdddSEd Tanous decoded = base64_decode(json_object_get_string(encoded),
112*a7d2cdddSEd Tanous json_object_get_string_len(encoded),
113*a7d2cdddSEd Tanous &decoded_len);
114*a7d2cdddSEd Tanous if (decoded == NULL) {
115f8fc7052SJohn Chung printf("Failed to allocate decode output buffer. \n");
116f8fc7052SJohn Chung } else {
117f8fc7052SJohn Chung memcpy(section_cper->DeviceTableEntry, decoded, decoded_len);
118205dd1d7SLawrence Tang free(decoded);
119f8fc7052SJohn Chung }
120205dd1d7SLawrence Tang
121205dd1d7SLawrence Tang //Page table entries.
122e407b4c8SLawrence Tang section_cper->PteL1 = json_object_get_uint64(
123e407b4c8SLawrence Tang json_object_object_get(section, "pageTableEntry_Level1"));
124e407b4c8SLawrence Tang section_cper->PteL2 = json_object_get_uint64(
125e407b4c8SLawrence Tang json_object_object_get(section, "pageTableEntry_Level2"));
126e407b4c8SLawrence Tang section_cper->PteL3 = json_object_get_uint64(
127e407b4c8SLawrence Tang json_object_object_get(section, "pageTableEntry_Level3"));
128e407b4c8SLawrence Tang section_cper->PteL4 = json_object_get_uint64(
129e407b4c8SLawrence Tang json_object_object_get(section, "pageTableEntry_Level4"));
130e407b4c8SLawrence Tang section_cper->PteL5 = json_object_get_uint64(
131e407b4c8SLawrence Tang json_object_object_get(section, "pageTableEntry_Level5"));
132e407b4c8SLawrence Tang section_cper->PteL6 = json_object_get_uint64(
133e407b4c8SLawrence Tang json_object_object_get(section, "pageTableEntry_Level6"));
134205dd1d7SLawrence Tang
135205dd1d7SLawrence Tang //Write to stream, free resources.
1363ab351feSLawrence Tang fwrite(section_cper, sizeof(EFI_IOMMU_DMAR_ERROR_DATA), 1, out);
137205dd1d7SLawrence Tang fflush(out);
138205dd1d7SLawrence Tang free(section_cper);
139205dd1d7SLawrence Tang }
140