1 /**
2 * Functions for generating pseudo-random CPER IA32/x64 sections.
3 *
4 * Author: Lawrence.Tang@arm.com
5 **/
6
7 #include <stdlib.h>
8 #include <string.h>
9 #include <libcper/Cper.h>
10 #include <libcper/generator/gen-utils.h>
11 #include <libcper/generator/sections/gen-section.h>
12 #define IA32X64_ERROR_STRUCTURE_SIZE 64
13
14 void *generate_ia32x64_error_structure(GEN_VALID_BITS_TEST_TYPE validBitsType);
15 size_t generate_ia32x64_context_structure(void **location);
16
17 //Generates a single pseudo-random IA32/x64 section, saving the resulting address to the given
18 //location. Returns the size of the newly created section.
generate_section_ia32x64(void ** location,GEN_VALID_BITS_TEST_TYPE validBitsType)19 size_t generate_section_ia32x64(void **location,
20 GEN_VALID_BITS_TEST_TYPE validBitsType)
21 {
22 //Set up for generation of error/context structures.
23 UINT16 error_structure_num = rand() % 4 + 1;
24 UINT16 context_structure_num = rand() % 4 + 1;
25 void *error_structures[error_structure_num];
26 void *context_structures[context_structure_num];
27 size_t context_structure_lengths[context_structure_num];
28
29 //Generate the structures.
30 for (int i = 0; i < error_structure_num; i++) {
31 error_structures[i] =
32 generate_ia32x64_error_structure(validBitsType);
33 }
34 for (int i = 0; i < context_structure_num; i++) {
35 context_structure_lengths[i] =
36 generate_ia32x64_context_structure(context_structures +
37 i);
38 }
39
40 //Create a valid IA32/x64 section.
41 size_t total_len =
42 64 + (IA32X64_ERROR_STRUCTURE_SIZE * error_structure_num);
43 for (int i = 0; i < context_structure_num; i++) {
44 total_len += context_structure_lengths[i];
45 }
46 UINT8 *section = generate_random_bytes(total_len);
47
48 //Null extend the end of the CPUID in the header.
49 for (int i = 0; i < 16; i++) {
50 *(section + 48 + i) = 0x0;
51 }
52
53 //Set header information.
54 UINT64 *validation = (UINT64 *)section;
55 *validation &= 0x3;
56 if (validBitsType == ALL_VALID) {
57 *validation = 0x3;
58 } else if (validBitsType == SOME_VALID) {
59 *validation = 0x2;
60 }
61 *validation |= error_structure_num << 2;
62 *validation |= context_structure_num << 8;
63
64 //Copy in structures, free resources.
65 UINT8 *cur_pos = section + 64;
66 for (int i = 0; i < error_structure_num; i++) {
67 memcpy(cur_pos, error_structures[i],
68 IA32X64_ERROR_STRUCTURE_SIZE);
69 free(error_structures[i]);
70 cur_pos += IA32X64_ERROR_STRUCTURE_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, exist.
80 *location = section;
81 return total_len;
82 }
83
84 //Generates a single IA32/x64 error structure. Must later be freed.
generate_ia32x64_error_structure(GEN_VALID_BITS_TEST_TYPE validBitsType)85 void *generate_ia32x64_error_structure(GEN_VALID_BITS_TEST_TYPE validBitsType)
86 {
87 UINT8 *error_structure =
88 generate_random_bytes(IA32X64_ERROR_STRUCTURE_SIZE);
89
90 //Set error structure reserved space to zero.
91 UINT64 *validation = (UINT64 *)(error_structure + 16);
92 *validation &= 0x1F;
93 if (validBitsType == ALL_VALID) {
94 *validation = 0x1F;
95 } else if (validBitsType == SOME_VALID) {
96 *validation = 0x15;
97 }
98
99 //Create a random type of error structure.
100 EFI_GUID *guid = (EFI_GUID *)error_structure;
101 UINT64 *check_info = (UINT64 *)(error_structure + 24);
102 int error_structure_type = rand() % 4;
103 switch (error_structure_type) {
104 //Cache
105 case 0:
106 memcpy(guid, &gEfiIa32x64ErrorTypeCacheCheckGuid,
107 sizeof(EFI_GUID));
108
109 //Set reserved space to zero.
110 *check_info = ~0x20FF00;
111 *check_info &= 0x3FFFFFFF;
112 break;
113
114 //TLB
115 case 1:
116 memcpy(guid, &gEfiIa32x64ErrorTypeTlbCheckGuid,
117 sizeof(EFI_GUID));
118
119 //Set reserved space to zero.
120 *check_info = ~0x20FF00;
121 *check_info &= 0x3FFFFFFF;
122 break;
123
124 //Bus
125 case 2:
126 memcpy(guid, &gEfiIa32x64ErrorTypeBusCheckGuid,
127 sizeof(EFI_GUID));
128
129 //Set reserved space to zero.
130 *check_info = ~0x20F800;
131 *check_info &= 0x7FFFFFFFF;
132 break;
133
134 //MS
135 case 3:
136 memcpy(guid, &gEfiIa32x64ErrorTypeMsCheckGuid,
137 sizeof(EFI_GUID));
138
139 //Set reserved space to zero.
140 *check_info = ~0xFFC0;
141 *check_info &= 0xFFFFFF;
142 break;
143 }
144
145 return error_structure;
146 }
147
148 //Generates a single IA32/x64 context structure. Must later be freed.
generate_ia32x64_context_structure(void ** location)149 size_t generate_ia32x64_context_structure(void **location)
150 {
151 //Initial length is 16 bytes. Add extra based on type.
152 int reg_type = rand() % 8;
153 int reg_size = 0;
154
155 //Set register size.
156 if (reg_type == 2) {
157 reg_size = 92; //IA32 registers.
158 } else if (reg_type == 3) {
159 reg_size = 244; //x64 registers.
160 } else {
161 reg_size = (rand() % 5 + 1) * 32; //Not table defined.
162 }
163
164 //Create structure randomly.
165 int total_size = 16 + reg_size;
166 UINT16 *context_structure = (UINT16 *)generate_random_bytes(total_size);
167
168 //If it is x64 registers, set reserved area accordingly.
169 if (reg_type == 3) {
170 UINT8 *reg_bytes = (UINT8 *)(context_structure + 8);
171 UINT32 *reserved = (UINT32 *)(reg_bytes + 140);
172 *reserved = 0;
173 }
174
175 //Set header information.
176 *(context_structure) = reg_type;
177 *(context_structure + 1) = reg_size;
178
179 //Set return values and exit.
180 *location = context_structure;
181 return total_size;
182 }
183