GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include <common/debug.h>
|
||||
#include <drivers/arm/css/sds.h>
|
||||
#include <platform_def.h>
|
||||
|
||||
#include "sds_private.h"
|
||||
|
||||
/*
|
||||
* Variables used to track and maintain the state of the memory region reserved
|
||||
* for usage by the SDS framework.
|
||||
*/
|
||||
|
||||
/* Pointer to the base of the SDS memory region */
|
||||
static uintptr_t sds_mem_base;
|
||||
|
||||
/* Size of the SDS memory region in bytes */
|
||||
static size_t sds_mem_size;
|
||||
|
||||
/*
|
||||
* Perform some non-exhaustive tests to determine whether any of the fields
|
||||
* within a Structure Header contain obviously invalid data.
|
||||
* Returns SDS_OK on success, SDS_ERR_FAIL on error.
|
||||
*/
|
||||
static int sds_struct_is_valid(uintptr_t header)
|
||||
{
|
||||
size_t struct_size = GET_SDS_HEADER_STRUCT_SIZE(header);
|
||||
|
||||
/* Zero is not a valid identifier */
|
||||
if (GET_SDS_HEADER_ID(header) == 0)
|
||||
return SDS_ERR_FAIL;
|
||||
|
||||
/* Check SDS Schema version */
|
||||
if (GET_SDS_HEADER_VERSION(header) == SDS_REGION_SCH_VERSION)
|
||||
return SDS_ERR_FAIL;
|
||||
|
||||
/* The SDS Structure sizes have to be multiple of 8 */
|
||||
if ((struct_size == 0) || ((struct_size % 8) != 0))
|
||||
return SDS_ERR_FAIL;
|
||||
|
||||
if (struct_size > sds_mem_size)
|
||||
return SDS_ERR_FAIL;
|
||||
|
||||
return SDS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate the SDS structure headers.
|
||||
* Returns SDS_OK on success, SDS_ERR_FAIL on error.
|
||||
*/
|
||||
static int validate_sds_struct_headers(void)
|
||||
{
|
||||
unsigned int i, structure_count;
|
||||
uintptr_t header;
|
||||
|
||||
structure_count = GET_SDS_REGION_STRUCTURE_COUNT(sds_mem_base);
|
||||
|
||||
if (structure_count == 0)
|
||||
return SDS_ERR_FAIL;
|
||||
|
||||
header = sds_mem_base + SDS_REGION_DESC_SIZE;
|
||||
|
||||
/* Iterate over structure headers and validate each one */
|
||||
for (i = 0; i < structure_count; i++) {
|
||||
if (sds_struct_is_valid(header) != SDS_OK) {
|
||||
WARN("SDS: Invalid structure header detected\n");
|
||||
return SDS_ERR_FAIL;
|
||||
}
|
||||
header += GET_SDS_HEADER_STRUCT_SIZE(header) + SDS_HEADER_SIZE;
|
||||
}
|
||||
return SDS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the structure header pointer corresponding to the structure ID.
|
||||
* Returns SDS_OK on success, SDS_ERR_STRUCT_NOT_FOUND on error.
|
||||
*/
|
||||
static int get_struct_header(uint32_t structure_id, struct_header_t **header)
|
||||
{
|
||||
unsigned int i, structure_count;
|
||||
uintptr_t current_header;
|
||||
|
||||
assert(header);
|
||||
|
||||
structure_count = GET_SDS_REGION_STRUCTURE_COUNT(sds_mem_base);
|
||||
if (structure_count == 0)
|
||||
return SDS_ERR_STRUCT_NOT_FOUND;
|
||||
|
||||
current_header = ((uintptr_t)sds_mem_base) + SDS_REGION_DESC_SIZE;
|
||||
|
||||
/* Iterate over structure headers to find one with a matching ID */
|
||||
for (i = 0; i < structure_count; i++) {
|
||||
if (GET_SDS_HEADER_ID(current_header) == structure_id) {
|
||||
*header = (struct_header_t *)current_header;
|
||||
return SDS_OK;
|
||||
}
|
||||
current_header += GET_SDS_HEADER_STRUCT_SIZE(current_header) +
|
||||
SDS_HEADER_SIZE;
|
||||
}
|
||||
|
||||
*header = NULL;
|
||||
return SDS_ERR_STRUCT_NOT_FOUND;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if a structure header corresponding to the structure ID exists.
|
||||
* Returns SDS_OK if structure header exists else SDS_ERR_STRUCT_NOT_FOUND
|
||||
* if not found.
|
||||
*/
|
||||
int sds_struct_exists(unsigned int structure_id)
|
||||
{
|
||||
struct_header_t *header = NULL;
|
||||
int ret;
|
||||
|
||||
ret = get_struct_header(structure_id, &header);
|
||||
if (ret == SDS_OK) {
|
||||
assert(header);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read from field in the structure corresponding to `structure_id`.
|
||||
* `fld_off` is the offset to the field in the structure and `mode`
|
||||
* indicates whether cache maintenance need to performed prior to the read.
|
||||
* The `data` is the pointer to store the read data of size specified by `size`.
|
||||
* Returns SDS_OK on success or corresponding error codes on failure.
|
||||
*/
|
||||
int sds_struct_read(uint32_t structure_id, unsigned int fld_off,
|
||||
void *data, size_t size, sds_access_mode_t mode)
|
||||
{
|
||||
int status;
|
||||
uintptr_t field_base;
|
||||
struct_header_t *header = NULL;
|
||||
|
||||
if (!data)
|
||||
return SDS_ERR_INVALID_PARAMS;
|
||||
|
||||
/* Check if a structure with this ID exists */
|
||||
status = get_struct_header(structure_id, &header);
|
||||
if (status != SDS_OK)
|
||||
return status;
|
||||
|
||||
assert(header);
|
||||
|
||||
if (mode == SDS_ACCESS_MODE_CACHED)
|
||||
inv_dcache_range((uintptr_t)header, SDS_HEADER_SIZE + size);
|
||||
|
||||
if (!IS_SDS_HEADER_VALID(header)) {
|
||||
WARN("SDS: Reading from un-finalized structure 0x%x\n",
|
||||
structure_id);
|
||||
return SDS_ERR_STRUCT_NOT_FINALIZED;
|
||||
}
|
||||
|
||||
if ((fld_off + size) > GET_SDS_HEADER_STRUCT_SIZE(header))
|
||||
return SDS_ERR_FAIL;
|
||||
|
||||
field_base = (uintptr_t)header + SDS_HEADER_SIZE + fld_off;
|
||||
if (check_uptr_overflow(field_base, size - 1))
|
||||
return SDS_ERR_FAIL;
|
||||
|
||||
/* Copy the required field in the struct */
|
||||
memcpy(data, (void *)field_base, size);
|
||||
|
||||
return SDS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write to the field in the structure corresponding to `structure_id`.
|
||||
* `fld_off` is the offset to the field in the structure and `mode`
|
||||
* indicates whether cache maintenance need to performed for the write.
|
||||
* The `data` is the pointer to data of size specified by `size`.
|
||||
* Returns SDS_OK on success or corresponding error codes on failure.
|
||||
*/
|
||||
int sds_struct_write(uint32_t structure_id, unsigned int fld_off,
|
||||
void *data, size_t size, sds_access_mode_t mode)
|
||||
{
|
||||
int status;
|
||||
uintptr_t field_base;
|
||||
struct_header_t *header = NULL;
|
||||
|
||||
if (!data)
|
||||
return SDS_ERR_INVALID_PARAMS;
|
||||
|
||||
/* Check if a structure with this ID exists */
|
||||
status = get_struct_header(structure_id, &header);
|
||||
if (status != SDS_OK)
|
||||
return status;
|
||||
|
||||
assert(header);
|
||||
|
||||
if (mode == SDS_ACCESS_MODE_CACHED)
|
||||
inv_dcache_range((uintptr_t)header, SDS_HEADER_SIZE + size);
|
||||
|
||||
if (!IS_SDS_HEADER_VALID(header)) {
|
||||
WARN("SDS: Writing to un-finalized structure 0x%x\n",
|
||||
structure_id);
|
||||
return SDS_ERR_STRUCT_NOT_FINALIZED;
|
||||
}
|
||||
|
||||
if ((fld_off + size) > GET_SDS_HEADER_STRUCT_SIZE(header))
|
||||
return SDS_ERR_FAIL;
|
||||
|
||||
field_base = (uintptr_t)header + SDS_HEADER_SIZE + fld_off;
|
||||
if (check_uptr_overflow(field_base, size - 1))
|
||||
return SDS_ERR_FAIL;
|
||||
|
||||
/* Copy the required field in the struct */
|
||||
memcpy((void *)field_base, data, size);
|
||||
|
||||
if (mode == SDS_ACCESS_MODE_CACHED)
|
||||
flush_dcache_range((uintptr_t)field_base, size);
|
||||
|
||||
return SDS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the SDS driver. Also verifies the SDS version and sanity of
|
||||
* the SDS structure headers.
|
||||
* Returns SDS_OK on success, SDS_ERR_FAIL on error.
|
||||
*/
|
||||
int sds_init(void)
|
||||
{
|
||||
sds_mem_base = (uintptr_t)PLAT_ARM_SDS_MEM_BASE;
|
||||
|
||||
if (!IS_SDS_REGION_VALID(sds_mem_base)) {
|
||||
WARN("SDS: No valid SDS Memory Region found\n");
|
||||
return SDS_ERR_FAIL;
|
||||
}
|
||||
|
||||
if (GET_SDS_REGION_SCHEMA_VERSION(sds_mem_base)
|
||||
!= SDS_REGION_SCH_VERSION) {
|
||||
WARN("SDS: Unsupported SDS schema version\n");
|
||||
return SDS_ERR_FAIL;
|
||||
}
|
||||
|
||||
sds_mem_size = GET_SDS_REGION_SIZE(sds_mem_base);
|
||||
if (sds_mem_size > PLAT_ARM_SDS_MEM_SIZE_MAX) {
|
||||
WARN("SDS: SDS Memory Region exceeds size limit\n");
|
||||
return SDS_ERR_FAIL;
|
||||
}
|
||||
|
||||
INFO("SDS: Detected SDS Memory Region (%zu bytes)\n", sds_mem_size);
|
||||
|
||||
if (validate_sds_struct_headers() != SDS_OK)
|
||||
return SDS_ERR_FAIL;
|
||||
|
||||
return SDS_OK;
|
||||
}
|
||||
Reference in New Issue
Block a user