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