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