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