diff options
Diffstat (limited to 'sys/arch')
| -rw-r--r-- | sys/arch/amd64/cpu/cpu.c | 10 | ||||
| -rw-r--r-- | sys/arch/amd64/cpu/spinlock.c | 16 |
2 files changed, 20 insertions, 6 deletions
diff --git a/sys/arch/amd64/cpu/cpu.c b/sys/arch/amd64/cpu/cpu.c index 4edc850..d9093fd 100644 --- a/sys/arch/amd64/cpu/cpu.c +++ b/sys/arch/amd64/cpu/cpu.c @@ -29,11 +29,21 @@ #include <sys/types.h> #include <sys/cdefs.h> +#include <sys/param.h> #include <os/trace.h> #include <mu/cpu.h> #include <md/msr.h> #include <md/lapic.h> +bool +mu_irq_state(void) +{ + uint64_t rflags; + + __asmv("pushfq; pop %0" : "=r" (rflags) :: "memory"); + return ISSET(rflags, BIT(9)) != 0; +} + struct cpu_info * cpu_self(void) { diff --git a/sys/arch/amd64/cpu/spinlock.c b/sys/arch/amd64/cpu/spinlock.c index 1cfa088..6857aa6 100644 --- a/sys/arch/amd64/cpu/spinlock.c +++ b/sys/arch/amd64/cpu/spinlock.c @@ -29,12 +29,15 @@ #include <sys/cdefs.h> #include <mu/spinlock.h> +#include <mu/irq.h> void mu_spinlock_acq(volatile size_t *lock, int flags) { - if (ISSET(flags, SPINLOCK_INTTOG)) { - asm volatile("cli"); + bool irq_en = mu_irq_state(); + + if (ISSET(flags, SPINLOCK_INTTOG) && irq_en) { + __asmv("cli"); } __asmv( @@ -48,6 +51,11 @@ mu_spinlock_acq(volatile size_t *lock, int flags) : "r" (lock) : "memory", "rax" ); + + if (ISSET(flags, SPINLOCK_INTTOG)) { + if (irq_en && !mu_irq_state()) + __asmv("sti"); + } } void @@ -60,8 +68,4 @@ mu_spinlock_rel(volatile size_t *lock, int flags) : : "memory", "rax" ); - - if (ISSET(flags, SPINLOCK_INTTOG)) { - asm volatile("sti"); - } } |
