xref: /openbmc/libcper/generator/sections/gen-section-arm.c (revision e42fb487839b242371b0150ab5b0b89c2d232976)
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 <libcper/BaseTypes.h>
10  #include <libcper/generator/gen-utils.h>
11  #include <libcper/generator/sections/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