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 
rtc_pta_copy_time_from_optee(struct pta_rtc_time * pta_time,struct optee_rtc_time * optee_time)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 
rtc_pta_get_time(uint32_t types,TEE_Param params[TEE_NUM_PARAMS])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 	pta_time = params[0].memref.buffer;
44 	if (!pta_time || params[0].memref.size != sizeof(*pta_time))
45 		return TEE_ERROR_BAD_PARAMETERS;
46 
47 	res = rtc_get_time(&time);
48 	if (res)
49 		return res;
50 
51 	rtc_pta_copy_time_from_optee(pta_time, &time);
52 
53 	return TEE_SUCCESS;
54 }
55 
rtc_pta_set_time(uint32_t types,TEE_Param params[TEE_NUM_PARAMS])56 static TEE_Result rtc_pta_set_time(uint32_t types,
57 				   TEE_Param params[TEE_NUM_PARAMS])
58 {
59 	struct optee_rtc_time time = { };
60 	struct pta_rtc_time *pta_time = NULL;
61 
62 	if (types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
63 				     TEE_PARAM_TYPE_NONE,
64 				     TEE_PARAM_TYPE_NONE,
65 				     TEE_PARAM_TYPE_NONE))
66 		return TEE_ERROR_BAD_PARAMETERS;
67 
68 	pta_time = params[0].memref.buffer;
69 	if (!pta_time || params[0].memref.size != sizeof(*pta_time))
70 		return TEE_ERROR_BAD_PARAMETERS;
71 
72 	time.tm_sec = pta_time->tm_sec;
73 	time.tm_min = pta_time->tm_min;
74 	time.tm_hour = pta_time->tm_hour;
75 	time.tm_mday = pta_time->tm_mday;
76 	time.tm_mon = pta_time->tm_mon;
77 	time.tm_year = pta_time->tm_year;
78 	time.tm_wday = pta_time->tm_wday;
79 
80 	return rtc_set_time(&time);
81 }
82 
rtc_pta_set_offset(uint32_t types,TEE_Param params[TEE_NUM_PARAMS])83 static TEE_Result rtc_pta_set_offset(uint32_t types,
84 				     TEE_Param params[TEE_NUM_PARAMS])
85 {
86 	if (types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
87 				     TEE_PARAM_TYPE_NONE,
88 				     TEE_PARAM_TYPE_NONE,
89 				     TEE_PARAM_TYPE_NONE))
90 		return TEE_ERROR_BAD_PARAMETERS;
91 
92 	return rtc_set_offset((int32_t)params[0].value.a);
93 }
94 
rtc_pta_get_offset(uint32_t types,TEE_Param params[TEE_NUM_PARAMS])95 static TEE_Result rtc_pta_get_offset(uint32_t types,
96 				     TEE_Param params[TEE_NUM_PARAMS])
97 {
98 	TEE_Result res = TEE_ERROR_GENERIC;
99 	long offset = 0;
100 
101 	if (types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT,
102 				     TEE_PARAM_TYPE_NONE,
103 				     TEE_PARAM_TYPE_NONE,
104 				     TEE_PARAM_TYPE_NONE))
105 		return TEE_ERROR_BAD_PARAMETERS;
106 
107 	res = rtc_get_offset(&offset);
108 	if (res)
109 		return res;
110 
111 	if (offset > INT32_MAX || offset < INT32_MIN)
112 		return TEE_ERROR_OVERFLOW;
113 
114 	params[0].value.a = (uint32_t)offset;
115 
116 	return res;
117 }
118 
rtc_pta_get_info(uint32_t types,TEE_Param params[TEE_NUM_PARAMS])119 static TEE_Result rtc_pta_get_info(uint32_t types,
120 				   TEE_Param params[TEE_NUM_PARAMS])
121 {
122 	TEE_Result res = TEE_ERROR_GENERIC;
123 	struct pta_rtc_info *info = NULL;
124 	struct optee_rtc_time range_min = { };
125 	struct optee_rtc_time range_max = { };
126 	uint64_t features = 0;
127 
128 	if (types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_OUTPUT,
129 				     TEE_PARAM_TYPE_NONE,
130 				     TEE_PARAM_TYPE_NONE,
131 				     TEE_PARAM_TYPE_NONE))
132 		return TEE_ERROR_BAD_PARAMETERS;
133 
134 	info = params[0].memref.buffer;
135 	if (!info || params[0].memref.size != sizeof(*info))
136 		return TEE_ERROR_BAD_PARAMETERS;
137 
138 	memset(info, 0, sizeof(*info));
139 
140 	res = rtc_get_info(&features, &range_min, &range_max);
141 	if (res)
142 		return res;
143 
144 	info->version = PTA_RTC_INFO_VERSION;
145 
146 	if (features & RTC_CORRECTION_FEATURE)
147 		info->features |= PTA_RTC_FEATURE_CORRECTION;
148 
149 	rtc_pta_copy_time_from_optee(&info->range_min, &range_min);
150 	rtc_pta_copy_time_from_optee(&info->range_max, &range_max);
151 
152 	return TEE_SUCCESS;
153 }
154 
open_session(uint32_t ptypes __unused,TEE_Param par[TEE_NUM_PARAMS]__unused,void ** session __unused)155 static TEE_Result open_session(uint32_t ptypes __unused,
156 			       TEE_Param par[TEE_NUM_PARAMS] __unused,
157 			       void **session __unused)
158 {
159 	struct ts_session *ts = ts_get_current_session();
160 	struct tee_ta_session *ta_session = to_ta_session(ts);
161 
162 	/* Only REE kernel is allowed to access RTC */
163 	if (ta_session->clnt_id.login != TEE_LOGIN_REE_KERNEL)
164 		return TEE_ERROR_ACCESS_DENIED;
165 
166 	return TEE_SUCCESS;
167 }
168 
invoke_command(void * session __unused,uint32_t cmd,uint32_t ptypes,TEE_Param params[TEE_NUM_PARAMS])169 static TEE_Result invoke_command(void *session __unused,
170 				 uint32_t cmd, uint32_t ptypes,
171 				 TEE_Param params[TEE_NUM_PARAMS])
172 {
173 	switch (cmd) {
174 	case PTA_CMD_RTC_GET_INFO:
175 		return rtc_pta_get_info(ptypes, params);
176 	case PTA_CMD_RTC_GET_TIME:
177 		return rtc_pta_get_time(ptypes, params);
178 	case PTA_CMD_RTC_SET_TIME:
179 		return rtc_pta_set_time(ptypes, params);
180 	case PTA_CMD_RTC_GET_OFFSET:
181 		return rtc_pta_get_offset(ptypes, params);
182 	case PTA_CMD_RTC_SET_OFFSET:
183 		return rtc_pta_set_offset(ptypes, params);
184 	default:
185 		break;
186 	}
187 
188 	return TEE_ERROR_NOT_IMPLEMENTED;
189 }
190 
191 pseudo_ta_register(.uuid = PTA_RTC_UUID, .name = PTA_NAME,
192 		   .flags = PTA_DEFAULT_FLAGS | TA_FLAG_CONCURRENT |
193 			    TA_FLAG_DEVICE_ENUM,
194 		   .open_session_entry_point = open_session,
195 		   .invoke_command_entry_point = invoke_command);
196