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 #include <nanohub/appRelocFormat.h>
18 
19 #include <string.h>
20 #include <stdint.h>
21 #include <heap.h>
22 #include <seos.h>
23 #include <cpu.h>
24 
25 #include <plat/cmsis.h>
26 
27 //reloc types for this cpu type
28 #define NANO_RELOC_TYPE_RAM	0
29 #define NANO_RELOC_TYPE_FLASH	1
30 
31 #define APP_FLASH_RELOC(_base, _offset) ((uint32_t)(_base) + FLASH_RELOC_OFFSET + (_offset))
32 #define APP_FLASH_RELOC_BASE(_base) APP_FLASH_RELOC(_base, 0)
33 #define APP_VEC(_app) ((struct AppFuncs*)&((_app)->vec))
34 
handleRelNumber(uint32_t * ofstP,uint32_t type,uint32_t flashAddr,uint32_t ramAddr,uint32_t * mem,uint32_t value)35 static bool handleRelNumber(uint32_t *ofstP, uint32_t type, uint32_t flashAddr, uint32_t ramAddr, uint32_t *mem, uint32_t value)
36 {
37     uint32_t base, where;
38 
39     switch (type) {
40 
41     case NANO_RELOC_TYPE_RAM:
42         base = ramAddr;
43         break;
44 
45     case NANO_RELOC_TYPE_FLASH:
46         base = flashAddr;
47         break;
48 
49     default:
50         return false;
51     }
52 
53     where = *ofstP + value;
54     *ofstP = where + 1;
55 
56     mem[where] += base;
57 
58     return true;
59 }
60 
handleRelocs(const uint8_t * relStart,const uint8_t * relEnd,uint32_t flashStart,uint32_t ramStart,void * mem)61 static bool handleRelocs(const uint8_t *relStart, const uint8_t *relEnd, uint32_t flashStart, uint32_t ramStart, void *mem)
62 {
63     uint32_t ofst = 0;
64     uint32_t type = 0;
65 
66     while (relStart != relEnd) {
67 
68         uint32_t rel = *relStart++;
69 
70         if (rel <= MAX_8_BIT_NUM) {
71 
72             if (!handleRelNumber(&ofst, type, flashStart, ramStart, mem, rel))
73                 return false;
74         }
75         else switch (rel) {
76 
77         case TOKEN_32BIT_OFST:
78             if (relEnd - relStart < 4)
79                 return false;
80             rel = *(uint32_t*)relStart;
81             relStart += sizeof(uint32_t);
82             if (!handleRelNumber(&ofst, type, flashStart, ramStart, mem, rel))
83                 return false;
84             break;
85 
86         case TOKEN_24BIT_OFST:
87             if (relEnd - relStart < 3)
88                 return false;
89             rel = *(uint16_t*)relStart;
90             relStart += sizeof(uint16_t);
91             rel += ((uint32_t)(*relStart++)) << 16;
92             if (!handleRelNumber(&ofst, type, flashStart, ramStart, mem, rel + MAX_16_BIT_NUM))
93                 return false;
94             break;
95 
96         case TOKEN_16BIT_OFST:
97             if (relEnd - relStart < 2)
98                 return false;
99             rel = *(uint16_t*)relStart;
100             relStart += sizeof(uint16_t);
101             if (!handleRelNumber(&ofst, type, flashStart, ramStart, mem, rel + MAX_8_BIT_NUM))
102                 return false;
103             break;
104 
105         case TOKEN_CONSECUTIVE:
106             if (relEnd - relStart < 1)
107                 return false;
108             rel = *relStart++;
109             rel += MIN_RUN_LEN;
110             while (rel--)
111                 if (!handleRelNumber(&ofst, type, flashStart, ramStart, mem, 0))
112                     return false;
113             break;
114 
115         case TOKEN_RELOC_TYPE_CHG:
116             if (relEnd - relStart < 1)
117                 return false;
118             rel = *relStart++;
119             rel++;
120             type += rel;
121             ofst = 0;
122             break;
123 
124         case TOKEN_RELOC_TYPE_NEXT:
125             type++;
126             ofst = 0;
127             break;
128         }
129     }
130 
131     return true;
132 }
133 
cpuInternalAppLoad(const struct AppHdr * appHdr,struct PlatAppInfo * platInfo)134 bool cpuInternalAppLoad(const struct AppHdr *appHdr, struct PlatAppInfo *platInfo)
135 {
136     platInfo->data = 0x00000000;
137 
138     return true;
139 }
140 
cpuAppLoad(const struct AppHdr * app,struct PlatAppInfo * platInfo)141 bool cpuAppLoad(const struct AppHdr *app, struct PlatAppInfo *platInfo)
142 {
143     const struct SectInfo *sect = &app->sect;
144     const uint8_t *relocsStart = (const uint8_t*)APP_FLASH_RELOC(app, sect->rel_start);
145     const uint8_t *relocsEnd = (const uint8_t*)APP_FLASH_RELOC(app, sect->rel_end);
146     uint8_t *mem = heapAlloc(sect->bss_end);
147 
148     if (!mem)
149         return false;
150 
151     //calculate and assign .DATA org (TODO: data_start must be always zero, exclude it form APP structures)
152     platInfo->data = mem + sect->data_start;
153 
154     //clear .BSS
155     memset(mem + sect->bss_start, 0, sect->bss_end - sect->bss_start);
156 
157     //copy initialized data and initialized .GOT
158     memcpy(mem + sect->data_start, (uint8_t*)APP_FLASH_RELOC(app, sect->data_data), sect->got_end - sect->data_start);
159 
160     //perform relocs
161     if (!handleRelocs(relocsStart, relocsEnd, (uintptr_t)APP_FLASH_RELOC_BASE(app), (uintptr_t)mem, (void*)mem)) {
162         osLog(LOG_ERROR, "Relocs are invalid in this app. Aborting app load\n");
163         heapFree(mem);
164         return false;
165     }
166 
167     return true;
168 }
169 
cpuAppUnload(const struct AppHdr * app,struct PlatAppInfo * platInfo)170 void cpuAppUnload(const struct AppHdr *app, struct PlatAppInfo *platInfo)
171 {
172     if (platInfo->data)
173         heapFree((uint8_t*)platInfo->data - app->sect.data_start);
174 }
175 
callWithR9(const void * base,uint32_t offset,void * data,uintptr_t arg1,uintptr_t arg2)176 static uintptr_t __attribute__((naked)) callWithR9(const void *base, uint32_t offset, void *data, uintptr_t arg1, uintptr_t arg2)
177 {
178     asm volatile (
179         "add  r12, r0, r1  \n"
180         "mov  r0,  r3      \n"
181         "ldr  r1,  [sp]    \n"
182         "push {r9, lr}     \n"
183         "mov  r9, r2       \n"
184         "blx  r12          \n"
185         "pop  {r9, pc}     \n"
186     );
187 
188     return 0; //dummy to fool gcc
189 }
190 
cpuAppInit(const struct AppHdr * app,struct PlatAppInfo * platInfo,uint32_t tid)191 bool cpuAppInit(const struct AppHdr *app, struct PlatAppInfo *platInfo, uint32_t tid)
192 {
193     if (platInfo->data)
194         return callWithR9((const void*)APP_FLASH_RELOC_BASE(app), app->vec.init, platInfo->data, tid, 0);
195     else
196         return APP_VEC(app)->init(tid);
197 }
198 
cpuAppEnd(const struct AppHdr * app,struct PlatAppInfo * platInfo)199 void cpuAppEnd(const struct AppHdr *app, struct PlatAppInfo *platInfo)
200 {
201     if (platInfo->data)
202         (void)callWithR9((const void*)APP_FLASH_RELOC_BASE(app), app->vec.end, platInfo->data, 0, 0);
203     else
204         APP_VEC(app)->end();
205     osLog(LOG_INFO, "App ID %016" PRIX64 "; TID=%04" PRIX32 " terminated\n", app->hdr.appId, osGetCurrentTid());
206 }
207 
cpuAppHandle(const struct AppHdr * app,struct PlatAppInfo * platInfo,uint32_t evtType,const void * evtData)208 void cpuAppHandle(const struct AppHdr *app, struct PlatAppInfo *platInfo, uint32_t evtType, const void* evtData)
209 {
210     if (platInfo->data)
211         (void)callWithR9((const void*)APP_FLASH_RELOC_BASE(app), app->vec.handle, platInfo->data, evtType, (uintptr_t)evtData);
212     else
213         APP_VEC(app)->handle(evtType, evtData);
214 }
215 
cpuAppInvoke(const struct AppHdr * app,struct PlatAppInfo * platInfo,void (* method)(uintptr_t,uintptr_t),uintptr_t arg1,uintptr_t arg2)216 void cpuAppInvoke(const struct AppHdr *app, struct PlatAppInfo *platInfo,
217                   void (*method)(uintptr_t, uintptr_t),uintptr_t arg1, uintptr_t arg2)
218 {
219     if (platInfo->data) {
220         uint32_t hasSvcAct = SCB->SHCSR & SCB_SHCSR_SVCALLACT_Msk;
221 
222         SCB->SHCSR &= ~SCB_SHCSR_SVCALLACT_Msk;
223         (void)callWithR9(0, (uint32_t)method, platInfo->data, arg1, arg2);
224         SCB->SHCSR |= hasSvcAct;
225     } else {
226         method(arg1, arg2);
227     }
228 }
229