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