From 4f7c28ff72a168e59b76288dfa088107a8863dd4 Mon Sep 17 00:00:00 2001 From: Collin Baker Date: Sun, 21 Oct 2018 18:22:58 -0700 Subject: [PATCH 1/2] Implement ScopedInterruptDisabler --- kernel/src/lib.rs | 1 + kernel/src/x86_util.rs | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 6e9f357..24be328 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -7,6 +7,7 @@ #![feature(core_panic_info)] #![feature(integer_atomics)] #![feature(lang_items)] +#![feature(optin_builtin_traits)] #![cfg_attr(not(test), no_std)] #[cfg(not(test))] diff --git a/kernel/src/x86_util.rs b/kernel/src/x86_util.rs index 7abeffb..4edae54 100644 --- a/kernel/src/x86_util.rs +++ b/kernel/src/x86_util.rs @@ -1,3 +1,5 @@ +use x86_64::registers::rflags; + pub unsafe fn outb(port: u16, value: u8) { asm!("outb %al, %dx" :: "{al}"(value), "{dx}"(port)); } @@ -7,3 +9,32 @@ pub unsafe fn inb(port: u16) -> u8 { asm!("inb %dx, %al" : "={al}"(value) : "{dx}"(port)); value } + +/// Disables interrupts while in scope. When dropped, this resets +/// rflags to their original state. +pub struct ScopedInterruptDisabler { + saved_flags: u64, +} + +impl !Send for ScopedInterruptDisabler {} +impl !Sync for ScopedInterruptDisabler {} + +impl ScopedInterruptDisabler { + pub fn new() -> ScopedInterruptDisabler { + let saved_flags = rflags::read_raw(); + + unsafe { + asm!("cli"); + } + + ScopedInterruptDisabler { + saved_flags: saved_flags, + } + } +} + +impl Drop for ScopedInterruptDisabler { + fn drop(&mut self) { + rflags::write_raw(self.saved_flags); + } +} From c5fc6f26a73f2bfaf336a4868a4588fc5eef00e8 Mon Sep 17 00:00:00 2001 From: Collin Baker Date: Sun, 21 Oct 2018 18:45:27 -0700 Subject: [PATCH 2/2] Replace manual interrupt disable/enable --- kernel/src/interrupts/irq.rs | 23 +++++++------------ kernel/src/rtc.rs | 44 ++++++++++++------------------------ 2 files changed, 23 insertions(+), 44 deletions(-) diff --git a/kernel/src/interrupts/irq.rs b/kernel/src/interrupts/irq.rs index 30e0bf2..b995dc8 100644 --- a/kernel/src/interrupts/irq.rs +++ b/kernel/src/interrupts/irq.rs @@ -1,3 +1,4 @@ +use x86_util::ScopedInterruptDisabler; use super::pic; use x86_64::structures::idt::ExceptionStackFrame; @@ -9,25 +10,17 @@ pub fn init() { } pub fn set_irq_handler(irq: u8, f: Option) { - unsafe { asm!("cli"); } - { - let mut irq_map = IRQ_MAP.lock(); - irq_map[irq as usize] = f; - } - unsafe { asm!("sti"); } + let _disable_interrupts = ScopedInterruptDisabler::new(); + let mut irq_map = IRQ_MAP.lock(); + + irq_map[irq as usize] = f; } fn get_irq_handler(irq: u8) -> Option { - let handler; - - unsafe { asm!("cli"); } - { - let irq_map = IRQ_MAP.lock(); - handler = irq_map[irq as usize]; - } - unsafe { asm!("sti"); } + let _disable_interrupts = ScopedInterruptDisabler::new(); + let irq_map = IRQ_MAP.lock(); - handler + irq_map[irq as usize] } fn handle_irq(irq: u8) { diff --git a/kernel/src/rtc.rs b/kernel/src/rtc.rs index ae5377a..b8da1a0 100644 --- a/kernel/src/rtc.rs +++ b/kernel/src/rtc.rs @@ -1,5 +1,5 @@ use interrupts; -use x86_util::{inb, outb}; +use x86_util::*; /// Rate controls the interrupt frequency. /// You can calculate the frequency with `frequency = 32768 >> (rate-1)`. @@ -41,14 +41,9 @@ pub fn init() { } pub fn get_time() -> RtcTime { - let return_time: RtcTime; - unsafe { - asm!("cli"); - let time = TIME.lock(); - return_time = *time; - asm!("sti"); - } - return_time + let _disable_interrupts = ScopedInterruptDisabler::new(); + let time = TIME.lock(); + *time } /// Handler for the RTC Update Interrupt. @@ -90,24 +85,16 @@ fn rtc_interrupt_handler() { // This is separate from reading the values in order to disable interrupts // for the least amount of time. - unsafe { - asm!("cli"); - } - - { - let mut time = TIME.lock(); - time.seconds = seconds; - time.minutes = minutes; - time.hours = hours; - time.day_of_week = day_of_week; - time.date_of_month = date_of_month; - time.year = year; - time.count += 1; - } - - unsafe { - asm!("sti"); - } + let _disable_interrupts = ScopedInterruptDisabler::new(); + + let mut time = TIME.lock(); + time.seconds = seconds; + time.minutes = minutes; + time.hours = hours; + time.day_of_week = day_of_week; + time.date_of_month = date_of_month; + time.year = year; + time.count += 1; } /// The values retreived from the RTC might be in BCD format. @@ -121,6 +108,7 @@ fn normalize(value: u8, binary_coded_decimal: bool) -> u8 { } unsafe fn enable_irq8() { + let _disable_interrupts = ScopedInterruptDisabler::new(); nmi_disable(); // Turn on periodic interrupts to IRQ8. @@ -139,11 +127,9 @@ unsafe fn enable_irq8() { } unsafe fn nmi_enable() { - asm!("sti"); outb(0x70, inb(0x70) & 0x7F); } unsafe fn nmi_disable() { - asm!("cli"); outb(0x70, inb(0x70) | 0x80); }