arm-trusted-firmware/common/runtime_svc.c
Antonio Nino Diaz 09d40e0e08 Sanitise includes across codebase
Enforce full include path for includes. Deprecate old paths.

The following folders inside include/lib have been left unchanged:

- include/lib/cpus/${ARCH}
- include/lib/el3_runtime/${ARCH}

The reason for this change is that having a global namespace for
includes isn't a good idea. It defeats one of the advantages of having
folders and it introduces problems that are sometimes subtle (because
you may not know the header you are actually including if there are two
of them).

For example, this patch had to be created because two headers were
called the same way: e0ea0928d5 ("Fix gpio includes of mt8173 platform
to avoid collision."). More recently, this patch has had similar
problems: 46f9b2c3a2 ("drivers: add tzc380 support").

This problem was introduced in commit 4ecca33988 ("Move include and
source files to logical locations"). At that time, there weren't too
many headers so it wasn't a real issue. However, time has shown that
this creates problems.

Platforms that want to preserve the way they include headers may add the
removed paths to PLAT_INCLUDES, but this is discouraged.

Change-Id: I39dc53ed98f9e297a5966e723d1936d6ccf2fc8f
Signed-off-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
2019-01-04 10:43:17 +00:00

168 lines
5.5 KiB
C

/*
* Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <common/debug.h>
#include <common/runtime_svc.h>
/*******************************************************************************
* The 'rt_svc_descs' array holds the runtime service descriptors exported by
* services by placing them in the 'rt_svc_descs' linker section.
* The 'rt_svc_descs_indices' array holds the index of a descriptor in the
* 'rt_svc_descs' array. When an SMC arrives, the OEN[29:24] bits and the call
* type[31] bit in the function id are combined to get an index into the
* 'rt_svc_descs_indices' array. This gives the index of the descriptor in the
* 'rt_svc_descs' array which contains the SMC handler.
******************************************************************************/
uint8_t rt_svc_descs_indices[MAX_RT_SVCS];
#define RT_SVC_DECS_NUM ((RT_SVC_DESCS_END - RT_SVC_DESCS_START)\
/ sizeof(rt_svc_desc_t))
/*******************************************************************************
* Function to invoke the registered `handle` corresponding to the smc_fid in
* AArch32 mode.
******************************************************************************/
#if SMCCC_MAJOR_VERSION == 1
uintptr_t handle_runtime_svc(uint32_t smc_fid,
void *cookie,
void *handle,
unsigned int flags)
{
u_register_t x1, x2, x3, x4;
unsigned int index;
unsigned int idx;
const rt_svc_desc_t *rt_svc_descs;
assert(handle != NULL);
idx = get_unique_oen_from_smc_fid(smc_fid);
assert(idx < MAX_RT_SVCS);
index = rt_svc_descs_indices[idx];
if (index >= RT_SVC_DECS_NUM)
SMC_RET1(handle, SMC_UNK);
rt_svc_descs = (rt_svc_desc_t *) RT_SVC_DESCS_START;
get_smc_params_from_ctx(handle, x1, x2, x3, x4);
return rt_svc_descs[index].handle(smc_fid, x1, x2, x3, x4, cookie,
handle, flags);
}
#endif /* SMCCC_MAJOR_VERSION */
/*******************************************************************************
* Simple routine to sanity check a runtime service descriptor before using it
******************************************************************************/
static int32_t validate_rt_svc_desc(const rt_svc_desc_t *desc)
{
if (desc == NULL)
return -EINVAL;
if (desc->start_oen > desc->end_oen)
return -EINVAL;
if (desc->end_oen >= OEN_LIMIT)
return -EINVAL;
#if SMCCC_MAJOR_VERSION == 1
if ((desc->call_type != SMC_TYPE_FAST) &&
(desc->call_type != SMC_TYPE_YIELD))
return -EINVAL;
#elif SMCCC_MAJOR_VERSION == 2
if (desc->is_vendor > 1U)
return -EINVAL;
#endif /* SMCCC_MAJOR_VERSION */
/* A runtime service having no init or handle function doesn't make sense */
if ((desc->init == NULL) && (desc->handle == NULL))
return -EINVAL;
return 0;
}
/*******************************************************************************
* This function calls the initialisation routine in the descriptor exported by
* a runtime service. Once a descriptor has been validated, its start & end
* owning entity numbers and the call type are combined to form a unique oen.
* The unique oen is used as an index into the 'rt_svc_descs_indices' array.
* The index of the runtime service descriptor is stored at this index.
******************************************************************************/
void __init runtime_svc_init(void)
{
int rc = 0;
uint8_t index, start_idx, end_idx;
rt_svc_desc_t *rt_svc_descs;
/* Assert the number of descriptors detected are less than maximum indices */
assert((RT_SVC_DESCS_END >= RT_SVC_DESCS_START) &&
(RT_SVC_DECS_NUM < MAX_RT_SVCS));
/* If no runtime services are implemented then simply bail out */
if (RT_SVC_DECS_NUM == 0U)
return;
/* Initialise internal variables to invalid state */
(void)memset(rt_svc_descs_indices, -1, sizeof(rt_svc_descs_indices));
rt_svc_descs = (rt_svc_desc_t *) RT_SVC_DESCS_START;
for (index = 0U; index < RT_SVC_DECS_NUM; index++) {
rt_svc_desc_t *service = &rt_svc_descs[index];
/*
* An invalid descriptor is an error condition since it is
* difficult to predict the system behaviour in the absence
* of this service.
*/
rc = validate_rt_svc_desc(service);
if (rc != 0) {
ERROR("Invalid runtime service descriptor %p\n",
(void *) service);
panic();
}
/*
* The runtime service may have separate rt_svc_desc_t
* for its fast smc and yielding smc. Since the service itself
* need to be initialized only once, only one of them will have
* an initialisation routine defined. Call the initialisation
* routine for this runtime service, if it is defined.
*/
if (service->init != NULL) {
rc = service->init();
if (rc != 0) {
ERROR("Error initializing runtime service %s\n",
service->name);
continue;
}
}
/*
* Fill the indices corresponding to the start and end
* owning entity numbers with the index of the
* descriptor which will handle the SMCs for this owning
* entity range.
*/
#if SMCCC_MAJOR_VERSION == 1
start_idx = (uint8_t)get_unique_oen(service->start_oen,
service->call_type);
end_idx = (uint8_t)get_unique_oen(service->end_oen,
service->call_type);
#elif SMCCC_MAJOR_VERSION == 2
start_idx = (uint8_t)get_rt_desc_idx(service->start_oen,
service->is_vendor);
end_idx = (uint8_t)get_rt_desc_idx(service->end_oen,
service->is_vendor);
#endif
assert(start_idx <= end_idx);
assert(end_idx < MAX_RT_SVCS);
for (; start_idx <= end_idx; start_idx++)
rt_svc_descs_indices[start_idx] = index;
}
}