102c801a5SLawrence Tang /**
202c801a5SLawrence Tang  * Functions for generating psuedo-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"
11*67cbed6bSLawrence Tang #include "gen-sections.h"
12*67cbed6bSLawrence 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 
1702c801a5SLawrence Tang //Generates a single psuedo-random IA32/x64 section, saving the resulting address to the given
1802c801a5SLawrence Tang //location. Returns the size of the newly created section.
1902c801a5SLawrence Tang size_t generate_section_ia32x64(void** location)
2002c801a5SLawrence Tang {
2102c801a5SLawrence Tang     //Set up for generation of error/context structures.
2202c801a5SLawrence Tang     UINT16 error_structure_num = rand() % 5;
2302c801a5SLawrence Tang     UINT16 context_structure_num = rand() % 5;
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.
2902c801a5SLawrence Tang     for (int i=0; i<error_structure_num; i++)
3002c801a5SLawrence Tang         error_structures[i] = generate_ia32x64_error_structure();
3102c801a5SLawrence Tang     for (int i=0; i<context_structure_num; i++)
3202c801a5SLawrence Tang         context_structure_lengths[i] = generate_ia32x64_context_structure(context_structures + i);
3302c801a5SLawrence Tang 
3402c801a5SLawrence Tang     //Create a valid IA32/x64 section.
3502c801a5SLawrence Tang     size_t total_len = 64 + (IA32X64_ERROR_STRUCTURE_SIZE * error_structure_num);
3602c801a5SLawrence Tang     for (int i=0; i<context_structure_num; i++)
3702c801a5SLawrence Tang         total_len += context_structure_lengths[i];
3802c801a5SLawrence Tang     UINT8* section = generate_random_bytes(total_len);
3902c801a5SLawrence Tang 
4002c801a5SLawrence Tang     //Set header information.
4102c801a5SLawrence Tang     UINT64* validation = (UINT64*)section;
4202c801a5SLawrence Tang     *validation &= 0b11;
4302c801a5SLawrence Tang     *validation |= error_structure_num << 2;
4402c801a5SLawrence Tang     *validation |= context_structure_num << 8;
4502c801a5SLawrence Tang 
4602c801a5SLawrence Tang     //Copy in structures, free resources.
4702c801a5SLawrence Tang     UINT8* cur_pos = section + 64;
4802c801a5SLawrence Tang     for (int i=0; i<error_structure_num; i++)
4902c801a5SLawrence Tang     {
5002c801a5SLawrence Tang         memcpy(cur_pos, error_structures[i], IA32X64_ERROR_STRUCTURE_SIZE);
5102c801a5SLawrence Tang         free(error_structures[i]);
5202c801a5SLawrence Tang         cur_pos += IA32X64_ERROR_STRUCTURE_SIZE;
5302c801a5SLawrence Tang     }
5402c801a5SLawrence Tang     for (int i=0; i<context_structure_num; i++)
5502c801a5SLawrence Tang     {
5602c801a5SLawrence Tang         memcpy(cur_pos, context_structures[i], context_structure_lengths[i]);
5702c801a5SLawrence Tang         free(context_structures[i]);
5802c801a5SLawrence Tang         cur_pos += context_structure_lengths[i];
5902c801a5SLawrence Tang     }
6002c801a5SLawrence Tang 
6102c801a5SLawrence Tang     //Set return values, exist.
6202c801a5SLawrence Tang     *location = section;
6302c801a5SLawrence Tang     return total_len;
6402c801a5SLawrence Tang }
6502c801a5SLawrence Tang 
6602c801a5SLawrence Tang //Generates a single IA32/x64 error structure. Must later be freed.
6702c801a5SLawrence Tang void* generate_ia32x64_error_structure()
6802c801a5SLawrence Tang {
6902c801a5SLawrence Tang     UINT8* error_structure = generate_random_bytes(IA32X64_ERROR_STRUCTURE_SIZE);
7002c801a5SLawrence Tang 
7102c801a5SLawrence Tang     //Create a random type of error structure.
7202c801a5SLawrence Tang     EFI_GUID* guid = (EFI_GUID*)error_structure;
7302c801a5SLawrence Tang     int error_structure_type = rand() % 4;
7402c801a5SLawrence Tang     switch (error_structure_type)
7502c801a5SLawrence Tang     {
7602c801a5SLawrence Tang         //Cache
7702c801a5SLawrence Tang         case 0:
7802c801a5SLawrence Tang             memcpy(guid, &gEfiIa32x64ErrorTypeCacheCheckGuid, sizeof(guid));
7902c801a5SLawrence Tang             memset(error_structure + 30, 0, 34);
8002c801a5SLawrence Tang             break;
8102c801a5SLawrence Tang 
8202c801a5SLawrence Tang         //TLB
8302c801a5SLawrence Tang         case 1:
8402c801a5SLawrence Tang             memcpy(guid, &gEfiIa32x64ErrorTypeTlbCheckGuid, sizeof(guid));
8502c801a5SLawrence Tang             memset(error_structure + 30, 0, 34);
8602c801a5SLawrence Tang             break;
8702c801a5SLawrence Tang 
8802c801a5SLawrence Tang         //Bus
8902c801a5SLawrence Tang         case 2:
9002c801a5SLawrence Tang             memcpy(guid, &gEfiIa32x64ErrorTypeBusCheckGuid, sizeof(guid));
9102c801a5SLawrence Tang             memset(error_structure + 35, 0, 29);
9202c801a5SLawrence Tang             break;
9302c801a5SLawrence Tang 
9402c801a5SLawrence Tang         //MS
9502c801a5SLawrence Tang         case 3:
9602c801a5SLawrence Tang             memcpy(guid, &gEfiIa32x64ErrorTypeMsCheckGuid, sizeof(guid));
9702c801a5SLawrence Tang             memset(error_structure + 24, 0, 38);
9802c801a5SLawrence Tang             break;
9902c801a5SLawrence Tang     }
10002c801a5SLawrence Tang 
10102c801a5SLawrence Tang     return error_structure;
10202c801a5SLawrence Tang }
10302c801a5SLawrence Tang 
10402c801a5SLawrence Tang //Generates a single IA32/x64 context structure. Must later be freed.
10502c801a5SLawrence Tang size_t generate_ia32x64_context_structure(void** location)
10602c801a5SLawrence Tang {
10702c801a5SLawrence Tang     //Initial length is 16 bytes. Add extra based on type.
10802c801a5SLawrence Tang     int reg_type = rand() % 8;
10902c801a5SLawrence Tang     int reg_size = 0;
11002c801a5SLawrence Tang 
11102c801a5SLawrence Tang     //Set register size.
11202c801a5SLawrence Tang     if (reg_type == 2)
11302c801a5SLawrence Tang         reg_size = 92; //IA32 registers.
11402c801a5SLawrence Tang     if (reg_type == 3)
11502c801a5SLawrence Tang         reg_size = 244; //x64 registers.
11602c801a5SLawrence Tang     else
11702c801a5SLawrence Tang         reg_size = rand() % 64; //Not table defined.
11802c801a5SLawrence Tang 
11902c801a5SLawrence Tang     //Create structure randomly.
12002c801a5SLawrence Tang     int total_size = 16 + reg_size;
12102c801a5SLawrence Tang     UINT16* context_structure = (UINT16*)generate_random_bytes(total_size);
12202c801a5SLawrence Tang 
12302c801a5SLawrence Tang     //Set header information.
12402c801a5SLawrence Tang     *(context_structure) = reg_type;
12502c801a5SLawrence Tang     *(context_structure + 1) = reg_size;
12602c801a5SLawrence Tang 
12702c801a5SLawrence Tang     //Set return values and exit.
12802c801a5SLawrence Tang     *location = context_structure;
12902c801a5SLawrence Tang     return total_size;
13002c801a5SLawrence Tang }