1532ed618SSoby Mathew /* 20709055eSAntonio Nino Diaz * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. 3532ed618SSoby Mathew * 482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 5532ed618SSoby Mathew */ 6532ed618SSoby Mathew 7532ed618SSoby Mathew #include <assert.h> 8532ed618SSoby Mathew #include <errno.h> 9532ed618SSoby Mathew #include <string.h> 10532ed618SSoby Mathew 1109d40e0eSAntonio Nino Diaz #include <common/debug.h> 1209d40e0eSAntonio Nino Diaz #include <common/runtime_svc.h> 1309d40e0eSAntonio Nino Diaz 14532ed618SSoby Mathew /******************************************************************************* 15532ed618SSoby Mathew * The 'rt_svc_descs' array holds the runtime service descriptors exported by 16532ed618SSoby Mathew * services by placing them in the 'rt_svc_descs' linker section. 17532ed618SSoby Mathew * The 'rt_svc_descs_indices' array holds the index of a descriptor in the 18532ed618SSoby Mathew * 'rt_svc_descs' array. When an SMC arrives, the OEN[29:24] bits and the call 19532ed618SSoby Mathew * type[31] bit in the function id are combined to get an index into the 20532ed618SSoby Mathew * 'rt_svc_descs_indices' array. This gives the index of the descriptor in the 21532ed618SSoby Mathew * 'rt_svc_descs' array which contains the SMC handler. 22532ed618SSoby Mathew ******************************************************************************/ 23532ed618SSoby Mathew uint8_t rt_svc_descs_indices[MAX_RT_SVCS]; 24532ed618SSoby Mathew 25532ed618SSoby Mathew #define RT_SVC_DECS_NUM ((RT_SVC_DESCS_END - RT_SVC_DESCS_START)\ 26532ed618SSoby Mathew / sizeof(rt_svc_desc_t)) 27532ed618SSoby Mathew 28532ed618SSoby Mathew /******************************************************************************* 292f370465SAntonio Nino Diaz * Function to invoke the registered `handle` corresponding to the smc_fid in 302f370465SAntonio Nino Diaz * AArch32 mode. 311ae0a49aSSoby Mathew ******************************************************************************/ 321ae0a49aSSoby Mathew uintptr_t handle_runtime_svc(uint32_t smc_fid, 331ae0a49aSSoby Mathew void *cookie, 341ae0a49aSSoby Mathew void *handle, 351ae0a49aSSoby Mathew unsigned int flags) 361ae0a49aSSoby Mathew { 371ae0a49aSSoby Mathew u_register_t x1, x2, x3, x4; 3881542c00SAntonio Nino Diaz unsigned int index; 396311f63dSVarun Wadekar unsigned int idx; 404a581b06SDimitris Papastamos const rt_svc_desc_t *rt_svc_descs; 411ae0a49aSSoby Mathew 4281542c00SAntonio Nino Diaz assert(handle != NULL); 431ae0a49aSSoby Mathew idx = get_unique_oen_from_smc_fid(smc_fid); 446311f63dSVarun Wadekar assert(idx < MAX_RT_SVCS); 451ae0a49aSSoby Mathew 461ae0a49aSSoby Mathew index = rt_svc_descs_indices[idx]; 4781542c00SAntonio Nino Diaz if (index >= RT_SVC_DECS_NUM) 481ae0a49aSSoby Mathew SMC_RET1(handle, SMC_UNK); 491ae0a49aSSoby Mathew 501ae0a49aSSoby Mathew rt_svc_descs = (rt_svc_desc_t *) RT_SVC_DESCS_START; 511ae0a49aSSoby Mathew 521ae0a49aSSoby Mathew get_smc_params_from_ctx(handle, x1, x2, x3, x4); 531ae0a49aSSoby Mathew 541ae0a49aSSoby Mathew return rt_svc_descs[index].handle(smc_fid, x1, x2, x3, x4, cookie, 551ae0a49aSSoby Mathew handle, flags); 561ae0a49aSSoby Mathew } 571ae0a49aSSoby Mathew 581ae0a49aSSoby Mathew /******************************************************************************* 59532ed618SSoby Mathew * Simple routine to sanity check a runtime service descriptor before using it 60532ed618SSoby Mathew ******************************************************************************/ 619d24d353SSandrine Bailleux static int32_t validate_rt_svc_desc(const rt_svc_desc_t *desc) 62532ed618SSoby Mathew { 63*0eeda638SMaheedhar Bollapalli if (desc == NULL) { 64532ed618SSoby Mathew return -EINVAL; 65*0eeda638SMaheedhar Bollapalli } 66*0eeda638SMaheedhar Bollapalli if (desc->start_oen > desc->end_oen) { 67532ed618SSoby Mathew return -EINVAL; 68*0eeda638SMaheedhar Bollapalli } 69*0eeda638SMaheedhar Bollapalli if (desc->end_oen >= OEN_LIMIT) { 70532ed618SSoby Mathew return -EINVAL; 71*0eeda638SMaheedhar Bollapalli } 722f370465SAntonio Nino Diaz if ((desc->call_type != SMC_TYPE_FAST) && 73*0eeda638SMaheedhar Bollapalli (desc->call_type != SMC_TYPE_YIELD)) { 74532ed618SSoby Mathew return -EINVAL; 75*0eeda638SMaheedhar Bollapalli } 76532ed618SSoby Mathew /* A runtime service having no init or handle function doesn't make sense */ 77*0eeda638SMaheedhar Bollapalli if ((desc->init == NULL) && (desc->handle == NULL)) { 78532ed618SSoby Mathew return -EINVAL; 79*0eeda638SMaheedhar Bollapalli } 80532ed618SSoby Mathew return 0; 81532ed618SSoby Mathew } 82532ed618SSoby Mathew 83532ed618SSoby Mathew /******************************************************************************* 84532ed618SSoby Mathew * This function calls the initialisation routine in the descriptor exported by 85532ed618SSoby Mathew * a runtime service. Once a descriptor has been validated, its start & end 86532ed618SSoby Mathew * owning entity numbers and the call type are combined to form a unique oen. 87532ed618SSoby Mathew * The unique oen is used as an index into the 'rt_svc_descs_indices' array. 88532ed618SSoby Mathew * The index of the runtime service descriptor is stored at this index. 89532ed618SSoby Mathew ******************************************************************************/ 9087c85134SDaniel Boulby void __init runtime_svc_init(void) 91532ed618SSoby Mathew { 926311f63dSVarun Wadekar int rc = 0; 9381542c00SAntonio Nino Diaz uint8_t index, start_idx, end_idx; 94e19ea3f2SDaniel Boulby rt_svc_desc_t *rt_svc_descs; 95532ed618SSoby Mathew 96532ed618SSoby Mathew /* Assert the number of descriptors detected are less than maximum indices */ 975e5e4162SSoby Mathew assert((RT_SVC_DESCS_END >= RT_SVC_DESCS_START) && 985e5e4162SSoby Mathew (RT_SVC_DECS_NUM < MAX_RT_SVCS)); 99532ed618SSoby Mathew 100532ed618SSoby Mathew /* If no runtime services are implemented then simply bail out */ 101*0eeda638SMaheedhar Bollapalli if (RT_SVC_DECS_NUM == 0U) { 102532ed618SSoby Mathew return; 103*0eeda638SMaheedhar Bollapalli } 104532ed618SSoby Mathew /* Initialise internal variables to invalid state */ 10581542c00SAntonio Nino Diaz (void)memset(rt_svc_descs_indices, -1, sizeof(rt_svc_descs_indices)); 106532ed618SSoby Mathew 107532ed618SSoby Mathew rt_svc_descs = (rt_svc_desc_t *) RT_SVC_DESCS_START; 10881542c00SAntonio Nino Diaz for (index = 0U; index < RT_SVC_DECS_NUM; index++) { 1099d24d353SSandrine Bailleux rt_svc_desc_t *service = &rt_svc_descs[index]; 110532ed618SSoby Mathew 111532ed618SSoby Mathew /* 112532ed618SSoby Mathew * An invalid descriptor is an error condition since it is 113532ed618SSoby Mathew * difficult to predict the system behaviour in the absence 114532ed618SSoby Mathew * of this service. 115532ed618SSoby Mathew */ 1169d24d353SSandrine Bailleux rc = validate_rt_svc_desc(service); 11781542c00SAntonio Nino Diaz if (rc != 0) { 1183a26a28cSSandrine Bailleux ERROR("Invalid runtime service descriptor %p\n", 1193a26a28cSSandrine Bailleux (void *) service); 1209d24d353SSandrine Bailleux panic(); 121532ed618SSoby Mathew } 122532ed618SSoby Mathew 123532ed618SSoby Mathew /* 124532ed618SSoby Mathew * The runtime service may have separate rt_svc_desc_t 12516292f54SDavid Cunado * for its fast smc and yielding smc. Since the service itself 126532ed618SSoby Mathew * need to be initialized only once, only one of them will have 127532ed618SSoby Mathew * an initialisation routine defined. Call the initialisation 128532ed618SSoby Mathew * routine for this runtime service, if it is defined. 129532ed618SSoby Mathew */ 13081542c00SAntonio Nino Diaz if (service->init != NULL) { 1319d24d353SSandrine Bailleux rc = service->init(); 13281542c00SAntonio Nino Diaz if (rc != 0) { 133532ed618SSoby Mathew ERROR("Error initializing runtime service %s\n", 1349d24d353SSandrine Bailleux service->name); 135532ed618SSoby Mathew continue; 136532ed618SSoby Mathew } 137532ed618SSoby Mathew } 138532ed618SSoby Mathew 139532ed618SSoby Mathew /* 140532ed618SSoby Mathew * Fill the indices corresponding to the start and end 141532ed618SSoby Mathew * owning entity numbers with the index of the 142532ed618SSoby Mathew * descriptor which will handle the SMCs for this owning 143532ed618SSoby Mathew * entity range. 144532ed618SSoby Mathew */ 14581542c00SAntonio Nino Diaz start_idx = (uint8_t)get_unique_oen(service->start_oen, 1469d24d353SSandrine Bailleux service->call_type); 14781542c00SAntonio Nino Diaz end_idx = (uint8_t)get_unique_oen(service->end_oen, 1489d24d353SSandrine Bailleux service->call_type); 1492f370465SAntonio Nino Diaz assert(start_idx <= end_idx); 1503a26a28cSSandrine Bailleux assert(end_idx < MAX_RT_SVCS); 151*0eeda638SMaheedhar Bollapalli for (; start_idx <= end_idx; start_idx++) { 152532ed618SSoby Mathew rt_svc_descs_indices[start_idx] = index; 153532ed618SSoby Mathew } 154532ed618SSoby Mathew } 155*0eeda638SMaheedhar Bollapalli } 156