diff --git a/src/acpi/madt.rs b/src/acpi/madt.rs index 28f76715b9da9eb291bf4da1985e158fd000e662..e95c5193f3851feb9a79eba41681652554abb7ba 100644 --- a/src/acpi/madt.rs +++ b/src/acpi/madt.rs @@ -45,7 +45,7 @@ impl Madt { println!(" XAPIC {}: {:>08X}", me, local_apic.address); } - if cfg!(feature = "multi_core"){ + if cfg!(feature = "multi_core") { let trampoline_frame = Frame::containing_address(PhysicalAddress::new(TRAMPOLINE)); let trampoline_page = Page::containing_address(VirtualAddress::new(TRAMPOLINE)); diff --git a/src/arch/x86_64/idt.rs b/src/arch/x86_64/idt.rs index ef50732995836c09f20bc4521427708fc2e5ea76..f9b9859539f77bc550cb8047a934b4466606c507 100644 --- a/src/arch/x86_64/idt.rs +++ b/src/arch/x86_64/idt.rs @@ -60,6 +60,7 @@ pub unsafe fn init() { // Set IPI handler (null) IDT[0x40].set_func(ipi::ipi); + IDT[0x41].set_func(ipi::pit); // Set syscall function IDT[0x80].set_func(syscall::syscall); diff --git a/src/arch/x86_64/interrupt/ipi.rs b/src/arch/x86_64/interrupt/ipi.rs index 325d9d8c00bdb29562dc6589b461075529e32609..2f7177c651c21db8d0464d2f656dfb29c48fef74 100644 --- a/src/arch/x86_64/interrupt/ipi.rs +++ b/src/arch/x86_64/interrupt/ipi.rs @@ -1,5 +1,17 @@ +use core::sync::atomic::Ordering; + +use context; use device::local_apic::LOCAL_APIC; +use super::irq::PIT_TICKS; interrupt!(ipi, { LOCAL_APIC.eoi(); }); + +interrupt!(pit, { + LOCAL_APIC.eoi(); + + if PIT_TICKS.fetch_add(1, Ordering::SeqCst) >= 10 { + let _ = context::switch(); + } +}); diff --git a/src/arch/x86_64/interrupt/irq.rs b/src/arch/x86_64/interrupt/irq.rs index 6cc5a1536bd177e46c25e6ba4dff120dcd0435d8..b463fd35c2c4b8ddd208130119137fe90ab003b1 100644 --- a/src/arch/x86_64/interrupt/irq.rs +++ b/src/arch/x86_64/interrupt/irq.rs @@ -1,10 +1,10 @@ -use context::timeout; -use device::pic; -use device::serial::{COM1, COM2}; use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; -use time; use context; +use context::timeout; +use device::{local_apic, pic}; +use device::serial::{COM1, COM2}; +use time; //resets to 0 in context::switch() pub static PIT_TICKS: AtomicUsize = ATOMIC_USIZE_INIT; @@ -39,6 +39,11 @@ pub unsafe fn acknowledge(irq: usize) { } interrupt!(pit, { + // Wake up other CPUs + if cfg!(feature = "multi_core") { + local_apic::LOCAL_APIC.set_icr(3 << 18 | 1 << 14 | 0x41); + } + // Saves CPU time by not sending IRQ event irq_trigger(0); const PIT_RATE: u64 = 2250286; @@ -52,12 +57,12 @@ interrupt!(pit, { pic::MASTER.ack(); + // Any better way of doing this? + timeout::trigger(); + if PIT_TICKS.fetch_add(1, Ordering::SeqCst) >= 10 { let _ = context::switch(); } - - // Any better way of doing this? - timeout::trigger(); }); interrupt!(keyboard, { diff --git a/src/context/context.rs b/src/context/context.rs index b6b8d0e48a7b73615f7af406682d75bd0ed57eb6..6449869732e389b20afe362defe75bac2982c934 100644 --- a/src/context/context.rs +++ b/src/context/context.rs @@ -231,11 +231,13 @@ impl Context { pub fn unblock(&mut self) -> bool { if self.status == Status::Blocked { self.status = Status::Runnable; - if let Some(cpu_id) = self.cpu_id { - if cpu_id != ::cpu_id() { - // Send IPI if not on current CPU - // TODO: Make this more architecture independent - unsafe { device::local_apic::LOCAL_APIC.ipi(cpu_id) }; + if cfg!(feature = "multi_core") { + if let Some(cpu_id) = self.cpu_id { + if cpu_id != ::cpu_id() { + // Send IPI if not on current CPU + // TODO: Make this more architecture independent + unsafe { device::local_apic::LOCAL_APIC.set_icr(3 << 18 | 1 << 14 | 0x40) }; + } } } true diff --git a/src/context/switch.rs b/src/context/switch.rs index 07024748bdb9bdc980c885579d3506793e05088e..859d5736e68eb0f6685a04bf8e62cddf8abb766a 100644 --- a/src/context/switch.rs +++ b/src/context/switch.rs @@ -42,14 +42,14 @@ pub unsafe fn switch() -> bool { } let check_context = |context: &mut Context| -> bool { + // Take ownership if not already owned if context.cpu_id == None { context.cpu_id = Some(cpu_id); // println!("{}: take {} {}", cpu_id, context.id, ::core::str::from_utf8_unchecked(&context.name.lock())); } + // Restore from signal if context.ksig_restore { - println!("Restore from ksig"); - let ksig = context.ksig.take().expect("context::switch: ksig not set with ksig_restore"); context.arch = ksig.0; if let Some(ref mut kfx) = context.kfx { @@ -64,16 +64,15 @@ pub unsafe fn switch() -> bool { } context.ksig_restore = false; - //TODO: Interrupt - if context.status == Status::Blocked { - context.unblock(); - } + context.unblock(); } + // Unblock when there are pending signals if context.status == Status::Blocked && !context.pending.is_empty() { context.unblock(); } + // Wake from sleep if context.status == Status::Blocked && context.wake.is_some() { let wake = context.wake.expect("context::switch: wake not set"); @@ -84,13 +83,8 @@ pub unsafe fn switch() -> bool { } } - if context.cpu_id == Some(cpu_id) { - if context.status == Status::Runnable && !context.running { - return true; - } - } - - false + // Switch to context if it needs to run, is not currently running, and is owned by the current CPU + !context.running && context.status == Status::Runnable && context.cpu_id == Some(cpu_id) }; for (pid, context_lock) in contexts.iter() { diff --git a/src/lib.rs b/src/lib.rs index c6f40ee737c0d0d30fc11cf1af9fdbc86a15182e..3bf770de4d8223434c03376b3b7ea2d354204b1e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -184,7 +184,7 @@ pub fn kmain(cpus: usize, env: &[u8]) -> ! { pub fn kmain_ap(id: usize) -> ! { CPU_ID.store(id, Ordering::SeqCst); - if cfg!(feature = "multi_core"){ + if cfg!(feature = "multi_core") { context::init(); let pid = syscall::getpid();