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>
9*01e3a44dSLawrence Tang #include <stdio.h>
1002c801a5SLawrence Tang #include "../../edk/Cper.h"
1102c801a5SLawrence Tang #include "../gen-utils.h"
1267cbed6bSLawrence Tang #include "gen-sections.h"
1367cbed6bSLawrence Tang #define IA32X64_ERROR_STRUCTURE_SIZE 64
1402c801a5SLawrence Tang 
1502c801a5SLawrence Tang void* generate_ia32x64_error_structure();
1602c801a5SLawrence Tang size_t generate_ia32x64_context_structure(void** location);
1702c801a5SLawrence Tang 
1802c801a5SLawrence Tang //Generates a single psuedo-random IA32/x64 section, saving the resulting address to the given
1902c801a5SLawrence Tang //location. Returns the size of the newly created section.
2002c801a5SLawrence Tang size_t generate_section_ia32x64(void** location)
2102c801a5SLawrence Tang {
2202c801a5SLawrence Tang     //Set up for generation of error/context structures.
2302c801a5SLawrence Tang     UINT16 error_structure_num = rand() % 5;
2402c801a5SLawrence Tang     UINT16 context_structure_num = rand() % 5;
2502c801a5SLawrence Tang     void* error_structures[error_structure_num];
2602c801a5SLawrence Tang     void* context_structures[context_structure_num];
2702c801a5SLawrence Tang     size_t context_structure_lengths[context_structure_num];
2802c801a5SLawrence Tang 
2902c801a5SLawrence Tang     //Generate the structures.
3002c801a5SLawrence Tang     for (int i=0; i<error_structure_num; i++)
3102c801a5SLawrence Tang         error_structures[i] = generate_ia32x64_error_structure();
3202c801a5SLawrence Tang     for (int i=0; i<context_structure_num; i++)
3302c801a5SLawrence Tang         context_structure_lengths[i] = generate_ia32x64_context_structure(context_structures + i);
3402c801a5SLawrence Tang 
3502c801a5SLawrence Tang     //Create a valid IA32/x64 section.
3602c801a5SLawrence Tang     size_t total_len = 64 + (IA32X64_ERROR_STRUCTURE_SIZE * error_structure_num);
3702c801a5SLawrence Tang     for (int i=0; i<context_structure_num; i++)
3802c801a5SLawrence Tang         total_len += context_structure_lengths[i];
3902c801a5SLawrence Tang     UINT8* section = generate_random_bytes(total_len);
4002c801a5SLawrence Tang 
41aacf0e26SLawrence Tang     //Null extend the end of the CPUID in the header.
42aacf0e26SLawrence Tang     for (int i=0; i<16; i++)
43aacf0e26SLawrence Tang         *(section + 48 + i) = 0x0;
44aacf0e26SLawrence Tang 
4502c801a5SLawrence Tang     //Set header information.
4602c801a5SLawrence Tang     UINT64* validation = (UINT64*)section;
4702c801a5SLawrence Tang     *validation &= 0b11;
4802c801a5SLawrence Tang     *validation |= error_structure_num << 2;
4902c801a5SLawrence Tang     *validation |= context_structure_num << 8;
5002c801a5SLawrence Tang 
5102c801a5SLawrence Tang     //Copy in structures, free resources.
5202c801a5SLawrence Tang     UINT8* cur_pos = section + 64;
5302c801a5SLawrence Tang     for (int i=0; i<error_structure_num; i++)
5402c801a5SLawrence Tang     {
5502c801a5SLawrence Tang         memcpy(cur_pos, error_structures[i], IA32X64_ERROR_STRUCTURE_SIZE);
5602c801a5SLawrence Tang         free(error_structures[i]);
5702c801a5SLawrence Tang         cur_pos += IA32X64_ERROR_STRUCTURE_SIZE;
5802c801a5SLawrence Tang     }
5902c801a5SLawrence Tang     for (int i=0; i<context_structure_num; i++)
6002c801a5SLawrence Tang     {
6102c801a5SLawrence Tang         memcpy(cur_pos, context_structures[i], context_structure_lengths[i]);
6202c801a5SLawrence Tang         free(context_structures[i]);
6302c801a5SLawrence Tang         cur_pos += context_structure_lengths[i];
6402c801a5SLawrence Tang     }
6502c801a5SLawrence Tang 
6602c801a5SLawrence Tang     //Set return values, exist.
6702c801a5SLawrence Tang     *location = section;
6802c801a5SLawrence Tang     return total_len;
6902c801a5SLawrence Tang }
7002c801a5SLawrence Tang 
7102c801a5SLawrence Tang //Generates a single IA32/x64 error structure. Must later be freed.
7202c801a5SLawrence Tang void* generate_ia32x64_error_structure()
7302c801a5SLawrence Tang {
7402c801a5SLawrence Tang     UINT8* error_structure = generate_random_bytes(IA32X64_ERROR_STRUCTURE_SIZE);
7502c801a5SLawrence Tang 
76aacf0e26SLawrence Tang     //Set error structure reserved space to zero.
77aacf0e26SLawrence Tang     UINT64* validation = (UINT64*)(error_structure + 16);
78aacf0e26SLawrence Tang     *validation &= 0x1F;
79aacf0e26SLawrence Tang 
8002c801a5SLawrence Tang     //Create a random type of error structure.
8102c801a5SLawrence Tang     EFI_GUID* guid = (EFI_GUID*)error_structure;
82aacf0e26SLawrence Tang     UINT64* check_info = (UINT64*)(error_structure + 24);
8302c801a5SLawrence Tang     int error_structure_type = rand() % 4;
8402c801a5SLawrence Tang     switch (error_structure_type)
8502c801a5SLawrence Tang     {
8602c801a5SLawrence Tang         //Cache
8702c801a5SLawrence Tang         case 0:
88d34f2b11SLawrence Tang             memcpy(guid, &gEfiIa32x64ErrorTypeCacheCheckGuid, sizeof(EFI_GUID));
89aacf0e26SLawrence Tang 
90aacf0e26SLawrence Tang             //Set reserved space to zero.
91aacf0e26SLawrence Tang             *check_info &= ~0xFF00;
92aacf0e26SLawrence Tang             *check_info &= 0x3FFFFFFF;
9302c801a5SLawrence Tang             break;
9402c801a5SLawrence Tang 
9502c801a5SLawrence Tang         //TLB
9602c801a5SLawrence Tang         case 1:
97d34f2b11SLawrence Tang             memcpy(guid, &gEfiIa32x64ErrorTypeTlbCheckGuid, sizeof(EFI_GUID));
98aacf0e26SLawrence Tang 
99aacf0e26SLawrence Tang             //Set reserved space to zero.
100aacf0e26SLawrence Tang             *check_info &= ~0xFF00;
101aacf0e26SLawrence Tang             *check_info &= 0x3FFFFFFF;
10202c801a5SLawrence Tang             break;
10302c801a5SLawrence Tang 
10402c801a5SLawrence Tang         //Bus
10502c801a5SLawrence Tang         case 2:
106d34f2b11SLawrence Tang             memcpy(guid, &gEfiIa32x64ErrorTypeBusCheckGuid, sizeof(EFI_GUID));
107aacf0e26SLawrence Tang 
108aacf0e26SLawrence Tang             //Set reserved space to zero.
109aacf0e26SLawrence Tang             *check_info &= ~0xF800;
110aacf0e26SLawrence Tang             *check_info &= 0x7FFFFFFFF;
11102c801a5SLawrence Tang             break;
11202c801a5SLawrence Tang 
11302c801a5SLawrence Tang         //MS
11402c801a5SLawrence Tang         case 3:
115d34f2b11SLawrence Tang             memcpy(guid, &gEfiIa32x64ErrorTypeMsCheckGuid, sizeof(EFI_GUID));
116aacf0e26SLawrence Tang 
117aacf0e26SLawrence Tang             //Set reserved space to zero.
118*01e3a44dSLawrence Tang             *check_info &= ~0xFFE0;
119aacf0e26SLawrence Tang             *check_info &= 0xFFFFFF;
12002c801a5SLawrence Tang             break;
12102c801a5SLawrence Tang     }
12202c801a5SLawrence Tang 
12302c801a5SLawrence Tang     return error_structure;
12402c801a5SLawrence Tang }
12502c801a5SLawrence Tang 
12602c801a5SLawrence Tang //Generates a single IA32/x64 context structure. Must later be freed.
12702c801a5SLawrence Tang size_t generate_ia32x64_context_structure(void** location)
12802c801a5SLawrence Tang {
12902c801a5SLawrence Tang     //Initial length is 16 bytes. Add extra based on type.
13002c801a5SLawrence Tang     int reg_type = rand() % 8;
13102c801a5SLawrence Tang     int reg_size = 0;
13202c801a5SLawrence Tang 
13302c801a5SLawrence Tang     //Set register size.
13402c801a5SLawrence Tang     if (reg_type == 2)
13502c801a5SLawrence Tang         reg_size = 92; //IA32 registers.
13602c801a5SLawrence Tang     if (reg_type == 3)
13702c801a5SLawrence Tang         reg_size = 244; //x64 registers.
13802c801a5SLawrence Tang     else
139*01e3a44dSLawrence Tang         reg_size = (rand() % 5) * 32; //Not table defined.
14002c801a5SLawrence Tang 
14102c801a5SLawrence Tang     //Create structure randomly.
14202c801a5SLawrence Tang     int total_size = 16 + reg_size;
14302c801a5SLawrence Tang     UINT16* context_structure = (UINT16*)generate_random_bytes(total_size);
14402c801a5SLawrence Tang 
14502c801a5SLawrence Tang     //Set header information.
14602c801a5SLawrence Tang     *(context_structure) = reg_type;
14702c801a5SLawrence Tang     *(context_structure + 1) = reg_size;
148*01e3a44dSLawrence Tang     printf("set reg size to %d (for type %d).\n", reg_size, reg_type);
14902c801a5SLawrence Tang 
15002c801a5SLawrence Tang     //Set return values and exit.
15102c801a5SLawrence Tang     *location = context_structure;
15202c801a5SLawrence Tang     return total_size;
15302c801a5SLawrence Tang }