ARM: Fix interrupt management

Interrupts where not correctly masked while in kernel, which
breaks one of the current main assumptions.

Also remove some duplication on ARM asm files, and add a function
to check the status of ARM irqs (not compiled by default)

Change-Id: I3c25d2b388f93fd8fe423998b94b3c4f140ba831
This commit is contained in:
Lionel Sambuc 2013-02-15 01:07:04 +01:00
parent eff37b8a8b
commit b36292e232
7 changed files with 169 additions and 109 deletions

View File

@ -64,7 +64,7 @@ CLEANFILES+= ${ORIG_UNPAGED_OBJS}
SRCS+= mpx.S arch_clock.c arch_do_vmctl.c arch_system.c \ SRCS+= mpx.S arch_clock.c arch_do_vmctl.c arch_system.c \
omap_serial.c omap_timer.c omap_intr.c exception.c \ omap_serial.c omap_timer.c omap_intr.c exception.c \
io_intr.S klib.S memory.c \ klib.S memory.c \
protect.c direct_tty_utils.c arch_reset.c \ protect.c direct_tty_utils.c arch_reset.c \
pg_utils.c phys_copy.S phys_memset.S exc.S pg_utils.c phys_copy.S phys_memset.S exc.S
OBJS.kernel+= ${UNPAGED_OBJS} OBJS.kernel+= ${UNPAGED_OBJS}

View File

@ -25,6 +25,7 @@ halt_cpu(void)
asm volatile("dsb"); asm volatile("dsb");
asm volatile("cpsie i"); asm volatile("cpsie i");
asm volatile("wfi"); asm volatile("wfi");
asm volatile("cpsid i");
} }
void void

View File

@ -159,10 +159,8 @@ struct proc * arch_finish_switch_to_user(void)
p = get_cpulocal_var(proc_ptr); p = get_cpulocal_var(proc_ptr);
*((reg_t *)stk) = (reg_t) p; *((reg_t *)stk) = (reg_t) p;
/* make sure I bit is clear in PSR so that interrupts won't be disabled /* turn interrupts on */
* once p's context is restored. this should not be possible. p->p_reg.psr &= ~(PSR_I|PSR_F);
*/
assert(!(p->p_reg.psr & PSR_I));
return p; return p;
} }

View File

@ -1,6 +1,23 @@
#ifndef _ARM_CPUFUNC_H #ifndef _ARM_CPUFUNC_H
#define _ARM_CPUFUNC_H #define _ARM_CPUFUNC_H
#if 0
/* check interrupt state */
static inline void check_int(unsigned int state, int line)
{
unsigned int cpsr = 0;
asm volatile("mrs %0, cpsr" : "=r" (cpsr));
if ((cpsr & PSR_F) != (state & PSR_F))
printf("%d: FIQs are unexpectedly %s\n", line, (cpsr & PSR_F) ? "MASKED" : "UNMASKED");
if ((cpsr & PSR_I) != (state & PSR_I))
printf("%d: IRQs are unexpectedly %s\n", line, (cpsr & PSR_I) ? "MASKED" : "UNMASKED");
}
#endif
/* Data memory barrier */ /* Data memory barrier */
static inline void dmb(void) static inline void dmb(void)
{ {
@ -28,8 +45,29 @@ static inline void barrier(void)
static inline void refresh_tlb(void) static inline void refresh_tlb(void)
{ {
dsb(); dsb();
/* Invalidate entire unified TLB */ /* Invalidate entire unified TLB */
asm volatile("mcr p15, 0, r0, c8, c7, 0 @ TLBIALL\n\t"); asm volatile("mcr p15, 0, %[zero], c8, c7, 0 @ TLBIALL\n\t" : : [zero] "r" (0));
#if 0
/* Invalidate entire data TLB */
asm volatile("mcr p15, 0, %[zero], c8, c6, 0" : : [zero] "r" (0));
/* Invalidate entire instruction TLB */
asm volatile("mcr p15, 0, %[zero], c8, c5, 0" : : [zero] "r" (0));
#endif
#if 0
/*
* Invalidate all instruction caches to PoU.
* Also flushes branch target cache.
*/
asm volatile("mcr p15, 0, %[zero], c7, c5, 0" : : [zero] "r" (0));
/* Invalidate entire branch predictor array */
asm volatile("mcr p15, 0, %[zero], c7, c5, 6" : : [zero] "r" (0)); /* flush BTB */
#endif
dsb(); dsb();
isb(); isb();
} }
@ -38,236 +76,269 @@ static inline void refresh_tlb(void)
/* Read System Control Register */ /* Read System Control Register */
static inline u32_t read_sctlr() static inline u32_t read_sctlr()
{ {
u32_t ctl; u32_t ctl;
asm volatile("mrc p15, 0, %[ctl], c1, c0, 0 @ Read SCTLR\n\t" asm volatile("mrc p15, 0, %[ctl], c1, c0, 0 @ Read SCTLR\n\t"
: [ctl] "=r" (ctl)); : [ctl] "=r" (ctl));
return ctl;
return ctl;
} }
/* Write System Control Register */ /* Write System Control Register */
static inline void write_sctlr(u32_t ctl) static inline void write_sctlr(u32_t ctl)
{ {
asm volatile("mcr p15, 0, %[ctl], c1, c0, 0 @ Write SCTLR\n\t" asm volatile("mcr p15, 0, %[ctl], c1, c0, 0 @ Write SCTLR\n\t"
: : [ctl] "r" (ctl)); : : [ctl] "r" (ctl));
isb();
} }
/* Read Translation Table Base Register 0 */ /* Read Translation Table Base Register 0 */
static inline u32_t read_ttbr0() static inline u32_t read_ttbr0()
{ {
u32_t bar; u32_t bar;
asm volatile("mrc p15, 0, %[bar], c2, c0, 0 @ Read TTBR0\n\t" asm volatile("mrc p15, 0, %[bar], c2, c0, 0 @ Read TTBR0\n\t"
: [bar] "=r" (bar)); : [bar] "=r" (bar));
return bar;
return bar;
} }
/* Write Translation Table Base Register 0 */ /* Write Translation Table Base Register 0 */
static inline void write_ttbr0(u32_t bar) static inline void write_ttbr0(u32_t bar)
{ {
barrier(); barrier();
asm volatile("mcr p15, 0, %[bar], c2, c0, 0 @ Write TTBR0\n\t"
: : [bar] "r" (bar)); asm volatile("mcr p15, 0, %[bar], c2, c0, 0 @ Write TTBR0\n\t"
refresh_tlb(); : : [bar] "r" (bar));
refresh_tlb();
} }
/* Reload Translation Table Base Register 0 */ /* Reload Translation Table Base Register 0 */
static inline void reload_ttbr0(void) static inline void reload_ttbr0(void)
{ {
reg_t ttbr = read_ttbr0(); reg_t ttbr = read_ttbr0();
write_ttbr0(ttbr);
refresh_tlb(); write_ttbr0(ttbr);
} }
/* Read Translation Table Base Register 1 */ /* Read Translation Table Base Register 1 */
static inline u32_t read_ttbr1() static inline u32_t read_ttbr1()
{ {
u32_t bar; u32_t bar;
asm volatile("mrc p15, 0, %[bar], c2, c0, 1 @ Read TTBR1\n\t" asm volatile("mrc p15, 0, %[bar], c2, c0, 1 @ Read TTBR1\n\t"
: [bar] "=r" (bar)); : [bar] "=r" (bar));
return bar;
return bar;
} }
/* Write Translation Table Base Register 1 */ /* Write Translation Table Base Register 1 */
static inline void write_ttbr1(u32_t bar) static inline void write_ttbr1(u32_t bar)
{ {
barrier(); barrier();
asm volatile("mcr p15, 0, %[bar], c2, c0, 1 @ Write TTBR1\n\t"
: : [bar] "r" (bar)); asm volatile("mcr p15, 0, %[bar], c2, c0, 1 @ Write TTBR1\n\t"
refresh_tlb(); : : [bar] "r" (bar));
refresh_tlb();
} }
/* Reload Translation Table Base Register 1 */ /* Reload Translation Table Base Register 1 */
static inline void reload_ttbr1(void) static inline void reload_ttbr1(void)
{ {
reg_t ttbr = read_ttbr1(); reg_t ttbr = read_ttbr1();
write_ttbr1(ttbr);
refresh_tlb(); write_ttbr1(ttbr);
} }
/* Read Translation Table Base Control Register */ /* Read Translation Table Base Control Register */
static inline u32_t read_ttbcr() static inline u32_t read_ttbcr()
{ {
u32_t bcr; u32_t bcr;
asm volatile("mrc p15, 0, %[bcr], c2, c0, 2 @ Read TTBCR\n\t" asm volatile("mrc p15, 0, %[bcr], c2, c0, 2 @ Read TTBCR\n\t"
: [bcr] "=r" (bcr)); : [bcr] "=r" (bcr));
return bcr;
return bcr;
} }
/* Write Translation Table Base Control Register */ /* Write Translation Table Base Control Register */
static inline void write_ttbcr(u32_t bcr) static inline void write_ttbcr(u32_t bcr)
{ {
asm volatile("mcr p15, 0, %[bcr], c2, c0, 2 @ Write TTBCR\n\t" asm volatile("mcr p15, 0, %[bcr], c2, c0, 2 @ Write TTBCR\n\t"
: : [bcr] "r" (bcr)); : : [bcr] "r" (bcr));
isb();
} }
/* Read Domain Access Control Register */ /* Read Domain Access Control Register */
static inline u32_t read_dacr() static inline u32_t read_dacr()
{ {
u32_t dacr; u32_t dacr;
asm volatile("mrc p15, 0, %[dacr], c3, c0, 0 @ Read DACR\n\t" asm volatile("mrc p15, 0, %[dacr], c3, c0, 0 @ Read DACR\n\t"
: [dacr] "=r" (dacr)); : [dacr] "=r" (dacr));
return dacr;
return dacr;
} }
/* Write Domain Access Control Register */ /* Write Domain Access Control Register */
static inline void write_dacr(u32_t dacr) static inline void write_dacr(u32_t dacr)
{ {
asm volatile("mcr p15, 0, %[dacr], c3, c0, 0 @ Write DACR\n\t" asm volatile("mcr p15, 0, %[dacr], c3, c0, 0 @ Write DACR\n\t"
: : [dacr] "r" (dacr)); : : [dacr] "r" (dacr));
isb();
} }
/* Read Data Fault Status Register */ /* Read Data Fault Status Register */
static inline u32_t read_dfsr() static inline u32_t read_dfsr()
{ {
u32_t fsr; u32_t fsr;
asm volatile("mrc p15, 0, %[fsr], c5, c0, 0 @ Read DFSR\n\t" asm volatile("mrc p15, 0, %[fsr], c5, c0, 0 @ Read DFSR\n\t"
: [fsr] "=r" (fsr)); : [fsr] "=r" (fsr));
return fsr;
return fsr;
} }
/* Write Data Fault Status Register */ /* Write Data Fault Status Register */
static inline void write_dfsr(u32_t fsr) static inline void write_dfsr(u32_t fsr)
{ {
asm volatile("mcr p15, 0, %[fsr], c5, c0, 0 @ Write DFSR\n\t" asm volatile("mcr p15, 0, %[fsr], c5, c0, 0 @ Write DFSR\n\t"
: : [fsr] "r" (fsr)); : : [fsr] "r" (fsr));
isb();
} }
/* Read Instruction Fault Status Register */ /* Read Instruction Fault Status Register */
static inline u32_t read_ifsr() static inline u32_t read_ifsr()
{ {
u32_t fsr; u32_t fsr;
asm volatile("mrc p15, 0, %[fsr], c5, c0, 1 @ Read IFSR\n\t" asm volatile("mrc p15, 0, %[fsr], c5, c0, 1 @ Read IFSR\n\t"
: [fsr] "=r" (fsr)); : [fsr] "=r" (fsr));
return fsr;
return fsr;
} }
/* Write Instruction Fault Status Register */ /* Write Instruction Fault Status Register */
static inline void write_ifsr(u32_t fsr) static inline void write_ifsr(u32_t fsr)
{ {
asm volatile("mcr p15, 0, %[fsr], c5, c0, 1 @ Write IFSR\n\t" asm volatile("mcr p15, 0, %[fsr], c5, c0, 1 @ Write IFSR\n\t"
: : [fsr] "r" (fsr)); : : [fsr] "r" (fsr));
isb();
} }
/* Read Data Fault Address Register */ /* Read Data Fault Address Register */
static inline u32_t read_dfar() static inline u32_t read_dfar()
{ {
u32_t far; u32_t far;
asm volatile("mrc p15, 0, %[far], c6, c0, 0 @ Read DFAR\n\t" asm volatile("mrc p15, 0, %[far], c6, c0, 0 @ Read DFAR\n\t"
: [far] "=r" (far)); : [far] "=r" (far));
return far;
return far;
} }
/* Write Data Fault Address Register */ /* Write Data Fault Address Register */
static inline void write_dfar(u32_t far) static inline void write_dfar(u32_t far)
{ {
asm volatile("mcr p15, 0, %[far], c6, c0, 0 @ Write DFAR\n\t" asm volatile("mcr p15, 0, %[far], c6, c0, 0 @ Write DFAR\n\t"
: : [far] "r" (far)); : : [far] "r" (far));
isb();
} }
/* Read Instruction Fault Address Register */ /* Read Instruction Fault Address Register */
static inline u32_t read_ifar() static inline u32_t read_ifar()
{ {
u32_t far; u32_t far;
asm volatile("mrc p15, 0, %[far], c6, c0, 2 @ Read IFAR\n\t" asm volatile("mrc p15, 0, %[far], c6, c0, 2 @ Read IFAR\n\t"
: [far] "=r" (far)); : [far] "=r" (far));
return far;
return far;
} }
/* Write Instruction Fault Address Register */ /* Write Instruction Fault Address Register */
static inline void write_ifar(u32_t far) static inline void write_ifar(u32_t far)
{ {
asm volatile("mcr p15, 0, %[far], c6, c0, 2 @ Write IFAR\n\t" asm volatile("mcr p15, 0, %[far], c6, c0, 2 @ Write IFAR\n\t"
: : [far] "r" (far)); : : [far] "r" (far));
isb();
} }
/* Read Vector Base Address Register */ /* Read Vector Base Address Register */
static inline u32_t read_vbar() static inline u32_t read_vbar()
{ {
u32_t vbar; u32_t vbar;
asm volatile("mrc p15, 0, %[vbar], c12, c0, 0 @ Read VBAR\n\t" asm volatile("mrc p15, 0, %[vbar], c12, c0, 0 @ Read VBAR\n\t"
: [vbar] "=r" (vbar)); : [vbar] "=r" (vbar));
return vbar;
return vbar;
} }
/* Write Vector Base Address Register */ /* Write Vector Base Address Register */
static inline void write_vbar(u32_t vbar) static inline void write_vbar(u32_t vbar)
{ {
asm volatile("mcr p15, 0, %[vbar], c12, c0, 0 @ Write VBAR\n\t" asm volatile("mcr p15, 0, %[vbar], c12, c0, 0 @ Write VBAR\n\t"
: : [vbar] "r" (vbar)); : : [vbar] "r" (vbar));
asm volatile("dsb");
isb();
} }
/* Read the Main ID Register */ /* Read the Main ID Register */
static inline u32_t read_midr() static inline u32_t read_midr()
{ {
u32_t id; u32_t id;
asm volatile("mrc p15, 0, %[id], c0, c0, 0 @ read MIDR\n\t" asm volatile("mrc p15, 0, %[id], c0, c0, 0 @ read MIDR\n\t"
: [id] "=r" (id)); : [id] "=r" (id));
return id;
return id;
} }
/* Read Auxiliary Control Register */ /* Read Auxiliary Control Register */
static inline u32_t read_actlr() static inline u32_t read_actlr()
{ {
u32_t ctl; u32_t ctl;
asm volatile("mrc p15, 0, %[ctl], c1, c0, 1 @ Read ACTLR\n\t" asm volatile("mrc p15, 0, %[ctl], c1, c0, 1 @ Read ACTLR\n\t"
: [ctl] "=r" (ctl)); : [ctl] "=r" (ctl));
return ctl;
return ctl;
} }
/* Write Auxiliary Control Register */ /* Write Auxiliary Control Register */
static inline void write_actlr(u32_t ctl) static inline void write_actlr(u32_t ctl)
{ {
asm volatile("mcr p15, 0, %[ctl], c1, c0, 1 @ Write ACTLR\n\t" asm volatile("mcr p15, 0, %[ctl], c1, c0, 1 @ Write ACTLR\n\t"
: : [ctl] "r" (ctl)); : : [ctl] "r" (ctl));
isb();
} }
/* Read Current Program Status Register */ /* Read Current Program Status Register */
static inline u32_t read_cpsr() static inline u32_t read_cpsr()
{ {
u32_t status; u32_t status;
asm volatile("mrs %[status], cpsr @ read CPSR" asm volatile("mrs %[status], cpsr @ read CPSR"
: [status] "=r" (status)); : [status] "=r" (status));
return status;
return status;
} }
/* Write Current Program Status Register */ /* Write Current Program Status Register */
static inline void write_cpsr(u32_t status) static inline void write_cpsr(u32_t status)
{ {
asm volatile("msr cpsr_c, %[status] @ write CPSR" asm volatile("msr cpsr_c, %[status] @ write CPSR"
: : [status] "r" (status)); : : [status] "r" (status));
} }
#endif /* _ARM_CPUFUNC_H */ #endif /* _ARM_CPUFUNC_H */

View File

@ -1,14 +0,0 @@
/* intr_disable(), intr_enable - Disable/Enable hardware interrupts. */
/* void intr_disable(void); */
/* void intr_enable(void); */
#include <machine/asm.h>
ENTRY(intr_disable)
dsb
cpsid i
bx lr
ENTRY(intr_enable)
dsb
cpsie i
bx lr

View File

@ -82,12 +82,14 @@ ENTRY(__user_copy_msg_pointer_failure)
mov r0, #-1 mov r0, #-1
bx lr bx lr
ENTRY(intr_enable)
ENTRY(interrupts_enable) ENTRY(interrupts_enable)
dsb dsb
cpsie i cpsie if
bx lr bx lr
ENTRY(intr_disable)
ENTRY(interrupts_disable) ENTRY(interrupts_disable)
dsb dsb
cpsid i cpsid if
bx lr bx lr

View File

@ -53,6 +53,8 @@ IMPORT(svc_stack)
.macro test_int_in_kernel, label .macro test_int_in_kernel, label
push {r3} push {r3}
ldr r3, [sp, #8] /* spsr */ ldr r3, [sp, #8] /* spsr */
orr r3, r3, #(PSR_F | PSR_I) /* mask interrupts on return */
str r3, [sp, #8] /* spsr */
and r3, r3, #PSR_MODE_MASK and r3, r3, #PSR_MODE_MASK
cmp r3, #MODE_USR cmp r3, #MODE_USR
pop {r3} pop {r3}