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 #ifndef _NANOHUB_SYSTEM_COMMS_H_ 18 #define _NANOHUB_SYSTEM_COMMS_H_ 19 20 #include <utils/Condition.h> 21 #include <utils/Mutex.h> 22 23 #include <map> 24 #include <vector> 25 26 #include <hardware/context_hub.h> 27 #include "nanohubhal.h" 28 #include "message_buf.h" 29 30 //rx: return 0 if handled, > 0 if not handled, < 0 if error happened 31 32 #define MSG_HANDLED 0 33 34 //messages to the HostIf nanoapp & their replies (mesages and replies both begin with u8 message_type) 35 #define NANOHUB_EXT_APPS_ON 0 // () -> (char success) 36 #define NANOHUB_EXT_APPS_OFF 1 // () -> (char success) 37 #define NANOHUB_EXT_APP_DELETE 2 // (u64 name) -> (char success) //idempotent 38 #define NANOHUB_QUERY_MEMINFO 3 // () -> (mem_info) 39 #define NANOHUB_QUERY_APPS 4 // (u32 idxStart) -> (app_info[idxStart] OR EMPTY IF NO MORE) 40 #define NANOHUB_QUERY_RSA_KEYS 5 // (u32 byteOffset) -> (u8 data[1 or more bytes] OR EMPTY IF NO MORE) 41 #define NANOHUB_START_UPLOAD 6 // (char isOs, u32 totalLenToTx) -> (char success) 42 #define NANOHUB_CONT_UPLOAD 7 // (u32 offset, u8 data[]) -> (char success) 43 #define NANOHUB_FINISH_UPLOAD 8 // () -> (char success) 44 #define NANOHUB_REBOOT 9 // () -> (char success) 45 46 // Custom defined private messages 47 #define CONTEXT_HUB_LOAD_OS (CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE + 1) 48 49 50 #define NANOHUB_APP_NOT_LOADED (-1) 51 #define NANOHUB_APP_LOADED (0) 52 53 #define NANOHUB_UPLOAD_CHUNK_SZ_MAX 64 54 #define NANOHUB_MEM_SZ_UNKNOWN 0xFFFFFFFFUL 55 56 namespace android { 57 58 namespace nanohub { 59 60 int system_comms_handle_rx(const nano_message *msg); 61 int system_comms_handle_tx(const hub_message_t *outMsg); 62 63 struct NanohubAppInfo { 64 hub_app_name_t name; 65 uint32_t version, flashUse, ramUse; 66 } __attribute__((packed)); 67 68 struct NanohubMemInfo { 69 //sizes 70 uint32_t flashSz, blSz, osSz, sharedSz, eeSz; 71 uint32_t ramSz; 72 73 //use 74 uint32_t blUse, osUse, sharedUse, eeUse; 75 uint32_t ramUse; 76 } __attribute__((packed)); 77 78 struct NanohubRsp { 79 uint32_t cmd; 80 int32_t status; 81 NanohubRsp(MessageBuf &buf, bool no_status = false); 82 }; 83 84 inline bool operator == (const hub_app_name_t &a, const hub_app_name_t &b) { 85 return a.id == b.id; 86 } 87 88 inline bool operator != (const hub_app_name_t &a, const hub_app_name_t &b) { 89 return !(a == b); 90 } 91 92 class SystemComm { 93 private: 94 95 /* 96 * Nanohub HAL sessions 97 * 98 * Session is an object that can group several message exchanges with FW, 99 * maintain state, and be waited for completion by someone else. 100 * 101 * As of this moment, since all sessions are triggered by client thread, 102 * and all the exchange is happening in local worker thread, it is only possible 103 * for client thread to wait on session completion. 104 * Allowing sessions to wait on each other will require a worker thread pool. 105 * It is now unnecessary, and not implemented. 106 */ 107 class ISession { 108 public: 109 virtual int setup(const hub_message_t *app_msg) = 0; 110 virtual int handleRx(MessageBuf &buf) = 0; 111 virtual int getState() const = 0; // FSM state 112 virtual int getStatus() const = 0; // execution status (result code) 113 virtual ~ISession() {} 114 }; 115 116 class SessionManager; 117 118 class Session : public ISession { 119 friend class SessionManager; 120 121 mutable Mutex mDoneLock; // controls condition and state transitions 122 Condition mDoneWait; 123 volatile int mState; 124 125 protected: 126 mutable Mutex mLock; // serializes message handling 127 int32_t mStatus; 128 129 enum { 130 SESSION_INIT = 0, 131 SESSION_DONE = 1, 132 SESSION_USER = 2, 133 }; 134 135 void complete() { 136 Mutex::Autolock _l(mDoneLock); 137 if (mState != SESSION_DONE) { 138 mState = SESSION_DONE; 139 mDoneWait.broadcast(); 140 } 141 } 142 void setState(int state) { 143 if (state == SESSION_DONE) { 144 complete(); 145 } else { 146 Mutex::Autolock _l(mDoneLock); 147 mState = state; 148 } 149 } 150 public: 151 Session() { mState = SESSION_INIT; mStatus = -1; } 152 int getStatus() const { 153 Mutex::Autolock _l(mLock); 154 return mStatus; 155 } 156 int wait() { 157 Mutex::Autolock _l(mDoneLock); 158 while (mState != SESSION_DONE) { 159 mDoneWait.wait(mDoneLock); 160 } 161 return 0; 162 } 163 virtual int getState() const override { 164 Mutex::Autolock _l(mDoneLock); 165 return mState; 166 } 167 virtual bool isDone() const { 168 Mutex::Autolock _l(mDoneLock); 169 return mState == SESSION_DONE; 170 } 171 virtual bool isRunning() const { 172 Mutex::Autolock _l(mDoneLock); 173 return mState > SESSION_DONE; 174 } 175 }; 176 177 class AppMgmtSession : public Session { 178 enum { 179 TRANSFER = SESSION_USER, 180 FINISH, 181 RELOAD, 182 REBOOT, 183 MGMT, 184 }; 185 uint32_t mCmd; // UPLOAD_APP | UPPLOAD_OS 186 uint32_t mResult; 187 std::vector<uint8_t> mData; 188 uint32_t mLen; 189 uint32_t mPos; 190 191 int setupMgmt(const hub_message_t *appMsg, uint32_t cmd); 192 int handleTransfer(NanohubRsp &rsp); 193 int handleFinish(NanohubRsp &rsp); 194 int handleReload(NanohubRsp &rsp); 195 int handleReboot(NanohubRsp &rsp); 196 int handleMgmt(NanohubRsp &rsp); 197 public: 198 AppMgmtSession() { 199 mCmd = 0; 200 mResult = 0; 201 mPos = 0; 202 mLen = 0; 203 } 204 virtual int handleRx(MessageBuf &buf) override; 205 virtual int setup(const hub_message_t *app_msg) override; 206 }; 207 208 class MemInfoSession : public Session { 209 public: 210 virtual int setup(const hub_message_t *app_msg) override; 211 virtual int handleRx(MessageBuf &buf) override; 212 }; 213 214 class KeyInfoSession : public Session { 215 std::vector<uint8_t> mRsaKeyData; 216 int requestRsaKeys(void); 217 public: 218 virtual int setup(const hub_message_t *) override; 219 virtual int handleRx(MessageBuf &buf) override; 220 bool haveKeys() const { 221 Mutex::Autolock _l(mLock); 222 return mRsaKeyData.size() > 0 && !isRunning(); 223 } 224 }; 225 226 class AppInfoSession : public Session { 227 std::vector<hub_app_info> mAppInfo; 228 int requestNext(); 229 public: 230 virtual int setup(const hub_message_t *) override; 231 virtual int handleRx(MessageBuf &buf) override; 232 }; 233 234 class GlobalSession : public Session { 235 public: 236 virtual int setup(const hub_message_t *) override; 237 virtual int handleRx(MessageBuf &buf) override; 238 }; 239 240 class SessionManager { 241 typedef std::map<int, Session* > SessionMap; 242 243 Mutex lock; 244 SessionMap sessions_; 245 GlobalSession mGlobal; 246 247 void next(SessionMap::iterator &pos) 248 { 249 Mutex::Autolock _l(lock); 250 pos->second->isDone() ? pos = sessions_.erase(pos) : ++pos; 251 } 252 253 public: 254 SessionManager() { 255 mGlobal.setup(nullptr); 256 } 257 int handleRx(MessageBuf &buf); 258 int setup_and_add(int id, Session *session, const hub_message_t *appMsg) { 259 Mutex::Autolock _l(lock); 260 if (sessions_.count(id) == 0 && !session->isRunning()) { 261 int ret = session->setup(appMsg); 262 if (ret < 0) { 263 session->complete(); 264 } else { 265 sessions_[id] = session; 266 } 267 return ret; 268 } 269 return -EBUSY; 270 } 271 272 } mSessions; 273 274 const hub_app_name_t mHostIfAppName = { 275 .id = NANO_APP_ID(NANOAPP_VENDOR_GOOGLE, 0) 276 }; 277 278 static SystemComm *getSystem() { 279 // this is thread-safe in c++11 280 static SystemComm theInstance; 281 return &theInstance; 282 } 283 284 SystemComm () = default; 285 ~SystemComm() = default; 286 287 int doHandleTx(const hub_message_t *txMsg); 288 int doHandleRx(const nano_message *rxMsg); 289 290 static void sendToApp(uint32_t typ, const void *data, uint32_t len) { 291 if (NanoHub::messageTracingEnabled()) { 292 dumpBuffer("HAL -> APP", get_hub_info()->os_app_name, typ, data, len); 293 } 294 NanoHub::sendToApp(&get_hub_info()->os_app_name, typ, data, len); 295 } 296 static int sendToSystem(const void *data, size_t len); 297 298 KeyInfoSession mKeySession; 299 AppMgmtSession mAppMgmtSession; 300 AppInfoSession mAppInfoSession; 301 MemInfoSession mMemInfoSession; 302 303 public: 304 static int handleTx(const hub_message_t *txMsg) { 305 return getSystem()->doHandleTx(txMsg); 306 } 307 static int handleRx(const nano_message *rxMsg) { 308 return getSystem()->doHandleRx(rxMsg); 309 } 310 }; 311 312 }; // namespace nanohub 313 314 }; // namespace android 315 316 #endif 317