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