102c801a5SLawrence Tang /**
2efe17e2cSLawrence Tang  * Functions for generating pseudo-random CPER IA32/x64 sections.
302c801a5SLawrence Tang  *
402c801a5SLawrence Tang  * Author: Lawrence.Tang@arm.com
502c801a5SLawrence Tang  **/
602c801a5SLawrence Tang 
702c801a5SLawrence Tang #include <stdlib.h>
802c801a5SLawrence Tang #include <string.h>
902c801a5SLawrence Tang #include "../../edk/Cper.h"
1002c801a5SLawrence Tang #include "../gen-utils.h"
118f977457SLawrence Tang #include "gen-section.h"
1267cbed6bSLawrence Tang #define IA32X64_ERROR_STRUCTURE_SIZE 64
1302c801a5SLawrence Tang 
1402c801a5SLawrence Tang void *generate_ia32x64_error_structure();
1502c801a5SLawrence Tang size_t generate_ia32x64_context_structure(void **location);
1602c801a5SLawrence Tang 
17efe17e2cSLawrence Tang //Generates a single pseudo-random IA32/x64 section, saving the resulting address to the given
1802c801a5SLawrence Tang //location. Returns the size of the newly created section.
generate_section_ia32x64(void ** location)1902c801a5SLawrence Tang size_t generate_section_ia32x64(void **location)
2002c801a5SLawrence Tang {
2102c801a5SLawrence Tang 	//Set up for generation of error/context structures.
22*f8fc7052SJohn Chung 	UINT16 error_structure_num = rand() % 4 + 1;
23*f8fc7052SJohn Chung 	UINT16 context_structure_num = rand() % 4 + 1;
2402c801a5SLawrence Tang 	void *error_structures[error_structure_num];
2502c801a5SLawrence Tang 	void *context_structures[context_structure_num];
2602c801a5SLawrence Tang 	size_t context_structure_lengths[context_structure_num];
2702c801a5SLawrence Tang 
2802c801a5SLawrence Tang 	//Generate the structures.
29*f8fc7052SJohn Chung 	for (int i = 0; i < error_structure_num; i++) {
3002c801a5SLawrence Tang 		error_structures[i] = generate_ia32x64_error_structure();
31*f8fc7052SJohn Chung 	}
32*f8fc7052SJohn Chung 	for (int i = 0; i < context_structure_num; i++) {
33*f8fc7052SJohn Chung 		context_structure_lengths[i] =
34*f8fc7052SJohn Chung 			generate_ia32x64_context_structure(context_structures +
35*f8fc7052SJohn Chung 							   i);
36*f8fc7052SJohn Chung 	}
3702c801a5SLawrence Tang 
3802c801a5SLawrence Tang 	//Create a valid IA32/x64 section.
39*f8fc7052SJohn Chung 	size_t total_len =
40*f8fc7052SJohn Chung 		64 + (IA32X64_ERROR_STRUCTURE_SIZE * error_structure_num);
41*f8fc7052SJohn Chung 	for (int i = 0; i < context_structure_num; i++) {
4202c801a5SLawrence Tang 		total_len += context_structure_lengths[i];
43*f8fc7052SJohn Chung 	}
4402c801a5SLawrence Tang 	UINT8 *section = generate_random_bytes(total_len);
4502c801a5SLawrence Tang 
46aacf0e26SLawrence Tang 	//Null extend the end of the CPUID in the header.
47*f8fc7052SJohn Chung 	for (int i = 0; i < 16; i++) {
48aacf0e26SLawrence Tang 		*(section + 48 + i) = 0x0;
49*f8fc7052SJohn Chung 	}
50aacf0e26SLawrence Tang 
5102c801a5SLawrence Tang 	//Set header information.
5202c801a5SLawrence Tang 	UINT64 *validation = (UINT64 *)section;
53*f8fc7052SJohn Chung 	*validation &= 0x3;
5402c801a5SLawrence Tang 	*validation |= error_structure_num << 2;
5502c801a5SLawrence Tang 	*validation |= context_structure_num << 8;
5602c801a5SLawrence Tang 
5702c801a5SLawrence Tang 	//Copy in structures, free resources.
5802c801a5SLawrence Tang 	UINT8 *cur_pos = section + 64;
59*f8fc7052SJohn Chung 	for (int i = 0; i < error_structure_num; i++) {
60*f8fc7052SJohn Chung 		memcpy(cur_pos, error_structures[i],
61*f8fc7052SJohn Chung 		       IA32X64_ERROR_STRUCTURE_SIZE);
6202c801a5SLawrence Tang 		free(error_structures[i]);
6302c801a5SLawrence Tang 		cur_pos += IA32X64_ERROR_STRUCTURE_SIZE;
6402c801a5SLawrence Tang 	}
65*f8fc7052SJohn Chung 	for (int i = 0; i < context_structure_num; i++) {
66*f8fc7052SJohn Chung 		memcpy(cur_pos, context_structures[i],
67*f8fc7052SJohn Chung 		       context_structure_lengths[i]);
6802c801a5SLawrence Tang 		free(context_structures[i]);
6902c801a5SLawrence Tang 		cur_pos += context_structure_lengths[i];
7002c801a5SLawrence Tang 	}
7102c801a5SLawrence Tang 
7202c801a5SLawrence Tang 	//Set return values, exist.
7302c801a5SLawrence Tang 	*location = section;
7402c801a5SLawrence Tang 	return total_len;
7502c801a5SLawrence Tang }
7602c801a5SLawrence Tang 
7702c801a5SLawrence Tang //Generates a single IA32/x64 error structure. Must later be freed.
generate_ia32x64_error_structure()7802c801a5SLawrence Tang void *generate_ia32x64_error_structure()
7902c801a5SLawrence Tang {
80*f8fc7052SJohn Chung 	UINT8 *error_structure =
81*f8fc7052SJohn Chung 		generate_random_bytes(IA32X64_ERROR_STRUCTURE_SIZE);
8202c801a5SLawrence Tang 
83aacf0e26SLawrence Tang 	//Set error structure reserved space to zero.
84aacf0e26SLawrence Tang 	UINT64 *validation = (UINT64 *)(error_structure + 16);
85aacf0e26SLawrence Tang 	*validation &= 0x1F;
86aacf0e26SLawrence Tang 
8702c801a5SLawrence Tang 	//Create a random type of error structure.
8802c801a5SLawrence Tang 	EFI_GUID *guid = (EFI_GUID *)error_structure;
89aacf0e26SLawrence Tang 	UINT64 *check_info = (UINT64 *)(error_structure + 24);
9002c801a5SLawrence Tang 	int error_structure_type = rand() % 4;
91*f8fc7052SJohn Chung 	switch (error_structure_type) {
9202c801a5SLawrence Tang 	//Cache
9302c801a5SLawrence Tang 	case 0:
94*f8fc7052SJohn Chung 		memcpy(guid, &gEfiIa32x64ErrorTypeCacheCheckGuid,
95*f8fc7052SJohn Chung 		       sizeof(EFI_GUID));
96aacf0e26SLawrence Tang 
97aacf0e26SLawrence Tang 		//Set reserved space to zero.
98*f8fc7052SJohn Chung 		*check_info &= ~0x20FF00;
99aacf0e26SLawrence Tang 		*check_info &= 0x3FFFFFFF;
10002c801a5SLawrence Tang 		break;
10102c801a5SLawrence Tang 
10202c801a5SLawrence Tang 	//TLB
10302c801a5SLawrence Tang 	case 1:
104*f8fc7052SJohn Chung 		memcpy(guid, &gEfiIa32x64ErrorTypeTlbCheckGuid,
105*f8fc7052SJohn Chung 		       sizeof(EFI_GUID));
106aacf0e26SLawrence Tang 
107aacf0e26SLawrence Tang 		//Set reserved space to zero.
108*f8fc7052SJohn Chung 		*check_info &= ~0x20FF00;
109aacf0e26SLawrence Tang 		*check_info &= 0x3FFFFFFF;
11002c801a5SLawrence Tang 		break;
11102c801a5SLawrence Tang 
11202c801a5SLawrence Tang 	//Bus
11302c801a5SLawrence Tang 	case 2:
114*f8fc7052SJohn Chung 		memcpy(guid, &gEfiIa32x64ErrorTypeBusCheckGuid,
115*f8fc7052SJohn Chung 		       sizeof(EFI_GUID));
116aacf0e26SLawrence Tang 
117aacf0e26SLawrence Tang 		//Set reserved space to zero.
118*f8fc7052SJohn Chung 		*check_info &= ~0x20F800;
119aacf0e26SLawrence Tang 		*check_info &= 0x7FFFFFFFF;
12002c801a5SLawrence Tang 		break;
12102c801a5SLawrence Tang 
12202c801a5SLawrence Tang 	//MS
12302c801a5SLawrence Tang 	case 3:
124*f8fc7052SJohn Chung 		memcpy(guid, &gEfiIa32x64ErrorTypeMsCheckGuid,
125*f8fc7052SJohn Chung 		       sizeof(EFI_GUID));
126aacf0e26SLawrence Tang 
127aacf0e26SLawrence Tang 		//Set reserved space to zero.
12801e3a44dSLawrence Tang 		*check_info &= ~0xFFE0;
129aacf0e26SLawrence Tang 		*check_info &= 0xFFFFFF;
13002c801a5SLawrence Tang 		break;
13102c801a5SLawrence Tang 	}
13202c801a5SLawrence Tang 
13302c801a5SLawrence Tang 	return error_structure;
13402c801a5SLawrence Tang }
13502c801a5SLawrence Tang 
13602c801a5SLawrence Tang //Generates a single IA32/x64 context structure. Must later be freed.
generate_ia32x64_context_structure(void ** location)13702c801a5SLawrence Tang size_t generate_ia32x64_context_structure(void **location)
13802c801a5SLawrence Tang {
13902c801a5SLawrence Tang 	//Initial length is 16 bytes. Add extra based on type.
14002c801a5SLawrence Tang 	int reg_type = rand() % 8;
14102c801a5SLawrence Tang 	int reg_size = 0;
14202c801a5SLawrence Tang 
14302c801a5SLawrence Tang 	//Set register size.
144*f8fc7052SJohn Chung 	if (reg_type == 2) {
14502c801a5SLawrence Tang 		reg_size = 92;			  //IA32 registers.
146*f8fc7052SJohn Chung 	} else if (reg_type == 3) {
14702c801a5SLawrence Tang 		reg_size = 244;			  //x64 registers.
148*f8fc7052SJohn Chung 	} else {
14904750a9eSLawrence Tang 		reg_size = (rand() % 5 + 1) * 32; //Not table defined.
15004750a9eSLawrence Tang 	}
15102c801a5SLawrence Tang 
15202c801a5SLawrence Tang 	//Create structure randomly.
15302c801a5SLawrence Tang 	int total_size = 16 + reg_size;
15402c801a5SLawrence Tang 	UINT16 *context_structure = (UINT16 *)generate_random_bytes(total_size);
15502c801a5SLawrence Tang 
15604750a9eSLawrence Tang 	//If it is x64 registers, set reserved area accordingly.
157*f8fc7052SJohn Chung 	if (reg_type == 3) {
15804750a9eSLawrence Tang 		UINT8 *reg_bytes = (UINT8 *)(context_structure + 8);
15904750a9eSLawrence Tang 		UINT32 *reserved = (UINT32 *)(reg_bytes + 140);
16004750a9eSLawrence Tang 		*reserved = 0;
16104750a9eSLawrence Tang 	}
16204750a9eSLawrence Tang 
16302c801a5SLawrence Tang 	//Set header information.
16402c801a5SLawrence Tang 	*(context_structure) = reg_type;
16502c801a5SLawrence Tang 	*(context_structure + 1) = reg_size;
16602c801a5SLawrence Tang 
16702c801a5SLawrence Tang 	//Set return values and exit.
16802c801a5SLawrence Tang 	*location = context_structure;
16902c801a5SLawrence Tang 	return total_size;
17002c801a5SLawrence Tang }
171