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 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 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 134 bool cpuInternalAppLoad(const struct AppHdr *appHdr, struct PlatAppInfo *platInfo) 135 { 136 platInfo->data = 0x00000000; 137 138 return true; 139 } 140 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 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 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 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 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 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 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