1 /*
2 * Copyright (C) 2022 Huawei Technologies Co., Ltd.
3 * Licensed under the Mulan PSL v2.
4 * You can use this software according to the terms and conditions of the Mulan PSL v2.
5 * You may obtain a copy of Mulan PSL v2 at:
6 * http://license.coscl.org.cn/MulanPSL2
7 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
8 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
9 * PURPOSE.
10 * See the Mulan PSL v2 for more details.
11 */
12 #include <securec.h>
13 #include <sys_timer.h>
14 #include <tee_log.h>
15 #include <tee_trusted_storage_api.h>
16 #include <tee_time_adapt.h>
17 #include <tee_misc.h>
18
19 #define PERSISTENT_TIME_BASE_FILE "sec_storage/persistent_time"
20 #define POSITIVE_DIR 1
21 #define NEGATIVE_DIR (-1)
22 struct time_offset {
23 int16_t dir;
24 uint32_t offset;
25 uint32_t base_sys_time;
26 };
27
TEE_GetSystemTime(TEE_Time * time)28 void TEE_GetSystemTime(TEE_Time *time)
29 {
30 #ifdef CONFIG_TEE_TIME_STUB
31 (void)time;
32 #else
33 struct timer_ops_t *time_ops = NULL;
34 uint64_t time_stamp;
35
36 if (time == NULL)
37 return;
38
39 time_ops = get_time_ops();
40 if (time_ops == NULL)
41 return;
42
43 time_stamp = time_ops->read_time_stamp();
44 time->seconds = UPPER_32_BITS(time_stamp);
45 time->millis = LOWER_32_BITS(time_stamp) / NS_PER_MSEC;
46 #endif
47 }
48
TEE_GetREETime(TEE_Time * time)49 void TEE_GetREETime(TEE_Time *time)
50 {
51 #ifdef CONFIG_TEE_TIME_STUB
52 (void)time;
53 #else
54 int32_t ret;
55 if (time == NULL) {
56 tloge("invalid param\n");
57 return;
58 }
59
60 ret = get_time_of_data(&time->seconds, &time->millis, NULL, 0);
61 if (ret != TMR_OK) {
62 tloge("get time of data failed\n");
63 return;
64 }
65 #endif
66 }
67
TEE_Wait(uint32_t mill_second)68 TEE_Result TEE_Wait(uint32_t mill_second)
69 {
70 #ifdef CONFIG_TEE_TIME_STUB
71 (void)mill_second;
72 return TEE_ERROR_NOT_SUPPORTED;
73 #else
74 struct timer_ops_t *time_ops = NULL;
75 time_ops = get_time_ops();
76 if (time_ops == NULL)
77 return TMR_ERR;
78
79 return time_ops->sleep(mill_second);
80 #endif
81 }
82
83 #ifndef CONFIG_TEE_TIME_STUB
get_rtc_time(void)84 static uint32_t get_rtc_time(void)
85 {
86 struct timer_ops_t *time_ops = NULL;
87 time_ops = get_time_ops();
88 if (time_ops == NULL)
89 return TIMER_INV_VALUE;
90
91 return time_ops->get_rtc_seconds();
92 }
93 #endif
94
TEE_SetTAPersistentTime(TEE_Time * time)95 TEE_Result TEE_SetTAPersistentTime(TEE_Time *time)
96 {
97 #ifdef CONFIG_TEE_TIME_STUB
98 (void)time;
99 return TEE_ERROR_NOT_SUPPORTED;
100 #else
101 struct time_offset offset_val = { 0 };
102 uint32_t seconds;
103 TEE_Result ret;
104 TEE_ObjectHandle object = NULL;
105
106 if (time == NULL) {
107 tloge("invalid param\n");
108 return TEE_ERROR_BAD_PARAMETERS;
109 }
110
111 /*
112 * Get sys time from RTC:always increase even if power off.
113 * Use TEE_SetTAPersistentTime and TEE_GetTAPersistentTime
114 * to get the true time that has past. A typical usecase in DRM.
115 */
116 seconds = get_rtc_time();
117 if (seconds == TIMER_INV_VALUE) {
118 tloge("Failed to get rtc time\n");
119 return TEE_ERROR_TIME_NEEDS_RESET;
120 }
121
122 offset_val.base_sys_time = seconds;
123 if (time->seconds >= seconds) {
124 offset_val.dir = POSITIVE_DIR;
125 offset_val.offset = time->seconds - seconds;
126 } else {
127 offset_val.dir = NEGATIVE_DIR;
128 offset_val.offset = seconds - time->seconds;
129 }
130
131 ret = TEE_CreatePersistentObject(TEE_OBJECT_STORAGE_PRIVATE, PERSISTENT_TIME_BASE_FILE,
132 strlen(PERSISTENT_TIME_BASE_FILE), TEE_DATA_FLAG_ACCESS_WRITE, TEE_HANDLE_NULL,
133 &offset_val, sizeof(offset_val), &object);
134 if (ret != TEE_SUCCESS) {
135 tloge("set TA persistent time error: ret is 0x%x\n", ret);
136 return ret;
137 }
138
139 TEE_CloseObject(object);
140 return ret;
141 #endif
142 }
143
144 #ifndef CONFIG_TEE_TIME_STUB
persistent_time_check(TEE_Time * time,const struct time_offset * offset_val)145 static TEE_Result persistent_time_check(TEE_Time *time, const struct time_offset *offset_val)
146 {
147 uint32_t seconds;
148 seconds = get_rtc_time();
149 if (seconds == TIMER_INV_VALUE) {
150 tloge("failed to get rtc time\n");
151 return TEE_ERROR_TIME_NEEDS_RESET;
152 }
153
154 if (seconds < offset_val->base_sys_time) {
155 tloge("time rollback\n");
156 return TEE_ERROR_TIME_NEEDS_RESET;
157 }
158
159 /*
160 * millis is always 0, because rtc accuracy is 1s.
161 * Depends on GP spec, even if time overflow we should return the actually time.
162 */
163 time->millis = 0;
164 if (offset_val->dir == NEGATIVE_DIR) {
165 time->seconds = seconds - offset_val->offset;
166 if (time->seconds > seconds) {
167 tloge("persistent time overflow\n");
168 return TEE_ERROR_OVERFLOW;
169 }
170 } else {
171 time->seconds = seconds + offset_val->offset;
172 if (time->seconds < seconds) {
173 tloge("persistent time overflow\n");
174 return TEE_ERROR_OVERFLOW;
175 }
176 }
177
178 return TEE_SUCCESS;
179 }
180 #endif
181
TEE_GetTAPersistentTime(TEE_Time * time)182 TEE_Result TEE_GetTAPersistentTime(TEE_Time *time)
183 {
184 #ifdef CONFIG_TEE_TIME_STUB
185 (void)time;
186 return TEE_ERROR_NOT_SUPPORTED;
187 #else
188 struct time_offset offset_val = { 0 };
189 TEE_ObjectHandle object = NULL;
190 uint32_t count = 0;
191 TEE_Result ret;
192
193 if (time == NULL) {
194 tloge("invalid param\n");
195 return TEE_ERROR_BAD_PARAMETERS;
196 }
197
198 /*
199 * For an error different
200 * from TEE_ERROR_OVERFLOW, this placeholder is filled with zeros.
201 */
202 time->seconds = 0;
203 time->millis = 0;
204 ret = TEE_OpenPersistentObject(TEE_OBJECT_STORAGE_PRIVATE, PERSISTENT_TIME_BASE_FILE,
205 strlen(PERSISTENT_TIME_BASE_FILE), TEE_DATA_FLAG_ACCESS_READ, &object);
206 if (ret != TEE_SUCCESS) {
207 tloge("failed to open persistent object\n");
208 return TEE_ERROR_TIME_NOT_SET;
209 }
210
211 ret = TEE_ReadObjectData(object, &offset_val, sizeof(offset_val), &count);
212 TEE_CloseObject(object);
213 if ((ret != TEE_SUCCESS) || (count != sizeof(offset_val))) {
214 tloge("read failed\n");
215 return TEE_ERROR_TIME_NOT_SET;
216 }
217
218 ret = persistent_time_check(time, &offset_val);
219 if (ret != TEE_SUCCESS) {
220 tloge("failed to check\n");
221 return ret;
222 }
223
224 return TEE_SUCCESS;
225 #endif
226 }
227