1de9707f9SLawrence Tang /**
2de9707f9SLawrence Tang  * Functions for generating psuedo-random CXL protocol error sections.
3de9707f9SLawrence Tang  *
4de9707f9SLawrence Tang  * Author: Lawrence.Tang@arm.com
5de9707f9SLawrence Tang  **/
6de9707f9SLawrence Tang 
7de9707f9SLawrence Tang #include <stdlib.h>
8de9707f9SLawrence Tang #include "../../edk/BaseTypes.h"
9de9707f9SLawrence Tang #include "../gen-utils.h"
10de9707f9SLawrence Tang #include "gen-sections.h"
11de9707f9SLawrence Tang 
12de9707f9SLawrence Tang //Generates a single psuedo-random CXL protocol error section, saving the resulting address to the given
13de9707f9SLawrence Tang //location. Returns the size of the newly created section.
14de9707f9SLawrence Tang size_t generate_section_cxl_protocol(void** location)
15de9707f9SLawrence Tang {
16de9707f9SLawrence Tang     //Create a random length for the CXL DVSEC and CXL error log.
17de9707f9SLawrence Tang     //The logs attached here do not necessarily conform to the specification, and are simply random.
18de9707f9SLawrence Tang     int dvsec_len = rand() % 64;
19de9707f9SLawrence Tang     int error_log_len = rand() % 64;
20de9707f9SLawrence Tang 
21de9707f9SLawrence Tang     //Create random bytes.
22de9707f9SLawrence Tang     int size = 116 + dvsec_len + error_log_len;
23de9707f9SLawrence Tang     UINT8* bytes = generate_random_bytes(size);
24de9707f9SLawrence Tang 
25de9707f9SLawrence Tang     //Set CXL agent type.
26de9707f9SLawrence Tang     int cxl_agent_type = rand() % 2;
27de9707f9SLawrence Tang     *(bytes + 8) = cxl_agent_type;
28de9707f9SLawrence Tang 
29de9707f9SLawrence Tang     //Set reserved areas to zero.
30de9707f9SLawrence Tang     UINT64* validation = (UINT64*)bytes;
31de9707f9SLawrence Tang     *validation &= 0b111111; //Validation bits 6-63.
32de9707f9SLawrence Tang     for (int i=0; i<7; i++)
33de9707f9SLawrence Tang         *(bytes + 9 + i) = 0; //Reserved bytes 9-15.
34de9707f9SLawrence Tang 
35de9707f9SLawrence Tang     //We only reserve bytes if it's a CXL 1.1 device, and not a host downstream port.
36de9707f9SLawrence Tang     if (cxl_agent_type == 0)
37de9707f9SLawrence Tang     {
38de9707f9SLawrence Tang         for (int i=0; i<3; i++)
39de9707f9SLawrence Tang             *(bytes + 20 + i) = 0; //CXL agent address bytes 5-7.
40de9707f9SLawrence Tang     }
41de9707f9SLawrence Tang 
42de9707f9SLawrence Tang     *(bytes + 34) &= ~0b111; //Device ID byte 10 bits 0-2.
43de9707f9SLawrence Tang     UINT32* reserved = (UINT32*)(bytes + 36);
44de9707f9SLawrence Tang     *reserved = 0; //Device ID bytes 12-15.
45de9707f9SLawrence Tang     reserved = (UINT32*)(bytes + 112);
46de9707f9SLawrence Tang     *reserved = 0; //Reserved bytes 112-115.
47de9707f9SLawrence Tang 
48*0a4b3f2dSLawrence Tang     //If the device is a host downstream port, serial/capability structure is invalid.
49*0a4b3f2dSLawrence Tang     if (cxl_agent_type != 0)
50*0a4b3f2dSLawrence Tang     {
51*0a4b3f2dSLawrence Tang         for (int i=0; i<68; i++)
52*0a4b3f2dSLawrence Tang             *(bytes + 40 + i) = 0; //Device serial & capability structure.
53*0a4b3f2dSLawrence Tang     }
54*0a4b3f2dSLawrence Tang 
55de9707f9SLawrence Tang     //Set expected values.
56de9707f9SLawrence Tang     UINT16* dvsec_length_field = (UINT16*)(bytes + 108);
57de9707f9SLawrence Tang     UINT16* error_log_len_field = (UINT16*)(bytes + 110);
58de9707f9SLawrence Tang     *dvsec_length_field = dvsec_len;
59de9707f9SLawrence Tang     *error_log_len_field = error_log_len;
60de9707f9SLawrence Tang 
61de9707f9SLawrence Tang     //Set return values, exit.
62de9707f9SLawrence Tang     *location = bytes;
63de9707f9SLawrence Tang     return size;
64de9707f9SLawrence Tang }