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