···446446__und_usr:447447 usr_entry uaccess=0448448449449- mov r2, r4450450- mov r3, r5451451-452452- @ r2 = regs->ARM_pc, which is either 2 or 4 bytes ahead of the453453- @ faulting instruction depending on Thumb mode.454454- @ r3 = regs->ARM_cpsr455455- @456456- @ The emulation code returns using r9 if it has emulated the457457- @ instruction, or the more conventional lr if we are to treat458458- @ this as a real undefined instruction459459- @460460- badr r9, ret_from_exception461461-462449 @ IRQs must be enabled before attempting to read the instruction from463450 @ user space since that could cause a page/translation fault if the464451 @ page table was modified by another CPU.465452 enable_irq466453467467- tst r3, #PSR_T_BIT @ Thumb mode?468468- bne __und_usr_thumb469469- sub r4, r2, #4 @ ARM instr at LR - 4470470-1: ldrt r0, [r4]471471- ARM_BE8(rev r0, r0) @ little endian instruction472472-454454+ tst r5, #PSR_T_BIT @ Thumb mode?455455+ mov r1, #2 @ set insn size to 2 for Thumb456456+ bne 0f @ handle as Thumb undef exception457457+#ifdef CONFIG_FPE_NWFPE458458+ adr r9, ret_from_exception459459+ bl call_fpe @ returns via R9 on success460460+#endif461461+ mov r1, #4 @ set insn size to 4 for ARM462462+0: mov r0, sp473463 uaccess_disable ip474474-475475- @ r0 = 32-bit ARM instruction which caused the exception476476- @ r2 = PC value for the following instruction (:= regs->ARM_pc)477477- @ r4 = PC value for the faulting instruction478478- @ lr = 32-bit undefined instruction function479479- badr lr, __und_usr_fault_32480480- b call_fpe481481-482482-__und_usr_thumb:483483- @ Thumb instruction484484- sub r4, r2, #2 @ First half of thumb instr at LR - 2485485-#if CONFIG_ARM_THUMB && __LINUX_ARM_ARCH__ >= 6 && CONFIG_CPU_V7486486-/*487487- * Thumb-2 instruction handling. Note that because pre-v6 and >= v6 platforms488488- * can never be supported in a single kernel, this code is not applicable at489489- * all when __LINUX_ARM_ARCH__ < 6. This allows simplifying assumptions to be490490- * made about .arch directives.491491- */492492-#if __LINUX_ARM_ARCH__ < 7493493-/* If the target CPU may not be Thumb-2-capable, a run-time check is needed: */494494- ldr_va r5, cpu_architecture495495- cmp r5, #CPU_ARCH_ARMv7496496- blo __und_usr_fault_16 @ 16bit undefined instruction497497-/*498498- * The following code won't get run unless the running CPU really is v7, so499499- * coding round the lack of ldrht on older arches is pointless. Temporarily500500- * override the assembler target arch with the minimum required instead:501501- */502502- .arch armv6t2503503-#endif504504-2: ldrht r5, [r4]505505-ARM_BE8(rev16 r5, r5) @ little endian instruction506506- cmp r5, #0xe800 @ 32bit instruction if xx != 0507507- blo __und_usr_fault_16_pan @ 16bit undefined instruction508508-3: ldrht r0, [r2]509509-ARM_BE8(rev16 r0, r0) @ little endian instruction510510- uaccess_disable ip511511- add r2, r2, #2 @ r2 is PC + 2, make it PC + 4512512- str r2, [sp, #S_PC] @ it's a 2x16bit instr, update513513- orr r0, r0, r5, lsl #16514514- badr lr, __und_usr_fault_32515515- @ r0 = the two 16-bit Thumb instructions which caused the exception516516- @ r2 = PC value for the following Thumb instruction (:= regs->ARM_pc)517517- @ r4 = PC value for the first 16-bit Thumb instruction518518- @ lr = 32bit undefined instruction function519519-520520-#if __LINUX_ARM_ARCH__ < 7521521-/* If the target arch was overridden, change it back: */522522-#ifdef CONFIG_CPU_32v6K523523- .arch armv6k524524-#else525525- .arch armv6526526-#endif527527-#endif /* __LINUX_ARM_ARCH__ < 7 */528528-#else /* !(CONFIG_ARM_THUMB && __LINUX_ARM_ARCH__ >= 6 && CONFIG_CPU_V7) */529529- b __und_usr_fault_16530530-#endif464464+ bl __und_fault465465+ b ret_from_exception531466 UNWIND(.fnend)532467ENDPROC(__und_usr)533533-534534-/*535535- * The out of line fixup for the ldrt instructions above.536536- */537537- .pushsection .text.fixup, "ax"538538- .align 2539539-4: str r4, [sp, #S_PC] @ retry current instruction540540- ret r9541541- .popsection542542- .pushsection __ex_table,"a"543543- .long 1b, 4b544544-#if CONFIG_ARM_THUMB && __LINUX_ARM_ARCH__ >= 6 && CONFIG_CPU_V7545545- .long 2b, 4b546546- .long 3b, 4b547547-#endif548548- .popsection549549-550550-/*551551- * Check whether the instruction is a co-processor instruction.552552- * If yes, we need to call the relevant co-processor handler.553553- *554554- * Note that we don't do a full check here for the co-processor555555- * instructions; all instructions with bit 27 set are well556556- * defined. The only instructions that should fault are the557557- * co-processor instructions. However, we have to watch out558558- * for the ARM6/ARM7 SWI bug.559559- *560560- * NEON is a special case that has to be handled here. Not all561561- * NEON instructions are co-processor instructions, so we have562562- * to make a special case of checking for them. Plus, there's563563- * five groups of them, so we have a table of mask/opcode pairs564564- * to check against, and if any match then we branch off into the565565- * NEON handler code.566566- *567567- * Emulators may wish to make use of the following registers:568568- * r0 = instruction opcode (32-bit ARM or two 16-bit Thumb)569569- * r2 = PC value to resume execution after successful emulation570570- * r9 = normal "successful" return address571571- * r10 = this threads thread_info structure572572- * lr = unrecognised instruction return address573573- * IRQs enabled, FIQs enabled.574574- */575575- @576576- @ Fall-through from Thumb-2 __und_usr577577- @578578-#ifdef CONFIG_NEON579579- get_thread_info r10 @ get current thread580580- adr r6, .LCneon_thumb_opcodes581581- b 2f582582-#endif583583-call_fpe:584584- get_thread_info r10 @ get current thread585585-#ifdef CONFIG_NEON586586- adr r6, .LCneon_arm_opcodes587587-2: ldr r5, [r6], #4 @ mask value588588- ldr r7, [r6], #4 @ opcode bits matching in mask589589- cmp r5, #0 @ end mask?590590- beq 1f591591- and r8, r0, r5592592- cmp r8, r7 @ NEON instruction?593593- bne 2b594594- mov r7, #1595595- strb r7, [r10, #TI_USED_CP + 10] @ mark CP#10 as used596596- strb r7, [r10, #TI_USED_CP + 11] @ mark CP#11 as used597597- b do_vfp @ let VFP handler handle this598598-1:599599-#endif600600- tst r0, #0x08000000 @ only CDP/CPRT/LDC/STC have bit 27601601- tstne r0, #0x04000000 @ bit 26 set on both ARM and Thumb-2602602- reteq lr603603- and r8, r0, #0x00000f00 @ mask out CP number604604- mov r7, #1605605- add r6, r10, r8, lsr #8 @ add used_cp[] array offset first606606- strb r7, [r6, #TI_USED_CP] @ set appropriate used_cp[]607607-#ifdef CONFIG_IWMMXT608608- @ Test if we need to give access to iWMMXt coprocessors609609- ldr r5, [r10, #TI_FLAGS]610610- rsbs r7, r8, #(1 << 8) @ CP 0 or 1 only611611- movscs r7, r5, lsr #(TIF_USING_IWMMXT + 1)612612- bcs iwmmxt_task_enable613613-#endif614614- ARM( add pc, pc, r8, lsr #6 )615615- THUMB( lsr r8, r8, #6 )616616- THUMB( add pc, r8 )617617- nop618618-619619- ret.w lr @ CP#0620620- W(b) do_fpe @ CP#1 (FPE)621621- W(b) do_fpe @ CP#2 (FPE)622622- ret.w lr @ CP#3623623- ret.w lr @ CP#4624624- ret.w lr @ CP#5625625- ret.w lr @ CP#6626626- ret.w lr @ CP#7627627- ret.w lr @ CP#8628628- ret.w lr @ CP#9629629-#ifdef CONFIG_VFP630630- W(b) do_vfp @ CP#10 (VFP)631631- W(b) do_vfp @ CP#11 (VFP)632632-#else633633- ret.w lr @ CP#10 (VFP)634634- ret.w lr @ CP#11 (VFP)635635-#endif636636- ret.w lr @ CP#12637637- ret.w lr @ CP#13638638- ret.w lr @ CP#14 (Debug)639639- ret.w lr @ CP#15 (Control)640640-641641-#ifdef CONFIG_NEON642642- .align 6643643-644644-.LCneon_arm_opcodes:645645- .word 0xfe000000 @ mask646646- .word 0xf2000000 @ opcode647647-648648- .word 0xff100000 @ mask649649- .word 0xf4000000 @ opcode650650-651651- .word 0x00000000 @ mask652652- .word 0x00000000 @ opcode653653-654654-.LCneon_thumb_opcodes:655655- .word 0xef000000 @ mask656656- .word 0xef000000 @ opcode657657-658658- .word 0xff100000 @ mask659659- .word 0xf9000000 @ opcode660660-661661- .word 0x00000000 @ mask662662- .word 0x00000000 @ opcode663663-#endif664664-665665-do_fpe:666666- add r10, r10, #TI_FPSTATE @ r10 = workspace667667- ldr_va pc, fp_enter, tmp=r4 @ Call FP module USR entry point668668-669669-/*670670- * The FP module is called with these registers set:671671- * r0 = instruction672672- * r2 = PC+4673673- * r9 = normal "successful" return address674674- * r10 = FP workspace675675- * lr = unrecognised FP instruction return address676676- */677677-678678- .pushsection .data679679- .align 2680680-ENTRY(fp_enter)681681- .word no_fp682682- .popsection683683-684684-ENTRY(no_fp)685685- ret lr686686-ENDPROC(no_fp)687687-688688-__und_usr_fault_32:689689- mov r1, #4690690- b 1f691691-__und_usr_fault_16_pan:692692- uaccess_disable ip693693-__und_usr_fault_16:694694- mov r1, #2695695-1: mov r0, sp696696- badr lr, ret_from_exception697697- b __und_fault698698-ENDPROC(__und_usr_fault_32)699699-ENDPROC(__und_usr_fault_16)700468701469 .align 5702470__pabt_usr:
+14-4
arch/arm/kernel/iwmmxt.S
···5858 .text5959 .arm60606161+ENTRY(iwmmxt_undef_handler)6262+ push {r9, r10, lr}6363+ get_thread_info r106464+ mov r9, pc6565+ b iwmmxt_task_enable6666+ mov r0, #06767+ pop {r9, r10, pc}6868+ENDPROC(iwmmxt_undef_handler)6969+6170/*6271 * Lazy switching of Concan coprocessor context6372 *7373+ * r0 = struct pt_regs pointer6474 * r10 = struct thread_info pointer6575 * r9 = ret_from_exception6676 * lr = undefined instr exit···9484 PJ4(mcr p15, 0, r2, c1, c0, 2)95859686 ldr r3, =concan_owner9797- add r0, r10, #TI_IWMMXT_STATE @ get task Concan save area9898- ldr r2, [sp, #60] @ current task pc value8787+ ldr r2, [r0, #S_PC] @ current task pc value9988 ldr r1, [r3] @ get current Concan owner100100- str r0, [r3] @ this task now owns Concan regs10189 sub r2, r2, #4 @ adjust pc back102102- str r2, [sp, #60]9090+ str r2, [r0, #S_PC]9191+ add r0, r10, #TI_IWMMXT_STATE @ get task Concan save area9292+ str r0, [r3] @ this task now owns Concan regs1039310494 mrc p15, 0, r2, c2, c0, 010595 mov r2, r2 @ cpwait
···5656 movne r2, r2, lsr #2 @ turned into # of sets5757 sub r2, r2, #(1 << 5)5858 stmia r1, {r2, r3}5959+#ifdef CONFIG_VFP6060+ mov r1, #1 @ disable quirky VFP6161+ str_l r1, VFP_arch_feroceon, r26262+#endif5963 ret lr60646165/*
+77
arch/arm/nwfpe/entry.S
···77 Direct questions, comments to Scott Bambrough <scottb@netwinder.org>8899*/1010+#include <linux/linkage.h>1011#include <asm/assembler.h>1112#include <asm/opcodes.h>1213···105104 @ plain LDR instruction. Weird, but it seems harmless.106105 .pushsection .text.fixup,"ax"107106 .align 2107107+.Lrep: str r4, [sp, #S_PC] @ retry current instruction108108.Lfix: ret r9 @ let the user eat segfaults109109 .popsection110110···113111 .align 3114112 .long .Lx1, .Lfix115113 .popsection114114+115115+ @116116+ @ Check whether the instruction is a co-processor instruction.117117+ @ If yes, we need to call the relevant co-processor handler.118118+ @ Only FPE instructions are dispatched here, everything else119119+ @ is handled by undef hooks.120120+ @121121+ @ Emulators may wish to make use of the following registers:122122+ @ r4 = PC value to resume execution after successful emulation123123+ @ r9 = normal "successful" return address124124+ @ lr = unrecognised instruction return address125125+ @ IRQs enabled, FIQs enabled.126126+ @127127+ENTRY(call_fpe)128128+ mov r2, r4129129+ sub r4, r4, #4 @ ARM instruction at user PC - 4130130+USERL( .Lrep, ldrt r0, [r4]) @ load opcode from user space131131+ARM_BE8(rev r0, r0) @ little endian instruction132132+133133+ uaccess_disable ip134134+135135+ get_thread_info r10 @ get current thread136136+ tst r0, #0x08000000 @ only CDP/CPRT/LDC/STC have bit 27137137+ reteq lr138138+ and r8, r0, #0x00000f00 @ mask out CP number139139+#ifdef CONFIG_IWMMXT140140+ @ Test if we need to give access to iWMMXt coprocessors141141+ ldr r5, [r10, #TI_FLAGS]142142+ rsbs r7, r8, #(1 << 8) @ CP 0 or 1 only143143+ movscs r7, r5, lsr #(TIF_USING_IWMMXT + 1)144144+ movcs r0, sp @ pass struct pt_regs145145+ bcs iwmmxt_task_enable146146+#endif147147+ add pc, pc, r8, lsr #6148148+ nop149149+150150+ ret lr @ CP#0151151+ b do_fpe @ CP#1 (FPE)152152+ b do_fpe @ CP#2 (FPE)153153+ ret lr @ CP#3154154+ ret lr @ CP#4155155+ ret lr @ CP#5156156+ ret lr @ CP#6157157+ ret lr @ CP#7158158+ ret lr @ CP#8159159+ ret lr @ CP#9160160+ ret lr @ CP#10 (VFP)161161+ ret lr @ CP#11 (VFP)162162+ ret lr @ CP#12163163+ ret lr @ CP#13164164+ ret lr @ CP#14 (Debug)165165+ ret lr @ CP#15 (Control)166166+167167+do_fpe:168168+ add r10, r10, #TI_FPSTATE @ r10 = workspace169169+ ldr_va pc, fp_enter, tmp=r4 @ Call FP module USR entry point170170+171171+ @172172+ @ The FP module is called with these registers set:173173+ @ r0 = instruction174174+ @ r2 = PC+4175175+ @ r9 = normal "successful" return address176176+ @ r10 = FP workspace177177+ @ lr = unrecognised FP instruction return address178178+ @179179+180180+ .pushsection .data181181+ .align 2182182+ENTRY(fp_enter)183183+ .word no_fp184184+ .popsection185185+186186+no_fp:187187+ ret lr188188+ENDPROC(no_fp)
···44 *55 * Copyright (C) 2004 ARM Limited.66 * Written by Deep Blue Solutions Limited.77- *88- * This code is called from the kernel's undefined instruction trap.99- * r1 holds the thread_info pointer1010- * r3 holds the return address for successful handling.1111- * lr holds the return address for unrecognised instructions.1212- * sp points to a struct pt_regs (as defined in include/asm/proc/ptrace.h)137 */148#include <linux/init.h>159#include <linux/linkage.h>···1218#include <linux/kern_levels.h>1319#include <asm/assembler.h>1420#include <asm/asm-offsets.h>1515-1616- .macro DBGSTR, str1717-#ifdef DEBUG1818- stmfd sp!, {r0-r3, ip, lr}1919- ldr r0, =1f2020- bl _printk2121- ldmfd sp!, {r0-r3, ip, lr}2222-2323- .pushsection .rodata, "a"2424-1: .ascii KERN_DEBUG "VFP: \str\n"2525- .byte 02626- .previous2727-#endif2828- .endm29213022 .macro DBGSTR1, str, arg3123#ifdef DEBUG···2848#endif2949 .endm30503131- .macro DBGSTR3, str, arg1, arg2, arg33232-#ifdef DEBUG3333- stmfd sp!, {r0-r3, ip, lr}3434- mov r3, \arg33535- mov r2, \arg23636- mov r1, \arg13737- ldr r0, =1f3838- bl _printk3939- ldmfd sp!, {r0-r3, ip, lr}4040-4141- .pushsection .rodata, "a"4242-1: .ascii KERN_DEBUG "VFP: \str\n"4343- .byte 04444- .previous4545-#endif4646- .endm4747-4848-4949-@ VFP hardware support entry point.5050-@5151-@ r0 = instruction opcode (32-bit ARM or two 16-bit Thumb)5252-@ r1 = thread_info pointer5353-@ r2 = PC value to resume execution after successful emulation5454-@ r3 = normal "successful" return address5555-@ lr = unrecognised instruction return address5656-@ IRQs enabled.5757-ENTRY(vfp_support_entry)5858- ldr r11, [r1, #TI_CPU] @ CPU number5959- add r10, r1, #TI_VFPSTATE @ r10 = workspace6060-6161- DBGSTR3 "instr %08x pc %08x state %p", r0, r2, r106262-6363- .fpu vfpv26464- VFPFMRX r1, FPEXC @ Is the VFP enabled?6565- DBGSTR1 "fpexc %08x", r16666- tst r1, #FPEXC_EN6767- bne look_for_VFP_exceptions @ VFP is already enabled6868-6969- DBGSTR1 "enable %x", r107070- ldr r9, vfp_current_hw_state_address7171- orr r1, r1, #FPEXC_EN @ user FPEXC has the enable bit set7272- ldr r4, [r9, r11, lsl #2] @ vfp_current_hw_state pointer7373- bic r5, r1, #FPEXC_EX @ make sure exceptions are disabled7474- cmp r4, r10 @ this thread owns the hw context?7575-#ifndef CONFIG_SMP7676- @ For UP, checking that this thread owns the hw context is7777- @ sufficient to determine that the hardware state is valid.7878- beq vfp_hw_state_valid7979-8080- @ On UP, we lazily save the VFP context. As a different8181- @ thread wants ownership of the VFP hardware, save the old8282- @ state if there was a previous (valid) owner.8383-8484- VFPFMXR FPEXC, r5 @ enable VFP, disable any pending8585- @ exceptions, so we can get at the8686- @ rest of it8787-8888- DBGSTR1 "save old state %p", r48989- cmp r4, #0 @ if the vfp_current_hw_state is NULL9090- beq vfp_reload_hw @ then the hw state needs reloading9191- VFPFSTMIA r4, r5 @ save the working registers9292- VFPFMRX r5, FPSCR @ current status9393-#ifndef CONFIG_CPU_FEROCEON9494- tst r1, #FPEXC_EX @ is there additional state to save?9595- beq 1f9696- VFPFMRX r6, FPINST @ FPINST (only if FPEXC.EX is set)9797- tst r1, #FPEXC_FP2V @ is there an FPINST2 to read?9898- beq 1f9999- VFPFMRX r8, FPINST2 @ FPINST2 if needed (and present)100100-1:101101-#endif102102- stmia r4, {r1, r5, r6, r8} @ save FPEXC, FPSCR, FPINST, FPINST2103103-vfp_reload_hw:104104-105105-#else106106- @ For SMP, if this thread does not own the hw context, then we107107- @ need to reload it. No need to save the old state as on SMP,108108- @ we always save the state when we switch away from a thread.109109- bne vfp_reload_hw110110-111111- @ This thread has ownership of the current hardware context.112112- @ However, it may have been migrated to another CPU, in which113113- @ case the saved state is newer than the hardware context.114114- @ Check this by looking at the CPU number which the state was115115- @ last loaded onto.116116- ldr ip, [r10, #VFP_CPU]117117- teq ip, r11118118- beq vfp_hw_state_valid119119-120120-vfp_reload_hw:121121- @ We're loading this threads state into the VFP hardware. Update122122- @ the CPU number which contains the most up to date VFP context.123123- str r11, [r10, #VFP_CPU]124124-125125- VFPFMXR FPEXC, r5 @ enable VFP, disable any pending126126- @ exceptions, so we can get at the127127- @ rest of it128128-#endif129129-130130- DBGSTR1 "load state %p", r10131131- str r10, [r9, r11, lsl #2] @ update the vfp_current_hw_state pointer5151+ENTRY(vfp_load_state)5252+ @ Load the current VFP state5353+ @ r0 - load location5454+ @ returns FPEXC5555+ DBGSTR1 "load VFP state %p", r013256 @ Load the saved state back into the VFP133133- VFPFLDMIA r10, r5 @ reload the working registers while5757+ VFPFLDMIA r0, r1 @ reload the working registers while13458 @ FPEXC is in a safe state135135- ldmia r10, {r1, r5, r6, r8} @ load FPEXC, FPSCR, FPINST, FPINST2136136-#ifndef CONFIG_CPU_FEROCEON137137- tst r1, #FPEXC_EX @ is there additional state to restore?5959+ ldmia r0, {r0-r3} @ load FPEXC, FPSCR, FPINST, FPINST26060+ tst r0, #FPEXC_EX @ is there additional state to restore?13861 beq 1f139139- VFPFMXR FPINST, r6 @ restore FPINST (only if FPEXC.EX is set)140140- tst r1, #FPEXC_FP2V @ is there an FPINST2 to write?6262+ VFPFMXR FPINST, r2 @ restore FPINST (only if FPEXC.EX is set)6363+ tst r0, #FPEXC_FP2V @ is there an FPINST2 to write?14164 beq 1f142142- VFPFMXR FPINST2, r8 @ FPINST2 if needed (and present)6565+ VFPFMXR FPINST2, r3 @ FPINST2 if needed (and present)143661:144144-#endif145145- VFPFMXR FPSCR, r5 @ restore status146146-147147-@ The context stored in the VFP hardware is up to date with this thread148148-vfp_hw_state_valid:149149- tst r1, #FPEXC_EX150150- bne process_exception @ might as well handle the pending151151- @ exception before retrying branch152152- @ out before setting an FPEXC that153153- @ stops us reading stuff154154- VFPFMXR FPEXC, r1 @ Restore FPEXC last155155- mov sp, r3 @ we think we have handled things156156- pop {lr}157157- sub r2, r2, #4 @ Retry current instruction - if Thumb158158- str r2, [sp, #S_PC] @ mode it's two 16-bit instructions,159159- @ else it's one 32-bit instruction, so160160- @ always subtract 4 from the following161161- @ instruction address.162162-163163-local_bh_enable_and_ret:164164- adr r0, .165165- mov r1, #SOFTIRQ_DISABLE_OFFSET166166- b __local_bh_enable_ip @ tail call167167-168168-look_for_VFP_exceptions:169169- @ Check for synchronous or asynchronous exception170170- tst r1, #FPEXC_EX | FPEXC_DEX171171- bne process_exception172172- @ On some implementations of the VFP subarch 1, setting FPSCR.IXE173173- @ causes all the CDP instructions to be bounced synchronously without174174- @ setting the FPEXC.EX bit175175- VFPFMRX r5, FPSCR176176- tst r5, #FPSCR_IXE177177- bne process_exception178178-179179- tst r5, #FPSCR_LENGTH_MASK180180- beq skip181181- orr r1, r1, #FPEXC_DEX182182- b process_exception183183-skip:184184-185185- @ Fall into hand on to next handler - appropriate coproc instr186186- @ not recognised by VFP187187-188188- DBGSTR "not VFP"189189- b local_bh_enable_and_ret190190-191191-process_exception:192192- DBGSTR "bounce"193193- mov sp, r3 @ setup for a return to the user code.194194- pop {lr}195195- mov r2, sp @ nothing stacked - regdump is at TOS196196-197197- @ Now call the C code to package up the bounce to the support code198198- @ r0 holds the trigger instruction199199- @ r1 holds the FPEXC value200200- @ r2 pointer to register dump201201- b VFP_bounce @ we have handled this - the support202202- @ code will raise an exception if203203- @ required. If not, the user code will204204- @ retry the faulted instruction205205-ENDPROC(vfp_support_entry)6767+ VFPFMXR FPSCR, r1 @ restore status6868+ ret lr6969+ENDPROC(vfp_load_state)2067020771ENTRY(vfp_save_state)20872 @ Save the current VFP state···65241 stmia r0, {r1, r2, r3, r12} @ save FPEXC, FPSCR, FPINST, FPINST266242 ret lr67243ENDPROC(vfp_save_state)6868-6969- .align7070-vfp_current_hw_state_address:7171- .word vfp_current_hw_state7224473245 .macro tbl_branch, base, tmp, shift74246#ifdef CONFIG_THUMB2_KERNEL
+146-62
arch/arm/vfp/vfpmodule.c
···1818#include <linux/uaccess.h>1919#include <linux/user.h>2020#include <linux/export.h>2121+#include <linux/perf_event.h>21222223#include <asm/cp15.h>2324#include <asm/cputype.h>···3130#include "vfpinstr.h"3231#include "vfp.h"33323434-/*3535- * Our undef handlers (in entry.S)3636- */3737-asmlinkage void vfp_support_entry(u32, void *, u32, u32);3838-3933static bool have_vfp __ro_after_init;40344135/*···3842 * Used in startup: set to non-zero if VFP checks fail3943 * After startup, holds VFP architecture4044 */4141-static unsigned int __initdata VFP_arch;4545+static unsigned int VFP_arch;4646+4747+#ifdef CONFIG_CPU_FEROCEON4848+extern unsigned int VFP_arch_feroceon __alias(VFP_arch);4949+#endif42504351/*4452 * The pointer to the vfpstate structure of the thread which currently···314314 * emulate it.315315 */316316 }317317+ perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->ARM_pc);317318 return exceptions & ~VFP_NAN_FLAG;318319}319320320321/*321322 * Package up a bounce condition.322323 */323323-void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)324324+static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)324325{325326 u32 fpscr, orig_fpscr, fpsid, exceptions;326327···357356 }358357359358 if (fpexc & FPEXC_EX) {360360-#ifndef CONFIG_CPU_FEROCEON361359 /*362360 * Asynchronous exception. The instruction is read from FPINST363361 * and the interrupted instruction has to be restarted.364362 */365363 trigger = fmrx(FPINST);366364 regs->ARM_pc -= 4;367367-#endif368365 } else if (!(fpexc & FPEXC_DEX)) {369366 /*370367 * Illegal combination of bits. It can be caused by an···370371 * on VFP subarch 1.371372 */372373 vfp_raise_exceptions(VFP_EXCEPTION_ERROR, trigger, fpscr, regs);373373- goto exit;374374+ return;374375 }375376376377 /*···401402 * the FPEXC.FP2V bit is valid only if FPEXC.EX is 1.402403 */403404 if ((fpexc & (FPEXC_EX | FPEXC_FP2V)) != (FPEXC_EX | FPEXC_FP2V))404404- goto exit;405405+ return;405406406407 /*407408 * The barrier() here prevents fpinst2 being read···414415 exceptions = vfp_emulate_instruction(trigger, orig_fpscr, regs);415416 if (exceptions)416417 vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs);417417- exit:418418- local_bh_enable();419418}420419421420static void vfp_enable(void *unused)···642645 return 0;643646}644647645645-/*646646- * Entered with:647647- *648648- * r0 = instruction opcode (32-bit ARM or two 16-bit Thumb)649649- * r1 = thread_info pointer650650- * r2 = PC value to resume execution after successful emulation651651- * r3 = normal "successful" return address652652- * lr = unrecognised instruction return address653653- */654654-asmlinkage void vfp_entry(u32 trigger, struct thread_info *ti, u32 resume_pc,655655- u32 resume_return_address)656656-{657657- if (unlikely(!have_vfp))658658- return;659659-660660- local_bh_disable();661661- vfp_support_entry(trigger, ti, resume_pc, resume_return_address);662662-}663663-664664-#ifdef CONFIG_KERNEL_MODE_NEON665665-666648static int vfp_kmode_exception(struct pt_regs *regs, unsigned int instr)667649{668650 /*···664688 return 1;665689}666690667667-static struct undef_hook vfp_kmode_exception_hook[] = {{691691+/*692692+ * vfp_support_entry - Handle VFP exception693693+ *694694+ * @regs: pt_regs structure holding the register state at exception entry695695+ * @trigger: The opcode of the instruction that triggered the exception696696+ *697697+ * Returns 0 if the exception was handled, or an error code otherwise.698698+ */699699+static int vfp_support_entry(struct pt_regs *regs, u32 trigger)700700+{701701+ struct thread_info *ti = current_thread_info();702702+ u32 fpexc;703703+704704+ if (unlikely(!have_vfp))705705+ return -ENODEV;706706+707707+ if (!user_mode(regs))708708+ return vfp_kmode_exception(regs, trigger);709709+710710+ local_bh_disable();711711+ fpexc = fmrx(FPEXC);712712+713713+ /*714714+ * If the VFP unit was not enabled yet, we have to check whether the715715+ * VFP state in the CPU's registers is the most recent VFP state716716+ * associated with the process. On UP systems, we don't save the VFP717717+ * state eagerly on a context switch, so we may need to save the718718+ * VFP state to memory first, as it may belong to another process.719719+ */720720+ if (!(fpexc & FPEXC_EN)) {721721+ /*722722+ * Enable the VFP unit but mask the FP exception flag for the723723+ * time being, so we can access all the registers.724724+ */725725+ fpexc |= FPEXC_EN;726726+ fmxr(FPEXC, fpexc & ~FPEXC_EX);727727+728728+ /*729729+ * Check whether or not the VFP state in the CPU's registers is730730+ * the most recent VFP state associated with this task. On SMP,731731+ * migration may result in multiple CPUs holding VFP states732732+ * that belong to the same task, but only the most recent one733733+ * is valid.734734+ */735735+ if (!vfp_state_in_hw(ti->cpu, ti)) {736736+ if (!IS_ENABLED(CONFIG_SMP) &&737737+ vfp_current_hw_state[ti->cpu] != NULL) {738738+ /*739739+ * This CPU is currently holding the most740740+ * recent VFP state associated with another741741+ * task, and we must save that to memory first.742742+ */743743+ vfp_save_state(vfp_current_hw_state[ti->cpu],744744+ fpexc);745745+ }746746+747747+ /*748748+ * We can now proceed with loading the task's VFP state749749+ * from memory into the CPU registers.750750+ */751751+ fpexc = vfp_load_state(&ti->vfpstate);752752+ vfp_current_hw_state[ti->cpu] = &ti->vfpstate;753753+#ifdef CONFIG_SMP754754+ /*755755+ * Record that this CPU is now the one holding the most756756+ * recent VFP state of the task.757757+ */758758+ ti->vfpstate.hard.cpu = ti->cpu;759759+#endif760760+ }761761+762762+ if (fpexc & FPEXC_EX)763763+ /*764764+ * Might as well handle the pending exception before765765+ * retrying branch out before setting an FPEXC that766766+ * stops us reading stuff.767767+ */768768+ goto bounce;769769+770770+ /*771771+ * No FP exception is pending: just enable the VFP and772772+ * replay the instruction that trapped.773773+ */774774+ fmxr(FPEXC, fpexc);775775+ } else {776776+ /* Check for synchronous or asynchronous exceptions */777777+ if (!(fpexc & (FPEXC_EX | FPEXC_DEX))) {778778+ u32 fpscr = fmrx(FPSCR);779779+780780+ /*781781+ * On some implementations of the VFP subarch 1,782782+ * setting FPSCR.IXE causes all the CDP instructions to783783+ * be bounced synchronously without setting the784784+ * FPEXC.EX bit785785+ */786786+ if (!(fpscr & FPSCR_IXE)) {787787+ if (!(fpscr & FPSCR_LENGTH_MASK)) {788788+ pr_debug("not VFP\n");789789+ local_bh_enable();790790+ return -ENOEXEC;791791+ }792792+ fpexc |= FPEXC_DEX;793793+ }794794+ }795795+bounce: regs->ARM_pc += 4;796796+ VFP_bounce(trigger, fpexc, regs);797797+ }798798+799799+ local_bh_enable();800800+ return 0;801801+}802802+803803+static struct undef_hook neon_support_hook[] = {{668804 .instr_mask = 0xfe000000,669805 .instr_val = 0xf2000000,670670- .cpsr_mask = MODE_MASK | PSR_T_BIT,671671- .cpsr_val = SVC_MODE,672672- .fn = vfp_kmode_exception,806806+ .cpsr_mask = PSR_T_BIT,807807+ .cpsr_val = 0,808808+ .fn = vfp_support_entry,673809}, {674810 .instr_mask = 0xff100000,675811 .instr_val = 0xf4000000,676676- .cpsr_mask = MODE_MASK | PSR_T_BIT,677677- .cpsr_val = SVC_MODE,678678- .fn = vfp_kmode_exception,812812+ .cpsr_mask = PSR_T_BIT,813813+ .cpsr_val = 0,814814+ .fn = vfp_support_entry,679815}, {680816 .instr_mask = 0xef000000,681817 .instr_val = 0xef000000,682682- .cpsr_mask = MODE_MASK | PSR_T_BIT,683683- .cpsr_val = SVC_MODE | PSR_T_BIT,684684- .fn = vfp_kmode_exception,818818+ .cpsr_mask = PSR_T_BIT,819819+ .cpsr_val = PSR_T_BIT,820820+ .fn = vfp_support_entry,685821}, {686822 .instr_mask = 0xff100000,687823 .instr_val = 0xf9000000,688688- .cpsr_mask = MODE_MASK | PSR_T_BIT,689689- .cpsr_val = SVC_MODE | PSR_T_BIT,690690- .fn = vfp_kmode_exception,691691-}, {692692- .instr_mask = 0x0c000e00,693693- .instr_val = 0x0c000a00,694694- .cpsr_mask = MODE_MASK,695695- .cpsr_val = SVC_MODE,696696- .fn = vfp_kmode_exception,824824+ .cpsr_mask = PSR_T_BIT,825825+ .cpsr_val = PSR_T_BIT,826826+ .fn = vfp_support_entry,697827}};698828699699-static int __init vfp_kmode_exception_hook_init(void)700700-{701701- int i;829829+static struct undef_hook vfp_support_hook = {830830+ .instr_mask = 0x0c000e00,831831+ .instr_val = 0x0c000a00,832832+ .fn = vfp_support_entry,833833+};702834703703- for (i = 0; i < ARRAY_SIZE(vfp_kmode_exception_hook); i++)704704- register_undef_hook(&vfp_kmode_exception_hook[i]);705705- return 0;706706-}707707-subsys_initcall(vfp_kmode_exception_hook_init);835835+#ifdef CONFIG_KERNEL_MODE_NEON708836709837/*710838 * Kernel-side NEON support functions···913833 * for NEON if the hardware has the MVFR registers.914834 */915835 if (IS_ENABLED(CONFIG_NEON) &&916916- (fmrx(MVFR1) & 0x000fff00) == 0x00011100)836836+ (fmrx(MVFR1) & 0x000fff00) == 0x00011100) {917837 elf_hwcap |= HWCAP_NEON;838838+ for (int i = 0; i < ARRAY_SIZE(neon_support_hook); i++)839839+ register_undef_hook(&neon_support_hook[i]);840840+ }918841919842 if (IS_ENABLED(CONFIG_VFPv3)) {920843 u32 mvfr0 = fmrx(MVFR0);···986903987904 have_vfp = true;988905906906+ register_undef_hook(&vfp_support_hook);989907 thread_register_notifier(&vfp_notifier_block);990908 vfp_pm_init();991909