1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "NanohubHAL"
18
19 #include <cassert>
20 #include <cerrno>
21 #include <cinttypes>
22
23 #include <endian.h>
24
25 #include <vector>
26
27 #include <utils/Log.h>
28
29 #include <endian.h>
30
31 #include <hardware/context_hub.h>
32 #include "nanohub_perdevice.h"
33 #include "system_comms.h"
34 #include "nanohubhal.h"
35
36 namespace android {
37
38 namespace nanohub {
39
readAppName(MessageBuf & buf,hub_app_name_t & name)40 static void readAppName(MessageBuf &buf, hub_app_name_t &name) {
41 name.id = buf.readU64();
42 }
43
writeAppName(MessageBuf & buf,const hub_app_name_t & name)44 static void writeAppName(MessageBuf &buf, const hub_app_name_t &name) {
45 buf.writeU64(name.id);
46 }
47
readNanohubAppInfo(MessageBuf & buf,NanohubAppInfo & info)48 static void readNanohubAppInfo(MessageBuf &buf, NanohubAppInfo &info) {
49 size_t pos = buf.getPos();
50 readAppName(buf, info.name);
51 info.version = buf.readU32();
52 info.flashUse = buf.readU32();
53 info.ramUse = buf.readU32();
54 if ((buf.getPos() - pos) != sizeof(info)) {
55 ALOGE("%s: failed to read object", __func__);
56 }
57 }
58
readNanohubMemInfo(MessageBuf & buf,NanohubMemInfo & mi)59 static void readNanohubMemInfo(MessageBuf &buf, NanohubMemInfo &mi) {
60 size_t pos = buf.getPos();
61 mi.flashSz = buf.readU32();
62 mi.blSz = buf.readU32();
63 mi.osSz = buf.readU32();
64 mi.sharedSz = buf.readU32();
65 mi.eeSz = buf.readU32();
66 mi.ramSz = buf.readU32();
67
68 mi.blUse = buf.readU32();
69 mi.osUse = buf.readU32();
70 mi.sharedUse = buf.readU32();
71 mi.eeUse = buf.readU32();
72 mi.ramUse = buf.readU32();
73 if ((buf.getPos() - pos) != sizeof(mi)) {
74 ALOGE("%s: failed to read object", __func__);
75 }
76 }
77
NanohubRsp(MessageBuf & buf,bool no_status)78 NanohubRsp::NanohubRsp(MessageBuf &buf, bool no_status) {
79 // all responses start with command
80 // most of them have 4-byte status (result code)
81 cmd = buf.readU8();
82 if (!buf.getSize()) {
83 status = -EINVAL;
84 } else if (no_status) {
85 status = 0;
86 } else {
87 status = buf.readU32();
88 }
89 }
90
sendToSystem(const void * data,size_t len)91 int SystemComm::sendToSystem(const void *data, size_t len) {
92 if (NanoHub::messageTracingEnabled()) {
93 dumpBuffer("HAL -> SYS", getSystem()->mHostIfAppName, 0, data, len);
94 }
95 return NanoHub::sendToDevice(&getSystem()->mHostIfAppName, data, len);
96 }
97
setup(const hub_message_t *)98 int SystemComm::AppInfoSession::setup(const hub_message_t *) {
99 Mutex::Autolock _l(mLock);
100 int suggestedSize = mAppInfo.size() ? mAppInfo.size() : 20;
101
102 mAppInfo.clear();
103 mAppInfo.reserve(suggestedSize);
104 setState(SESSION_USER);
105
106 return requestNext();
107 }
108
deviceAppNameToHost(const hub_app_name_t src)109 inline hub_app_name_t deviceAppNameToHost(const hub_app_name_t src) {
110 hub_app_name_t res = { .id = le64toh(src.id) };
111 return res;
112 }
113
hostAppNameToDevice(const hub_app_name_t src)114 inline hub_app_name_t hostAppNameToDevice(const hub_app_name_t src) {
115 hub_app_name_t res = { .id = htole64(src.id) };
116 return res;
117 }
118
handleRx(MessageBuf & buf)119 int SystemComm::AppInfoSession::handleRx(MessageBuf &buf)
120 {
121 Mutex::Autolock _l(mLock);
122
123 NanohubRsp rsp(buf, true);
124 if (rsp.cmd != NANOHUB_QUERY_APPS) {
125 return 1;
126 }
127 size_t len = buf.getRoom();
128 if (len != sizeof(NanohubAppInfo) && len) {
129 ALOGE("%s: Invalid data size; have %zu, need %zu", __func__,
130 len, sizeof(NanohubAppInfo));
131 return -EINVAL;
132 }
133 if (getState() != SESSION_USER) {
134 ALOGE("%s: Invalid state; have %d, need %d", __func__, getState(), SESSION_USER);
135 return -EINVAL;
136 }
137 if (len) {
138 NanohubAppInfo info;
139 readNanohubAppInfo(buf, info);
140 hub_app_info appInfo;
141 appInfo.num_mem_ranges = 0;
142 if (info.flashUse != NANOHUB_MEM_SZ_UNKNOWN) {
143 mem_range_t &range = appInfo.mem_usage[appInfo.num_mem_ranges++];
144 range.type = HUB_MEM_TYPE_MAIN;
145 range.total_bytes = info.flashUse;
146 }
147 if (info.ramUse != NANOHUB_MEM_SZ_UNKNOWN) {
148 mem_range_t &range = appInfo.mem_usage[appInfo.num_mem_ranges++];
149 range.type = HUB_MEM_TYPE_RAM;
150 range.total_bytes = info.ramUse;
151 }
152
153 appInfo.app_name = info.name;
154 appInfo.version = info.version;
155
156 mAppInfo.push_back(appInfo);
157 return requestNext();
158 } else {
159 sendToApp(CONTEXT_HUB_QUERY_APPS,
160 static_cast<const void *>(mAppInfo.data()),
161 mAppInfo.size() * sizeof(mAppInfo[0]));
162 complete();
163 }
164
165 return 0;
166 }
167
requestNext()168 int SystemComm::AppInfoSession::requestNext()
169 {
170 char data[MAX_RX_PACKET];
171 MessageBuf buf(data, sizeof(data));
172 buf.writeU8(NANOHUB_QUERY_APPS);
173 buf.writeU32(mAppInfo.size());
174 return sendToSystem(buf.getData(), buf.getPos());
175 }
176
setup(const hub_message_t *)177 int SystemComm::GlobalSession::setup(const hub_message_t *) {
178 Mutex::Autolock _l(mLock);
179
180 setState(SESSION_USER);
181
182 return 0;
183 }
184
handleRx(MessageBuf & buf)185 int SystemComm::GlobalSession::handleRx(MessageBuf &buf)
186 {
187 Mutex::Autolock _l(mLock);
188
189 NanohubRsp rsp(buf);
190 if (rsp.cmd != NANOHUB_REBOOT) {
191 return 1;
192 }
193
194 ALOGW("Nanohub reboot status [UNSOLICITED]: %08" PRIX32, rsp.status);
195 sendToApp(CONTEXT_HUB_OS_REBOOT, &rsp.status, sizeof(rsp.status));
196
197 return 0;
198 }
199
setup(const hub_message_t *)200 int SystemComm::MemInfoSession::setup(const hub_message_t *)
201 {
202 Mutex::Autolock _l(mLock);
203 char data[MAX_RX_PACKET];
204 MessageBuf buf(data, sizeof(data));
205 buf.writeU8(NANOHUB_QUERY_MEMINFO);
206
207 setState(SESSION_USER);
208 return sendToSystem(buf.getData(), buf.getPos());
209 }
210
handleRx(MessageBuf & buf)211 int SystemComm::MemInfoSession::handleRx(MessageBuf &buf)
212 {
213 Mutex::Autolock _l(mLock);
214 NanohubRsp rsp(buf, true);
215
216 if (rsp.cmd != NANOHUB_QUERY_MEMINFO)
217 return 1;
218
219 size_t len = buf.getRoom();
220
221 if (len != sizeof(NanohubMemInfo)) {
222 ALOGE("%s: Invalid data size: %zu", __func__, len);
223 return -EINVAL;
224 }
225 if (getState() != SESSION_USER) {
226 ALOGE("%s: Invalid state; have %d, need %d", __func__, getState(), SESSION_USER);
227 return -EINVAL;
228 }
229
230 NanohubMemInfo mi;
231 readNanohubMemInfo(buf, mi);
232 std::vector<mem_range_t> ranges;
233 ranges.reserve(4);
234
235 //if each is valid, copy to output area
236 if (mi.sharedSz != NANOHUB_MEM_SZ_UNKNOWN &&
237 mi.sharedUse != NANOHUB_MEM_SZ_UNKNOWN)
238 ranges.push_back({
239 .type = HUB_MEM_TYPE_MAIN,
240 .total_bytes = mi.sharedSz,
241 .free_bytes = mi.sharedSz - mi.sharedUse,
242 });
243
244 if (mi.osSz != NANOHUB_MEM_SZ_UNKNOWN &&
245 mi.osUse != NANOHUB_MEM_SZ_UNKNOWN)
246 ranges.push_back({
247 .type = HUB_MEM_TYPE_OS,
248 .total_bytes = mi.osSz,
249 .free_bytes = mi.osSz - mi.osUse,
250 });
251
252 if (mi.eeSz != NANOHUB_MEM_SZ_UNKNOWN &&
253 mi.eeUse != NANOHUB_MEM_SZ_UNKNOWN)
254 ranges.push_back({
255 .type = HUB_MEM_TYPE_EEDATA,
256 .total_bytes = mi.eeSz,
257 .free_bytes = mi.eeSz - mi.eeUse,
258 });
259
260 if (mi.ramSz != NANOHUB_MEM_SZ_UNKNOWN &&
261 mi.ramUse != NANOHUB_MEM_SZ_UNKNOWN)
262 ranges.push_back({
263 .type = HUB_MEM_TYPE_RAM,
264 .total_bytes = mi.ramSz,
265 .free_bytes = mi.ramSz - mi.ramUse,
266 });
267
268 //send it out
269 sendToApp(CONTEXT_HUB_QUERY_MEMORY,
270 static_cast<const void *>(ranges.data()),
271 ranges.size() * sizeof(ranges[0]));
272
273 complete();
274
275 return 0;
276 }
277
setup(const hub_message_t * appMsg)278 int SystemComm::AppMgmtSession::setup(const hub_message_t *appMsg)
279 {
280 Mutex::Autolock _l(mLock);
281
282 char data[MAX_RX_PACKET];
283 MessageBuf buf(data, sizeof(data));
284 const uint8_t *msgData = static_cast<const uint8_t*>(appMsg->message);
285
286 mCmd = appMsg->message_type;
287 mLen = appMsg->message_len;
288 mPos = 0;
289
290 switch (mCmd) {
291 case CONTEXT_HUB_APPS_ENABLE:
292 return setupMgmt(appMsg, NANOHUB_EXT_APPS_ON);
293 case CONTEXT_HUB_APPS_DISABLE:
294 return setupMgmt(appMsg, NANOHUB_EXT_APPS_OFF);
295 case CONTEXT_HUB_UNLOAD_APP:
296 return setupMgmt(appMsg, NANOHUB_EXT_APP_DELETE);
297 case CONTEXT_HUB_LOAD_OS:
298 case CONTEXT_HUB_LOAD_APP:
299 mData.clear();
300 mData = std::vector<uint8_t>(msgData, msgData + mLen);
301 setState(TRANSFER);
302
303 buf.writeU8(NANOHUB_START_UPLOAD);
304 buf.writeU8(mCmd == CONTEXT_HUB_LOAD_OS ? 1 : 0);
305 buf.writeU32(mLen);
306 return sendToSystem(buf.getData(), buf.getPos());
307
308 case CONTEXT_HUB_OS_REBOOT:
309 setState(REBOOT);
310 buf.writeU8(NANOHUB_REBOOT);
311 return sendToSystem(buf.getData(), buf.getPos());
312 }
313
314 return -EINVAL;
315 }
316
setupMgmt(const hub_message_t * appMsg,uint32_t cmd)317 int SystemComm::AppMgmtSession::setupMgmt(const hub_message_t *appMsg, uint32_t cmd)
318 {
319 const hub_app_name_t &appName = *static_cast<const hub_app_name_t*>(appMsg->message);
320 if (appMsg->message_len != sizeof(appName)) {
321 return -EINVAL;
322 }
323
324 char data[MAX_RX_PACKET];
325 MessageBuf buf(data, sizeof(data));
326 buf.writeU8(cmd);
327 writeAppName(buf, appName);
328 setState(MGMT);
329
330 return sendToSystem(buf.getData(), buf.getPos());
331 }
332
handleRx(MessageBuf & buf)333 int SystemComm::AppMgmtSession::handleRx(MessageBuf &buf)
334 {
335 int ret = 0;
336 Mutex::Autolock _l(mLock);
337 NanohubRsp rsp(buf);
338
339 switch (getState()) {
340 case TRANSFER:
341 ret = handleTransfer(rsp);
342 break;
343 case FINISH:
344 ret = handleFinish(rsp);
345 break;
346 case RELOAD:
347 ret = handleReload(rsp);
348 break;
349 case REBOOT:
350 ret = handleReboot(rsp);
351 break;
352 case MGMT:
353 ret = handleMgmt(rsp);
354 break;
355 }
356
357 return ret;
358 }
359
handleTransfer(NanohubRsp & rsp)360 int SystemComm::AppMgmtSession::handleTransfer(NanohubRsp &rsp)
361 {
362 if (rsp.cmd != NANOHUB_CONT_UPLOAD && rsp.cmd != NANOHUB_START_UPLOAD)
363 return 1;
364
365 char data[MAX_RX_PACKET];
366 MessageBuf buf(data, sizeof(data));
367
368 static_assert(NANOHUB_UPLOAD_CHUNK_SZ_MAX <= (MAX_RX_PACKET-5),
369 "Invalid chunk size");
370
371 if (mPos < mLen) {
372 uint32_t chunkSize = mLen - mPos;
373
374 if (chunkSize > NANOHUB_UPLOAD_CHUNK_SZ_MAX) {
375 chunkSize = NANOHUB_UPLOAD_CHUNK_SZ_MAX;
376 }
377
378 buf.writeU8(NANOHUB_CONT_UPLOAD);
379 buf.writeU32(mPos);
380 buf.writeRaw(&mData[mPos], chunkSize);
381 mPos += chunkSize;
382 } else {
383 buf.writeU8(NANOHUB_FINISH_UPLOAD);
384 setState(FINISH);
385 }
386
387 return sendToSystem(buf.getData(), buf.getPos());
388 }
389
handleFinish(NanohubRsp & rsp)390 int SystemComm::AppMgmtSession::handleFinish(NanohubRsp &rsp)
391 {
392 if (rsp.cmd != NANOHUB_FINISH_UPLOAD)
393 return 1;
394
395 int ret = 0;
396 const bool success = rsp.status != 0;
397 mData.clear();
398
399 if (success) {
400 char data[MAX_RX_PACKET];
401 MessageBuf buf(data, sizeof(data));
402 // until app header is passed, we don't know who to start, so we reboot
403 buf.writeU8(NANOHUB_REBOOT);
404 setState(RELOAD);
405 ret = sendToSystem(buf.getData(), buf.getPos());
406 } else {
407 int32_t result = NANOHUB_APP_NOT_LOADED;
408
409 sendToApp(mCmd, &result, sizeof(result));
410 complete();
411 }
412
413 return ret;
414 }
415
416 /* reboot notification, when triggered as part of App reload sequence */
handleReload(NanohubRsp & rsp)417 int SystemComm::AppMgmtSession::handleReload(NanohubRsp &rsp)
418 {
419 int32_t result = NANOHUB_APP_LOADED;
420
421 ALOGI("Nanohub reboot status [NEW APP START]: %08" PRIX32, rsp.status);
422
423 sendToApp(mCmd, &result, sizeof(result));
424
425 // in addition to sending response to the CONTEXT_HUB_LOAD_APP command,
426 // we should send unsolicited reboot notification;
427 // I choose to do it here rather than delegate it to global session
428 // because I want the log to clearly differentiate between UNSOLICITED reboots
429 // (meaning FW faults) and REQUESTED reboots.
430 sendToApp(CONTEXT_HUB_OS_REBOOT, &rsp.status, sizeof(rsp.status));
431
432 complete();
433
434 return 0;
435 }
436
437 /* reboot notification, when triggered by App request */
handleReboot(NanohubRsp & rsp)438 int SystemComm::AppMgmtSession::handleReboot(NanohubRsp &rsp)
439 {
440 ALOGI("Nanohub reboot status [USER REQ]: %08" PRIX32, rsp.status);
441
442 sendToApp(mCmd, &rsp.status, sizeof(rsp.status));
443 complete();
444
445 return 0;
446 }
447
handleMgmt(NanohubRsp & rsp)448 int SystemComm::AppMgmtSession::handleMgmt(NanohubRsp &rsp)
449 {
450 Mutex::Autolock _l(mLock);
451 bool valid = false;
452
453 ALOGI("Nanohub MGMT response: CMD=%02X; STATUS=%08" PRIX32, rsp.cmd, rsp.status);
454
455 switch (rsp.cmd) {
456 case NANOHUB_EXT_APPS_OFF:
457 valid = mCmd == CONTEXT_HUB_APPS_DISABLE;
458 break;
459 case NANOHUB_EXT_APPS_ON:
460 valid = mCmd == CONTEXT_HUB_APPS_ENABLE;
461 break;
462 case NANOHUB_EXT_APP_DELETE:
463 valid = mCmd == CONTEXT_HUB_UNLOAD_APP;
464 break;
465 default:
466 return 1;
467 }
468
469 if (!valid) {
470 ALOGE("Invalid response for this state: APP CMD=%02X", mCmd);
471 return -EINVAL;
472 }
473
474 sendToApp(mCmd, &rsp.status, sizeof(rsp.status));
475 complete();
476
477 return 0;
478 }
479
setup(const hub_message_t *)480 int SystemComm::KeyInfoSession::setup(const hub_message_t *) {
481 Mutex::Autolock _l(mLock);
482 mRsaKeyData.clear();
483 setState(SESSION_USER);
484 mStatus = -EBUSY;
485 return requestRsaKeys();
486 }
487
handleRx(MessageBuf & buf)488 int SystemComm::KeyInfoSession::handleRx(MessageBuf &buf)
489 {
490 Mutex::Autolock _l(mLock);
491 NanohubRsp rsp(buf, true);
492
493 if (getState() != SESSION_USER) {
494 // invalid state
495 mStatus = -EFAULT;
496 return mStatus;
497 }
498
499 if (buf.getRoom()) {
500 mRsaKeyData.insert(mRsaKeyData.end(),
501 buf.getData() + buf.getPos(),
502 buf.getData() + buf.getSize());
503 return requestRsaKeys();
504 } else {
505 mStatus = 0;
506 complete();
507 return 0;
508 }
509 }
510
requestRsaKeys(void)511 int SystemComm::KeyInfoSession::requestRsaKeys(void)
512 {
513 char data[MAX_RX_PACKET];
514 MessageBuf buf(data, sizeof(data));
515
516 buf.writeU8(NANOHUB_QUERY_APPS);
517 buf.writeU32(mRsaKeyData.size());
518
519 return sendToSystem(buf.getData(), buf.getPos());
520 }
521
doHandleRx(const nano_message * msg)522 int SystemComm::doHandleRx(const nano_message *msg)
523 {
524 //we only care for messages from HostIF
525 if (msg->hdr.app_name != mHostIfAppName)
526 return 1;
527
528 //they must all be at least 1 byte long
529 if (!msg->hdr.len) {
530 return -EINVAL;
531 }
532 MessageBuf buf(reinterpret_cast<const char*>(msg->data), msg->hdr.len);
533 if (NanoHub::messageTracingEnabled()) {
534 dumpBuffer("SYS -> HAL", mHostIfAppName, 0, buf.getData(), buf.getSize());
535 }
536 int status = mSessions.handleRx(buf);
537 if (status) {
538 // provide default handler for any system message, that is not properly handled
539 dumpBuffer(status > 0 ? "HAL (not handled)" : "HAL (error)",
540 mHostIfAppName, 0, buf.getData(), buf.getSize(), status);
541 status = status > 0 ? 0 : status;
542 }
543
544 return status;
545 }
546
handleRx(MessageBuf & buf)547 int SystemComm::SessionManager::handleRx(MessageBuf &buf)
548 {
549 int status = 1;
550
551 // pass message to all active sessions, in arbitrary order
552 // 1st session that handles the message terminates the loop
553 for (auto pos = sessions_.begin();
554 pos != sessions_.end() && status > 0; next(pos)) {
555 Session *session = pos->second;
556 status = session->handleRx(buf);
557 if (status < 0) {
558 session->complete();
559 }
560 }
561 if (status > 0) {
562 status = mGlobal.handleRx(buf);
563 }
564
565 return status;
566 }
567
doHandleTx(const hub_message_t * appMsg)568 int SystemComm::doHandleTx(const hub_message_t *appMsg)
569 {
570 int status = 0;
571
572 switch (appMsg->message_type) {
573 case CONTEXT_HUB_LOAD_APP:
574 if (!mKeySession.haveKeys()) {
575 status = mSessions.setup_and_add(CONTEXT_HUB_LOAD_APP, &mKeySession, appMsg);
576 if (status < 0) {
577 break;
578 }
579 mKeySession.wait();
580 status = mKeySession.getStatus();
581 if (status < 0) {
582 break;
583 }
584 }
585 status = mSessions.setup_and_add(CONTEXT_HUB_LOAD_APP, &mAppMgmtSession, appMsg);
586 break;
587 case CONTEXT_HUB_APPS_ENABLE:
588 case CONTEXT_HUB_APPS_DISABLE:
589 case CONTEXT_HUB_UNLOAD_APP:
590 // all APP-modifying commands share session key, to ensure they can't happen at the same time
591 status = mSessions.setup_and_add(CONTEXT_HUB_LOAD_APP, &mAppMgmtSession, appMsg);
592 break;
593
594 case CONTEXT_HUB_QUERY_APPS:
595 status = mSessions.setup_and_add(CONTEXT_HUB_QUERY_APPS, &mAppInfoSession, appMsg);
596 break;
597
598 case CONTEXT_HUB_QUERY_MEMORY:
599 status = mSessions.setup_and_add(CONTEXT_HUB_QUERY_MEMORY, &mMemInfoSession, appMsg);
600 break;
601
602 default:
603 ALOGW("Unknown os message type %u\n", appMsg->message_type);
604 return -EINVAL;
605 }
606
607 return status;
608 }
609
610 }; // namespace nanohub
611
612 }; // namespace android
613