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