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