xref: /openbmc/libcper/generator/sections/gen-section-arm.c (revision 043d5f4b4f95d9f2a4f8182850ed0e6f2b076b15)
1 /**
2  * Functions for generating pseudo-random CPER ARM processor sections.
3  *
4  * Author: Lawrence.Tang@arm.com
5  **/
6 
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <libcper/BaseTypes.h>
11 #include <libcper/Cper.h>
12 #include <libcper/generator/gen-utils.h>
13 #include <libcper/generator/sections/gen-section.h>
14 #define ARM_ERROR_INFO_SIZE 32
15 
16 void *generate_arm_error_info(GEN_VALID_BITS_TEST_TYPE validBitsType);
17 size_t generate_arm_context_info(void **location);
18 
19 //Generates a single pseudo-random ARM processor section, saving the resulting address to the given
20 //location. Returns the size of the newly created section.
generate_section_arm(void ** location,GEN_VALID_BITS_TEST_TYPE validBitsType)21 size_t generate_section_arm(void **location,
22 			    GEN_VALID_BITS_TEST_TYPE validBitsType)
23 {
24 	//Set up for generation of error/context structures.
25 	UINT16 error_structure_num = cper_rand() % 4 + 1; //Must be at least 1.
26 	UINT16 context_structure_num = cper_rand() % 3 + 1;
27 	void *error_structures[error_structure_num];
28 	void *context_structures[context_structure_num];
29 	size_t context_structure_lengths[context_structure_num];
30 
31 	//Generate the structures.
32 	for (int i = 0; i < error_structure_num; i++) {
33 		error_structures[i] = generate_arm_error_info(validBitsType);
34 	}
35 	for (int i = 0; i < context_structure_num; i++) {
36 		context_structure_lengths[i] =
37 			generate_arm_context_info(context_structures + i);
38 	}
39 
40 	//Determine a random amount of vendor specific info.
41 	size_t vendor_info_len = cper_rand() % 16 + 4;
42 
43 	//Create the section as a whole.
44 	size_t total_len = 40 + (error_structure_num * ARM_ERROR_INFO_SIZE);
45 	for (int i = 0; i < context_structure_num; i++) {
46 		total_len += context_structure_lengths[i];
47 	}
48 	total_len += vendor_info_len;
49 	UINT8 *section = generate_random_bytes(total_len);
50 
51 	//Set header information.
52 	UINT16 *info_nums = (UINT16 *)(section + 4);
53 	*info_nums = error_structure_num;
54 	*(info_nums + 1) = context_structure_num;
55 	UINT32 *section_length = (UINT32 *)(section + 8);
56 	*section_length = total_len;
57 
58 	//Error affinity.
59 	*(section + 12) = cper_rand() % 4;
60 
61 	//Reserved zero bytes.
62 	UINT32 *validation = (UINT32 *)section;
63 	*validation &= 0xF;
64 	if (validBitsType == ALL_VALID) {
65 		*validation = 0xF;
66 	} else if (validBitsType == SOME_VALID) {
67 		*validation = 0xA;
68 	}
69 	UINT32 *running_state = (UINT32 *)(section + 32);
70 	*running_state &= 0x1;
71 	memset(section + 13, 0, 3);
72 
73 	//Copy in the sections/context structures, free resources.
74 	UINT8 *cur_pos = section + 40;
75 	for (int i = 0; i < error_structure_num; i++) {
76 		memcpy(cur_pos, error_structures[i], ARM_ERROR_INFO_SIZE);
77 		free(error_structures[i]);
78 		cur_pos += ARM_ERROR_INFO_SIZE;
79 	}
80 	for (int i = 0; i < context_structure_num; i++) {
81 		memcpy(cur_pos, context_structures[i],
82 		       context_structure_lengths[i]);
83 		free(context_structures[i]);
84 		cur_pos += context_structure_lengths[i];
85 	}
86 
87 	//vendor specific
88 	for (size_t i = 0; i < vendor_info_len; i++) {
89 		//Ensure only printable ascii is used so we don't
90 		// fail base64E
91 		*cur_pos = cper_rand() % (0x7f - 0x20) + 0x20;
92 		cur_pos += 1;
93 	}
94 
95 	//Set return values and exit.
96 	*location = section;
97 	return total_len;
98 }
99 
100 //Generates a single pseudo-random ARM error info structure. Must be later freed.
generate_arm_error_info(GEN_VALID_BITS_TEST_TYPE validBitsType)101 void *generate_arm_error_info(GEN_VALID_BITS_TEST_TYPE validBitsType)
102 {
103 	UINT8 *error_info = generate_random_bytes(ARM_ERROR_INFO_SIZE);
104 
105 	//Version (zero for revision of table referenced), length.
106 	*error_info = 0;
107 	*(error_info + 1) = ARM_ERROR_INFO_SIZE;
108 
109 	//Type of error. UEFI spec uses bit positions: 1=Cache, 2=TLB, 4=Bus, 8=Microarch
110 	const UINT8 error_type_values[] = { 1, 2, 4, 8 };
111 	UINT8 error_type = error_type_values[cper_rand() % 4];
112 	*(error_info + 4) = error_type;
113 
114 	//Reserved bits for error information.
115 	UINT16 *validation = (UINT16 *)(error_info + 2);
116 	*validation &= 0x1F;
117 	if (validBitsType == ALL_VALID) {
118 		*validation = 0x1F;
119 	} else if (validBitsType == SOME_VALID) {
120 		*validation = 0x15;
121 	}
122 
123 	//Make sure reserved bits are zero according with the type.
124 	UINT64 *error_subinfo = (UINT64 *)(error_info + 8);
125 	switch (error_type) {
126 	//Cache/TLB
127 	case ARM_ERROR_INFORMATION_TYPE_CACHE:
128 	case ARM_ERROR_INFORMATION_TYPE_TLB:
129 		*error_subinfo &= 0xFFFFFFF;
130 		//Reserved bits for cache/tlb.
131 		UINT16 *val_cache = (UINT16 *)(error_info + 8);
132 		if (validBitsType == ALL_VALID) {
133 			*val_cache = 0x7F;
134 		} else if (validBitsType == SOME_VALID) {
135 			*val_cache = 0x55;
136 		}
137 		break;
138 
139 	//Bus
140 	case ARM_ERROR_INFORMATION_TYPE_BUS:
141 		*error_subinfo &= 0xFFFFFFFFFFF;
142 		UINT16 *val_bus = (UINT16 *)(error_info + 8);
143 		if (validBitsType == ALL_VALID) {
144 			*val_bus = 0xFFF;
145 		} else if (validBitsType == SOME_VALID) {
146 			*val_bus = 0x555;
147 		}
148 
149 		break;
150 
151 	//Microarch/other.
152 	default:
153 		break;
154 	}
155 
156 	//flags
157 	UINT8 *flags = (UINT8 *)(error_info + 7);
158 	*flags &= 0xF;
159 
160 	return error_info;
161 }
162 
163 //Generates a single pseudo-random ARM context info structure. Must be later freed.
generate_arm_context_info(void ** location)164 size_t generate_arm_context_info(void **location)
165 {
166 	//Initial length is 8 bytes. Add extra based on type.
167 	UINT16 reg_type = cper_rand() % 9;
168 	UINT32 reg_size = 0;
169 
170 	//Set register size.
171 	switch (reg_type) {
172 	//AARCH32 GPR, AARCH32 EL2
173 	case 0:
174 	case 2:
175 		reg_size = 64;
176 		break;
177 
178 	//AARCH32 EL1
179 	case 1:
180 		reg_size = 96;
181 		break;
182 
183 	//AARCH32 EL3
184 	case 3:
185 		reg_size = 8;
186 		break;
187 
188 	//AARCH64 GPR
189 	case 4:
190 		reg_size = 256;
191 		break;
192 
193 	//AARCH64 EL1
194 	case 5:
195 		reg_size = 136;
196 		break;
197 
198 	//AARCH64 EL2
199 	case 6:
200 		reg_size = 120;
201 		break;
202 
203 	//AARCH64 EL3
204 	case 7:
205 		reg_size = 80;
206 		break;
207 
208 	//Misc. single register.
209 	case 8:
210 		reg_size = 10;
211 		break;
212 	}
213 
214 	//Create context structure randomly.
215 	int total_size = 8 + reg_size;
216 	UINT16 *context_info = (UINT16 *)generate_random_bytes(total_size);
217 
218 	//UEFI spec is not clear about bit 15 in the
219 	// reg type 8 section. This sets it to 0 to
220 	// avoid confusion for now.
221 	if (reg_type == 8) {
222 		UINT8 *reg_decode = (UINT8 *)context_info;
223 		*(reg_decode + 9) &= 0x7F;
224 	}
225 
226 	//Set header information.
227 	*(context_info + 1) = reg_type;
228 	*((UINT32 *)(context_info + 2)) = reg_size;
229 
230 	//Set return values and exit.
231 	*location = context_info;
232 	return total_size;
233 }
234