1de9707f9SLawrence Tang /**
2efe17e2cSLawrence Tang  * Functions for generating pseudo-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"
108f977457SLawrence Tang #include "gen-section.h"
11de9707f9SLawrence Tang 
12efe17e2cSLawrence Tang //Generates a single pseudo-random CXL protocol error section, saving the resulting address to the given
13de9707f9SLawrence Tang //location. Returns the size of the newly created section.
generate_section_cxl_protocol(void ** location)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;
31*f8fc7052SJohn Chung 	*validation &= 0x3F;	      //Validation bits 6-63.
32*f8fc7052SJohn Chung 	for (int i = 0; i < 7; i++) {
33de9707f9SLawrence Tang 		*(bytes + 9 + i) = 0; //Reserved bytes 9-15.
34de9707f9SLawrence Tang 	}
35de9707f9SLawrence Tang 
36*f8fc7052SJohn Chung 	//We only reserve bytes if it's a CXL 1.1 device, and not a host downstream port.
37*f8fc7052SJohn Chung 	if (cxl_agent_type == 0) {
38*f8fc7052SJohn Chung 		for (int i = 0; i < 3; i++) {
39*f8fc7052SJohn Chung 			*(bytes + 21 + i) = 0; //CXL agent address bytes 5-7.
40*f8fc7052SJohn Chung 		}
41*f8fc7052SJohn Chung 	}
42*f8fc7052SJohn Chung 
43*f8fc7052SJohn Chung 	*(bytes + 34) &= ~0x7; //Device ID byte 10 bits 0-2.
44de9707f9SLawrence Tang 	UINT32 *reserved = (UINT32 *)(bytes + 36);
45de9707f9SLawrence Tang 	*reserved = 0;	       //Device ID bytes 12-15.
46de9707f9SLawrence Tang 	reserved = (UINT32 *)(bytes + 112);
47de9707f9SLawrence Tang 	*reserved = 0;	       //Reserved bytes 112-115.
48de9707f9SLawrence Tang 
490a4b3f2dSLawrence Tang 	//If the device is a host downstream port, serial/capability structure is invalid.
50*f8fc7052SJohn Chung 	if (cxl_agent_type != 0) {
51*f8fc7052SJohn Chung 		for (int i = 0; i < 68; i++) {
52*f8fc7052SJohn Chung 			*(bytes + 40 + i) =
53*f8fc7052SJohn Chung 				0; //Device serial & capability structure.
54*f8fc7052SJohn Chung 		}
550a4b3f2dSLawrence Tang 	}
560a4b3f2dSLawrence Tang 
57de9707f9SLawrence Tang 	//Set expected values.
58de9707f9SLawrence Tang 	UINT16 *dvsec_length_field = (UINT16 *)(bytes + 108);
59de9707f9SLawrence Tang 	UINT16 *error_log_len_field = (UINT16 *)(bytes + 110);
60de9707f9SLawrence Tang 	*dvsec_length_field = dvsec_len;
61de9707f9SLawrence Tang 	*error_log_len_field = error_log_len;
62de9707f9SLawrence Tang 
63de9707f9SLawrence Tang 	//Set return values, exit.
64de9707f9SLawrence Tang 	*location = bytes;
65de9707f9SLawrence Tang 	return size;
66de9707f9SLawrence Tang }
67