cpuport.c 10.5 KB
Newer Older
B
bernard.xiong@gmail.com 已提交
1
/*
mysterywolf's avatar
mysterywolf 已提交
2
 * Copyright (c) 2006-2021, RT-Thread Development Team
B
bernard.xiong@gmail.com 已提交
3
 *
4
 * SPDX-License-Identifier: Apache-2.0
B
bernard.xiong@gmail.com 已提交
5 6
 *
 * Change Logs:
7 8 9 10
 * Date         Author      Notes
 * 2009-01-05   Bernard     first version
 * 2011-02-14   onelife     Modify for EFM32
 * 2011-06-17   onelife     Merge all of the C source code into cpuport.c
wuyangyong's avatar
wuyangyong 已提交
11
 * 2012-12-23   aozima      stack addr align to 8byte.
12
 * 2012-12-29   Bernard     Add exception hook.
13
 * 2013-07-09   aozima      enhancement hard fault exception handler.
14
 * 2019-07-03   yangjie     add __rt_ffs() for armclang.
B
bernard.xiong@gmail.com 已提交
15
 */
wuyangyong's avatar
wuyangyong 已提交
16 17 18

#include <rtthread.h>

wuyangyong's avatar
wuyangyong 已提交
19
struct exception_stack_frame
wuyangyong's avatar
wuyangyong 已提交
20
{
wuyangyong's avatar
wuyangyong 已提交
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
    rt_uint32_t r0;
    rt_uint32_t r1;
    rt_uint32_t r2;
    rt_uint32_t r3;
    rt_uint32_t r12;
    rt_uint32_t lr;
    rt_uint32_t pc;
    rt_uint32_t psr;
};

struct stack_frame
{
    /* r4 ~ r11 register */
    rt_uint32_t r4;
    rt_uint32_t r5;
    rt_uint32_t r6;
    rt_uint32_t r7;
    rt_uint32_t r8;
    rt_uint32_t r9;
    rt_uint32_t r10;
    rt_uint32_t r11;

    struct exception_stack_frame exception_stack_frame;
wuyangyong's avatar
wuyangyong 已提交
44 45
};

B
bernard.xiong@gmail.com 已提交
46
/* flag in interrupt handling */
wuyangyong's avatar
wuyangyong 已提交
47 48
rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
rt_uint32_t rt_thread_switch_interrupt_flag;
49 50
/* exception hook */
static rt_err_t (*rt_exception_hook)(void *context) = RT_NULL;
wuyangyong's avatar
wuyangyong 已提交
51

B
bernard.xiong@gmail.com 已提交
52
/**
wuyangyong's avatar
wuyangyong 已提交
53 54 55 56 57 58 59 60
 * This function will initialize thread stack
 *
 * @param tentry the entry of thread
 * @param parameter the parameter of entry
 * @param stack_addr the beginning stack address
 * @param texit the function will be called when thread exit
 *
 * @return stack address
B
bernard.xiong@gmail.com 已提交
61
 */
62 63
rt_uint8_t *rt_hw_stack_init(void       *tentry,
                             void       *parameter,
wuyangyong's avatar
wuyangyong 已提交
64
                             rt_uint8_t *stack_addr,
65
                             void       *texit)
wuyangyong's avatar
wuyangyong 已提交
66
{
wuyangyong's avatar
wuyangyong 已提交
67 68 69 70
    struct stack_frame *stack_frame;
    rt_uint8_t         *stk;
    unsigned long       i;

71 72 73
    stk  = stack_addr + sizeof(rt_uint32_t);
    stk  = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);
    stk -= sizeof(struct stack_frame);
wuyangyong's avatar
wuyangyong 已提交
74 75

    stack_frame = (struct stack_frame *)stk;
wuyangyong's avatar
wuyangyong 已提交
76

wuyangyong's avatar
wuyangyong 已提交
77 78 79 80 81
    /* init all register */
    for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++)
    {
        ((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef;
    }
wuyangyong's avatar
wuyangyong 已提交
82

wuyangyong's avatar
wuyangyong 已提交
83 84 85 86 87 88 89 90
    stack_frame->exception_stack_frame.r0  = (unsigned long)parameter; /* r0 : argument */
    stack_frame->exception_stack_frame.r1  = 0;                        /* r1 */
    stack_frame->exception_stack_frame.r2  = 0;                        /* r2 */
    stack_frame->exception_stack_frame.r3  = 0;                        /* r3 */
    stack_frame->exception_stack_frame.r12 = 0;                        /* r12 */
    stack_frame->exception_stack_frame.lr  = (unsigned long)texit;     /* lr */
    stack_frame->exception_stack_frame.pc  = (unsigned long)tentry;    /* entry point, pc */
    stack_frame->exception_stack_frame.psr = 0x01000000L;              /* PSR */
wuyangyong's avatar
wuyangyong 已提交
91

wuyangyong's avatar
wuyangyong 已提交
92 93
    /* return task's current stack address */
    return stk;
wuyangyong's avatar
wuyangyong 已提交
94 95
}

B
bernard.xiong@gmail.com 已提交
96
/**
97 98 99 100 101 102
 * This function set the hook, which is invoked on fault exception handling.
 *
 * @param exception_handle the exception handling hook function.
 */
void rt_hw_exception_install(rt_err_t (*exception_handle)(void* context))
{
V
visitor83 已提交
103
    rt_exception_hook = exception_handle;
104 105
}

106 107 108 109
#define SCB_CFSR        (*(volatile const unsigned *)0xE000ED28) /* Configurable Fault Status Register */
#define SCB_HFSR        (*(volatile const unsigned *)0xE000ED2C) /* HardFault Status Register */
#define SCB_MMAR        (*(volatile const unsigned *)0xE000ED34) /* MemManage Fault Address register */
#define SCB_BFAR        (*(volatile const unsigned *)0xE000ED38) /* Bus Fault Address Register */
110 111
#define SCB_AIRCR       (*(volatile unsigned long *)0xE000ED0C)  /* Reset control Address Register */
#define SCB_RESET_VALUE 0x05FA0004                               /* Reset value, write to SCB_AIRCR can reset cpu */
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288

#define SCB_CFSR_MFSR   (*(volatile const unsigned char*)0xE000ED28)  /* Memory-management Fault Status Register */
#define SCB_CFSR_BFSR   (*(volatile const unsigned char*)0xE000ED29)  /* Bus Fault Status Register */
#define SCB_CFSR_UFSR   (*(volatile const unsigned short*)0xE000ED2A) /* Usage Fault Status Register */

#ifdef RT_USING_FINSH
static void usage_fault_track(void)
{
    rt_kprintf("usage fault:\n");
    rt_kprintf("SCB_CFSR_UFSR:0x%02X ", SCB_CFSR_UFSR);

    if(SCB_CFSR_UFSR & (1<<0))
    {
        /* [0]:UNDEFINSTR */
        rt_kprintf("UNDEFINSTR ");
    }

    if(SCB_CFSR_UFSR & (1<<1))
    {
        /* [1]:INVSTATE */
        rt_kprintf("INVSTATE ");
    }

    if(SCB_CFSR_UFSR & (1<<2))
    {
        /* [2]:INVPC */
        rt_kprintf("INVPC ");
    }

    if(SCB_CFSR_UFSR & (1<<3))
    {
        /* [3]:NOCP */
        rt_kprintf("NOCP ");
    }

    if(SCB_CFSR_UFSR & (1<<8))
    {
        /* [8]:UNALIGNED */
        rt_kprintf("UNALIGNED ");
    }

    if(SCB_CFSR_UFSR & (1<<9))
    {
        /* [9]:DIVBYZERO */
        rt_kprintf("DIVBYZERO ");
    }

    rt_kprintf("\n");
}

static void bus_fault_track(void)
{
    rt_kprintf("bus fault:\n");
    rt_kprintf("SCB_CFSR_BFSR:0x%02X ", SCB_CFSR_BFSR);

    if(SCB_CFSR_BFSR & (1<<0))
    {
        /* [0]:IBUSERR */
        rt_kprintf("IBUSERR ");
    }

    if(SCB_CFSR_BFSR & (1<<1))
    {
        /* [1]:PRECISERR */
        rt_kprintf("PRECISERR ");
    }

    if(SCB_CFSR_BFSR & (1<<2))
    {
        /* [2]:IMPRECISERR */
        rt_kprintf("IMPRECISERR ");
    }

    if(SCB_CFSR_BFSR & (1<<3))
    {
        /* [3]:UNSTKERR */
        rt_kprintf("UNSTKERR ");
    }

    if(SCB_CFSR_BFSR & (1<<4))
    {
        /* [4]:STKERR */
        rt_kprintf("STKERR ");
    }

    if(SCB_CFSR_BFSR & (1<<7))
    {
        rt_kprintf("SCB->BFAR:%08X\n", SCB_BFAR);
    }
    else
    {
        rt_kprintf("\n");
    }
}

static void mem_manage_fault_track(void)
{
    rt_kprintf("mem manage fault:\n");
    rt_kprintf("SCB_CFSR_MFSR:0x%02X ", SCB_CFSR_MFSR);

    if(SCB_CFSR_MFSR & (1<<0))
    {
        /* [0]:IACCVIOL */
        rt_kprintf("IACCVIOL ");
    }

    if(SCB_CFSR_MFSR & (1<<1))
    {
        /* [1]:DACCVIOL */
        rt_kprintf("DACCVIOL ");
    }

    if(SCB_CFSR_MFSR & (1<<3))
    {
        /* [3]:MUNSTKERR */
        rt_kprintf("MUNSTKERR ");
    }

    if(SCB_CFSR_MFSR & (1<<4))
    {
        /* [4]:MSTKERR */
        rt_kprintf("MSTKERR ");
    }

    if(SCB_CFSR_MFSR & (1<<7))
    {
        /* [7]:MMARVALID */
        rt_kprintf("SCB->MMAR:%08X\n", SCB_MMAR);
    }
    else
    {
        rt_kprintf("\n");
    }
}

static void hard_fault_track(void)
{
    if(SCB_HFSR & (1UL<<1))
    {
        /* [1]:VECTBL, Indicates hard fault is caused by failed vector fetch. */
        rt_kprintf("failed vector fetch\n");
    }

    if(SCB_HFSR & (1UL<<30))
    {
        /* [30]:FORCED, Indicates hard fault is taken because of bus fault,
                        memory management fault, or usage fault. */
        if(SCB_CFSR_BFSR)
        {
            bus_fault_track();
        }

        if(SCB_CFSR_MFSR)
        {
            mem_manage_fault_track();
        }

        if(SCB_CFSR_UFSR)
        {
            usage_fault_track();
        }
    }

    if(SCB_HFSR & (1UL<<31))
    {
        /* [31]:DEBUGEVT, Indicates hard fault is triggered by debug event. */
        rt_kprintf("debug event\n");
    }
}
#endif /* RT_USING_FINSH */

struct exception_info
{
    rt_uint32_t exc_return;
    struct stack_frame stack_frame;
};

289 290
/*
 * fault exception handler
B
bernard.xiong@gmail.com 已提交
291
 */
292
void rt_hw_hard_fault_exception(struct exception_info * exception_info)
wuyangyong's avatar
wuyangyong 已提交
293
{
294
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
V
visitor83 已提交
295
    extern long list_thread(void);
296
#endif
297
    struct stack_frame* context = &exception_info->stack_frame;
298

V
visitor83 已提交
299 300 301
    if (rt_exception_hook != RT_NULL)
    {
        rt_err_t result;
302

303
        result = rt_exception_hook(exception_info);
V
visitor83 已提交
304 305 306
        if (result == RT_EOK)
            return;
    }
wuyangyong's avatar
wuyangyong 已提交
307

308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
    rt_kprintf("psr: 0x%08x\n", context->exception_stack_frame.psr);

    rt_kprintf("r00: 0x%08x\n", context->exception_stack_frame.r0);
    rt_kprintf("r01: 0x%08x\n", context->exception_stack_frame.r1);
    rt_kprintf("r02: 0x%08x\n", context->exception_stack_frame.r2);
    rt_kprintf("r03: 0x%08x\n", context->exception_stack_frame.r3);
    rt_kprintf("r04: 0x%08x\n", context->r4);
    rt_kprintf("r05: 0x%08x\n", context->r5);
    rt_kprintf("r06: 0x%08x\n", context->r6);
    rt_kprintf("r07: 0x%08x\n", context->r7);
    rt_kprintf("r08: 0x%08x\n", context->r8);
    rt_kprintf("r09: 0x%08x\n", context->r9);
    rt_kprintf("r10: 0x%08x\n", context->r10);
    rt_kprintf("r11: 0x%08x\n", context->r11);
    rt_kprintf("r12: 0x%08x\n", context->exception_stack_frame.r12);
    rt_kprintf(" lr: 0x%08x\n", context->exception_stack_frame.lr);
    rt_kprintf(" pc: 0x%08x\n", context->exception_stack_frame.pc);
325

326 327 328
    if(exception_info->exc_return & (1 << 2) )
    {
        rt_kprintf("hard fault on thread: %s\r\n\r\n", rt_thread_self()->name);
329

330
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
331
        list_thread();
332
#endif
333 334 335 336 337
    }
    else
    {
        rt_kprintf("hard fault on handler\r\n\r\n");
    }
338

339 340 341 342 343
#ifdef RT_USING_FINSH
    hard_fault_track();
#endif /* RT_USING_FINSH */

    while (1);
wuyangyong's avatar
wuyangyong 已提交
344 345
}

B
bernard.xiong@gmail.com 已提交
346 347 348
/**
 * shutdown CPU
 */
349
RT_WEAK void rt_hw_cpu_shutdown(void)
wuyangyong's avatar
wuyangyong 已提交
350
{
wuyangyong's avatar
wuyangyong 已提交
351
    rt_kprintf("shutdown...\n");
wuyangyong's avatar
wuyangyong 已提交
352

wuyangyong's avatar
wuyangyong 已提交
353
    RT_ASSERT(0);
wuyangyong's avatar
wuyangyong 已提交
354
}
355

356 357 358 359 360 361 362 363
/**
 * reset CPU
 */
RT_WEAK void rt_hw_cpu_reset(void)
{
    SCB_AIRCR = SCB_RESET_VALUE;
}

364 365
#ifdef RT_USING_CPU_FFS
/**
366
 * This function finds the first bit set (beginning with the least significant bit)
367 368
 * in value and return the index of that bit.
 *
369
 * Bits are numbered starting at 1 (the least significant bit).  A return value of
370
 * zero from any of these functions means that the argument was zero.
371 372
 *
 * @return return the index of the first bit set. If value is 0, then this function
373 374 375 376 377
 * shall return 0.
 */
#if defined(__CC_ARM)
__asm int __rt_ffs(int value)
{
378 379
    CMP     r0, #0x00
    BEQ     exit
380

381 382 383
    RBIT    r0, r0
    CLZ     r0, r0
    ADDS    r0, r0, #0x01
384

385
exit
386
    BX      lr
387
}
388
#elif defined(__clang__)
389 390 391 392
int __rt_ffs(int value)
{
    __asm volatile(
        "CMP     r0, #0x00            \n"
393
        "BEQ     1f                   \n"
394 395 396 397 398

        "RBIT    r0, r0               \n"
        "CLZ     r0, r0               \n"
        "ADDS    r0, r0, #0x01        \n"

399
        "1:                           \n"
400 401 402 403 404 405

        : "=r"(value)
        : "r"(value)
    );
    return value;
}
406 407 408
#elif defined(__IAR_SYSTEMS_ICC__)
int __rt_ffs(int value)
{
409 410
    if (value == 0) return value;

411 412 413 414 415
    asm("RBIT %0, %1" : "=r"(value) : "r"(value));
    asm("CLZ  %0, %1" : "=r"(value) : "r"(value));
    asm("ADDS %0, %1, #0x01" : "=r"(value) : "r"(value));

    return value;
416 417 418 419
}
#elif defined(__GNUC__)
int __rt_ffs(int value)
{
420
    return __builtin_ffs(value);
421 422 423 424
}
#endif

#endif