xref: /optee_os/core/tee/tee_time_generic.c (revision b01047730e77127c23a36591643eeb8bb0487d68)
1 /*
2  * Copyright (c) 2014, STMicroelectronics International N.V.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 #include <kernel/tee_time.h>
28 
29 #include <string.h>
30 #include <stdlib.h>
31 #include <kernel/tee_rpc.h>
32 #include <kernel/tee_core_trace.h>
33 #include <utee_defines.h>
34 #include <kernel/thread.h>
35 #include <sm/teesmc.h>
36 #include <mm/core_mmu.h>
37 
38 /*
39  * tee_time_get_ree_time(): this function implements the GP Internal API
40  * function TEE_GetREETime()
41  * Goal is to get the time of the Rich Execution Environment
42  * This is why this time is provided through the supplicant
43  */
44 TEE_Result tee_time_get_ree_time(TEE_Time *time)
45 {
46 	TEE_Result res = TEE_ERROR_BAD_PARAMETERS;
47 	struct teesmc32_arg *arg;
48 	struct teesmc32_param *params;
49 	paddr_t pharg = 0;
50 	paddr_t phpayload = 0;
51 	paddr_t cookie = 0;
52 	TEE_Time *payload;
53 
54 	if (!time)
55 		goto exit;
56 
57 	pharg = thread_rpc_alloc_arg(TEESMC32_GET_ARG_SIZE(1));
58 	if (!pharg)
59 		goto exit;
60 	thread_st_rpc_alloc_payload(sizeof(TEE_Time), &phpayload, &cookie);
61 	if (!phpayload)
62 		goto exit;
63 
64 	if (!TEE_ALIGNMENT_IS_OK(pharg, struct teesmc32_arg) ||
65 	    !TEE_ALIGNMENT_IS_OK(phpayload, TEE_Time))
66 		goto exit;
67 
68 	if (core_pa2va(pharg, (uint32_t *)&arg) ||
69 	    core_pa2va(phpayload, (uint32_t *)&payload))
70 		goto exit;
71 
72 	arg->cmd = TEE_RPC_GET_TIME;
73 	arg->ret = TEE_ERROR_GENERIC;
74 	arg->num_params = 1;
75 	params = TEESMC32_GET_PARAMS(arg);
76 	params[0].attr = TEESMC_ATTR_TYPE_MEMREF_OUTPUT |
77 			 (TEESMC_ATTR_CACHE_I_WRITE_THR |
78 			  TEESMC_ATTR_CACHE_O_WRITE_THR) <<
79 				TEESMC_ATTR_CACHE_SHIFT;
80 	params[0].u.memref.buf_ptr = phpayload;
81 	params[0].u.memref.size = sizeof(TEE_Time);
82 
83 	thread_rpc_cmd(pharg);
84 	res = arg->ret;
85 	if (res != TEE_SUCCESS)
86 		goto exit;
87 
88 	*time = *payload;
89 
90 exit:
91 	thread_rpc_free_arg(pharg);
92 	thread_st_rpc_free_payload(cookie);
93 	return res;
94 }
95 
96 struct tee_ta_time_offs {
97 	TEE_UUID uuid;
98 	TEE_Time offs;
99 	bool positive;
100 };
101 
102 static struct tee_ta_time_offs *tee_time_offs;
103 static size_t tee_time_num_offs;
104 
105 static TEE_Result tee_time_ta_get_offs(const TEE_UUID *uuid,
106 				       const TEE_Time **offs, bool *positive)
107 {
108 	size_t n;
109 
110 	for (n = 0; n < tee_time_num_offs; n++) {
111 		if (memcmp(uuid, &tee_time_offs[n].uuid, sizeof(TEE_UUID))
112 				== 0) {
113 			*offs = &tee_time_offs[n].offs;
114 			*positive = tee_time_offs[n].positive;
115 			return TEE_SUCCESS;
116 		}
117 	}
118 	return TEE_ERROR_TIME_NOT_SET;
119 }
120 
121 static TEE_Result tee_time_ta_set_offs(const TEE_UUID *uuid,
122 				       const TEE_Time *offs, bool positive)
123 {
124 	size_t n;
125 	struct tee_ta_time_offs *o;
126 
127 	for (n = 0; n < tee_time_num_offs; n++) {
128 		if (memcmp(uuid, &tee_time_offs[n].uuid, sizeof(TEE_UUID))
129 				== 0) {
130 			tee_time_offs[n].offs = *offs;
131 			tee_time_offs[n].positive = positive;
132 			return TEE_SUCCESS;
133 		}
134 	}
135 
136 	n = tee_time_num_offs + 1;
137 	o = malloc(n * sizeof(struct tee_ta_time_offs));
138 	if (o == NULL)
139 		return TEE_ERROR_OUT_OF_MEMORY;
140 	memcpy(o, tee_time_offs,
141 	       tee_time_num_offs * sizeof(struct tee_ta_time_offs));
142 	free(tee_time_offs);
143 	tee_time_offs = o;
144 	tee_time_offs[tee_time_num_offs].uuid = *uuid;
145 	tee_time_offs[tee_time_num_offs].offs = *offs;
146 	tee_time_offs[tee_time_num_offs].positive = positive;
147 	tee_time_num_offs = n;
148 	return TEE_SUCCESS;
149 }
150 
151 TEE_Result tee_time_get_ta_time(const TEE_UUID *uuid, TEE_Time *time)
152 {
153 	TEE_Result res;
154 	const TEE_Time *offs;
155 	bool positive;
156 	TEE_Time t;
157 	TEE_Time t2;
158 
159 	res = tee_time_ta_get_offs(uuid, &offs, &positive);
160 	if (res != TEE_SUCCESS)
161 		return res;
162 
163 	res = tee_time_get_sys_time(&t);
164 	if (res != TEE_SUCCESS)
165 		return res;
166 
167 	if (positive) {
168 		TEE_TIME_ADD(t, *offs, t2);
169 
170 		/* Detect wrapping, the wrapped time should be returned. */
171 		if (TEE_TIME_LT(t2, t))
172 			res = TEE_ERROR_OVERFLOW;
173 	} else {
174 		TEE_TIME_SUB(t, *offs, t2);
175 
176 		/* Detect wrapping, the wrapped time should be returned. */
177 		if (TEE_TIME_LE(t, t2))
178 			res = TEE_ERROR_OVERFLOW;
179 	}
180 	*time = t2;
181 
182 	return res;
183 }
184 
185 TEE_Result tee_time_set_ta_time(const TEE_UUID *uuid, const TEE_Time *time)
186 {
187 	TEE_Result res;
188 	TEE_Time offs;
189 	TEE_Time t;
190 
191 	/* Check that time is normalized. */
192 	if (time->millis >= TEE_TIME_MILLIS_BASE)
193 		return TEE_ERROR_BAD_PARAMETERS;
194 
195 	res = tee_time_get_sys_time(&t);
196 	if (res != TEE_SUCCESS)
197 		return res;
198 
199 	if (TEE_TIME_LT(t, *time)) {
200 		TEE_TIME_SUB(*time, t, offs);
201 		return tee_time_ta_set_offs(uuid, &offs, true);
202 	} else {
203 		TEE_TIME_SUB(t, *time, offs);
204 		return tee_time_ta_set_offs(uuid, &offs, false);
205 	}
206 }
207