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