102c801a5SLawrence Tang /**
2*efe17e2cSLawrence 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"
1167cbed6bSLawrence Tang #include "gen-sections.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 
17*efe17e2cSLawrence 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.
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 
40aacf0e26SLawrence Tang     //Null extend the end of the CPUID in the header.
41aacf0e26SLawrence Tang     for (int i=0; i<16; i++)
42aacf0e26SLawrence Tang         *(section + 48 + i) = 0x0;
43aacf0e26SLawrence Tang 
4402c801a5SLawrence Tang     //Set header information.
4502c801a5SLawrence Tang     UINT64* validation = (UINT64*)section;
4602c801a5SLawrence Tang     *validation &= 0b11;
4702c801a5SLawrence Tang     *validation |= error_structure_num << 2;
4802c801a5SLawrence Tang     *validation |= context_structure_num << 8;
4902c801a5SLawrence Tang 
5002c801a5SLawrence Tang     //Copy in structures, free resources.
5102c801a5SLawrence Tang     UINT8* cur_pos = section + 64;
5202c801a5SLawrence Tang     for (int i=0; i<error_structure_num; i++)
5302c801a5SLawrence Tang     {
5402c801a5SLawrence Tang         memcpy(cur_pos, error_structures[i], IA32X64_ERROR_STRUCTURE_SIZE);
5502c801a5SLawrence Tang         free(error_structures[i]);
5602c801a5SLawrence Tang         cur_pos += IA32X64_ERROR_STRUCTURE_SIZE;
5702c801a5SLawrence Tang     }
5802c801a5SLawrence Tang     for (int i=0; i<context_structure_num; i++)
5902c801a5SLawrence Tang     {
6002c801a5SLawrence Tang         memcpy(cur_pos, context_structures[i], context_structure_lengths[i]);
6102c801a5SLawrence Tang         free(context_structures[i]);
6202c801a5SLawrence Tang         cur_pos += context_structure_lengths[i];
6302c801a5SLawrence Tang     }
6402c801a5SLawrence Tang 
6502c801a5SLawrence Tang     //Set return values, exist.
6602c801a5SLawrence Tang     *location = section;
6702c801a5SLawrence Tang     return total_len;
6802c801a5SLawrence Tang }
6902c801a5SLawrence Tang 
7002c801a5SLawrence Tang //Generates a single IA32/x64 error structure. Must later be freed.
7102c801a5SLawrence Tang void* generate_ia32x64_error_structure()
7202c801a5SLawrence Tang {
7302c801a5SLawrence Tang     UINT8* error_structure = generate_random_bytes(IA32X64_ERROR_STRUCTURE_SIZE);
7402c801a5SLawrence Tang 
75aacf0e26SLawrence Tang     //Set error structure reserved space to zero.
76aacf0e26SLawrence Tang     UINT64* validation = (UINT64*)(error_structure + 16);
77aacf0e26SLawrence Tang     *validation &= 0x1F;
78aacf0e26SLawrence Tang 
7902c801a5SLawrence Tang     //Create a random type of error structure.
8002c801a5SLawrence Tang     EFI_GUID* guid = (EFI_GUID*)error_structure;
81aacf0e26SLawrence Tang     UINT64* check_info = (UINT64*)(error_structure + 24);
8202c801a5SLawrence Tang     int error_structure_type = rand() % 4;
8302c801a5SLawrence Tang     switch (error_structure_type)
8402c801a5SLawrence Tang     {
8502c801a5SLawrence Tang         //Cache
8602c801a5SLawrence Tang         case 0:
87d34f2b11SLawrence Tang             memcpy(guid, &gEfiIa32x64ErrorTypeCacheCheckGuid, sizeof(EFI_GUID));
88aacf0e26SLawrence Tang 
89aacf0e26SLawrence Tang             //Set reserved space to zero.
90aacf0e26SLawrence Tang             *check_info &= ~0xFF00;
91aacf0e26SLawrence Tang             *check_info &= 0x3FFFFFFF;
9202c801a5SLawrence Tang             break;
9302c801a5SLawrence Tang 
9402c801a5SLawrence Tang         //TLB
9502c801a5SLawrence Tang         case 1:
96d34f2b11SLawrence Tang             memcpy(guid, &gEfiIa32x64ErrorTypeTlbCheckGuid, sizeof(EFI_GUID));
97aacf0e26SLawrence Tang 
98aacf0e26SLawrence Tang             //Set reserved space to zero.
99aacf0e26SLawrence Tang             *check_info &= ~0xFF00;
100aacf0e26SLawrence Tang             *check_info &= 0x3FFFFFFF;
10102c801a5SLawrence Tang             break;
10202c801a5SLawrence Tang 
10302c801a5SLawrence Tang         //Bus
10402c801a5SLawrence Tang         case 2:
105d34f2b11SLawrence Tang             memcpy(guid, &gEfiIa32x64ErrorTypeBusCheckGuid, sizeof(EFI_GUID));
106aacf0e26SLawrence Tang 
107aacf0e26SLawrence Tang             //Set reserved space to zero.
108aacf0e26SLawrence Tang             *check_info &= ~0xF800;
109aacf0e26SLawrence Tang             *check_info &= 0x7FFFFFFFF;
11002c801a5SLawrence Tang             break;
11102c801a5SLawrence Tang 
11202c801a5SLawrence Tang         //MS
11302c801a5SLawrence Tang         case 3:
114d34f2b11SLawrence Tang             memcpy(guid, &gEfiIa32x64ErrorTypeMsCheckGuid, sizeof(EFI_GUID));
115aacf0e26SLawrence Tang 
116aacf0e26SLawrence Tang             //Set reserved space to zero.
11701e3a44dSLawrence Tang             *check_info &= ~0xFFE0;
118aacf0e26SLawrence Tang             *check_info &= 0xFFFFFF;
11902c801a5SLawrence Tang             break;
12002c801a5SLawrence Tang     }
12102c801a5SLawrence Tang 
12202c801a5SLawrence Tang     return error_structure;
12302c801a5SLawrence Tang }
12402c801a5SLawrence Tang 
12502c801a5SLawrence Tang //Generates a single IA32/x64 context structure. Must later be freed.
12602c801a5SLawrence Tang size_t generate_ia32x64_context_structure(void** location)
12702c801a5SLawrence Tang {
12802c801a5SLawrence Tang     //Initial length is 16 bytes. Add extra based on type.
12902c801a5SLawrence Tang     int reg_type = rand() % 8;
13002c801a5SLawrence Tang     int reg_size = 0;
13102c801a5SLawrence Tang 
13202c801a5SLawrence Tang     //Set register size.
13302c801a5SLawrence Tang     if (reg_type == 2)
13404750a9eSLawrence Tang     {
13502c801a5SLawrence Tang         reg_size = 92; //IA32 registers.
13604750a9eSLawrence Tang     }
13704750a9eSLawrence Tang     else if (reg_type == 3)
13804750a9eSLawrence Tang     {
13902c801a5SLawrence Tang         reg_size = 244; //x64 registers.
14004750a9eSLawrence Tang     }
14102c801a5SLawrence Tang     else
14204750a9eSLawrence Tang     {
14304750a9eSLawrence Tang         reg_size = (rand() % 5 + 1) * 32; //Not table defined.
14404750a9eSLawrence Tang     }
14502c801a5SLawrence Tang 
14602c801a5SLawrence Tang     //Create structure randomly.
14702c801a5SLawrence Tang     int total_size = 16 + reg_size;
14802c801a5SLawrence Tang     UINT16* context_structure = (UINT16*)generate_random_bytes(total_size);
14902c801a5SLawrence Tang 
15004750a9eSLawrence Tang     //If it is x64 registers, set reserved area accordingly.
15104750a9eSLawrence Tang     if (reg_type == 3)
15204750a9eSLawrence Tang     {
15304750a9eSLawrence Tang         UINT8* reg_bytes = (UINT8*)(context_structure + 8);
15404750a9eSLawrence Tang         UINT32* reserved = (UINT32*)(reg_bytes + 140);
15504750a9eSLawrence Tang         *reserved = 0;
15604750a9eSLawrence Tang     }
15704750a9eSLawrence Tang 
15802c801a5SLawrence Tang     //Set header information.
15902c801a5SLawrence Tang     *(context_structure) = reg_type;
16002c801a5SLawrence Tang     *(context_structure + 1) = reg_size;
16102c801a5SLawrence Tang 
16202c801a5SLawrence Tang     //Set return values and exit.
16302c801a5SLawrence Tang     *location = context_structure;
16402c801a5SLawrence Tang     return total_size;
16502c801a5SLawrence Tang }