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 <string.h>
9 #include "../../edk/BaseTypes.h"
10 #include "../gen-utils.h"
11 #include "gen-section.h"
12 #define ARM_ERROR_INFO_SIZE 32
13 
14 void *generate_arm_error_info();
15 size_t generate_arm_context_info(void **location);
16 
17 //Generates a single pseudo-random ARM processor section, saving the resulting address to the given
18 //location. Returns the size of the newly created section.
generate_section_arm(void ** location)19 size_t generate_section_arm(void **location)
20 {
21 	//Set up for generation of error/context structures.
22 	UINT16 error_structure_num = rand() % 4 + 1; //Must be at least 1.
23 	UINT16 context_structure_num = rand() % 3 + 1;
24 	void *error_structures[error_structure_num];
25 	void *context_structures[context_structure_num];
26 	size_t context_structure_lengths[context_structure_num];
27 
28 	//Generate the structures.
29 	for (int i = 0; i < error_structure_num; i++) {
30 		error_structures[i] = generate_arm_error_info();
31 	}
32 	for (int i = 0; i < context_structure_num; i++) {
33 		context_structure_lengths[i] =
34 			generate_arm_context_info(context_structures + i);
35 	}
36 
37 	//Determine a random amount of vendor specific info.
38 	int vendor_info_len = rand() % 16;
39 
40 	//Create the section as a whole.
41 	size_t total_len = 40 + (error_structure_num * ARM_ERROR_INFO_SIZE);
42 	for (int i = 0; i < context_structure_num; i++) {
43 		total_len += context_structure_lengths[i];
44 	}
45 	total_len += vendor_info_len;
46 	UINT8 *section = generate_random_bytes(total_len);
47 
48 	//Set header information.
49 	UINT16 *info_nums = (UINT16 *)(section + 4);
50 	*info_nums = error_structure_num;
51 	*(info_nums + 1) = context_structure_num;
52 	UINT32 *section_length = (UINT32 *)(section + 8);
53 	*section_length = total_len;
54 
55 	//Error affinity.
56 	*(section + 12) = rand() % 4;
57 
58 	//Reserved zero bytes.
59 	UINT64 *validation = (UINT64 *)section;
60 	*validation &= 0x7;
61 	UINT32 *running_state = (UINT32 *)(section + 32);
62 	*running_state &= 0x1;
63 	memset(section + 13, 0, 3);
64 
65 	//Copy in the sections/context structures, free resources.
66 	UINT8 *cur_pos = section + 40;
67 	for (int i = 0; i < error_structure_num; i++) {
68 		memcpy(cur_pos, error_structures[i], ARM_ERROR_INFO_SIZE);
69 		free(error_structures[i]);
70 		cur_pos += ARM_ERROR_INFO_SIZE;
71 	}
72 	for (int i = 0; i < context_structure_num; i++) {
73 		memcpy(cur_pos, context_structures[i],
74 		       context_structure_lengths[i]);
75 		free(context_structures[i]);
76 		cur_pos += context_structure_lengths[i];
77 	}
78 
79 	//Set return values and exit.
80 	*location = section;
81 	return total_len;
82 }
83 
84 //Generates a single pseudo-random ARM error info structure. Must be later freed.
generate_arm_error_info()85 void *generate_arm_error_info()
86 {
87 	UINT8 *error_info = generate_random_bytes(ARM_ERROR_INFO_SIZE);
88 
89 	//Version (zero for revision of table referenced), length.
90 	*error_info = 0;
91 	*(error_info + 1) = ARM_ERROR_INFO_SIZE;
92 
93 	//Type of error.
94 	UINT8 error_type = rand() % 4;
95 	*(error_info + 4) = error_type;
96 
97 	//Reserved bits for error information.
98 	UINT16 *validation = (UINT16 *)(error_info + 2);
99 	*validation &= 0x1F;
100 
101 	//Make sure reserved bits are zero according with the type.
102 	UINT64 *error_subinfo = (UINT64 *)(error_info + 8);
103 	switch (error_type) {
104 	//Cache/TLB
105 	case 0:
106 	case 1:
107 		*error_subinfo &= 0xFFFFFFF;
108 		break;
109 
110 	//Bus
111 	case 2:
112 		*error_subinfo &= 0xFFFFFFFFFFF;
113 		break;
114 
115 	//Microarch/other.
116 	default:
117 		break;
118 	}
119 
120 	return error_info;
121 }
122 
123 //Generates a single pseudo-random ARM context info structure. Must be later freed.
generate_arm_context_info(void ** location)124 size_t generate_arm_context_info(void **location)
125 {
126 	//Initial length is 8 bytes. Add extra based on type.
127 	UINT16 reg_type = rand() % 9;
128 	UINT32 reg_size = 0;
129 
130 	//Set register size.
131 	switch (reg_type) {
132 	//AARCH32 GPR, AARCH32 EL2
133 	case 0:
134 	case 2:
135 		reg_size = 64;
136 		break;
137 
138 	//AARCH32 EL1
139 	case 1:
140 		reg_size = 96;
141 		break;
142 
143 	//AARCH32 EL3
144 	case 3:
145 		reg_size = 8;
146 		break;
147 
148 	//AARCH64 GPR
149 	case 4:
150 		reg_size = 256;
151 		break;
152 
153 	//AARCH64 EL1
154 	case 5:
155 		reg_size = 136;
156 		break;
157 
158 	//AARCH64 EL2
159 	case 6:
160 		reg_size = 120;
161 		break;
162 
163 	//AARCH64 EL3
164 	case 7:
165 		reg_size = 80;
166 		break;
167 
168 	//Misc. single register.
169 	case 8:
170 		reg_size = 10;
171 		break;
172 	}
173 
174 	//Create context structure randomly.
175 	int total_size = 8 + reg_size;
176 	UINT16 *context_info = (UINT16 *)generate_random_bytes(total_size);
177 
178 	//Set header information.
179 	*(context_info + 1) = reg_type;
180 	*((UINT32 *)(context_info + 2)) = reg_size;
181 
182 	//Set return values and exit.
183 	*location = context_info;
184 	return total_size;
185 }
186