167cbed6bSLawrence Tang /**
2efe17e2cSLawrence Tang  * Functions for generating pseudo-random CPER ARM processor sections.
367cbed6bSLawrence Tang  *
467cbed6bSLawrence Tang  * Author: Lawrence.Tang@arm.com
567cbed6bSLawrence Tang  **/
667cbed6bSLawrence Tang 
767cbed6bSLawrence Tang #include <stdlib.h>
867cbed6bSLawrence Tang #include <string.h>
967cbed6bSLawrence Tang #include "../../edk/BaseTypes.h"
1067cbed6bSLawrence Tang #include "../gen-utils.h"
118f977457SLawrence Tang #include "gen-section.h"
1267cbed6bSLawrence Tang #define ARM_ERROR_INFO_SIZE 32
1367cbed6bSLawrence Tang 
1467cbed6bSLawrence Tang void *generate_arm_error_info();
1567cbed6bSLawrence Tang size_t generate_arm_context_info(void **location);
1667cbed6bSLawrence Tang 
17efe17e2cSLawrence Tang //Generates a single pseudo-random ARM processor section, saving the resulting address to the given
1867cbed6bSLawrence Tang //location. Returns the size of the newly created section.
generate_section_arm(void ** location)1967cbed6bSLawrence Tang size_t generate_section_arm(void **location)
2067cbed6bSLawrence Tang {
2167cbed6bSLawrence Tang 	//Set up for generation of error/context structures.
2267cbed6bSLawrence Tang 	UINT16 error_structure_num = rand() % 4 + 1; //Must be at least 1.
23*f8fc7052SJohn Chung 	UINT16 context_structure_num = rand() % 3 + 1;
2467cbed6bSLawrence Tang 	void *error_structures[error_structure_num];
2567cbed6bSLawrence Tang 	void *context_structures[context_structure_num];
2667cbed6bSLawrence Tang 	size_t context_structure_lengths[context_structure_num];
2767cbed6bSLawrence Tang 
2867cbed6bSLawrence Tang 	//Generate the structures.
29*f8fc7052SJohn Chung 	for (int i = 0; i < error_structure_num; i++) {
3067cbed6bSLawrence Tang 		error_structures[i] = generate_arm_error_info();
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_arm_context_info(context_structures + i);
35*f8fc7052SJohn Chung 	}
3667cbed6bSLawrence Tang 
3767cbed6bSLawrence Tang 	//Determine a random amount of vendor specific info.
3867cbed6bSLawrence Tang 	int vendor_info_len = rand() % 16;
3967cbed6bSLawrence Tang 
4067cbed6bSLawrence Tang 	//Create the section as a whole.
4167cbed6bSLawrence Tang 	size_t total_len = 40 + (error_structure_num * ARM_ERROR_INFO_SIZE);
42*f8fc7052SJohn Chung 	for (int i = 0; i < context_structure_num; i++) {
4367cbed6bSLawrence Tang 		total_len += context_structure_lengths[i];
44*f8fc7052SJohn Chung 	}
4567cbed6bSLawrence Tang 	total_len += vendor_info_len;
4667cbed6bSLawrence Tang 	UINT8 *section = generate_random_bytes(total_len);
4767cbed6bSLawrence Tang 
4867cbed6bSLawrence Tang 	//Set header information.
4967cbed6bSLawrence Tang 	UINT16 *info_nums = (UINT16 *)(section + 4);
5067cbed6bSLawrence Tang 	*info_nums = error_structure_num;
5167cbed6bSLawrence Tang 	*(info_nums + 1) = context_structure_num;
5267cbed6bSLawrence Tang 	UINT32 *section_length = (UINT32 *)(section + 8);
5367cbed6bSLawrence Tang 	*section_length = total_len;
5467cbed6bSLawrence Tang 
5567cbed6bSLawrence Tang 	//Error affinity.
5667cbed6bSLawrence Tang 	*(section + 12) = rand() % 4;
5767cbed6bSLawrence Tang 
5867cbed6bSLawrence Tang 	//Reserved zero bytes.
5901e3a44dSLawrence Tang 	UINT64 *validation = (UINT64 *)section;
60*f8fc7052SJohn Chung 	*validation &= 0x7;
6101e3a44dSLawrence Tang 	UINT32 *running_state = (UINT32 *)(section + 32);
62*f8fc7052SJohn Chung 	*running_state &= 0x1;
6367cbed6bSLawrence Tang 	memset(section + 13, 0, 3);
6467cbed6bSLawrence Tang 
6567cbed6bSLawrence Tang 	//Copy in the sections/context structures, free resources.
6667cbed6bSLawrence Tang 	UINT8 *cur_pos = section + 40;
67*f8fc7052SJohn Chung 	for (int i = 0; i < error_structure_num; i++) {
6867cbed6bSLawrence Tang 		memcpy(cur_pos, error_structures[i], ARM_ERROR_INFO_SIZE);
6967cbed6bSLawrence Tang 		free(error_structures[i]);
7067cbed6bSLawrence Tang 		cur_pos += ARM_ERROR_INFO_SIZE;
7167cbed6bSLawrence Tang 	}
72*f8fc7052SJohn Chung 	for (int i = 0; i < context_structure_num; i++) {
73*f8fc7052SJohn Chung 		memcpy(cur_pos, context_structures[i],
74*f8fc7052SJohn Chung 		       context_structure_lengths[i]);
7567cbed6bSLawrence Tang 		free(context_structures[i]);
7667cbed6bSLawrence Tang 		cur_pos += context_structure_lengths[i];
7767cbed6bSLawrence Tang 	}
7867cbed6bSLawrence Tang 
7967cbed6bSLawrence Tang 	//Set return values and exit.
8067cbed6bSLawrence Tang 	*location = section;
8167cbed6bSLawrence Tang 	return total_len;
8267cbed6bSLawrence Tang }
8367cbed6bSLawrence Tang 
8467cbed6bSLawrence Tang //Generates a single pseudo-random ARM error info structure. Must be later freed.
generate_arm_error_info()8567cbed6bSLawrence Tang void *generate_arm_error_info()
8667cbed6bSLawrence Tang {
8767cbed6bSLawrence Tang 	UINT8 *error_info = generate_random_bytes(ARM_ERROR_INFO_SIZE);
8867cbed6bSLawrence Tang 
8967cbed6bSLawrence Tang 	//Version (zero for revision of table referenced), length.
9067cbed6bSLawrence Tang 	*error_info = 0;
9167cbed6bSLawrence Tang 	*(error_info + 1) = ARM_ERROR_INFO_SIZE;
9267cbed6bSLawrence Tang 
9367cbed6bSLawrence Tang 	//Type of error.
9467cbed6bSLawrence Tang 	UINT8 error_type = rand() % 4;
9567cbed6bSLawrence Tang 	*(error_info + 4) = error_type;
9667cbed6bSLawrence Tang 
9701e3a44dSLawrence Tang 	//Reserved bits for error information.
9801e3a44dSLawrence Tang 	UINT16 *validation = (UINT16 *)(error_info + 2);
9901e3a44dSLawrence Tang 	*validation &= 0x1F;
10001e3a44dSLawrence Tang 
10167cbed6bSLawrence Tang 	//Make sure reserved bits are zero according with the type.
10267cbed6bSLawrence Tang 	UINT64 *error_subinfo = (UINT64 *)(error_info + 8);
103*f8fc7052SJohn Chung 	switch (error_type) {
10467cbed6bSLawrence Tang 	//Cache/TLB
10567cbed6bSLawrence Tang 	case 0:
10667cbed6bSLawrence Tang 	case 1:
10767cbed6bSLawrence Tang 		*error_subinfo &= 0xFFFFFFF;
10867cbed6bSLawrence Tang 		break;
10967cbed6bSLawrence Tang 
11067cbed6bSLawrence Tang 	//Bus
11167cbed6bSLawrence Tang 	case 2:
11267cbed6bSLawrence Tang 		*error_subinfo &= 0xFFFFFFFFFFF;
11367cbed6bSLawrence Tang 		break;
11467cbed6bSLawrence Tang 
11567cbed6bSLawrence Tang 	//Microarch/other.
11667cbed6bSLawrence Tang 	default:
11767cbed6bSLawrence Tang 		break;
11867cbed6bSLawrence Tang 	}
11967cbed6bSLawrence Tang 
12067cbed6bSLawrence Tang 	return error_info;
12167cbed6bSLawrence Tang }
12267cbed6bSLawrence Tang 
12367cbed6bSLawrence Tang //Generates a single pseudo-random ARM context info structure. Must be later freed.
generate_arm_context_info(void ** location)12467cbed6bSLawrence Tang size_t generate_arm_context_info(void **location)
12567cbed6bSLawrence Tang {
12667cbed6bSLawrence Tang 	//Initial length is 8 bytes. Add extra based on type.
12767cbed6bSLawrence Tang 	UINT16 reg_type = rand() % 9;
12867cbed6bSLawrence Tang 	UINT32 reg_size = 0;
12967cbed6bSLawrence Tang 
13067cbed6bSLawrence Tang 	//Set register size.
131*f8fc7052SJohn Chung 	switch (reg_type) {
13267cbed6bSLawrence Tang 	//AARCH32 GPR, AARCH32 EL2
13367cbed6bSLawrence Tang 	case 0:
13467cbed6bSLawrence Tang 	case 2:
13567cbed6bSLawrence Tang 		reg_size = 64;
13667cbed6bSLawrence Tang 		break;
13767cbed6bSLawrence Tang 
13867cbed6bSLawrence Tang 	//AARCH32 EL1
13967cbed6bSLawrence Tang 	case 1:
14067cbed6bSLawrence Tang 		reg_size = 96;
14167cbed6bSLawrence Tang 		break;
14267cbed6bSLawrence Tang 
14367cbed6bSLawrence Tang 	//AARCH32 EL3
14467cbed6bSLawrence Tang 	case 3:
14567cbed6bSLawrence Tang 		reg_size = 8;
14667cbed6bSLawrence Tang 		break;
14767cbed6bSLawrence Tang 
14867cbed6bSLawrence Tang 	//AARCH64 GPR
14967cbed6bSLawrence Tang 	case 4:
15067cbed6bSLawrence Tang 		reg_size = 256;
15167cbed6bSLawrence Tang 		break;
15267cbed6bSLawrence Tang 
15367cbed6bSLawrence Tang 	//AARCH64 EL1
15467cbed6bSLawrence Tang 	case 5:
15567cbed6bSLawrence Tang 		reg_size = 136;
15667cbed6bSLawrence Tang 		break;
15767cbed6bSLawrence Tang 
15867cbed6bSLawrence Tang 	//AARCH64 EL2
15967cbed6bSLawrence Tang 	case 6:
16067cbed6bSLawrence Tang 		reg_size = 120;
16167cbed6bSLawrence Tang 		break;
16267cbed6bSLawrence Tang 
16367cbed6bSLawrence Tang 	//AARCH64 EL3
16467cbed6bSLawrence Tang 	case 7:
16567cbed6bSLawrence Tang 		reg_size = 80;
16667cbed6bSLawrence Tang 		break;
16767cbed6bSLawrence Tang 
16867cbed6bSLawrence Tang 	//Misc. single register.
16967cbed6bSLawrence Tang 	case 8:
17067cbed6bSLawrence Tang 		reg_size = 10;
17167cbed6bSLawrence Tang 		break;
17267cbed6bSLawrence Tang 	}
17367cbed6bSLawrence Tang 
17467cbed6bSLawrence Tang 	//Create context structure randomly.
17567cbed6bSLawrence Tang 	int total_size = 8 + reg_size;
17667cbed6bSLawrence Tang 	UINT16 *context_info = (UINT16 *)generate_random_bytes(total_size);
17767cbed6bSLawrence Tang 
17867cbed6bSLawrence Tang 	//Set header information.
17967cbed6bSLawrence Tang 	*(context_info + 1) = reg_type;
18067cbed6bSLawrence Tang 	*((UINT32 *)(context_info + 2)) = reg_size;
18167cbed6bSLawrence Tang 
18267cbed6bSLawrence Tang 	//Set return values and exit.
18367cbed6bSLawrence Tang 	*location = context_info;
18467cbed6bSLawrence Tang 	return total_size;
18567cbed6bSLawrence Tang }
186