xref: /openbmc/libcper/sections/cper-section-dmar-iommu.c (revision ad6c880fc739b6ca750c3ab594e270efd972c2ac)
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 #include <string.h>
16 
17 //Converts a single IOMMU specific DMAr CPER section into JSON IR.
cper_section_dmar_iommu_to_ir(const UINT8 * section,UINT32 size,char ** desc_string)18 json_object *cper_section_dmar_iommu_to_ir(const UINT8 *section, UINT32 size,
19 					   char **desc_string)
20 {
21 	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 
33 	if (size < sizeof(EFI_IOMMU_DMAR_ERROR_DATA)) {
34 		return NULL;
35 	}
36 
37 	EFI_IOMMU_DMAR_ERROR_DATA *iommu_error =
38 		(EFI_IOMMU_DMAR_ERROR_DATA *)section;
39 	json_object *section_ir = json_object_new_object();
40 
41 	//Revision.
42 	json_object_object_add(section_ir, "revision",
43 			       json_object_new_int(iommu_error->Revision));
44 
45 	//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));
50 
51 	//IOMMU event log entry.
52 	//The format of these entries differ widely by the type of error.
53 	int32_t encoded_len = 0;
54 
55 	char *encoded = base64_encode((UINT8 *)iommu_error->EventLogEntry, 16,
56 				      &encoded_len);
57 	if (encoded == NULL) {
58 		cper_print_log("Failed to allocate encode output buffer. \n");
59 
60 		return NULL;
61 	}
62 	json_object_object_add(section_ir, "eventLogEntry",
63 			       json_object_new_string_len(encoded,
64 							  encoded_len));
65 	free(encoded);
66 
67 	//Device table entry (as base64).
68 	encoded_len = 0;
69 
70 	encoded = base64_encode((UINT8 *)iommu_error->DeviceTableEntry, 32,
71 				&encoded_len);
72 	if (encoded == NULL) {
73 		cper_print_log("Failed to allocate encode output buffer. \n");
74 		return NULL;
75 	}
76 	json_object_object_add(section_ir, "deviceTableEntry",
77 			       json_object_new_string_len(encoded,
78 							  encoded_len));
79 	free(encoded);
80 
81 	//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));
94 
95 	return section_ir;
96 }
97 
98 //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)99 void ir_section_dmar_iommu_to_cper(json_object *section, FILE *out)
100 {
101 	EFI_IOMMU_DMAR_ERROR_DATA *section_cper =
102 		(EFI_IOMMU_DMAR_ERROR_DATA *)calloc(
103 			1, sizeof(EFI_IOMMU_DMAR_ERROR_DATA));
104 
105 	//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"));
112 
113 	//IOMMU event log entry.
114 	json_object *encoded = json_object_object_get(section, "eventLogEntry");
115 	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) {
121 		cper_print_log("Failed to allocate decode output buffer. \n");
122 	} else {
123 		memcpy(section_cper->EventLogEntry, decoded, decoded_len);
124 		free(decoded);
125 	}
126 	//Device table entry.
127 	encoded = json_object_object_get(section, "deviceTableEntry");
128 	decoded_len = 0;
129 
130 	decoded = base64_decode(json_object_get_string(encoded),
131 				json_object_get_string_len(encoded),
132 				&decoded_len);
133 	if (decoded == NULL) {
134 		cper_print_log("Failed to allocate decode output buffer. \n");
135 	} else {
136 		memcpy(section_cper->DeviceTableEntry, decoded, decoded_len);
137 		free(decoded);
138 	}
139 
140 	//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"));
153 
154 	//Write to stream, free resources.
155 	fwrite(section_cper, sizeof(EFI_IOMMU_DMAR_ERROR_DATA), 1, out);
156 	fflush(out);
157 	free(section_cper);
158 }
159