/*******************************************************************************
 * 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 runtime_svc_init(void)
{
	int rc = 0;
	unsigned int index, start_idx, end_idx;

	/* 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 == 0)
		return;

	/* Initialise internal variables to invalid state */
	memset(rt_svc_descs_indices, -1, sizeof(rt_svc_descs_indices));

	rt_svc_descs = (rt_svc_desc_t *) RT_SVC_DESCS_START;
	for (index = 0; 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) {
			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) {
			rc = service->init();
			if (rc) {
				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.
		 */
		start_idx = get_unique_oen(rt_svc_descs[index].start_oen,
				service->call_type);
		assert(start_idx < MAX_RT_SVCS);
		end_idx = get_unique_oen(rt_svc_descs[index].end_oen,
				service->call_type);
		assert(end_idx < MAX_RT_SVCS);
		for (; start_idx <= end_idx; start_idx++)
			rt_svc_descs_indices[start_idx] = index;
	}
}
/*******************************************************************************
 * 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 runtime_svc_init(void)
{
	int32_t rc = 0;
	uint32_t index, start_idx, end_idx;
	uint64_t rt_svc_descs_num;

	/* If no runtime services are implemented then simply bail out */
	rt_svc_descs_num = RT_SVC_DESCS_END - RT_SVC_DESCS_START;
	rt_svc_descs_num /= sizeof(rt_svc_desc_t);
	if (rt_svc_descs_num == 0)
		return;

	/* Initialise internal variables to invalid state */
	memset(rt_svc_descs_indices, -1, sizeof(rt_svc_descs_indices));

	rt_svc_descs = (rt_svc_desc_t *) RT_SVC_DESCS_START;
	for (index = 0; index < rt_svc_descs_num; 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(&rt_svc_descs[index]);
		if (rc) {
			ERROR("Invalid runtime service descriptor 0x%lx (%s)\n",
					(uintptr_t) &rt_svc_descs[index],
					rt_svc_descs[index].name);
			goto error;
		}

		/*
		 * The runtime service may have seperate rt_svc_desc_t
		 * for its fast smc and standard 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 (rt_svc_descs[index].init) {
			rc = rt_svc_descs[index].init();
			if (rc) {
				ERROR("Error initializing runtime service %s\n",
						rt_svc_descs[index].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.
		 */
		start_idx = get_unique_oen(rt_svc_descs[index].start_oen,
				rt_svc_descs[index].call_type);
		end_idx = get_unique_oen(rt_svc_descs[index].end_oen,
				rt_svc_descs[index].call_type);

		for (; start_idx <= end_idx; start_idx++)
			rt_svc_descs_indices[start_idx] = index;
	}

	return;
error:
	panic();
}