2 * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
4 * SPDX-License-Identifier: BSD-3-Clause
7 #include <arch_helpers.h>
15 #include "sds_private.h"
18 * Variables used to track and maintain the state of the memory region reserved
19 * for usage by the SDS framework.
22 /* Pointer to the base of the SDS memory region */
23 static uintptr_t sds_mem_base
;
25 /* Size of the SDS memory region in bytes */
26 static size_t sds_mem_size
;
29 * Perform some non-exhaustive tests to determine whether any of the fields
30 * within a Structure Header contain obviously invalid data.
31 * Returns SDS_OK on success, SDS_ERR_FAIL on error.
33 static int sds_struct_is_valid(uintptr_t header
)
35 size_t struct_size
= GET_SDS_HEADER_STRUCT_SIZE(header
);
37 /* Zero is not a valid identifier */
38 if (GET_SDS_HEADER_ID(header
) == 0)
41 /* Check SDS Schema version */
42 if (GET_SDS_HEADER_VERSION(header
) == SDS_REGION_SCH_VERSION
)
45 /* The SDS Structure sizes have to be multiple of 8 */
46 if ((struct_size
== 0) || ((struct_size
% 8) != 0))
49 if (struct_size
> sds_mem_size
)
56 * Validate the SDS structure headers.
57 * Returns SDS_OK on success, SDS_ERR_FAIL on error.
59 static int validate_sds_struct_headers(void)
61 unsigned int i
, structure_count
;
64 structure_count
= GET_SDS_REGION_STRUCTURE_COUNT(sds_mem_base
);
66 if (structure_count
== 0)
69 header
= sds_mem_base
+ SDS_REGION_DESC_SIZE
;
71 /* Iterate over structure headers and validate each one */
72 for (i
= 0; i
< structure_count
; i
++) {
73 if (sds_struct_is_valid(header
) != SDS_OK
) {
74 WARN("SDS: Invalid structure header detected\n");
77 header
+= GET_SDS_HEADER_STRUCT_SIZE(header
) + SDS_HEADER_SIZE
;
83 * Get the structure header pointer corresponding to the structure ID.
84 * Returns SDS_OK on success, SDS_ERR_STRUCT_NOT_FOUND on error.
86 static int get_struct_header(uint32_t structure_id
, struct_header_t
**header
)
88 unsigned int i
, structure_count
;
89 uintptr_t current_header
;
93 structure_count
= GET_SDS_REGION_STRUCTURE_COUNT(sds_mem_base
);
94 if (structure_count
== 0)
95 return SDS_ERR_STRUCT_NOT_FOUND
;
97 current_header
= ((uintptr_t)sds_mem_base
) + SDS_REGION_DESC_SIZE
;
99 /* Iterate over structure headers to find one with a matching ID */
100 for (i
= 0; i
< structure_count
; i
++) {
101 if (GET_SDS_HEADER_ID(current_header
) == structure_id
) {
102 *header
= (struct_header_t
*)current_header
;
105 current_header
+= GET_SDS_HEADER_STRUCT_SIZE(current_header
) +
110 return SDS_ERR_STRUCT_NOT_FOUND
;
114 * Check if a structure header corresponding to the structure ID exists.
115 * Returns SDS_OK if structure header exists else SDS_ERR_STRUCT_NOT_FOUND
118 int sds_struct_exists(unsigned int structure_id
)
120 struct_header_t
*header
= NULL
;
123 ret
= get_struct_header(structure_id
, &header
);
132 * Read from field in the structure corresponding to `structure_id`.
133 * `fld_off` is the offset to the field in the structure and `mode`
134 * indicates whether cache maintenance need to performed prior to the read.
135 * The `data` is the pointer to store the read data of size specified by `size`.
136 * Returns SDS_OK on success or corresponding error codes on failure.
138 int sds_struct_read(uint32_t structure_id
, unsigned int fld_off
,
139 void *data
, size_t size
, sds_access_mode_t mode
)
142 uintptr_t field_base
;
143 struct_header_t
*header
= NULL
;
146 return SDS_ERR_INVALID_PARAMS
;
148 /* Check if a structure with this ID exists */
149 status
= get_struct_header(structure_id
, &header
);
150 if (status
!= SDS_OK
)
155 if (mode
== SDS_ACCESS_MODE_CACHED
)
156 inv_dcache_range((uintptr_t)header
, SDS_HEADER_SIZE
+ size
);
158 if (!IS_SDS_HEADER_VALID(header
)) {
159 WARN("SDS: Reading from un-finalized structure 0x%x\n",
161 return SDS_ERR_STRUCT_NOT_FINALIZED
;
164 if ((fld_off
+ size
) > GET_SDS_HEADER_STRUCT_SIZE(header
))
167 field_base
= (uintptr_t)header
+ SDS_HEADER_SIZE
+ fld_off
;
168 if (check_uptr_overflow(field_base
, size
- 1))
171 /* Copy the required field in the struct */
172 memcpy(data
, (void *)field_base
, size
);
178 * Write to the field in the structure corresponding to `structure_id`.
179 * `fld_off` is the offset to the field in the structure and `mode`
180 * indicates whether cache maintenance need to performed for the write.
181 * The `data` is the pointer to data of size specified by `size`.
182 * Returns SDS_OK on success or corresponding error codes on failure.
184 int sds_struct_write(uint32_t structure_id
, unsigned int fld_off
,
185 void *data
, size_t size
, sds_access_mode_t mode
)
188 uintptr_t field_base
;
189 struct_header_t
*header
= NULL
;
192 return SDS_ERR_INVALID_PARAMS
;
194 /* Check if a structure with this ID exists */
195 status
= get_struct_header(structure_id
, &header
);
196 if (status
!= SDS_OK
)
201 if (mode
== SDS_ACCESS_MODE_CACHED
)
202 inv_dcache_range((uintptr_t)header
, SDS_HEADER_SIZE
+ size
);
204 if (!IS_SDS_HEADER_VALID(header
)) {
205 WARN("SDS: Writing to un-finalized structure 0x%x\n",
207 return SDS_ERR_STRUCT_NOT_FINALIZED
;
210 if ((fld_off
+ size
) > GET_SDS_HEADER_STRUCT_SIZE(header
))
213 field_base
= (uintptr_t)header
+ SDS_HEADER_SIZE
+ fld_off
;
214 if (check_uptr_overflow(field_base
, size
- 1))
217 /* Copy the required field in the struct */
218 memcpy((void *)field_base
, data
, size
);
220 if (mode
== SDS_ACCESS_MODE_CACHED
)
221 flush_dcache_range((uintptr_t)field_base
, size
);
227 * Initialize the SDS driver. Also verifies the SDS version and sanity of
228 * the SDS structure headers.
229 * Returns SDS_OK on success, SDS_ERR_FAIL on error.
233 sds_mem_base
= (uintptr_t)PLAT_ARM_SDS_MEM_BASE
;
235 if (!IS_SDS_REGION_VALID(sds_mem_base
)) {
236 WARN("SDS: No valid SDS Memory Region found\n");
240 if (GET_SDS_REGION_SCHEMA_VERSION(sds_mem_base
)
241 != SDS_REGION_SCH_VERSION
) {
242 WARN("SDS: Unsupported SDS schema version\n");
246 sds_mem_size
= GET_SDS_REGION_SIZE(sds_mem_base
);
247 if (sds_mem_size
> PLAT_ARM_SDS_MEM_SIZE_MAX
) {
248 WARN("SDS: SDS Memory Region exceeds size limit\n");
252 INFO("SDS: Detected SDS Memory Region (%zu bytes)\n", sds_mem_size
);
254 if (validate_sds_struct_headers() != SDS_OK
)