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