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*f8fc7052SJohn Chung #include "libbase64.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.
16*f8fc7052SJohn 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*f8fc7052SJohn Chung 	char *encoded = malloc(2 * 16);
35*f8fc7052SJohn Chung 	size_t encoded_len = 0;
36*f8fc7052SJohn Chung 	if (!encoded) {
37*f8fc7052SJohn Chung 		printf("Failed to allocate encode output buffer. \n");
38*f8fc7052SJohn Chung 	} else {
39*f8fc7052SJohn Chung 		base64_encode((const char *)iommu_error->EventLogEntry, 16,
40*f8fc7052SJohn Chung 			      encoded, &encoded_len, 0);
41e407b4c8SLawrence Tang 		json_object_object_add(section_ir, "eventLogEntry",
42*f8fc7052SJohn Chung 				       json_object_new_string_len(encoded,
43*f8fc7052SJohn Chung 								  encoded_len));
44ce0f82bfSLawrence Tang 		free(encoded);
45*f8fc7052SJohn Chung 	}
46db1b7ce2SLawrence Tang 
47d7e8ca34SLawrence Tang 	//Device table entry (as base64).
48*f8fc7052SJohn Chung 	encoded = malloc(2 * 32);
49*f8fc7052SJohn Chung 	encoded_len = 0;
50*f8fc7052SJohn Chung 	if (!encoded) {
51*f8fc7052SJohn Chung 		printf("Failed to allocate encode output buffer. \n");
52*f8fc7052SJohn Chung 	} else {
53*f8fc7052SJohn Chung 		base64_encode((const char *)iommu_error->DeviceTableEntry, 32,
54*f8fc7052SJohn Chung 			      encoded, &encoded_len, 0);
55e407b4c8SLawrence Tang 		json_object_object_add(section_ir, "deviceTableEntry",
56*f8fc7052SJohn Chung 				       json_object_new_string_len(encoded,
57*f8fc7052SJohn Chung 								  encoded_len));
58d7e8ca34SLawrence Tang 		free(encoded);
59*f8fc7052SJohn Chung 	}
60db1b7ce2SLawrence Tang 
61db1b7ce2SLawrence Tang 	//Page table entries.
62e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level6",
63e407b4c8SLawrence Tang 			       json_object_new_uint64(iommu_error->PteL6));
64e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level5",
65e407b4c8SLawrence Tang 			       json_object_new_uint64(iommu_error->PteL5));
66e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level4",
67e407b4c8SLawrence Tang 			       json_object_new_uint64(iommu_error->PteL4));
68e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level3",
69e407b4c8SLawrence Tang 			       json_object_new_uint64(iommu_error->PteL3));
70e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level2",
71e407b4c8SLawrence Tang 			       json_object_new_uint64(iommu_error->PteL2));
72e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level1",
73e407b4c8SLawrence Tang 			       json_object_new_uint64(iommu_error->PteL1));
74db1b7ce2SLawrence Tang 
75db1b7ce2SLawrence Tang 	return section_ir;
76db1b7ce2SLawrence Tang }
77205dd1d7SLawrence Tang 
78205dd1d7SLawrence Tang //Converts a single DMAR IOMMU CPER-JSON section into CPER binary, outputting to the given stream.
79205dd1d7SLawrence Tang void ir_section_dmar_iommu_to_cper(json_object *section, FILE *out)
80205dd1d7SLawrence Tang {
81205dd1d7SLawrence Tang 	EFI_IOMMU_DMAR_ERROR_DATA *section_cper =
82e407b4c8SLawrence Tang 		(EFI_IOMMU_DMAR_ERROR_DATA *)calloc(
83e407b4c8SLawrence Tang 			1, sizeof(EFI_IOMMU_DMAR_ERROR_DATA));
84205dd1d7SLawrence Tang 
85205dd1d7SLawrence Tang 	//Revision, registers.
86e407b4c8SLawrence Tang 	section_cper->Revision = (UINT8)json_object_get_int(
87e407b4c8SLawrence Tang 		json_object_object_get(section, "revision"));
88e407b4c8SLawrence Tang 	section_cper->Control = json_object_get_uint64(
89e407b4c8SLawrence Tang 		json_object_object_get(section, "controlRegister"));
90e407b4c8SLawrence Tang 	section_cper->Status = json_object_get_uint64(
91e407b4c8SLawrence Tang 		json_object_object_get(section, "statusRegister"));
92205dd1d7SLawrence Tang 
93205dd1d7SLawrence Tang 	//IOMMU event log entry.
94205dd1d7SLawrence Tang 	json_object *encoded = json_object_object_get(section, "eventLogEntry");
95*f8fc7052SJohn Chung 	char *decoded = malloc(json_object_get_string_len(encoded));
96*f8fc7052SJohn Chung 	size_t decoded_len = 0;
97*f8fc7052SJohn Chung 	if (!decoded) {
98*f8fc7052SJohn Chung 		printf("Failed to allocate decode output buffer. \n");
99*f8fc7052SJohn Chung 	} else {
100*f8fc7052SJohn Chung 		base64_decode(json_object_get_string(encoded),
101*f8fc7052SJohn Chung 			      json_object_get_string_len(encoded), decoded,
102*f8fc7052SJohn Chung 			      &decoded_len, 0);
103*f8fc7052SJohn Chung 		memcpy(section_cper->EventLogEntry, decoded, decoded_len);
104205dd1d7SLawrence Tang 		free(decoded);
105*f8fc7052SJohn Chung 	}
106205dd1d7SLawrence Tang 
107205dd1d7SLawrence Tang 	//Device table entry.
108205dd1d7SLawrence Tang 	encoded = json_object_object_get(section, "deviceTableEntry");
109*f8fc7052SJohn Chung 	decoded = malloc(json_object_get_string_len(encoded));
110*f8fc7052SJohn Chung 	decoded_len = 0;
111*f8fc7052SJohn Chung 	if (!decoded) {
112*f8fc7052SJohn Chung 		printf("Failed to allocate decode output buffer. \n");
113*f8fc7052SJohn Chung 	} else {
114*f8fc7052SJohn Chung 		base64_decode(json_object_get_string(encoded),
115*f8fc7052SJohn Chung 			      json_object_get_string_len(encoded), decoded,
116*f8fc7052SJohn Chung 			      &decoded_len, 0);
117*f8fc7052SJohn Chung 		memcpy(section_cper->DeviceTableEntry, decoded, decoded_len);
118205dd1d7SLawrence Tang 		free(decoded);
119*f8fc7052SJohn 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