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