Home | History | Annotate | Download | only in contexthubhal
      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 
     40 static void readAppName(MessageBuf &buf, hub_app_name_t &name) {
     41     name.id = buf.readU64();
     42 }
     43 
     44 static void writeAppName(MessageBuf &buf, const hub_app_name_t &name) {
     45     buf.writeU64(name.id);
     46 }
     47 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 */
    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 */
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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