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