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"
11*8f977457SLawrence 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.
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.
2367cbed6bSLawrence Tang     UINT16 context_structure_num = rand() % 3;
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.
2967cbed6bSLawrence Tang     for (int i=0; i<error_structure_num; i++)
3067cbed6bSLawrence Tang         error_structures[i] = generate_arm_error_info();
3167cbed6bSLawrence Tang     for (int i=0; i<context_structure_num; i++)
3267cbed6bSLawrence Tang         context_structure_lengths[i] = generate_arm_context_info(context_structures + i);
3367cbed6bSLawrence Tang 
3467cbed6bSLawrence Tang     //Determine a random amount of vendor specific info.
3567cbed6bSLawrence Tang     int vendor_info_len = rand() % 16;
3667cbed6bSLawrence Tang 
3767cbed6bSLawrence Tang     //Create the section as a whole.
3867cbed6bSLawrence Tang     size_t total_len = 40 + (error_structure_num * ARM_ERROR_INFO_SIZE);
3967cbed6bSLawrence Tang     for (int i=0; i<context_structure_num; i++)
4067cbed6bSLawrence Tang         total_len += context_structure_lengths[i];
4167cbed6bSLawrence Tang     total_len += vendor_info_len;
4267cbed6bSLawrence Tang     UINT8* section = generate_random_bytes(total_len);
4367cbed6bSLawrence Tang 
4467cbed6bSLawrence Tang     //Set header information.
4567cbed6bSLawrence Tang     UINT16* info_nums = (UINT16*)(section + 4);
4667cbed6bSLawrence Tang     *info_nums = error_structure_num;
4767cbed6bSLawrence Tang     *(info_nums + 1) = context_structure_num;
4867cbed6bSLawrence Tang     UINT32* section_length = (UINT32*)(section + 8);
4967cbed6bSLawrence Tang     *section_length = total_len;
5067cbed6bSLawrence Tang 
5167cbed6bSLawrence Tang     //Error affinity.
5267cbed6bSLawrence Tang     *(section + 12) = rand() % 4;
5367cbed6bSLawrence Tang 
5467cbed6bSLawrence Tang     //Reserved zero bytes.
5501e3a44dSLawrence Tang     UINT64* validation = (UINT64*)section;
5601e3a44dSLawrence Tang     *validation &= 0b111;
5701e3a44dSLawrence Tang     UINT32* running_state = (UINT32*)(section + 32);
5801e3a44dSLawrence Tang     *running_state &= 0b1;
5967cbed6bSLawrence Tang     memset(section + 13, 0, 3);
6067cbed6bSLawrence Tang 
6167cbed6bSLawrence Tang     //Copy in the sections/context structures, free resources.
6267cbed6bSLawrence Tang     UINT8* cur_pos = section + 40;
6367cbed6bSLawrence Tang     for (int i=0; i<error_structure_num; i++)
6467cbed6bSLawrence Tang     {
6567cbed6bSLawrence Tang         memcpy(cur_pos, error_structures[i], ARM_ERROR_INFO_SIZE);
6667cbed6bSLawrence Tang         free(error_structures[i]);
6767cbed6bSLawrence Tang         cur_pos += ARM_ERROR_INFO_SIZE;
6867cbed6bSLawrence Tang     }
6967cbed6bSLawrence Tang     for (int i=0; i<context_structure_num; i++)
7067cbed6bSLawrence Tang     {
7167cbed6bSLawrence Tang         memcpy(cur_pos, context_structures[i], context_structure_lengths[i]);
7267cbed6bSLawrence Tang         free(context_structures[i]);
7367cbed6bSLawrence Tang         cur_pos += context_structure_lengths[i];
7467cbed6bSLawrence Tang     }
7567cbed6bSLawrence Tang 
7667cbed6bSLawrence Tang     //Set return values and exit.
7767cbed6bSLawrence Tang     *location = section;
7867cbed6bSLawrence Tang     return total_len;
7967cbed6bSLawrence Tang }
8067cbed6bSLawrence Tang 
8167cbed6bSLawrence Tang //Generates a single pseudo-random ARM error info structure. Must be later freed.
8267cbed6bSLawrence Tang void* generate_arm_error_info()
8367cbed6bSLawrence Tang {
8467cbed6bSLawrence Tang     UINT8* error_info = generate_random_bytes(ARM_ERROR_INFO_SIZE);
8567cbed6bSLawrence Tang 
8667cbed6bSLawrence Tang     //Version (zero for revision of table referenced), length.
8767cbed6bSLawrence Tang     *error_info = 0;
8867cbed6bSLawrence Tang     *(error_info + 1) = ARM_ERROR_INFO_SIZE;
8967cbed6bSLawrence Tang 
9067cbed6bSLawrence Tang     //Type of error.
9167cbed6bSLawrence Tang     UINT8 error_type = rand() % 4;
9267cbed6bSLawrence Tang     *(error_info + 4) = error_type;
9367cbed6bSLawrence Tang 
9401e3a44dSLawrence Tang     //Reserved bits for error information.
9501e3a44dSLawrence Tang     UINT16* validation = (UINT16*)(error_info + 2);
9601e3a44dSLawrence Tang     *validation &= 0x1F;
9701e3a44dSLawrence Tang 
9867cbed6bSLawrence Tang     //Make sure reserved bits are zero according with the type.
9967cbed6bSLawrence Tang     UINT64* error_subinfo = (UINT64*)(error_info + 8);
10067cbed6bSLawrence Tang     switch (error_type)
10167cbed6bSLawrence Tang     {
10267cbed6bSLawrence Tang         //Cache/TLB
10367cbed6bSLawrence Tang         case 0:
10467cbed6bSLawrence Tang         case 1:
10567cbed6bSLawrence Tang             *error_subinfo &= 0xFFFFFFF;
10667cbed6bSLawrence Tang             break;
10767cbed6bSLawrence Tang 
10867cbed6bSLawrence Tang         //Bus
10967cbed6bSLawrence Tang         case 2:
11067cbed6bSLawrence Tang             *error_subinfo &= 0xFFFFFFFFFFF;
11167cbed6bSLawrence Tang             break;
11267cbed6bSLawrence Tang 
11367cbed6bSLawrence Tang         //Microarch/other.
11467cbed6bSLawrence Tang         default:
11567cbed6bSLawrence Tang             break;
11667cbed6bSLawrence Tang     }
11767cbed6bSLawrence Tang 
11867cbed6bSLawrence Tang     return error_info;
11967cbed6bSLawrence Tang }
12067cbed6bSLawrence Tang 
12167cbed6bSLawrence Tang //Generates a single pseudo-random ARM context info structure. Must be later freed.
12267cbed6bSLawrence Tang size_t generate_arm_context_info(void** location)
12367cbed6bSLawrence Tang {
12467cbed6bSLawrence Tang     //Initial length is 8 bytes. Add extra based on type.
12567cbed6bSLawrence Tang     UINT16 reg_type = rand() % 9;
12667cbed6bSLawrence Tang     UINT32 reg_size = 0;
12767cbed6bSLawrence Tang 
12867cbed6bSLawrence Tang     //Set register size.
12967cbed6bSLawrence Tang     switch (reg_type)
13067cbed6bSLawrence Tang     {
13167cbed6bSLawrence Tang         //AARCH32 GPR, AARCH32 EL2
13267cbed6bSLawrence Tang         case 0:
13367cbed6bSLawrence Tang         case 2:
13467cbed6bSLawrence Tang             reg_size = 64;
13567cbed6bSLawrence Tang             break;
13667cbed6bSLawrence Tang 
13767cbed6bSLawrence Tang         //AARCH32 EL1
13867cbed6bSLawrence Tang         case 1:
13967cbed6bSLawrence Tang             reg_size = 96;
14067cbed6bSLawrence Tang             break;
14167cbed6bSLawrence Tang 
14267cbed6bSLawrence Tang         //AARCH32 EL3
14367cbed6bSLawrence Tang         case 3:
14467cbed6bSLawrence Tang             reg_size = 8;
14567cbed6bSLawrence Tang             break;
14667cbed6bSLawrence Tang 
14767cbed6bSLawrence Tang         //AARCH64 GPR
14867cbed6bSLawrence Tang         case 4:
14967cbed6bSLawrence Tang             reg_size = 256;
15067cbed6bSLawrence Tang             break;
15167cbed6bSLawrence Tang 
15267cbed6bSLawrence Tang         //AARCH64 EL1
15367cbed6bSLawrence Tang         case 5:
15467cbed6bSLawrence Tang             reg_size = 136;
15567cbed6bSLawrence Tang             break;
15667cbed6bSLawrence Tang 
15767cbed6bSLawrence Tang         //AARCH64 EL2
15867cbed6bSLawrence Tang         case 6:
15967cbed6bSLawrence Tang             reg_size = 120;
16067cbed6bSLawrence Tang             break;
16167cbed6bSLawrence Tang 
16267cbed6bSLawrence Tang         //AARCH64 EL3
16367cbed6bSLawrence Tang         case 7:
16467cbed6bSLawrence Tang             reg_size = 80;
16567cbed6bSLawrence Tang             break;
16667cbed6bSLawrence Tang 
16767cbed6bSLawrence Tang         //Misc. single register.
16867cbed6bSLawrence Tang         case 8:
16967cbed6bSLawrence Tang             reg_size = 10;
17067cbed6bSLawrence Tang             break;
17167cbed6bSLawrence Tang     }
17267cbed6bSLawrence Tang 
17367cbed6bSLawrence Tang     //Create context structure randomly.
17467cbed6bSLawrence Tang     int total_size = 8 + reg_size;
17567cbed6bSLawrence Tang     UINT16* context_info = (UINT16*)generate_random_bytes(total_size);
17667cbed6bSLawrence Tang 
17767cbed6bSLawrence Tang     //Set header information.
17867cbed6bSLawrence Tang     *(context_info + 1) = reg_type;
17967cbed6bSLawrence Tang     *((UINT32*)(context_info + 2)) = reg_size;
18067cbed6bSLawrence Tang 
18167cbed6bSLawrence Tang     //Set return values and exit.
18267cbed6bSLawrence Tang     *location = context_info;
18367cbed6bSLawrence Tang     return total_size;
18467cbed6bSLawrence Tang }