#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/seq_file.h>
#include <asm/cacheflush.h>
/*
* 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)