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