1 /**
2 * Describes functions for converting IOMMU specific DMAr CPER sections from binary and JSON format
3 * into an intermediate format.
4 *
5 * Author: Lawrence.Tang@arm.com
6 **/
7 #include <stdio.h>
8 #include <string.h>
9 #include <json.h>
10 #include "base64.h"
11 #include "Cper.h"
12 #include "../cper-utils.h"
13 #include "cper-section-dmar-iommu.h"
14
15 //Converts a single IOMMU specific DMAr CPER section into JSON IR.
cper_section_dmar_iommu_to_ir(void * section)16 json_object *cper_section_dmar_iommu_to_ir(void *section)
17 {
18 EFI_IOMMU_DMAR_ERROR_DATA *iommu_error =
19 (EFI_IOMMU_DMAR_ERROR_DATA *)section;
20 json_object *section_ir = json_object_new_object();
21
22 //Revision.
23 json_object_object_add(section_ir, "revision",
24 json_object_new_int(iommu_error->Revision));
25
26 //IOMMU registers.
27 json_object_object_add(section_ir, "controlRegister",
28 json_object_new_uint64(iommu_error->Control));
29 json_object_object_add(section_ir, "statusRegister",
30 json_object_new_uint64(iommu_error->Status));
31
32 //IOMMU event log entry.
33 //The format of these entries differ widely by the type of error.
34 int32_t encoded_len = 0;
35
36 char *encoded = base64_encode((UINT8 *)iommu_error->EventLogEntry, 16,
37 &encoded_len);
38 if (encoded == NULL) {
39 printf("Failed to allocate encode output buffer. \n");
40
41 return NULL;
42 }
43 json_object_object_add(section_ir, "eventLogEntry",
44 json_object_new_string_len(encoded,
45 encoded_len));
46 free(encoded);
47
48 //Device table entry (as base64).
49 encoded_len = 0;
50
51 encoded = base64_encode((UINT8 *)iommu_error->DeviceTableEntry, 32,
52 &encoded_len);
53 if (encoded == NULL) {
54 printf("Failed to allocate encode output buffer. \n");
55 return NULL;
56 }
57 json_object_object_add(section_ir, "deviceTableEntry",
58 json_object_new_string_len(encoded,
59 encoded_len));
60 free(encoded);
61
62 //Page table entries.
63 json_object_object_add(section_ir, "pageTableEntry_Level6",
64 json_object_new_uint64(iommu_error->PteL6));
65 json_object_object_add(section_ir, "pageTableEntry_Level5",
66 json_object_new_uint64(iommu_error->PteL5));
67 json_object_object_add(section_ir, "pageTableEntry_Level4",
68 json_object_new_uint64(iommu_error->PteL4));
69 json_object_object_add(section_ir, "pageTableEntry_Level3",
70 json_object_new_uint64(iommu_error->PteL3));
71 json_object_object_add(section_ir, "pageTableEntry_Level2",
72 json_object_new_uint64(iommu_error->PteL2));
73 json_object_object_add(section_ir, "pageTableEntry_Level1",
74 json_object_new_uint64(iommu_error->PteL1));
75
76 return section_ir;
77 }
78
79 //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)80 void ir_section_dmar_iommu_to_cper(json_object *section, FILE *out)
81 {
82 EFI_IOMMU_DMAR_ERROR_DATA *section_cper =
83 (EFI_IOMMU_DMAR_ERROR_DATA *)calloc(
84 1, sizeof(EFI_IOMMU_DMAR_ERROR_DATA));
85
86 //Revision, registers.
87 section_cper->Revision = (UINT8)json_object_get_int(
88 json_object_object_get(section, "revision"));
89 section_cper->Control = json_object_get_uint64(
90 json_object_object_get(section, "controlRegister"));
91 section_cper->Status = json_object_get_uint64(
92 json_object_object_get(section, "statusRegister"));
93
94 //IOMMU event log entry.
95 json_object *encoded = json_object_object_get(section, "eventLogEntry");
96 int32_t decoded_len = 0;
97
98 UINT8 *decoded = base64_decode(json_object_get_string(encoded),
99 json_object_get_string_len(encoded),
100 &decoded_len);
101 if (decoded == NULL) {
102 printf("Failed to allocate decode output buffer. \n");
103 } else {
104 memcpy(section_cper->EventLogEntry, decoded, decoded_len);
105 free(decoded);
106 }
107 //Device table entry.
108 encoded = json_object_object_get(section, "deviceTableEntry");
109 decoded_len = 0;
110
111 decoded = base64_decode(json_object_get_string(encoded),
112 json_object_get_string_len(encoded),
113 &decoded_len);
114 if (decoded == NULL) {
115 printf("Failed to allocate decode output buffer. \n");
116 } else {
117 memcpy(section_cper->DeviceTableEntry, decoded, decoded_len);
118 free(decoded);
119 }
120
121 //Page table entries.
122 section_cper->PteL1 = json_object_get_uint64(
123 json_object_object_get(section, "pageTableEntry_Level1"));
124 section_cper->PteL2 = json_object_get_uint64(
125 json_object_object_get(section, "pageTableEntry_Level2"));
126 section_cper->PteL3 = json_object_get_uint64(
127 json_object_object_get(section, "pageTableEntry_Level3"));
128 section_cper->PteL4 = json_object_get_uint64(
129 json_object_object_get(section, "pageTableEntry_Level4"));
130 section_cper->PteL5 = json_object_get_uint64(
131 json_object_object_get(section, "pageTableEntry_Level5"));
132 section_cper->PteL6 = json_object_get_uint64(
133 json_object_object_get(section, "pageTableEntry_Level6"));
134
135 //Write to stream, free resources.
136 fwrite(section_cper, sizeof(EFI_IOMMU_DMAR_ERROR_DATA), 1, out);
137 fflush(out);
138 free(section_cper);
139 }
140