Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-only */
0002 /*
0003  * linux/arch/arm/kernel/entry-v7m.S
0004  *
0005  * Copyright (C) 2008 ARM Ltd.
0006  *
0007  * Low-level vector interface routines for the ARMv7-M architecture
0008  */
0009 #include <asm/memory.h>
0010 #include <asm/glue.h>
0011 #include <asm/thread_notify.h>
0012 #include <asm/v7m.h>
0013 
0014 #include "entry-header.S"
0015 
0016 #ifdef CONFIG_TRACE_IRQFLAGS
0017 #error "CONFIG_TRACE_IRQFLAGS not supported on the current ARMv7M implementation"
0018 #endif
0019 
0020 __invalid_entry:
0021     v7m_exception_entry
0022 #ifdef CONFIG_PRINTK
0023     adr r0, strerr
0024     mrs r1, ipsr
0025     mov r2, lr
0026     bl  _printk
0027 #endif
0028     mov r0, sp
0029     bl  show_regs
0030 1:  b   1b
0031 ENDPROC(__invalid_entry)
0032 
0033 strerr: .asciz  "\nUnhandled exception: IPSR = %08lx LR = %08lx\n"
0034 
0035     .align  2
0036 __irq_entry:
0037     v7m_exception_entry
0038 
0039     @
0040     @ Invoke the IRQ handler
0041     @
0042     mov r0, sp
0043     ldr_this_cpu sp, irq_stack_ptr, r1, r2
0044 
0045     @
0046     @ If we took the interrupt while running in the kernel, we may already
0047     @ be using the IRQ stack, so revert to the original value in that case.
0048     @
0049     subs    r2, sp, r0      @ SP above bottom of IRQ stack?
0050     rsbscs  r2, r2, #THREAD_SIZE    @ ... and below the top?
0051     movcs   sp, r0
0052 
0053     push    {r0, lr}        @ preserve LR and original SP
0054 
0055     @ routine called with r0 = struct pt_regs *
0056     bl  generic_handle_arch_irq
0057 
0058     pop {r0, lr}
0059     mov sp, r0
0060 
0061     @
0062     @ Check for any pending work if returning to user
0063     @
0064     ldr r1, =BASEADDR_V7M_SCB
0065     ldr r0, [r1, V7M_SCB_ICSR]
0066     tst r0, V7M_SCB_ICSR_RETTOBASE
0067     beq 2f
0068 
0069     get_thread_info tsk
0070     ldr r2, [tsk, #TI_FLAGS]
0071     movs    r2, r2, lsl #16
0072     beq 2f          @ no work pending
0073     mov r0, #V7M_SCB_ICSR_PENDSVSET
0074     str r0, [r1, V7M_SCB_ICSR]  @ raise PendSV
0075 
0076 2:
0077     @ registers r0-r3 and r12 are automatically restored on exception
0078     @ return. r4-r7 were not clobbered in v7m_exception_entry so for
0079     @ correctness they don't need to be restored. So only r8-r11 must be
0080     @ restored here. The easiest way to do so is to restore r0-r7, too.
0081     ldmia   sp!, {r0-r11}
0082     add sp, #PT_REGS_SIZE-S_IP
0083     cpsie   i
0084     bx  lr
0085 ENDPROC(__irq_entry)
0086 
0087 __pendsv_entry:
0088     v7m_exception_entry
0089 
0090     ldr r1, =BASEADDR_V7M_SCB
0091     mov r0, #V7M_SCB_ICSR_PENDSVCLR
0092     str r0, [r1, V7M_SCB_ICSR]  @ clear PendSV
0093 
0094     @ execute the pending work, including reschedule
0095     get_thread_info tsk
0096     mov why, #0
0097     b   ret_to_user_from_irq
0098 ENDPROC(__pendsv_entry)
0099 
0100 /*
0101  * Register switch for ARMv7-M processors.
0102  * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
0103  * previous and next are guaranteed not to be the same.
0104  */
0105 ENTRY(__switch_to)
0106     .fnstart
0107     .cantunwind
0108     add ip, r1, #TI_CPU_SAVE
0109     stmia   ip!, {r4 - r11}     @ Store most regs on stack
0110     str sp, [ip], #4
0111     str lr, [ip], #4
0112     mov r5, r0
0113     mov r6, r2          @ Preserve 'next'
0114     add r4, r2, #TI_CPU_SAVE
0115     ldr r0, =thread_notify_head
0116     mov r1, #THREAD_NOTIFY_SWITCH
0117     bl  atomic_notifier_call_chain
0118     mov r0, r5
0119     mov r1, r6
0120     ldmia   r4, {r4 - r12, lr}  @ Load all regs saved previously
0121     set_current r1, r2
0122     mov sp, ip
0123     bx  lr
0124     .fnend
0125 ENDPROC(__switch_to)
0126 
0127     .data
0128 #if CONFIG_CPU_V7M_NUM_IRQ <= 112
0129     .align  9
0130 #else
0131     .align  10
0132 #endif
0133 
0134 /*
0135  * Vector table (Natural alignment need to be ensured)
0136  */
0137 ENTRY(vector_table)
0138     .long   0           @ 0 - Reset stack pointer
0139     .long   __invalid_entry     @ 1 - Reset
0140     .long   __invalid_entry     @ 2 - NMI
0141     .long   __invalid_entry     @ 3 - HardFault
0142     .long   __invalid_entry     @ 4 - MemManage
0143     .long   __invalid_entry     @ 5 - BusFault
0144     .long   __invalid_entry     @ 6 - UsageFault
0145     .long   __invalid_entry     @ 7 - Reserved
0146     .long   __invalid_entry     @ 8 - Reserved
0147     .long   __invalid_entry     @ 9 - Reserved
0148     .long   __invalid_entry     @ 10 - Reserved
0149     .long   vector_swi      @ 11 - SVCall
0150     .long   __invalid_entry     @ 12 - Debug Monitor
0151     .long   __invalid_entry     @ 13 - Reserved
0152     .long   __pendsv_entry      @ 14 - PendSV
0153     .long   __invalid_entry     @ 15 - SysTick
0154     .rept   CONFIG_CPU_V7M_NUM_IRQ
0155     .long   __irq_entry     @ External Interrupts
0156     .endr
0157     .align  2
0158     .globl  exc_ret
0159 exc_ret:
0160     .space  4