aboutsummaryrefslogtreecommitdiff
path: root/include/common/runtime_svc.h
blob: 59bf158b4367d009b822c8256c6522d302a7c419 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
/*
 * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#ifndef RUNTIME_SVC_H
#define RUNTIME_SVC_H

#include <common/bl_common.h>		/* to include exception types */
#include <lib/cassert.h>
#include <lib/utils_def.h>
#include <smccc_helpers.h>	/* to include SMCCC definitions */

/*******************************************************************************
 * Structure definition, typedefs & constants for the runtime service framework
 ******************************************************************************/

/*
 * Constants to allow the assembler access a runtime service
 * descriptor
 */
#ifdef AARCH32
#define RT_SVC_SIZE_LOG2	U(4)
#define RT_SVC_DESC_INIT	U(8)
#define RT_SVC_DESC_HANDLE	U(12)
#else
#define RT_SVC_SIZE_LOG2	U(5)
#define RT_SVC_DESC_INIT	U(16)
#define RT_SVC_DESC_HANDLE	U(24)
#endif /* AARCH32 */
#define SIZEOF_RT_SVC_DESC	(U(1) << RT_SVC_SIZE_LOG2)


/*
 * In SMCCC 1.X, the function identifier has 6 bits for the owning entity number
 * and a single bit for the type of smc call. When taken together, those values
 * limit the maximum number of runtime services to 128.
 *
 * In SMCCC 2.X the type bit is always 1 and there are only 4 OEN bits in the
 * compatibility namespace, so the total number of services is 16. The LSB of
 * namespace is also added to these 4 bits to make space for the vendor service
 * handler and so the total number of runtime services is 32.
 */
#if SMCCC_MAJOR_VERSION == 1
#define MAX_RT_SVCS		U(128)
#elif SMCCC_MAJOR_VERSION == 2
#define MAX_RT_SVCS		U(32)
#endif

#ifndef __ASSEMBLY__

/* Prototype for runtime service initializing function */
typedef int32_t (*rt_svc_init_t)(void);

/*
 * Prototype for runtime service SMC handler function. x0 (SMC Function ID) to
 * x4 are as passed by the caller. Rest of the arguments to SMC and the context
 * can be accessed using the handle pointer. The cookie parameter is reserved
 * for future use
 */
typedef uintptr_t (*rt_svc_handle_t)(uint32_t smc_fid,
				  u_register_t x1,
				  u_register_t x2,
				  u_register_t x3,
				  u_register_t x4,
				  void *cookie,
				  void *handle,
				  u_register_t flags);
typedef struct rt_svc_desc {
	uint8_t start_oen;
	uint8_t end_oen;
#if SMCCC_MAJOR_VERSION == 1
	uint8_t call_type;
#elif SMCCC_MAJOR_VERSION == 2
	uint8_t is_vendor;
#endif
	const char *name;
	rt_svc_init_t init;
	rt_svc_handle_t handle;
} rt_svc_desc_t;

/*
 * Convenience macros to declare a service descriptor
 */
#if SMCCC_MAJOR_VERSION == 1

#define DECLARE_RT_SVC(_name, _start, _end, _type, _setup, _smch)	\
	static const rt_svc_desc_t __svc_desc_ ## _name			\
		__section("rt_svc_descs") __used = {			\
			.start_oen = (_start),				\
			.end_oen = (_end),				\
			.call_type = (_type),				\
			.name = #_name,					\
			.init = (_setup),				\
			.handle = (_smch)				\
		}

#elif SMCCC_MAJOR_VERSION == 2

#define DECLARE_RT_SVC(_name, _start, _end, _type, _setup, _smch)	\
	static const rt_svc_desc_t __svc_desc_ ## _name			\
		__section("rt_svc_descs") __used = {			\
			.start_oen = (_start),				\
			.end_oen = (_end),				\
			.is_vendor = 0,					\
			.name = #_name,					\
			.init = (_setup),				\
			.handle = (_smch),				\
		};							\
	CASSERT((_type) == SMC_TYPE_FAST, rt_svc_type_check_ ## _name)

/*
 * The higher 16 entries of the runtime services are used for the vendor
 * specific descriptor.
 */
#define DECLARE_RT_SVC_VENDOR(_setup, _smch)				\
	static const rt_svc_desc_t __svc_desc_vendor			\
		__section("rt_svc_descs") __used = {			\
			.start_oen = 0,					\
			.end_oen = 15,					\
			.is_vendor = 1,					\
			.name = "vendor_rt_svc",			\
			.init = _setup,					\
			.handle = _smch,				\
		}

#endif /* SMCCC_MAJOR_VERSION */

/*
 * Compile time assertions related to the 'rt_svc_desc' structure to:
 * 1. ensure that the assembler and the compiler view of the size
 *    of the structure are the same.
 * 2. ensure that the assembler and the compiler see the initialisation
 *    routine at the same offset.
 * 3. ensure that the assembler and the compiler see the handler
 *    routine at the same offset.
 */
CASSERT((sizeof(rt_svc_desc_t) == SIZEOF_RT_SVC_DESC), \
	assert_sizeof_rt_svc_desc_mismatch);
CASSERT(RT_SVC_DESC_INIT == __builtin_offsetof(rt_svc_desc_t, init), \
	assert_rt_svc_desc_init_offset_mismatch);
CASSERT(RT_SVC_DESC_HANDLE == __builtin_offsetof(rt_svc_desc_t, handle), \
	assert_rt_svc_desc_handle_offset_mismatch);


#if SMCCC_MAJOR_VERSION == 1
/*
 * This function combines the call type and the owning entity number
 * corresponding to a runtime service to generate a unique owning entity number.
 * This unique oen is used to access an entry in the 'rt_svc_descs_indices'
 * array. The entry contains the index of the service descriptor in the
 * 'rt_svc_descs' array.
 */
static inline uint32_t get_unique_oen(uint32_t oen, uint32_t call_type)
{
	return ((call_type & FUNCID_TYPE_MASK) << FUNCID_OEN_WIDTH) |
		(oen & FUNCID_OEN_MASK);
}

/*
 * This function generates the unique owning entity number from the SMC Function
 * ID. This unique oen is used to access an entry in the 'rt_svc_descs_indices'
 * array to invoke the corresponding runtime service handler during SMC
 * handling.
 */
static inline uint32_t get_unique_oen_from_smc_fid(uint32_t fid)
{
	return get_unique_oen(GET_SMC_OEN(fid), GET_SMC_TYPE(fid));
}

#elif SMCCC_MAJOR_VERSION == 2

/*
 * This function combines the owning entity number corresponding to a runtime
 * service with one extra bit for the vendor namespace to generate an index into
 * the 'rt_svc_descs_indices' array. The entry contains the index of the service
 * descriptor in the 'rt_svc_descs' array.
 */
static inline uint32_t get_rt_desc_idx(uint32_t oen, uint32_t is_vendor)
{
	return ((is_vendor & 1U) << FUNCID_OEN_WIDTH) |
		(oen & FUNCID_OEN_MASK);
}

#endif

/*******************************************************************************
 * Function & variable prototypes
 ******************************************************************************/
void runtime_svc_init(void);
uintptr_t handle_runtime_svc(uint32_t smc_fid, void *cookie, void *handle,
						unsigned int flags);
IMPORT_SYM(uintptr_t, __RT_SVC_DESCS_START__,		RT_SVC_DESCS_START);
IMPORT_SYM(uintptr_t, __RT_SVC_DESCS_END__,		RT_SVC_DESCS_END);
void init_crash_reporting(void);

extern uint8_t rt_svc_descs_indices[MAX_RT_SVCS];

#endif /*__ASSEMBLY__*/
#endif /* RUNTIME_SVC_H */