import exynos 7570 bsp
[GitHub/LineageOS/android_hardware_samsung_slsi_exynos7580.git] / mobicore / ClientLib / src / proxy_common.h
1 /*
2 * Copyright (c) 2013-2015 TRUSTONIC LIMITED
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
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the TRUSTONIC LIMITED nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <algorithm>
33 #include <mutex>
34 #include <string>
35 #include <vector>
36
37 #include <stdlib.h> // malloc, free
38 #include <sys/mman.h> // mmap, munmap
39
40 #include "mc_user.h" // mc_ioctl_buffer
41
42 #pragma GCC diagnostic push
43 #pragma GCC diagnostic ignored "-Wconversion"
44 #include "mc.pb.h"
45 #pragma GCC diagnostic pop
46
47 #define SOCKET_PATH "@/com/trustonic/tee_proxy"
48 #define PROTOCOL_MAGIC "T7e3"
49 #define PROTOCOL_VERSION 1
50
51 /*
52 * ProtoBuf gives us the serialisation mechanism, but that's not enough to send
53 * our RPC messages: we also need to pass the method we want to call, the total
54 * length of the data, and a magic number is usually welcome too. While at it,
55 * we'll throw a version number just in case.
56 *
57 * Hence:
58 * ----------------------
59 * | Magic number | 4 bytes (text)
60 * ----------------------
61 * | Method | Version | 2 + 2 bytes (LE)
62 * ----------------------
63 * | Message length | 4 bytes (LE)
64 * ----------------------
65 * | |
66 * | Message data | N bytes (text)
67 * ~ ~
68 * | |
69 * ----------------------
70 */
71
72 namespace com {
73 namespace trustonic {
74 namespace tee_proxy {
75
76 struct RequestHeader {
77 char magic[4];
78 uint16_t version;
79 uint16_t method;
80 uint32_t length;
81 };
82
83 struct ResponseHeader {
84 char magic[4];
85 uint16_t version;
86 uint16_t method;
87 int32_t proto_rc; // -errno if negative, length of data otherwise
88 uint32_t method_rc; // errno from called method on server side
89 };
90
91 enum RpcMethod {
92 OPEN_SESSION = 0,
93 OPEN_TRUSTLET = 1,
94 CLOSE_SESSION = 2,
95 NOTIFY = 3,
96 WAIT = 4,
97 MAP = 5,
98 UNMAP = 6,
99 GET_ERROR = 7,
100 GET_VERSION = 9,
101 GP_REQUESTCANCELLATION = 27,
102 };
103
104 class Session {
105 public:
106 class Buffer {
107 enum Type {
108 NONE, // No buffer
109 CLIENT, // Buffer managed by caller (client side)
110 SERVER, // Buffer mmap'd (server side)
111 };
112 mc_ioctl_buffer info_;
113 void* address_;
114 Type type_;
115 int alloc(size_t length, uint32_t flags = MC_IO_MAP_INPUT_OUTPUT) {
116 // No posix_memalign, aligned_alloc, valloc, memalign, pvalloc in
117 // Android so we rely on mmap to give us page-aligned memory
118 size_t page_mask = sysconf(_SC_PAGESIZE) - 1;
119 size_t aligned_length = (length + page_mask) & ~page_mask;
120 void* buf = ::mmap(0, aligned_length, PROT_READ | PROT_WRITE,
121 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
122 if (buf == MAP_FAILED) {
123 LOG_E("Failed to allocate");
124 return -1;
125 }
126 type_ = SERVER;
127 address_ = buf;
128 info_.va = reinterpret_cast<uintptr_t>(address_);
129 info_.len = static_cast<uint32_t>(length);
130 info_.flags = flags;
131 LOG_D("alloc'd buffer %p:%u:%x", address_, info_.len, info_.flags);
132 return 0;
133 }
134 public:
135 Buffer(const Buffer&) = delete;
136 Buffer& operator=(const Buffer&) = delete;
137 // Constructor from buffer: allocate and fill in
138 Buffer(std::string buffer): address_(nullptr) {
139 if (!alloc(buffer.length())) {
140 update(buffer);
141 }
142 }
143 // Constructor for client TCI: pointer and length (can be null) given
144 Buffer(void* address, size_t length): address_(address) {
145 if (address_) {
146 info_.va = reinterpret_cast<uintptr_t>(address_);
147 info_.len = static_cast<uint32_t>(length);
148 info_.flags = MC_IO_MAP_INPUT_OUTPUT;
149 type_ = CLIENT;
150 LOG_D("use buffer %p:%u:%x", address_, info_.len, info_.flags);
151 } else {
152 info_.va = 0;
153 info_.len = 0;
154 info_.flags = 0;
155 type_ = NONE;
156 }
157 info_.sva = 0;
158 }
159 // Constructor for server buffer: allocate
160 Buffer(uint32_t length, uint32_t flags): address_(nullptr) {
161 alloc(length, flags);
162 }
163 // Constructor for client buffer: info given
164 Buffer(mc_ioctl_buffer info): info_(info) {
165 address_ = reinterpret_cast<void*>(
166 static_cast<uintptr_t>(info_.va));
167 type_ = CLIENT;
168 LOG_D("use buffer %p:%u:%x", address_, info_.len, info_.flags);
169 }
170 ~Buffer() {
171 if (type_ == Buffer::SERVER) {
172 LOG_D("unmap buffer %p:%u:%x", address_, info_.len,
173 info_.flags);
174 ::munmap(address_, info_.len);
175 }
176 }
177 // Accessors
178 const mc_ioctl_buffer& info() const {
179 return info_;
180 }
181 void* address() const {
182 return address_;
183 }
184 void setSva(uint64_t sva) {
185 info_.sva = sva;
186 }
187 int update(const std::string& buf) {
188 if (buf.length() != info_.len) {
189 LOG_E("Failed to update TCI");
190 return -1;
191 }
192 if (type_ != NONE) {
193 ::memcpy(address_, buf.c_str(), info_.len);
194 }
195 return 0;
196 }
197 };
198 private:
199 uint32_t id_;
200 Buffer* tci_;
201 std::mutex buffers_mutex_;
202 std::vector<Buffer*> buffers_;
203 public:
204 Session(uint32_t id, Buffer* tci): id_(id), tci_(tci) {}
205 ~Session() {
206 delete tci_;
207 for (auto& buf: buffers_) {
208 delete buf;
209 }
210 }
211 uint32_t id() const {
212 return id_;
213 }
214 bool hasTci() const {
215 return tci_;
216 }
217 const void* tci() const {
218 return tci_->address();
219 }
220 size_t tciLen() const {
221 return tci_->info().len;
222 }
223 int updateTci(const std::string& buf) {
224 return tci_->update(buf);
225 }
226 void addBuffer(Buffer* buffer) {
227 LOG_D("%p %s: 0x%llx", this, __FUNCTION__, buffer->info().sva);
228 std::lock_guard<std::mutex> buffers_lock(buffers_mutex_);
229 buffers_.push_back(buffer);
230 }
231 void addBuffer(mc_ioctl_buffer& info) {
232 LOG_D("%p %s: 0x%llx", this, __FUNCTION__, info.sva);
233 std::lock_guard<std::mutex> buffers_lock(buffers_mutex_);
234 auto buffer = new Buffer(info);
235 buffers_.push_back(buffer);
236 }
237 int removeBuffer(uint64_t sva) {
238 LOG_D("%p %s: %jx", this, __FUNCTION__, sva);
239 std::lock_guard<std::mutex> buffers_lock(buffers_mutex_);
240 auto it = std::find_if(buffers_.begin(), buffers_.end(),
241 [this, sva](Buffer* buffer) {
242 return buffer->info().sva == sva;
243 });
244 if (it == buffers_.end()) {
245 // Not found
246 return -1;
247 }
248 delete *it;
249 buffers_.erase(it);
250 return 0;
251 }
252 // Must be called under buffers_mutex_
253 Buffer* findBuffer(uint64_t sva) {
254 for (auto& buf: buffers_) {
255 if (buf->info().sva == sva) {
256 return buf;
257 }
258 }
259 return nullptr;
260 }
261 std::mutex& buffersMutex() {
262 return buffers_mutex_;
263 }
264 const std::vector<Buffer*>& buffers() {
265 return buffers_;
266 }
267 };
268
269 static int recv_all(int sock, const char* what, void* buffer, size_t length,
270 bool may_close = false) {
271 auto cbuffer = static_cast<char*>(buffer);
272 size_t count = 0;
273 while (count < length) {
274 ssize_t rc = ::recv(sock, &cbuffer[count], length - count, 0);
275 if (rc <= 0) {
276 if (rc == 0) {
277 if (may_close) {
278 LOG_D("socket closed");
279 } else {
280 LOG_E("socket closed while receiving %s", what);
281 }
282 return -1;
283 }
284 if (errno != EINTR) {
285 LOG_ERRNO(what);
286 return -1;
287 }
288 LOG_D("signal ignored while sending %s", what);
289 continue;
290 } else {
291 count += rc;
292 }
293 }
294 return 0;
295 }
296
297 static const int32_t timeout_max = 1000; // 1s
298
299 static int send_all(int sock, const char* what, const void* buffer,
300 size_t length) {
301 auto cbuffer = static_cast<const char*>(buffer);
302 size_t count = 0;
303 while (count < length) {
304 ssize_t rc = ::send(sock, &cbuffer[count], length - count,
305 MSG_NOSIGNAL);
306 if (rc <= 0) {
307 if (rc == 0) {
308 LOG_E("socket closed while sending %s", what);
309 return -1;
310 }
311 if (errno != EINTR) {
312 LOG_ERRNO(what);
313 return -1;
314 }
315 LOG_D("signal ignored while sending %s", what);
316 continue;
317 } else {
318 count += rc;
319 }
320 }
321 return 0;
322 }
323
324 #ifndef NDEBUG
325 static const char* methodToString(enum RpcMethod method) {
326 switch (method) {
327 case OPEN_SESSION:
328 return "openSession";
329 case OPEN_TRUSTLET:
330 return "openTruslet";
331 case CLOSE_SESSION:
332 return "closeSession";
333 case NOTIFY:
334 return "notify";
335 case WAIT:
336 return "waitNotification";
337 case MAP:
338 return "map";
339 case UNMAP:
340 return "unmap";
341 case GET_ERROR:
342 return "getError";
343 case GET_VERSION:
344 return "getVersion";
345 case GP_REQUESTCANCELLATION:
346 return "gpRequestCancellation";
347 }
348 return "unknown";
349 }
350 #endif
351
352 } // namespace tee_proxy
353 } // namespace trustonic
354 } // namespace com