1 /*
2 * Copyright (c) 2016, Google. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #define LOG_TAG "NanohubHAL"
31
32 #include <cassert>
33 #include <cerrno>
34 #include <cinttypes>
35
36 #include <endian.h>
37
38 #include <vector>
39
40 #include <utils/Log.h>
41
42 #include <endian.h>
43
44 #include <hardware/context_hub.h>
45 #include "nanohub_perdevice.h"
46 #include "system_comms.h"
47 #include "nanohubhal.h"
48
49 namespace android {
50
51 namespace nanohub {
52
readAppName(MessageBuf & buf,hub_app_name_t & name)53 static void readAppName(MessageBuf &buf, hub_app_name_t &name) {
54 name.id = buf.readU64();
55 }
56
writeAppName(MessageBuf & buf,const hub_app_name_t & name)57 static void writeAppName(MessageBuf &buf, const hub_app_name_t &name) {
58 buf.writeU64(name.id);
59 }
60
readNanohubAppInfo(MessageBuf & buf,NanohubAppInfo & info)61 static void readNanohubAppInfo(MessageBuf &buf, NanohubAppInfo &info) {
62 size_t pos = buf.getPos();
63 readAppName(buf, info.name);
64 info.version = buf.readU32();
65 info.flashUse = buf.readU32();
66 info.ramUse = buf.readU32();
67 if ((buf.getPos() - pos) != sizeof(info)) {
68 ALOGE("%s: failed to read object", __func__);
69 }
70 }
71
readNanohubMemInfo(MessageBuf & buf,NanohubMemInfo & mi)72 static void readNanohubMemInfo(MessageBuf &buf, NanohubMemInfo &mi) {
73 size_t pos = buf.getPos();
74 mi.flashSz = buf.readU32();
75 mi.blSz = buf.readU32();
76 mi.osSz = buf.readU32();
77 mi.sharedSz = buf.readU32();
78 mi.eeSz = buf.readU32();
79 mi.ramSz = buf.readU32();
80
81 mi.blUse = buf.readU32();
82 mi.osUse = buf.readU32();
83 mi.sharedUse = buf.readU32();
84 mi.eeUse = buf.readU32();
85 mi.ramUse = buf.readU32();
86 if ((buf.getPos() - pos) != sizeof(mi)) {
87 ALOGE("%s: failed to read object", __func__);
88 }
89 }
90
NanohubRsp(MessageBuf & buf,bool no_status)91 NanohubRsp::NanohubRsp(MessageBuf &buf, bool no_status) {
92 // all responses start with command
93 // most of them have 4-byte status (result code)
94 cmd = buf.readU8();
95 if (!buf.getSize()) {
96 status = -EINVAL;
97 } else if (no_status) {
98 status = 0;
99 } else {
100 status = buf.readU32();
101 }
102 }
103
sendToSystem(const void * data,size_t len)104 int SystemComm::sendToSystem(const void *data, size_t len) {
105 if (NanoHub::messageTracingEnabled()) {
106 dumpBuffer("HAL -> SYS", getSystem()->mHostIfAppName, 0, data, len);
107 }
108 return NanoHub::sendToDevice(&getSystem()->mHostIfAppName, data, len);
109 }
110
setup(const hub_message_t *)111 int SystemComm::AppInfoSession::setup(const hub_message_t *) {
112 Mutex::Autolock _l(mLock);
113 int suggestedSize = mAppInfo.size() ? mAppInfo.size() : 20;
114
115 mAppInfo.clear();
116 mAppInfo.reserve(suggestedSize);
117 setState(SESSION_USER);
118
119 return requestNext();
120 }
121
deviceAppNameToHost(const hub_app_name_t src)122 inline hub_app_name_t deviceAppNameToHost(const hub_app_name_t src) {
123 hub_app_name_t res = { .id = le64toh(src.id) };
124 return res;
125 }
126
hostAppNameToDevice(const hub_app_name_t src)127 inline hub_app_name_t hostAppNameToDevice(const hub_app_name_t src) {
128 hub_app_name_t res = { .id = htole64(src.id) };
129 return res;
130 }
131
handleRx(MessageBuf & buf)132 int SystemComm::AppInfoSession::handleRx(MessageBuf &buf)
133 {
134 Mutex::Autolock _l(mLock);
135
136 NanohubRsp rsp(buf, true);
137 if (rsp.cmd != NANOHUB_QUERY_APPS) {
138 return 1;
139 }
140 size_t len = buf.getRoom();
141 if (len != sizeof(NanohubAppInfo) && len) {
142 ALOGE("%s: Invalid data size; have %zu, need %zu", __func__,
143 len, sizeof(NanohubAppInfo));
144 return -EINVAL;
145 }
146 if (getState() != SESSION_USER) {
147 ALOGE("%s: Invalid state; have %d, need %d", __func__, getState(), SESSION_USER);
148 return -EINVAL;
149 }
150 if (len) {
151 NanohubAppInfo info;
152 readNanohubAppInfo(buf, info);
153 hub_app_info appInfo;
154 appInfo.num_mem_ranges = 0;
155 if (info.flashUse != NANOHUB_MEM_SZ_UNKNOWN) {
156 mem_range_t &range = appInfo.mem_usage[appInfo.num_mem_ranges++];
157 range.type = HUB_MEM_TYPE_MAIN;
158 range.total_bytes = info.flashUse;
159 }
160 if (info.ramUse != NANOHUB_MEM_SZ_UNKNOWN) {
161 mem_range_t &range = appInfo.mem_usage[appInfo.num_mem_ranges++];
162 range.type = HUB_MEM_TYPE_RAM;
163 range.total_bytes = info.ramUse;
164 }
165
166 appInfo.app_name = info.name;
167 appInfo.version = info.version;
168
169 mAppInfo.push_back(appInfo);
170 return requestNext();
171 } else {
172 sendToApp(CONTEXT_HUB_QUERY_APPS,
173 static_cast<const void *>(mAppInfo.data()),
174 mAppInfo.size() * sizeof(mAppInfo[0]));
175 complete();
176 }
177
178 return 0;
179 }
180
requestNext()181 int SystemComm::AppInfoSession::requestNext()
182 {
183 char data[MAX_RX_PACKET];
184 MessageBuf buf(data, sizeof(data));
185 buf.writeU8(NANOHUB_QUERY_APPS);
186 buf.writeU32(mAppInfo.size());
187 return sendToSystem(buf.getData(), buf.getPos());
188 }
189
setup(const hub_message_t *)190 int SystemComm::MemInfoSession::setup(const hub_message_t *)
191 {
192 Mutex::Autolock _l(mLock);
193 char data[MAX_RX_PACKET];
194 MessageBuf buf(data, sizeof(data));
195 buf.writeU8(NANOHUB_QUERY_MEMINFO);
196
197 setState(SESSION_USER);
198 return sendToSystem(buf.getData(), buf.getPos());
199 }
200
handleRx(MessageBuf & buf)201 int SystemComm::MemInfoSession::handleRx(MessageBuf &buf)
202 {
203 Mutex::Autolock _l(mLock);
204 NanohubRsp rsp(buf, true);
205
206 if (rsp.cmd != NANOHUB_QUERY_MEMINFO)
207 return 1;
208
209 size_t len = buf.getRoom();
210
211 if (len != sizeof(NanohubMemInfo)) {
212 ALOGE("%s: Invalid data size: %zu", __func__, len);
213 return -EINVAL;
214 }
215 if (getState() != SESSION_USER) {
216 ALOGE("%s: Invalid state; have %d, need %d", __func__, getState(), SESSION_USER);
217 return -EINVAL;
218 }
219
220 NanohubMemInfo mi;
221 readNanohubMemInfo(buf, mi);
222 std::vector<mem_range_t> ranges;
223 ranges.reserve(4);
224
225 //if each is valid, copy to output area
226 if (mi.sharedSz != NANOHUB_MEM_SZ_UNKNOWN &&
227 mi.sharedUse != NANOHUB_MEM_SZ_UNKNOWN)
228 ranges.push_back({
229 .type = HUB_MEM_TYPE_MAIN,
230 .total_bytes = mi.sharedSz,
231 .free_bytes = mi.sharedSz - mi.sharedUse,
232 });
233
234 if (mi.osSz != NANOHUB_MEM_SZ_UNKNOWN &&
235 mi.osUse != NANOHUB_MEM_SZ_UNKNOWN)
236 ranges.push_back({
237 .type = HUB_MEM_TYPE_OS,
238 .total_bytes = mi.osSz,
239 .free_bytes = mi.osSz - mi.osUse,
240 });
241
242 if (mi.eeSz != NANOHUB_MEM_SZ_UNKNOWN &&
243 mi.eeUse != NANOHUB_MEM_SZ_UNKNOWN)
244 ranges.push_back({
245 .type = HUB_MEM_TYPE_EEDATA,
246 .total_bytes = mi.eeSz,
247 .free_bytes = mi.eeSz - mi.eeUse,
248 });
249
250 if (mi.ramSz != NANOHUB_MEM_SZ_UNKNOWN &&
251 mi.ramUse != NANOHUB_MEM_SZ_UNKNOWN)
252 ranges.push_back({
253 .type = HUB_MEM_TYPE_RAM,
254 .total_bytes = mi.ramSz,
255 .free_bytes = mi.ramSz - mi.ramUse,
256 });
257
258 //send it out
259 sendToApp(CONTEXT_HUB_QUERY_MEMORY,
260 static_cast<const void *>(ranges.data()),
261 ranges.size() * sizeof(ranges[0]));
262
263 complete();
264
265 return 0;
266 }
267
setup(const hub_message_t * appMsg)268 int SystemComm::AppMgmtSession::setup(const hub_message_t *appMsg)
269 {
270 Mutex::Autolock _l(mLock);
271
272 mCmd = appMsg->message_type;
273 mLen = appMsg->message_len;
274 mPos = 0;
275
276 switch (mCmd) {
277 case CONTEXT_HUB_APPS_ENABLE:
278 return setupMgmt(appMsg, NANOHUB_EXT_APPS_ON);
279 case CONTEXT_HUB_APPS_DISABLE:
280 return setupMgmt(appMsg, NANOHUB_EXT_APPS_OFF);
281 case CONTEXT_HUB_UNLOAD_APP:
282 return setupMgmt(appMsg, NANOHUB_EXT_APP_DELETE);
283 case CONTEXT_HUB_LOAD_OS:
284 case CONTEXT_HUB_LOAD_APP:
285 const uint8_t *p = static_cast<const uint8_t*>(appMsg->message);
286 mData.clear();
287 mData = std::vector<uint8_t>(p, p + mLen);
288 setState(TRANSFER);
289
290 char data[MAX_RX_PACKET];
291 MessageBuf buf(data, sizeof(data));
292 buf.writeU8(NANOHUB_START_UPLOAD);
293 buf.writeU8(mCmd == CONTEXT_HUB_LOAD_OS ? 1 : 0);
294 buf.writeU32(mLen);
295
296 return sendToSystem(buf.getData(), buf.getPos());
297 break;
298 }
299
300 return -EINVAL;
301 }
302
setupMgmt(const hub_message_t * appMsg,uint32_t cmd)303 int SystemComm::AppMgmtSession::setupMgmt(const hub_message_t *appMsg, uint32_t cmd)
304 {
305 const hub_app_name_t &appName = *static_cast<const hub_app_name_t*>(appMsg->message);
306 if (appMsg->message_len != sizeof(appName)) {
307 return -EINVAL;
308 }
309
310 char data[MAX_RX_PACKET];
311 MessageBuf buf(data, sizeof(data));
312 buf.writeU8(cmd);
313 writeAppName(buf, appName);
314 setState(MGMT);
315
316 return sendToSystem(buf.getData(), buf.getPos());
317 }
318
handleRx(MessageBuf & buf)319 int SystemComm::AppMgmtSession::handleRx(MessageBuf &buf)
320 {
321 int ret = 0;
322 Mutex::Autolock _l(mLock);
323 NanohubRsp rsp(buf);
324
325 switch (getState()) {
326 case TRANSFER:
327 ret = handleTransfer(rsp);
328 break;
329 case FINISH:
330 ret = handleFinish(rsp);
331 break;
332 case RELOAD:
333 ret = handleReload(rsp);
334 break;
335 case MGMT:
336 ret = handleMgmt(rsp);
337 break;
338 }
339
340 return ret;
341 }
342
handleTransfer(NanohubRsp & rsp)343 int SystemComm::AppMgmtSession::handleTransfer(NanohubRsp &rsp)
344 {
345 if (rsp.cmd != NANOHUB_CONT_UPLOAD && rsp.cmd != NANOHUB_START_UPLOAD)
346 return 1;
347
348 char data[MAX_RX_PACKET];
349 MessageBuf buf(data, sizeof(data));
350
351 static_assert(NANOHUB_UPLOAD_CHUNK_SZ_MAX <= (MAX_RX_PACKET-5),
352 "Invalid chunk size");
353
354 if (mPos < mLen) {
355 uint32_t chunkSize = mLen - mPos;
356
357 if (chunkSize > NANOHUB_UPLOAD_CHUNK_SZ_MAX) {
358 chunkSize = NANOHUB_UPLOAD_CHUNK_SZ_MAX;
359 }
360
361 buf.writeU8(NANOHUB_CONT_UPLOAD);
362 buf.writeU32(mPos);
363 buf.writeRaw(&mData[mPos], chunkSize);
364 mPos += chunkSize;
365 } else {
366 buf.writeU8(NANOHUB_FINISH_UPLOAD);
367 setState(FINISH);
368 }
369
370 return sendToSystem(buf.getData(), buf.getPos());
371 }
372
handleFinish(NanohubRsp & rsp)373 int SystemComm::AppMgmtSession::handleFinish(NanohubRsp &rsp)
374 {
375 if (rsp.cmd != NANOHUB_FINISH_UPLOAD)
376 return 1;
377
378 int ret = 0;
379 const bool success = rsp.status != 0;
380 mData.clear();
381
382 if (success) {
383 char data[MAX_RX_PACKET];
384 MessageBuf buf(data, sizeof(data));
385 // until app header is passed, we don't know who to start, so we reboot
386 buf.writeU8(NANOHUB_REBOOT);
387 setState(RELOAD);
388 ret = sendToSystem(buf.getData(), buf.getPos());
389 } else {
390 int32_t result = NANOHUB_APP_NOT_LOADED;
391
392 sendToApp(mCmd, &result, sizeof(result));
393 complete();
394 }
395
396 return ret;
397 }
398
399 /* reboot notification is not yet supported in FW; this code is for (near) future */
handleReload(NanohubRsp & rsp)400 int SystemComm::AppMgmtSession::handleReload(NanohubRsp &rsp)
401 {
402 int32_t result = NANOHUB_APP_LOADED;
403
404 ALOGI("Nanohub reboot status: %08" PRIX32, rsp.status);
405
406 sendToApp(mCmd, &result, sizeof(result));
407 complete();
408
409 return 0;
410 }
411
handleMgmt(NanohubRsp & rsp)412 int SystemComm::AppMgmtSession::handleMgmt(NanohubRsp &rsp)
413 {
414 Mutex::Autolock _l(mLock);
415 bool valid = false;
416
417 ALOGI("Nanohub MGMT response: CMD=%02X; STATUS=%08" PRIX32, rsp.cmd, rsp.status);
418
419 switch (rsp.cmd) {
420 case NANOHUB_EXT_APPS_OFF:
421 valid = mCmd == CONTEXT_HUB_APPS_DISABLE;
422 break;
423 case NANOHUB_EXT_APPS_ON:
424 valid = mCmd == CONTEXT_HUB_APPS_ENABLE;
425 break;
426 case NANOHUB_EXT_APP_DELETE:
427 valid = mCmd == CONTEXT_HUB_UNLOAD_APP;
428 break;
429 default:
430 return 1;
431 }
432
433 if (!valid) {
434 ALOGE("Invalid response for this state: APP CMD=%02X", mCmd);
435 return -EINVAL;
436 }
437
438 sendToApp(mCmd, &rsp.status, sizeof(rsp.status));
439 complete();
440
441 return 0;
442 }
443
setup(const hub_message_t *)444 int SystemComm::KeyInfoSession::setup(const hub_message_t *) {
445 Mutex::Autolock _l(mLock);
446 mRsaKeyData.clear();
447 setState(SESSION_USER);
448 mStatus = -EBUSY;
449 return requestRsaKeys();
450 }
451
handleRx(MessageBuf & buf)452 int SystemComm::KeyInfoSession::handleRx(MessageBuf &buf)
453 {
454 Mutex::Autolock _l(mLock);
455 NanohubRsp rsp(buf, true);
456
457 if (getState() != SESSION_USER) {
458 // invalid state
459 mStatus = -EFAULT;
460 return mStatus;
461 }
462
463 if (buf.getRoom()) {
464 mRsaKeyData.insert(mRsaKeyData.end(),
465 buf.getData() + buf.getPos(),
466 buf.getData() + buf.getSize());
467 return requestRsaKeys();
468 } else {
469 mStatus = 0;
470 complete();
471 return 0;
472 }
473 }
474
requestRsaKeys(void)475 int SystemComm::KeyInfoSession::requestRsaKeys(void)
476 {
477 char data[MAX_RX_PACKET];
478 MessageBuf buf(data, sizeof(data));
479
480 buf.writeU8(NANOHUB_QUERY_APPS);
481 buf.writeU32(mRsaKeyData.size());
482
483 return sendToSystem(buf.getData(), buf.getPos());
484 }
485
doHandleRx(const nano_message * msg)486 int SystemComm::doHandleRx(const nano_message *msg)
487 {
488 //we only care for messages from HostIF
489 if (msg->hdr.app_name != mHostIfAppName)
490 return 1;
491
492 //they must all be at least 1 byte long
493 if (!msg->hdr.len) {
494 return -EINVAL;
495 }
496 MessageBuf buf(reinterpret_cast<const char*>(msg->data), msg->hdr.len);
497 if (NanoHub::messageTracingEnabled()) {
498 dumpBuffer("SYS -> HAL", mHostIfAppName, 0, buf.getData(), buf.getSize());
499 }
500 int status = mSessions.handleRx(buf);
501 if (status) {
502 // provide default handler for any system message, that is not properly handled
503 dumpBuffer(status > 0 ? "HAL (not handled)" : "HAL (error)",
504 mHostIfAppName, 0, buf.getData(), buf.getSize(), status);
505 status = status > 0 ? 0 : status;
506 }
507
508 return status;
509 }
510
handleRx(MessageBuf & buf)511 int SystemComm::SessionManager::handleRx(MessageBuf &buf)
512 {
513 int status = 1;
514
515 // pass message to all active sessions, in arbitrary order
516 // 1st session that handles the message terminates the loop
517 for (auto pos = sessions_.begin();
518 pos != sessions_.end() && status > 0; next(pos)) {
519 Session *session = pos->second;
520 status = session->handleRx(buf);
521 if (status < 0) {
522 session->complete();
523 }
524 }
525
526 return status;
527 }
528
doHandleTx(const hub_message_t * appMsg)529 int SystemComm::doHandleTx(const hub_message_t *appMsg)
530 {
531 int status = 0;
532
533 switch (appMsg->message_type) {
534 case CONTEXT_HUB_LOAD_APP:
535 if (!mKeySession.haveKeys()) {
536 status = mSessions.setup_and_add(CONTEXT_HUB_LOAD_APP, &mKeySession, appMsg);
537 if (status < 0) {
538 break;
539 }
540 mKeySession.wait();
541 status = mKeySession.getStatus();
542 if (status < 0) {
543 break;
544 }
545 }
546 status = mSessions.setup_and_add(CONTEXT_HUB_LOAD_APP, &mAppMgmtSession, appMsg);
547 break;
548 case CONTEXT_HUB_APPS_ENABLE:
549 case CONTEXT_HUB_APPS_DISABLE:
550 case CONTEXT_HUB_UNLOAD_APP:
551 // all APP-modifying commands share session key, to ensure they can't happen at the same time
552 status = mSessions.setup_and_add(CONTEXT_HUB_LOAD_APP, &mAppMgmtSession, appMsg);
553 break;
554
555 case CONTEXT_HUB_QUERY_APPS:
556 status = mSessions.setup_and_add(CONTEXT_HUB_QUERY_APPS, &mAppInfoSession, appMsg);
557 break;
558
559 case CONTEXT_HUB_QUERY_MEMORY:
560 status = mSessions.setup_and_add(CONTEXT_HUB_QUERY_MEMORY, &mMemInfoSession, appMsg);
561 break;
562
563 default:
564 ALOGW("Unknown os message type %u\n", appMsg->message_type);
565 return -EINVAL;
566 }
567
568 return status;
569 }
570
571 }; // namespace nanohub
572
573 }; // namespace android
574