xref: /optee_os/core/pta/rtc.c (revision 1dc9a12629acd80fd4fdaa87a8bca8cfd6c559a6)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (C) 2018, Linaro Limited
4  * Copyright (c) 2021, EPAM Systems. All rights reserved.
5  * Copyright (c) 2022, Microchip
6  *
7  */
8 
9 #include <drivers/rtc.h>
10 #include <kernel/pseudo_ta.h>
11 #include <pta_rtc.h>
12 #include <string.h>
13 #include <tee_api_defines.h>
14 #include <tee_api_defines_extensions.h>
15 
16 #define PTA_NAME "rtc.pta"
17 
18 static void rtc_pta_copy_time_from_optee(struct pta_rtc_time *pta_time,
19 					 struct optee_rtc_time *optee_time)
20 {
21 	pta_time->tm_sec = optee_time->tm_sec;
22 	pta_time->tm_min = optee_time->tm_min;
23 	pta_time->tm_hour = optee_time->tm_hour;
24 	pta_time->tm_mday = optee_time->tm_mday;
25 	pta_time->tm_mon = optee_time->tm_mon;
26 	pta_time->tm_year = optee_time->tm_year;
27 	pta_time->tm_wday = optee_time->tm_wday;
28 }
29 
30 static TEE_Result rtc_pta_get_time(uint32_t types,
31 				   TEE_Param params[TEE_NUM_PARAMS])
32 {
33 	TEE_Result res = TEE_ERROR_GENERIC;
34 	struct optee_rtc_time time = { };
35 	struct pta_rtc_time *pta_time = NULL;
36 
37 	if (types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_OUTPUT,
38 				     TEE_PARAM_TYPE_NONE,
39 				     TEE_PARAM_TYPE_NONE,
40 				     TEE_PARAM_TYPE_NONE))
41 		return TEE_ERROR_BAD_PARAMETERS;
42 
43 	if (!IS_ALIGNED_WITH_TYPE(params[0].memref.buffer, typeof(*pta_time)))
44 		return TEE_ERROR_BAD_PARAMETERS;
45 
46 	pta_time = params[0].memref.buffer;
47 	if (!pta_time || params[0].memref.size != sizeof(*pta_time))
48 		return TEE_ERROR_BAD_PARAMETERS;
49 
50 	res = rtc_get_time(&time);
51 	if (res)
52 		return res;
53 
54 	rtc_pta_copy_time_from_optee(pta_time, &time);
55 
56 	return TEE_SUCCESS;
57 }
58 
59 static TEE_Result rtc_pta_set_time(uint32_t types,
60 				   TEE_Param params[TEE_NUM_PARAMS])
61 {
62 	struct optee_rtc_time time = { };
63 	struct pta_rtc_time *pta_time = NULL;
64 
65 	if (types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
66 				     TEE_PARAM_TYPE_NONE,
67 				     TEE_PARAM_TYPE_NONE,
68 				     TEE_PARAM_TYPE_NONE))
69 		return TEE_ERROR_BAD_PARAMETERS;
70 
71 	if (!IS_ALIGNED_WITH_TYPE(params[0].memref.buffer, typeof(*pta_time)))
72 		return TEE_ERROR_BAD_PARAMETERS;
73 
74 	pta_time = params[0].memref.buffer;
75 	if (!pta_time || params[0].memref.size != sizeof(*pta_time))
76 		return TEE_ERROR_BAD_PARAMETERS;
77 
78 	time.tm_sec = pta_time->tm_sec;
79 	time.tm_min = pta_time->tm_min;
80 	time.tm_hour = pta_time->tm_hour;
81 	time.tm_mday = pta_time->tm_mday;
82 	time.tm_mon = pta_time->tm_mon;
83 	time.tm_year = pta_time->tm_year;
84 	time.tm_wday = pta_time->tm_wday;
85 
86 	return rtc_set_time(&time);
87 }
88 
89 static TEE_Result rtc_pta_set_offset(uint32_t types,
90 				     TEE_Param params[TEE_NUM_PARAMS])
91 {
92 	if (types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
93 				     TEE_PARAM_TYPE_NONE,
94 				     TEE_PARAM_TYPE_NONE,
95 				     TEE_PARAM_TYPE_NONE))
96 		return TEE_ERROR_BAD_PARAMETERS;
97 
98 	return rtc_set_offset((int32_t)params[0].value.a);
99 }
100 
101 static TEE_Result rtc_pta_get_offset(uint32_t types,
102 				     TEE_Param params[TEE_NUM_PARAMS])
103 {
104 	TEE_Result res = TEE_ERROR_GENERIC;
105 	long offset = 0;
106 
107 	if (types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT,
108 				     TEE_PARAM_TYPE_NONE,
109 				     TEE_PARAM_TYPE_NONE,
110 				     TEE_PARAM_TYPE_NONE))
111 		return TEE_ERROR_BAD_PARAMETERS;
112 
113 	res = rtc_get_offset(&offset);
114 	if (res)
115 		return res;
116 
117 	if (offset > INT32_MAX || offset < INT32_MIN)
118 		return TEE_ERROR_OVERFLOW;
119 
120 	params[0].value.a = (uint32_t)offset;
121 
122 	return res;
123 }
124 
125 static TEE_Result rtc_pta_get_info(uint32_t types,
126 				   TEE_Param params[TEE_NUM_PARAMS])
127 {
128 	TEE_Result res = TEE_ERROR_GENERIC;
129 	struct pta_rtc_info *info = NULL;
130 	struct optee_rtc_time range_min = { };
131 	struct optee_rtc_time range_max = { };
132 	uint64_t features = 0;
133 
134 	if (types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_OUTPUT,
135 				     TEE_PARAM_TYPE_NONE,
136 				     TEE_PARAM_TYPE_NONE,
137 				     TEE_PARAM_TYPE_NONE))
138 		return TEE_ERROR_BAD_PARAMETERS;
139 
140 	if (!IS_ALIGNED_WITH_TYPE(params[0].memref.buffer, typeof(*info)))
141 		return TEE_ERROR_BAD_PARAMETERS;
142 
143 	info = params[0].memref.buffer;
144 	if (!info || params[0].memref.size != sizeof(*info))
145 		return TEE_ERROR_BAD_PARAMETERS;
146 
147 	memset(info, 0, sizeof(*info));
148 
149 	res = rtc_get_info(&features, &range_min, &range_max);
150 	if (res)
151 		return res;
152 
153 	info->version = PTA_RTC_INFO_VERSION;
154 
155 	if (features & RTC_CORRECTION_FEATURE)
156 		info->features |= PTA_RTC_FEATURE_CORRECTION;
157 
158 	rtc_pta_copy_time_from_optee(&info->range_min, &range_min);
159 	rtc_pta_copy_time_from_optee(&info->range_max, &range_max);
160 
161 	return TEE_SUCCESS;
162 }
163 
164 static TEE_Result open_session(uint32_t ptypes __unused,
165 			       TEE_Param par[TEE_NUM_PARAMS] __unused,
166 			       void **session __unused)
167 {
168 	struct ts_session *ts = ts_get_current_session();
169 	struct tee_ta_session *ta_session = to_ta_session(ts);
170 
171 	/* Only REE kernel is allowed to access RTC */
172 	if (ta_session->clnt_id.login != TEE_LOGIN_REE_KERNEL)
173 		return TEE_ERROR_ACCESS_DENIED;
174 
175 	return TEE_SUCCESS;
176 }
177 
178 static TEE_Result invoke_command(void *session __unused,
179 				 uint32_t cmd, uint32_t ptypes,
180 				 TEE_Param params[TEE_NUM_PARAMS])
181 {
182 	switch (cmd) {
183 	case PTA_CMD_RTC_GET_INFO:
184 		return rtc_pta_get_info(ptypes, params);
185 	case PTA_CMD_RTC_GET_TIME:
186 		return rtc_pta_get_time(ptypes, params);
187 	case PTA_CMD_RTC_SET_TIME:
188 		return rtc_pta_set_time(ptypes, params);
189 	case PTA_CMD_RTC_GET_OFFSET:
190 		return rtc_pta_get_offset(ptypes, params);
191 	case PTA_CMD_RTC_SET_OFFSET:
192 		return rtc_pta_set_offset(ptypes, params);
193 	default:
194 		break;
195 	}
196 
197 	return TEE_ERROR_NOT_IMPLEMENTED;
198 }
199 
200 pseudo_ta_register(.uuid = PTA_RTC_UUID, .name = PTA_NAME,
201 		   .flags = PTA_DEFAULT_FLAGS | TA_FLAG_CONCURRENT |
202 			    TA_FLAG_DEVICE_ENUM,
203 		   .open_session_entry_point = open_session,
204 		   .invoke_command_entry_point = invoke_command);
205