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