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