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