xref: /aosp_15_r20/external/arm-trusted-firmware/drivers/arm/css/sds/sds.c (revision 54fd6939e177f8ff529b10183254802c76df6d08)
1*54fd6939SJiyong Park /*
2*54fd6939SJiyong Park  * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
3*54fd6939SJiyong Park  *
4*54fd6939SJiyong Park  * SPDX-License-Identifier: BSD-3-Clause
5*54fd6939SJiyong Park  */
6*54fd6939SJiyong Park 
7*54fd6939SJiyong Park #include <assert.h>
8*54fd6939SJiyong Park #include <stdint.h>
9*54fd6939SJiyong Park #include <string.h>
10*54fd6939SJiyong Park 
11*54fd6939SJiyong Park #include <arch_helpers.h>
12*54fd6939SJiyong Park #include <common/debug.h>
13*54fd6939SJiyong Park #include <drivers/arm/css/sds.h>
14*54fd6939SJiyong Park #include <platform_def.h>
15*54fd6939SJiyong Park 
16*54fd6939SJiyong Park #include "sds_private.h"
17*54fd6939SJiyong Park 
18*54fd6939SJiyong Park /*
19*54fd6939SJiyong Park  * Variables used to track and maintain the state of the memory region reserved
20*54fd6939SJiyong Park  * for usage by the SDS framework.
21*54fd6939SJiyong Park  */
22*54fd6939SJiyong Park 
23*54fd6939SJiyong Park /* Pointer to the base of the SDS memory region */
24*54fd6939SJiyong Park static uintptr_t sds_mem_base;
25*54fd6939SJiyong Park 
26*54fd6939SJiyong Park /* Size of the SDS memory region in bytes */
27*54fd6939SJiyong Park static size_t sds_mem_size;
28*54fd6939SJiyong Park 
29*54fd6939SJiyong Park /*
30*54fd6939SJiyong Park  * Perform some non-exhaustive tests to determine whether any of the fields
31*54fd6939SJiyong Park  * within a Structure Header contain obviously invalid data.
32*54fd6939SJiyong Park  * Returns SDS_OK on success, SDS_ERR_FAIL on error.
33*54fd6939SJiyong Park  */
sds_struct_is_valid(uintptr_t header)34*54fd6939SJiyong Park static int sds_struct_is_valid(uintptr_t header)
35*54fd6939SJiyong Park {
36*54fd6939SJiyong Park 	size_t struct_size = GET_SDS_HEADER_STRUCT_SIZE(header);
37*54fd6939SJiyong Park 
38*54fd6939SJiyong Park 	/* Zero is not a valid identifier */
39*54fd6939SJiyong Park 	if (GET_SDS_HEADER_ID(header) == 0)
40*54fd6939SJiyong Park 		return SDS_ERR_FAIL;
41*54fd6939SJiyong Park 
42*54fd6939SJiyong Park 	/* Check SDS Schema version */
43*54fd6939SJiyong Park 	if (GET_SDS_HEADER_VERSION(header) == SDS_REGION_SCH_VERSION)
44*54fd6939SJiyong Park 		return SDS_ERR_FAIL;
45*54fd6939SJiyong Park 
46*54fd6939SJiyong Park 	/* The SDS Structure sizes have to be multiple of 8 */
47*54fd6939SJiyong Park 	if ((struct_size == 0) || ((struct_size % 8) != 0))
48*54fd6939SJiyong Park 		return SDS_ERR_FAIL;
49*54fd6939SJiyong Park 
50*54fd6939SJiyong Park 	if (struct_size > sds_mem_size)
51*54fd6939SJiyong Park 		return SDS_ERR_FAIL;
52*54fd6939SJiyong Park 
53*54fd6939SJiyong Park 	return SDS_OK;
54*54fd6939SJiyong Park }
55*54fd6939SJiyong Park 
56*54fd6939SJiyong Park /*
57*54fd6939SJiyong Park  * Validate the SDS structure headers.
58*54fd6939SJiyong Park  * Returns SDS_OK on success, SDS_ERR_FAIL on error.
59*54fd6939SJiyong Park  */
validate_sds_struct_headers(void)60*54fd6939SJiyong Park static int validate_sds_struct_headers(void)
61*54fd6939SJiyong Park {
62*54fd6939SJiyong Park 	unsigned int i, structure_count;
63*54fd6939SJiyong Park 	uintptr_t header;
64*54fd6939SJiyong Park 
65*54fd6939SJiyong Park 	structure_count = GET_SDS_REGION_STRUCTURE_COUNT(sds_mem_base);
66*54fd6939SJiyong Park 
67*54fd6939SJiyong Park 	if (structure_count == 0)
68*54fd6939SJiyong Park 		return SDS_ERR_FAIL;
69*54fd6939SJiyong Park 
70*54fd6939SJiyong Park 	header = sds_mem_base + SDS_REGION_DESC_SIZE;
71*54fd6939SJiyong Park 
72*54fd6939SJiyong Park 	/* Iterate over structure headers and validate each one */
73*54fd6939SJiyong Park 	for (i = 0; i < structure_count; i++) {
74*54fd6939SJiyong Park 		if (sds_struct_is_valid(header) != SDS_OK) {
75*54fd6939SJiyong Park 			WARN("SDS: Invalid structure header detected\n");
76*54fd6939SJiyong Park 			return SDS_ERR_FAIL;
77*54fd6939SJiyong Park 		}
78*54fd6939SJiyong Park 		header += GET_SDS_HEADER_STRUCT_SIZE(header) + SDS_HEADER_SIZE;
79*54fd6939SJiyong Park 	}
80*54fd6939SJiyong Park 	return SDS_OK;
81*54fd6939SJiyong Park }
82*54fd6939SJiyong Park 
83*54fd6939SJiyong Park /*
84*54fd6939SJiyong Park  * Get the structure header pointer corresponding to the structure ID.
85*54fd6939SJiyong Park  * Returns SDS_OK on success, SDS_ERR_STRUCT_NOT_FOUND on error.
86*54fd6939SJiyong Park  */
get_struct_header(uint32_t structure_id,struct_header_t ** header)87*54fd6939SJiyong Park static int get_struct_header(uint32_t structure_id, struct_header_t **header)
88*54fd6939SJiyong Park {
89*54fd6939SJiyong Park 	unsigned int i, structure_count;
90*54fd6939SJiyong Park 	uintptr_t current_header;
91*54fd6939SJiyong Park 
92*54fd6939SJiyong Park 	assert(header);
93*54fd6939SJiyong Park 
94*54fd6939SJiyong Park 	structure_count = GET_SDS_REGION_STRUCTURE_COUNT(sds_mem_base);
95*54fd6939SJiyong Park 	if (structure_count == 0)
96*54fd6939SJiyong Park 		return SDS_ERR_STRUCT_NOT_FOUND;
97*54fd6939SJiyong Park 
98*54fd6939SJiyong Park 	current_header = ((uintptr_t)sds_mem_base) + SDS_REGION_DESC_SIZE;
99*54fd6939SJiyong Park 
100*54fd6939SJiyong Park 	/* Iterate over structure headers to find one with a matching ID */
101*54fd6939SJiyong Park 	for (i = 0; i < structure_count; i++) {
102*54fd6939SJiyong Park 		if (GET_SDS_HEADER_ID(current_header) == structure_id) {
103*54fd6939SJiyong Park 			*header = (struct_header_t *)current_header;
104*54fd6939SJiyong Park 			return SDS_OK;
105*54fd6939SJiyong Park 		}
106*54fd6939SJiyong Park 		current_header += GET_SDS_HEADER_STRUCT_SIZE(current_header) +
107*54fd6939SJiyong Park 						SDS_HEADER_SIZE;
108*54fd6939SJiyong Park 	}
109*54fd6939SJiyong Park 
110*54fd6939SJiyong Park 	*header = NULL;
111*54fd6939SJiyong Park 	return SDS_ERR_STRUCT_NOT_FOUND;
112*54fd6939SJiyong Park }
113*54fd6939SJiyong Park 
114*54fd6939SJiyong Park /*
115*54fd6939SJiyong Park  * Check if a structure header corresponding to the structure ID exists.
116*54fd6939SJiyong Park  * Returns SDS_OK if structure header exists else SDS_ERR_STRUCT_NOT_FOUND
117*54fd6939SJiyong Park  * if not found.
118*54fd6939SJiyong Park  */
sds_struct_exists(unsigned int structure_id)119*54fd6939SJiyong Park int sds_struct_exists(unsigned int structure_id)
120*54fd6939SJiyong Park {
121*54fd6939SJiyong Park 	struct_header_t *header = NULL;
122*54fd6939SJiyong Park 	int ret;
123*54fd6939SJiyong Park 
124*54fd6939SJiyong Park 	ret = get_struct_header(structure_id, &header);
125*54fd6939SJiyong Park 	if (ret == SDS_OK) {
126*54fd6939SJiyong Park 		assert(header);
127*54fd6939SJiyong Park 	}
128*54fd6939SJiyong Park 
129*54fd6939SJiyong Park 	return ret;
130*54fd6939SJiyong Park }
131*54fd6939SJiyong Park 
132*54fd6939SJiyong Park /*
133*54fd6939SJiyong Park  * Read from field in the structure corresponding to `structure_id`.
134*54fd6939SJiyong Park  * `fld_off` is the offset to the field in the structure and `mode`
135*54fd6939SJiyong Park  * indicates whether cache maintenance need to performed prior to the read.
136*54fd6939SJiyong Park  * The `data` is the pointer to store the read data of size specified by `size`.
137*54fd6939SJiyong Park  * Returns SDS_OK on success or corresponding error codes on failure.
138*54fd6939SJiyong Park  */
sds_struct_read(uint32_t structure_id,unsigned int fld_off,void * data,size_t size,sds_access_mode_t mode)139*54fd6939SJiyong Park int sds_struct_read(uint32_t structure_id, unsigned int fld_off,
140*54fd6939SJiyong Park 		void *data, size_t size, sds_access_mode_t mode)
141*54fd6939SJiyong Park {
142*54fd6939SJiyong Park 	int status;
143*54fd6939SJiyong Park 	uintptr_t field_base;
144*54fd6939SJiyong Park 	struct_header_t *header = NULL;
145*54fd6939SJiyong Park 
146*54fd6939SJiyong Park 	if (!data)
147*54fd6939SJiyong Park 		return SDS_ERR_INVALID_PARAMS;
148*54fd6939SJiyong Park 
149*54fd6939SJiyong Park 	/* Check if a structure with this ID exists */
150*54fd6939SJiyong Park 	status = get_struct_header(structure_id, &header);
151*54fd6939SJiyong Park 	if (status != SDS_OK)
152*54fd6939SJiyong Park 		return status;
153*54fd6939SJiyong Park 
154*54fd6939SJiyong Park 	assert(header);
155*54fd6939SJiyong Park 
156*54fd6939SJiyong Park 	if (mode == SDS_ACCESS_MODE_CACHED)
157*54fd6939SJiyong Park 		inv_dcache_range((uintptr_t)header, SDS_HEADER_SIZE + size);
158*54fd6939SJiyong Park 
159*54fd6939SJiyong Park 	if (!IS_SDS_HEADER_VALID(header)) {
160*54fd6939SJiyong Park 		WARN("SDS: Reading from un-finalized structure 0x%x\n",
161*54fd6939SJiyong Park 				structure_id);
162*54fd6939SJiyong Park 		return SDS_ERR_STRUCT_NOT_FINALIZED;
163*54fd6939SJiyong Park 	}
164*54fd6939SJiyong Park 
165*54fd6939SJiyong Park 	if ((fld_off + size) > GET_SDS_HEADER_STRUCT_SIZE(header))
166*54fd6939SJiyong Park 		return SDS_ERR_FAIL;
167*54fd6939SJiyong Park 
168*54fd6939SJiyong Park 	field_base = (uintptr_t)header + SDS_HEADER_SIZE + fld_off;
169*54fd6939SJiyong Park 	if (check_uptr_overflow(field_base, size - 1))
170*54fd6939SJiyong Park 		return SDS_ERR_FAIL;
171*54fd6939SJiyong Park 
172*54fd6939SJiyong Park 	/* Copy the required field in the struct */
173*54fd6939SJiyong Park 	memcpy(data, (void *)field_base, size);
174*54fd6939SJiyong Park 
175*54fd6939SJiyong Park 	return SDS_OK;
176*54fd6939SJiyong Park }
177*54fd6939SJiyong Park 
178*54fd6939SJiyong Park /*
179*54fd6939SJiyong Park  * Write to the field in the structure corresponding to `structure_id`.
180*54fd6939SJiyong Park  * `fld_off` is the offset to the field in the structure and `mode`
181*54fd6939SJiyong Park  * indicates whether cache maintenance need to performed for the write.
182*54fd6939SJiyong Park  * The `data` is the pointer to data of size specified by `size`.
183*54fd6939SJiyong Park  * Returns SDS_OK on success or corresponding error codes on failure.
184*54fd6939SJiyong Park  */
sds_struct_write(uint32_t structure_id,unsigned int fld_off,void * data,size_t size,sds_access_mode_t mode)185*54fd6939SJiyong Park int sds_struct_write(uint32_t structure_id, unsigned int fld_off,
186*54fd6939SJiyong Park 		void *data, size_t size, sds_access_mode_t mode)
187*54fd6939SJiyong Park {
188*54fd6939SJiyong Park 	int status;
189*54fd6939SJiyong Park 	uintptr_t field_base;
190*54fd6939SJiyong Park 	struct_header_t *header = NULL;
191*54fd6939SJiyong Park 
192*54fd6939SJiyong Park 	if (!data)
193*54fd6939SJiyong Park 		return SDS_ERR_INVALID_PARAMS;
194*54fd6939SJiyong Park 
195*54fd6939SJiyong Park 	/* Check if a structure with this ID exists */
196*54fd6939SJiyong Park 	status = get_struct_header(structure_id, &header);
197*54fd6939SJiyong Park 	if (status != SDS_OK)
198*54fd6939SJiyong Park 		return status;
199*54fd6939SJiyong Park 
200*54fd6939SJiyong Park 	assert(header);
201*54fd6939SJiyong Park 
202*54fd6939SJiyong Park 	if (mode == SDS_ACCESS_MODE_CACHED)
203*54fd6939SJiyong Park 		inv_dcache_range((uintptr_t)header, SDS_HEADER_SIZE + size);
204*54fd6939SJiyong Park 
205*54fd6939SJiyong Park 	if (!IS_SDS_HEADER_VALID(header)) {
206*54fd6939SJiyong Park 		WARN("SDS: Writing to un-finalized structure 0x%x\n",
207*54fd6939SJiyong Park 				structure_id);
208*54fd6939SJiyong Park 		return SDS_ERR_STRUCT_NOT_FINALIZED;
209*54fd6939SJiyong Park 	}
210*54fd6939SJiyong Park 
211*54fd6939SJiyong Park 	if ((fld_off + size) > GET_SDS_HEADER_STRUCT_SIZE(header))
212*54fd6939SJiyong Park 		return SDS_ERR_FAIL;
213*54fd6939SJiyong Park 
214*54fd6939SJiyong Park 	field_base = (uintptr_t)header + SDS_HEADER_SIZE + fld_off;
215*54fd6939SJiyong Park 	if (check_uptr_overflow(field_base, size - 1))
216*54fd6939SJiyong Park 		return SDS_ERR_FAIL;
217*54fd6939SJiyong Park 
218*54fd6939SJiyong Park 	/* Copy the required field in the struct */
219*54fd6939SJiyong Park 	memcpy((void *)field_base, data, size);
220*54fd6939SJiyong Park 
221*54fd6939SJiyong Park 	if (mode == SDS_ACCESS_MODE_CACHED)
222*54fd6939SJiyong Park 		flush_dcache_range((uintptr_t)field_base, size);
223*54fd6939SJiyong Park 
224*54fd6939SJiyong Park 	return SDS_OK;
225*54fd6939SJiyong Park }
226*54fd6939SJiyong Park 
227*54fd6939SJiyong Park /*
228*54fd6939SJiyong Park  * Initialize the SDS driver. Also verifies the SDS version and sanity of
229*54fd6939SJiyong Park  * the SDS structure headers.
230*54fd6939SJiyong Park  * Returns SDS_OK on success, SDS_ERR_FAIL on error.
231*54fd6939SJiyong Park  */
sds_init(void)232*54fd6939SJiyong Park int sds_init(void)
233*54fd6939SJiyong Park {
234*54fd6939SJiyong Park 	sds_mem_base = (uintptr_t)PLAT_ARM_SDS_MEM_BASE;
235*54fd6939SJiyong Park 
236*54fd6939SJiyong Park 	if (!IS_SDS_REGION_VALID(sds_mem_base)) {
237*54fd6939SJiyong Park 		WARN("SDS: No valid SDS Memory Region found\n");
238*54fd6939SJiyong Park 		return SDS_ERR_FAIL;
239*54fd6939SJiyong Park 	}
240*54fd6939SJiyong Park 
241*54fd6939SJiyong Park 	if (GET_SDS_REGION_SCHEMA_VERSION(sds_mem_base)
242*54fd6939SJiyong Park 				!= SDS_REGION_SCH_VERSION) {
243*54fd6939SJiyong Park 		WARN("SDS: Unsupported SDS schema version\n");
244*54fd6939SJiyong Park 		return SDS_ERR_FAIL;
245*54fd6939SJiyong Park 	}
246*54fd6939SJiyong Park 
247*54fd6939SJiyong Park 	sds_mem_size = GET_SDS_REGION_SIZE(sds_mem_base);
248*54fd6939SJiyong Park 	if (sds_mem_size > PLAT_ARM_SDS_MEM_SIZE_MAX) {
249*54fd6939SJiyong Park 		WARN("SDS: SDS Memory Region exceeds size limit\n");
250*54fd6939SJiyong Park 		return SDS_ERR_FAIL;
251*54fd6939SJiyong Park 	}
252*54fd6939SJiyong Park 
253*54fd6939SJiyong Park 	INFO("SDS: Detected SDS Memory Region (%zu bytes)\n", sds_mem_size);
254*54fd6939SJiyong Park 
255*54fd6939SJiyong Park 	if (validate_sds_struct_headers() != SDS_OK)
256*54fd6939SJiyong Park 		return SDS_ERR_FAIL;
257*54fd6939SJiyong Park 
258*54fd6939SJiyong Park 	return SDS_OK;
259*54fd6939SJiyong Park }
260