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