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