• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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