X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Farm%2Fkernel%2Ffiq.c;h=e8e90346f11c10702857a04adeb4fd2f935e1336;hb=16c70f8c1b54b61c3b951b6fb220df250fe09b32;hp=6f7938162e46cc635cda8049a1a0717e45dbaa0a;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c index 6f7938162..e8e90346f 100644 --- a/arch/arm/kernel/fiq.c +++ b/arch/arm/kernel/fiq.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -46,32 +47,16 @@ #include #include -#define FIQ_VECTOR (vectors_base() + 0x1c) - static unsigned long no_fiq_insn; -static inline void unprotect_page_0(void) -{ - modify_domain(DOMAIN_USER, DOMAIN_MANAGER); -} - -static inline void protect_page_0(void) -{ - modify_domain(DOMAIN_USER, DOMAIN_CLIENT); -} - /* Default reacquire function * - we always relinquish FIQ control * - we always reacquire FIQ control */ static int fiq_def_op(void *ref, int relinquish) { - if (!relinquish) { - unprotect_page_0(); - *(unsigned long *)FIQ_VECTOR = no_fiq_insn; - protect_page_0(); - flush_icache_range(FIQ_VECTOR, FIQ_VECTOR + 4); - } + if (!relinquish) + set_fiq_handler(&no_fiq_insn, sizeof(no_fiq_insn)); return 0; } @@ -93,56 +78,51 @@ int show_fiq_list(struct seq_file *p, void *v) void set_fiq_handler(void *start, unsigned int length) { - unprotect_page_0(); - - memcpy((void *)FIQ_VECTOR, start, length); - - protect_page_0(); - flush_icache_range(FIQ_VECTOR, FIQ_VECTOR + length); + memcpy((void *)0xffff001c, start, length); + flush_icache_range(0xffff001c, 0xffff001c + length); + if (!vectors_high()) + flush_icache_range(0x1c, 0x1c + length); } /* * Taking an interrupt in FIQ mode is death, so both these functions - * disable irqs for the duration. + * disable irqs for the duration. Note - these functions are almost + * entirely coded in assembly. */ -void set_fiq_regs(struct pt_regs *regs) +void __attribute__((naked)) set_fiq_regs(struct pt_regs *regs) { - register unsigned long tmp, tmp2; - __asm__ volatile ( - "mrs %0, cpsr\n\ - mov %1, %3\n\ - msr cpsr_c, %1 @ select FIQ mode\n\ + register unsigned long tmp; + asm volatile ( + "mov ip, sp\n\ + stmfd sp!, {fp, ip, lr, pc}\n\ + sub fp, ip, #4\n\ + mrs %0, cpsr\n\ + msr cpsr_c, %2 @ select FIQ mode\n\ mov r0, r0\n\ - ldmia %2, {r8 - r14}\n\ + ldmia %1, {r8 - r14}\n\ msr cpsr_c, %0 @ return to SVC mode\n\ - mov r0, r0" - : "=&r" (tmp), "=&r" (tmp2) - : "r" (®s->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE) - /* These registers aren't modified by the above code in a way - visible to the compiler, but we mark them as clobbers anyway - so that GCC won't put any of the input or output operands in - them. */ - : "r8", "r9", "r10", "r11", "r12", "r13", "r14"); + mov r0, r0\n\ + ldmfd sp, {fp, sp, pc}" + : "=&r" (tmp) + : "r" (®s->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE)); } -void get_fiq_regs(struct pt_regs *regs) +void __attribute__((naked)) get_fiq_regs(struct pt_regs *regs) { - register unsigned long tmp, tmp2; - __asm__ volatile ( - "mrs %0, cpsr\n\ - mov %1, %3\n\ - msr cpsr_c, %1 @ select FIQ mode\n\ + register unsigned long tmp; + asm volatile ( + "mov ip, sp\n\ + stmfd sp!, {fp, ip, lr, pc}\n\ + sub fp, ip, #4\n\ + mrs %0, cpsr\n\ + msr cpsr_c, %2 @ select FIQ mode\n\ mov r0, r0\n\ - stmia %2, {r8 - r14}\n\ + stmia %1, {r8 - r14}\n\ msr cpsr_c, %0 @ return to SVC mode\n\ - mov r0, r0" - : "=&r" (tmp), "=&r" (tmp2) - : "r" (®s->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE) - /* These registers aren't modified by the above code in a way - visible to the compiler, but we mark them as clobbers anyway - so that GCC won't put any of the input or output operands in - them. */ - : "r8", "r9", "r10", "r11", "r12", "r13", "r14"); + mov r0, r0\n\ + ldmfd sp, {fp, sp, pc}" + : "=&r" (tmp) + : "r" (®s->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE)); } int claim_fiq(struct fiq_handler *f) @@ -198,6 +178,5 @@ EXPORT_SYMBOL(disable_fiq); void __init init_FIQ(void) { - no_fiq_insn = *(unsigned long *)FIQ_VECTOR; - set_fs(get_fs()); + no_fiq_insn = *(unsigned long *)0xffff001c; }