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