• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <plat/inc/cmsis.h>
18 #include <plat/inc/plat.h>
19 #include <plat/inc/pwr.h>
20 #include <plat/inc/wdt.h>
21 #include <syscall.h>
22 #include <string.h>
23 #include <seos.h>
24 #include <heap.h>
25 #include <cpu.h>
26 #include <util.h>
27 #include <reset.h>
28 
29 
30 #define HARD_FAULT_DROPBOX_MAGIC_MASK       0xFFFFC000
31 #define HARD_FAULT_DROPBOX_MAGIC_VAL        0x31414000
32 #define HARD_FAULT_DROPBOX_MAGIC_HAVE_DROP  0x00002000
33 #define HARD_FAULT_DROPBOX_MAGIC_DATA_MASK  0x00001FFF
34 
35 struct RamPersistedDataAndDropbox {
36     uint32_t magic; // and part of dropbox
37     uint32_t r[16];
38     uint32_t sr_hfsr_cfsr_lo;
39     uint32_t bits;
40     uint16_t tid;
41     uint16_t trig:2;
42     uint16_t RFU:14;
43 };
44 
45 /* //if your device persists ram, you can use this instead:
46  * static struct RamPersistedDataAndDropbox* getPersistedData(void)
47  * {
48  *     static struct RamPersistedDataAndDropbox __attribute__((section(".neverinit"))) dbx;
49  *     return &dbx;
50  * }
51  */
52 
getPersistedData(void)53 static struct RamPersistedDataAndDropbox* getPersistedData(void)
54 {
55     uint32_t bytes = 0;
56     void *loc = platGetPersistentRamStore(&bytes);
57 
58     return bytes >= sizeof(struct RamPersistedDataAndDropbox) ? (struct RamPersistedDataAndDropbox*)loc : NULL;
59 }
60 
getInitedPersistedData(void)61 static struct RamPersistedDataAndDropbox* getInitedPersistedData(void)
62 {
63     struct RamPersistedDataAndDropbox* dbx = getPersistedData();
64 
65     if ((dbx->magic & HARD_FAULT_DROPBOX_MAGIC_MASK) != HARD_FAULT_DROPBOX_MAGIC_VAL) {
66         dbx->bits = 0;
67         dbx->magic = HARD_FAULT_DROPBOX_MAGIC_VAL;
68     }
69 
70     return dbx;
71 }
72 
cpuInit(void)73 void cpuInit(void)
74 {
75     /* set SVC to be highest possible priority */
76     NVIC_SetPriority(SVCall_IRQn, 0xff);
77 
78     /* FPU on */
79     SCB->CPACR |= 0x00F00000;
80 }
81 
82 //pack all our SR regs into 45 bits
cpuPackSrBits(uint32_t * dstLo,uint32_t * dstHi,uint32_t sr,uint32_t hfsr,uint32_t cfsr)83 static void cpuPackSrBits(uint32_t *dstLo, uint32_t *dstHi, uint32_t sr, uint32_t hfsr, uint32_t cfsr)
84 {
85     //mask of useful bits:
86     // SR:   11111111 00000000 11111101 11111111 (total of 23 bits)
87     // HFSR: 01000000 00000000 00000000 00000010 (total of  2 bits)
88     // CFSR: 00000011 00001111 10111111 10111111 (total of 20 bits)
89     // so our total is 45 bits. we pack this into 2 longs (for now)
90 
91     sr   &= 0xFF00FDFF;
92     hfsr &= 0x40000002;
93     cfsr &= 0x030FBFBF;
94 
95     *dstLo = sr | ((cfsr << 4) & 0x00FF0000) | (hfsr >> 12) | (hfsr << 8);
96     *dstHi = ((cfsr & 0x01000000) >> 18) | ((cfsr & 0x02000000) >> 13) | (cfsr & 0x00000fff);
97 }
98 
99 //unpack the SR bits
cpuUnpackSrBits(uint32_t srcLo,uint32_t srcHi,uint32_t * srP,uint32_t * hfsrP,uint32_t * cfsrP)100 static void cpuUnpackSrBits(uint32_t srcLo, uint32_t srcHi, uint32_t *srP, uint32_t *hfsrP, uint32_t *cfsrP)
101 {
102     *srP = srcLo & 0xFF00FDFF;
103     *hfsrP = ((srcLo << 12) & 0x40000000) | ((srcLo >> 8) & 0x00000002);
104     *cfsrP = ((srcLo & 0x00FB0000) >> 4) | (srcHi & 0x0FBF) | ((srcHi << 13) & 0x02000000) | ((srcHi << 18) & 0x01000000);
105 }
106 
cpuDbxDump(struct RamPersistedDataAndDropbox * dbx)107 static void cpuDbxDump(struct RamPersistedDataAndDropbox *dbx)
108 {
109     uint32_t i, hfsr, cfsr, sr, code;
110     const char *trigName;
111     static const char *trigNames[] = { "UNKNOWN", "HARD FAULT", "WDT" };
112 
113     if (dbx) {
114         for (i = 0; i < 8; i++)
115             osLog(LOG_INFO, "  R%02lu  = 0x%08lX  R%02lu  = 0x%08lX\n",
116                   i, dbx->r[i], i + 8, dbx->r[i+8]);
117 
118         cpuUnpackSrBits(dbx->sr_hfsr_cfsr_lo, dbx->magic & HARD_FAULT_DROPBOX_MAGIC_DATA_MASK, &sr, &hfsr, &cfsr);
119 
120         osLog(LOG_INFO, "  xPSR = 0x%08lX  HFSR = 0x%08lX\n", sr, hfsr);
121         osLog(LOG_INFO, "  CFSR = 0x%08lX  BITS = 0x%08lX\n", cfsr, dbx->bits);
122         // reboot source (if known), reported as TRIG
123         // so far we have 2 reboot sources reported here:
124         // 1 - HARD FAULT
125         // 2 - WDT
126         code = dbx->trig;
127         trigName = trigNames[code < ARRAY_SIZE(trigNames) ? code : 0];
128         osLog(LOG_INFO, "  TID  = 0x%04" PRIX16 "  TRIG = 0x%04" PRIX16 " [%s]\n", dbx->tid, dbx->trig, trigName);
129     }
130 }
131 
cpuInitLate(void)132 void cpuInitLate(void)
133 {
134     struct RamPersistedDataAndDropbox *dbx = getInitedPersistedData();
135     uint32_t reason = pwrResetReason();
136     const char *reasonDesc = "";
137 
138     // if we detected WDT reboot reason, we are likely not having data in dropbox
139     // All we can do is report that WDT reset happened
140     if ((reason & (RESET_WINDOW_WATCHDOG|RESET_INDEPENDENT_WATCHDOG)) != 0)
141         reasonDesc = "; HW WDT RESET";
142 
143     osLog(LOG_INFO, "Reboot reason: 0x%08" PRIX32 "%s\n", reason, reasonDesc);
144 
145     /* print and clear dropbox */
146     if (dbx->magic & HARD_FAULT_DROPBOX_MAGIC_HAVE_DROP) {
147         osLog(LOG_INFO, "Dropbox not empty. Contents:\n");
148         cpuDbxDump(dbx);
149     }
150     dbx->magic &=~ HARD_FAULT_DROPBOX_MAGIC_HAVE_DROP;
151 }
152 
cpuRamPersistentBitGet(uint32_t which)153 bool cpuRamPersistentBitGet(uint32_t which)
154 {
155     struct RamPersistedDataAndDropbox *dbx = getInitedPersistedData();
156 
157     return (which < CPU_NUM_PERSISTENT_RAM_BITS) && ((dbx->bits >> which) & 1);
158 }
159 
cpuRamPersistentBitSet(uint32_t which,bool on)160 void cpuRamPersistentBitSet(uint32_t which, bool on)
161 {
162     struct RamPersistedDataAndDropbox *dbx = getInitedPersistedData();
163 
164     if (which < CPU_NUM_PERSISTENT_RAM_BITS) {
165         if (on)
166             dbx->bits |= (1ULL << which);
167         else
168             dbx->bits &=~ (1ULL << which);
169     }
170 }
171 
cpuIntsOff(void)172 uint64_t cpuIntsOff(void)
173 {
174     uint32_t state;
175 
176     asm volatile (
177         "mrs %0, PRIMASK    \n"
178         "cpsid i            \n"
179         :"=r"(state)
180     );
181 
182     return state;
183 }
184 
cpuIntsOn(void)185 uint64_t cpuIntsOn(void)
186 {
187     uint32_t state;
188 
189     asm volatile (
190         "mrs %0, PRIMASK    \n"
191         "cpsie i            \n"
192         :"=r"(state)
193     );
194 
195     return state;
196 }
197 
cpuIntsRestore(uint64_t state)198 void cpuIntsRestore(uint64_t state)
199 {
200 
201     asm volatile(
202         "msr PRIMASK, %0   \n"
203         ::"r"((uint32_t)state)
204     );
205 }
206 
207 /*
208  * Stack layout for HW interrupt handlers [ARM7-M]
209  * ===============================================
210  * orig_SP[8...25] = FPU state (S0..S15, FPSCR, Reserved) [if enabled]
211  * orig_SP[7] = xPSR
212  * orig_SP[6] = ReturnAddress
213  * orig_SP[5] = LR (R14)
214  * orig_SP[4] = R12
215  * orig_SP[3..0] = R3..R0
216  *
217  * upon entry, new value of LR is calculated as follows:
218  * LR := 0xFFFFFFE0 | <Control.FPCA ? 0 : 0x10> | <Mode_Handler ? 0 : 8> | <SPSEL ? 4 : 0> | 0x01
219  *
220  * upon exit, PC value is interpreted  according to the same rule (see LR above)
221  * if bits 28..31 of PC equal 0xF, return from interrupt is executed
222  * this way, "bx lr" would perform return from interrupt to the previous state
223  */
224 
syscallHandler(uintptr_t * excRegs)225 static void __attribute__((used)) syscallHandler(uintptr_t *excRegs)
226 {
227     uint16_t *svcPC = ((uint16_t *)(excRegs[6])) - 1;
228     uint32_t svcNo = (*svcPC) & 0xFF;
229     uint32_t syscallNr = excRegs[0];
230     SyscallFunc handler;
231     va_list args_long = *(va_list*)(excRegs + 1);
232     uintptr_t *fastParams = excRegs + 1;
233     va_list args_fast = *(va_list*)(&fastParams);
234 
235     if (svcNo > 1)
236         osLog(LOG_WARN, "Unknown SVC 0x%02lX called at 0x%08lX\n", svcNo, (unsigned long)svcPC);
237     else if (!(handler = syscallGetHandler(syscallNr)))
238         osLog(LOG_WARN, "Unknown syscall 0x%08lX called at 0x%08lX\n", (unsigned long)syscallNr, (unsigned long)svcPC);
239     else
240         handler(excRegs, svcNo ? args_fast : args_long);
241 }
242 
243 void SVC_Handler(void);
SVC_Handler(void)244 void __attribute__((naked)) SVC_Handler(void)
245 {
246     asm volatile(
247         "tst lr, #4         \n"
248         "ite eq             \n"
249         "mrseq r0, msp      \n"
250         "mrsne r0, psp      \n"
251         "b syscallHandler   \n"
252     );
253 }
254 
logHardFault(uintptr_t * excRegs,uintptr_t * otherRegs,bool tinyStack,uint32_t code)255 static void __attribute__((used)) logHardFault(uintptr_t *excRegs, uintptr_t* otherRegs, bool tinyStack, uint32_t code)
256 {
257     struct RamPersistedDataAndDropbox *dbx = getInitedPersistedData();
258     uint32_t i, hi;
259 
260     wdtPing();
261 
262     for (i = 0; i < 4; i++)
263         dbx->r[i] = excRegs[i];
264     for (i = 0; i < 8; i++)
265         dbx->r[i + 4] = otherRegs[i];
266     dbx->r[12] = excRegs[4];
267     dbx->r[13] = (uint32_t)(excRegs + 8);
268     dbx->r[14] = excRegs[5];
269     dbx->r[15] = excRegs[6];
270 
271     cpuPackSrBits(&dbx->sr_hfsr_cfsr_lo, &hi, excRegs[7], SCB->HFSR, SCB->CFSR);
272     dbx->magic |= HARD_FAULT_DROPBOX_MAGIC_HAVE_DROP | (hi & HARD_FAULT_DROPBOX_MAGIC_DATA_MASK);
273     dbx->tid = osGetCurrentTid();
274     dbx->trig = code;
275 
276     if (!tinyStack) {
277         osLog(LOG_ERROR, "*HARD FAULT*\n");
278         cpuDbxDump(dbx);
279     }
280 
281     NVIC_SystemReset();
282 }
283 
284 static uint32_t  __attribute__((used)) hfStack[16];
285 
286 void cpuCommonFaultCode(void);
cpuCommonFaultCode(void)287 void __attribute__((naked)) cpuCommonFaultCode(void)
288 {
289     // r0 contains Fault IRQ code
290     asm volatile(
291         "ldr r3, =__stack_bottom + 64 \n"
292         "cmp sp, r3                \n"
293         "itte le                   \n"
294         "ldrle sp, =hfStack + 64   \n"
295         "movle r2, #1              \n"
296         "movgt r2, #0              \n"
297         "mov r3, r0                \n"
298         "tst lr, #4                \n"
299         "ite eq                    \n"
300         "mrseq r0, msp             \n"
301         "mrsne r0, psp             \n"
302         "push  {r4-r11}            \n"
303         "mov   r1, sp              \n"
304         "b     logHardFault        \n"
305     );
306 }
307 
308 void HardFault_Handler(void);
HardFault_Handler(void)309 void __attribute__((naked)) HardFault_Handler(void)
310 {
311     asm volatile(
312         "mov    r0, #1             \n"
313         "b      cpuCommonFaultCode \n"
314     );
315 }
316