From c2644adf3d37b68911df5087f641150d583c65fa Mon Sep 17 00:00:00 2001 From: Jeremy Soller <jackpot51@gmail.com> Date: Tue, 5 Dec 2017 21:26:45 -0700 Subject: [PATCH] Improve multi_core support --- src/acpi/madt.rs | 2 +- src/arch/x86_64/idt.rs | 1 + src/arch/x86_64/interrupt/ipi.rs | 12 ++++++++++++ src/arch/x86_64/interrupt/irq.rs | 19 ++++++++++++------- src/context/context.rs | 12 +++++++----- src/context/switch.rs | 20 +++++++------------- src/lib.rs | 2 +- 7 files changed, 41 insertions(+), 27 deletions(-) diff --git a/src/acpi/madt.rs b/src/acpi/madt.rs index 28f7671..e95c519 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 ef50732..f9b9859 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 325d9d8..2f7177c 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 6cc5a15..b463fd3 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 b6b8d0e..6449869 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 0702474..859d573 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 c6f40ee..3bf770d 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(); -- GitLab