From fac0e783ef5202ea89906e51ccf1cf1311fe0eab Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 8 Oct 2023 15:18:23 +0200 Subject: [PATCH] Refactor profiling code. --- src/arch/x86_64/gdt.rs | 13 +- src/arch/x86_64/idt.rs | 19 +-- src/arch/x86_64/interrupt/exception.rs | 45 +----- src/arch/x86_64/ipi.rs | 7 +- src/arch/x86_64/start.rs | 10 +- src/main.rs | 32 +--- src/percpu.rs | 74 +-------- src/profiling.rs | 216 +++++++++++++++++++++++++ src/scheme/debug.rs | 40 ++--- src/scheme/serio.rs | 16 +- 10 files changed, 262 insertions(+), 210 deletions(-) create mode 100644 src/profiling.rs diff --git a/src/arch/x86_64/gdt.rs b/src/arch/x86_64/gdt.rs index 04c8615a50..86fa4f1beb 100644 --- a/src/arch/x86_64/gdt.rs +++ b/src/arch/x86_64/gdt.rs @@ -5,7 +5,7 @@ use core::mem; use crate::LogicalCpuId; use crate::paging::{RmmA, RmmArch}; -use crate::percpu::{PercpuBlock, RingBuffer}; +use crate::percpu::PercpuBlock; use x86::bits64::task::TaskStateSegment; use x86::Ring; @@ -204,17 +204,6 @@ pub unsafe fn init_paging(stack_offset: usize, cpu_id: LogicalCpuId) { profiling: None, }; } -pub unsafe fn init_allocator() { - let percpu = PercpuBlock::current(); - - if percpu.cpu_id.get() == 4 { return } - - let profiling = RingBuffer::create(); - - crate::scheme::debug::BUFS[percpu.cpu_id.get() as usize].store(profiling as *const _ as *mut _, core::sync::atomic::Ordering::SeqCst); - (core::ptr::addr_of!(percpu.profiling) as *mut Option<&'static RingBuffer>).write(Some(profiling)); -} - #[derive(Copy, Clone, Debug)] #[repr(packed)] pub struct GdtEntry { diff --git a/src/arch/x86_64/idt.rs b/src/arch/x86_64/idt.rs index ac4c1a54e7..35c1410fdb 100644 --- a/src/arch/x86_64/idt.rs +++ b/src/arch/x86_64/idt.rs @@ -8,6 +8,7 @@ use hashbrown::HashMap; use x86::segmentation::Descriptor as X86IdtEntry; use x86::dtables::{self, DescriptorTablePointer}; +use crate::profiling::maybe_setup_timer; use crate::{interrupt::*, LogicalCpuId}; use crate::interrupt::irq::{__generic_interrupts_end, __generic_interrupts_start}; use crate::ipi::IpiKind; @@ -111,26 +112,26 @@ const fn new_idt_reservations() -> [AtomicU64; 4] { } /// Initialize the IDT for a -pub unsafe fn init_paging_post_heap(is_bsp: bool, cpu_id: LogicalCpuId) { +pub unsafe fn init_paging_post_heap(cpu_id: LogicalCpuId) { let mut idts_guard = IDTS.write(); let idts_btree = idts_guard.get_or_insert_with(HashMap::new); - if is_bsp { + if cpu_id == LogicalCpuId::BSP { idts_btree.insert(cpu_id, &mut INIT_BSP_IDT); } else { let idt = idts_btree.entry(cpu_id).or_insert_with(|| Box::leak(Box::new(Idt::new()))); - init_generic(is_bsp, idt); + init_generic(cpu_id, idt); } } /// Initializes a fully functional IDT for use before it be moved into the map. This is ONLY called /// on the BSP, since the kernel heap is ready for the APs. pub unsafe fn init_paging_bsp() { - init_generic(true, &mut INIT_BSP_IDT); + init_generic(LogicalCpuId::BSP, &mut INIT_BSP_IDT); } /// Initializes an IDT for any type of processor. -pub unsafe fn init_generic(is_bsp: bool, idt: &mut Idt) { +pub unsafe fn init_generic(cpu_id: LogicalCpuId, idt: &mut Idt) { let (current_idt, current_reservations) = (&mut idt.entries, &mut idt.reservations); let idtr: DescriptorTablePointer = DescriptorTablePointer { @@ -208,7 +209,7 @@ pub unsafe fn init_generic(is_bsp: bool, idt: &mut Idt) { // reserve bits 31:0, i.e. the first 32 interrupts, which are reserved for exceptions *current_reservations[0].get_mut() |= 0x0000_0000_FFFF_FFFF; - if is_bsp { + if cpu_id == LogicalCpuId::BSP { // Set up IRQs current_idt[32].set_func(irq::pit_stack); current_idt[33].set_func(irq::keyboard); @@ -232,14 +233,12 @@ pub unsafe fn init_generic(is_bsp: bool, idt: &mut Idt) { // reserve bits 49:32, which are for the standard IRQs, and for the local apic timer and error. *current_reservations[0].get_mut() |= 0x0003_FFFF_0000_0000; } else { - current_idt[32].set_func(irq::aux_timer); // TODO: use_default_irqs! but also the legacy IRQs that are only needed on one CPU current_idt[49].set_func(irq::lapic_error); // reserve bit 49 - *current_reservations[0].get_mut() |= 1 << 32 | 1 << 49; + *current_reservations[0].get_mut() |= 1 << 49; } - // Set IPI handlers current_idt[IpiKind::Wakeup as usize].set_func(ipi::wakeup); current_idt[IpiKind::Switch as usize].set_func(ipi::switch); @@ -256,6 +255,8 @@ pub unsafe fn init_generic(is_bsp: bool, idt: &mut Idt) { current_idt[0x80].set_flags(IdtFlags::PRESENT | IdtFlags::RING_3 | IdtFlags::INTERRUPT); idt.set_reserved_mut(0x80, true); + maybe_setup_timer(idt, cpu_id); + dtables::lidt(&idtr); } diff --git a/src/arch/x86_64/interrupt/exception.rs b/src/arch/x86_64/interrupt/exception.rs index 997232189c..3094309f37 100644 --- a/src/arch/x86_64/interrupt/exception.rs +++ b/src/arch/x86_64/interrupt/exception.rs @@ -1,9 +1,7 @@ -use core::sync::atomic::Ordering; - use x86::irq::PageFaultError; use crate::memory::GenericPfFlags; -use crate::scheme::serio::IS_PROFILING; +use crate::ptrace; use crate::{ interrupt::stack_trace, paging::VirtualAddress, @@ -48,46 +46,7 @@ interrupt_stack!(debug, @paranoid, |stack| { }); interrupt_stack!(non_maskable, @paranoid, |stack| { - let Some(profiling) = crate::percpu::PercpuBlock::current().profiling else { - return; - }; - if !IS_PROFILING.load(Ordering::Relaxed) { - return; - } - if stack.iret.cs & 0b00 == 0b11 { - profiling.nmi_ucount.store(profiling.nmi_ucount.load(Ordering::Relaxed) + 1, Ordering::Relaxed); - return; - } else if stack.iret.rflags & (1 << 9) != 0 { - // Interrupts were enabled, i.e. we were in kmain, so ignore. - return; - } else { - profiling.nmi_kcount.store(profiling.nmi_kcount.load(Ordering::Relaxed) + 1, Ordering::Relaxed); - }; - - let mut buf = [0_usize; 32]; - buf[0] = stack.iret.rip & !(1<<63); - buf[1] = x86::time::rdtsc() as usize; - - let mut bp = stack.preserved.rbp; - - let mut len = 2; - - for i in 2..32 { - if bp.saturating_add(16) < crate::KERNEL_HEAP_OFFSET || bp >= crate::KERNEL_HEAP_OFFSET + crate::PML4_SIZE { - break; - } - let ip = ((bp + 8) as *const usize).read(); - bp = (bp as *const usize).read(); - - if ip < crate::kernel_executable_offsets::__text_start() || ip >= crate::kernel_executable_offsets::__text_end() { - break; - } - buf[i] = ip; - - len = i + 1; - } - - let _ = profiling.extend(&buf[..len]); + crate::profiling::nmi_handler(stack); }); interrupt_stack!(breakpoint, |stack| { diff --git a/src/arch/x86_64/ipi.rs b/src/arch/x86_64/ipi.rs index 4f3919b0f3..00c2a0ec0f 100644 --- a/src/arch/x86_64/ipi.rs +++ b/src/arch/x86_64/ipi.rs @@ -28,8 +28,9 @@ pub fn ipi(kind: IpiKind, target: IpiTarget) { if matches!(kind, IpiKind::Profile) { let icr = (target as u64) << 18 | 1 << 14 | 0b100 << 8; unsafe { LOCAL_APIC.set_icr(icr) }; - } else { - let icr = (target as u64) << 18 | 1 << 14 | (kind as u64); - unsafe { LOCAL_APIC.set_icr(icr) }; + return; } + + let icr = (target as u64) << 18 | 1 << 14 | (kind as u64); + unsafe { LOCAL_APIC.set_icr(icr) }; } diff --git a/src/arch/x86_64/start.rs b/src/arch/x86_64/start.rs index 77ff2cdc85..a3bd054387 100644 --- a/src/arch/x86_64/start.rs +++ b/src/arch/x86_64/start.rs @@ -6,7 +6,7 @@ use core::slice; use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering, AtomicU32}; -use crate::{allocator, memory, LogicalCpuId}; +use crate::{allocator, memory, LogicalCpuId, profiling}; #[cfg(feature = "acpi")] use crate::acpi; use crate::arch::pti; @@ -150,13 +150,13 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! { // Setup kernel heap allocator::init(); - gdt::init_allocator(); + profiling::init(); // Set up double buffer for grpahical debug now that heap is available #[cfg(feature = "graphical_debug")] graphical_debug::init_heap(); - idt::init_paging_post_heap(true, LogicalCpuId::BSP); + idt::init_paging_post_heap(LogicalCpuId::BSP); // Activate memory logging log::init(); @@ -236,10 +236,10 @@ pub unsafe extern fn kstart_ap(args_ptr: *const KernelArgsAp) -> ! { // Set up GDT with TLS gdt::init_paging(stack_end, cpu_id); - gdt::init_allocator(); + profiling::init(); // Set up IDT for AP - idt::init_paging_post_heap(false, cpu_id); + idt::init_paging_post_heap(cpu_id); crate::alternative::early_init(false); diff --git a/src/main.rs b/src/main.rs index 5da87d4da5..37e09cf8f9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -60,7 +60,6 @@ extern crate alloc; #[macro_use] extern crate bitflags; -use core::sync::atomic::AtomicUsize; use core::sync::atomic::{AtomicU32, Ordering}; use crate::scheme::SchemeNamespace; @@ -122,6 +121,9 @@ mod percpu; /// Process tracing mod ptrace; +/// Performance profiling of the kernel +pub mod profiling; + /// Schemes, filesystem handlers mod scheme; @@ -188,7 +190,7 @@ fn kmain(cpu_count: u32, bootstrap: Bootstrap) -> ! { info!("Env: {:?}", ::core::str::from_utf8(bootstrap.env)); BOOTSTRAP.call_once(|| bootstrap); - crate::ACK.fetch_add(1, Ordering::SeqCst); + profiling::ready_for_profiling(); match context::contexts_mut().spawn(userspace_init) { Ok(context_lock) => { @@ -216,32 +218,10 @@ fn kmain(cpu_count: u32, bootstrap: Bootstrap) -> ! { } } -pub static ACK: AtomicUsize = AtomicUsize::new(0); - /// This is the main kernel entry point for secondary CPUs #[allow(unreachable_code, unused_variables)] fn kmain_ap(cpu_id: LogicalCpuId) -> ! { - if cpu_id.get() == 4 { - unsafe { - for i in 33..255 { - crate::idt::IDTS.write().as_mut().unwrap().get_mut(&cpu_id).unwrap().entries[i].set_func(crate::interrupt::ipi::wakeup); - } - - let apic = &mut crate::device::local_apic::LOCAL_APIC; - apic.set_lvt_timer((0b01 << 17) | 32); - apic.set_div_conf(0b1011); - apic.set_init_count(0xffff_f); - - while ACK.load(Ordering::Relaxed) < 4 { - core::hint::spin_loop(); - } - - interrupt::enable_and_nop(); - loop { - interrupt::halt(); - } - } - } + profiling::maybe_run_profiling_helper_forever(cpu_id); if cfg!(feature = "multi_core") { context::init(); @@ -249,7 +229,7 @@ fn kmain_ap(cpu_id: LogicalCpuId) -> ! { let pid = syscall::getpid(); info!("AP {}: {:?}", cpu_id, pid); - crate::ACK.fetch_add(1, Ordering::SeqCst); + profiling::ready_for_profiling(); loop { unsafe { diff --git a/src/percpu.rs b/src/percpu.rs index 899296118d..c7bd84b7c2 100644 --- a/src/percpu.rs +++ b/src/percpu.rs @@ -1,10 +1,6 @@ -use core::cell::UnsafeCell; -use core::sync::atomic::{AtomicUsize, Ordering}; - -use alloc::boxed::Box; - use crate::LogicalCpuId; use crate::context::switch::ContextSwitchPercpu; +use crate::profiling::RingBuffer; /// The percpu block, that stored all percpu variables. pub struct PercpuBlock { @@ -20,72 +16,4 @@ pub struct PercpuBlock { pub profiling: Option<&'static RingBuffer>, } -const N: usize = 64 * 1024 * 1024; - -pub struct RingBuffer { - head: AtomicUsize, - tail: AtomicUsize, - buf: &'static [UnsafeCell; N], - pub(crate) nmi_kcount: AtomicUsize, - pub(crate) nmi_ucount: AtomicUsize, -} - -impl RingBuffer { - unsafe fn advance_head(&self, n: usize) { - self.head.store(self.head.load(Ordering::Acquire).wrapping_add(n), Ordering::Release); - } - unsafe fn advance_tail(&self, n: usize) { - self.tail.store(self.tail.load(Ordering::Acquire).wrapping_add(n), Ordering::Release); - } - unsafe fn sender_owned(&self) -> [&[UnsafeCell]; 2] { - let head = self.head.load(Ordering::Acquire) % N; - let tail = self.tail.load(Ordering::Acquire) % N; - - if head <= tail { - [&self.buf[tail..], &self.buf[..head]] - } else { - [&self.buf[tail..head], &[]] - } - } - unsafe fn receiver_owned(&self) -> [&[UnsafeCell]; 2] { - let head = self.head.load(Ordering::Acquire) % N; - let tail = self.tail.load(Ordering::Acquire) % N; - - if head > tail { - [&self.buf[head..], &self.buf[..tail]] - } else { - [&self.buf[head..tail], &[]] - } - } - pub unsafe fn extend(&self, mut slice: &[usize]) -> usize { - let mut n = 0; - for mut sender_slice in self.sender_owned() { - while !slice.is_empty() && !sender_slice.is_empty() { - sender_slice[0].get().write(slice[0]); - slice = &slice[1..]; - sender_slice = &sender_slice[1..]; - n += 1; - } - } - self.advance_tail(n); - n - } - pub unsafe fn peek(&self) -> [&[usize]; 2] { - self.receiver_owned().map(|slice| core::slice::from_raw_parts(slice.as_ptr().cast(), slice.len())) - } - pub unsafe fn advance(&self, n: usize) { - self.advance_head(n) - } - pub fn create() -> &'static Self { - - Box::leak(Box::new(Self { - head: AtomicUsize::new(0), - tail: AtomicUsize::new(0), - buf: Box::leak(unsafe { Box::new_zeroed().assume_init() }), - nmi_kcount: AtomicUsize::new(0), - nmi_ucount: AtomicUsize::new(0), - })) - } -} - // PercpuBlock::current() is implemented somewhere in the arch-specific modules diff --git a/src/profiling.rs b/src/profiling.rs new file mode 100644 index 0000000000..5ae8621c1f --- /dev/null +++ b/src/profiling.rs @@ -0,0 +1,216 @@ +use core::cell::UnsafeCell; +use core::mem::size_of; +use core::sync::atomic::{AtomicUsize, Ordering, AtomicPtr, AtomicBool, AtomicU32}; + +use alloc::boxed::Box; + +use crate::idt::Idt; +use crate::interrupt::irq::aux_timer; +use crate::{LogicalCpuId, interrupt}; +use crate::interrupt::InterruptStack; +use crate::percpu::PercpuBlock; +use crate::syscall::error::*; +use crate::syscall::usercopy::UserSliceWo; + +const N: usize = 64 * 1024 * 1024; + +pub const HARDCODED_CPU_COUNT: u32 = 4; + +pub const PROFILER_CPU: LogicalCpuId = LogicalCpuId::new(HARDCODED_CPU_COUNT); + +pub struct RingBuffer { + head: AtomicUsize, + tail: AtomicUsize, + buf: &'static [UnsafeCell; N], + pub(crate) nmi_kcount: AtomicUsize, + pub(crate) nmi_ucount: AtomicUsize, +} + +impl RingBuffer { + unsafe fn advance_head(&self, n: usize) { + self.head.store(self.head.load(Ordering::Acquire).wrapping_add(n), Ordering::Release); + } + unsafe fn advance_tail(&self, n: usize) { + self.tail.store(self.tail.load(Ordering::Acquire).wrapping_add(n), Ordering::Release); + } + unsafe fn sender_owned(&self) -> [&[UnsafeCell]; 2] { + let head = self.head.load(Ordering::Acquire) % N; + let tail = self.tail.load(Ordering::Acquire) % N; + + if head <= tail { + [&self.buf[tail..], &self.buf[..head]] + } else { + [&self.buf[tail..head], &[]] + } + } + unsafe fn receiver_owned(&self) -> [&[UnsafeCell]; 2] { + let head = self.head.load(Ordering::Acquire) % N; + let tail = self.tail.load(Ordering::Acquire) % N; + + if head > tail { + [&self.buf[head..], &self.buf[..tail]] + } else { + [&self.buf[head..tail], &[]] + } + } + pub unsafe fn extend(&self, mut slice: &[usize]) -> usize { + let mut n = 0; + for mut sender_slice in self.sender_owned() { + while !slice.is_empty() && !sender_slice.is_empty() { + sender_slice[0].get().write(slice[0]); + slice = &slice[1..]; + sender_slice = &sender_slice[1..]; + n += 1; + } + } + self.advance_tail(n); + n + } + pub unsafe fn peek(&self) -> [&[usize]; 2] { + self.receiver_owned().map(|slice| core::slice::from_raw_parts(slice.as_ptr().cast(), slice.len())) + } + pub unsafe fn advance(&self, n: usize) { + self.advance_head(n) + } + pub fn create() -> &'static Self { + + Box::leak(Box::new(Self { + head: AtomicUsize::new(0), + tail: AtomicUsize::new(0), + buf: Box::leak(unsafe { Box::new_zeroed().assume_init() }), + nmi_kcount: AtomicUsize::new(0), + nmi_ucount: AtomicUsize::new(0), + })) + } +} +const NULL: AtomicPtr = AtomicPtr::new(core::ptr::null_mut()); +pub static BUFS: [AtomicPtr; 4] = [NULL; 4]; + +pub const PROFILE_TOGGLEABLE: bool = true; +pub static IS_PROFILING: AtomicBool = AtomicBool::new(false); + +pub fn serio_command(index: usize, data: u8) { + if PROFILE_TOGGLEABLE { + if index == 0 && data == 30 { + log::info!("Enabling profiling"); + IS_PROFILING.store(true, Ordering::SeqCst); + } else if index == 0 && data == 48 { + log::info!("Disabling profiling"); + IS_PROFILING.store(false, Ordering::SeqCst); + } + } +} + +pub fn drain_buffer(cpu_num: LogicalCpuId, buf: UserSliceWo) -> Result { + unsafe { + let Some(src) = BUFS.get(cpu_num.get() as usize).ok_or(Error::new(EBADFD))?.load(Ordering::Relaxed).as_ref() else { + return Ok(0); + }; + let byte_slices = src.peek().map(|words| core::slice::from_raw_parts(words.as_ptr().cast::(), words.len() * size_of::())); + + let copied_1 = buf.copy_common_bytes_from_slice(byte_slices[0])?; + src.advance(copied_1 / size_of::()); + + let copied_2 = if let Some(remaining) = buf.advance(copied_1) { + remaining.copy_common_bytes_from_slice(byte_slices[1])? + } else { + 0 + }; + src.advance(copied_2 / size_of::()); + + Ok(copied_1 + copied_2) + } +} + +pub unsafe fn nmi_handler(stack: &InterruptStack) { + let Some(profiling) = crate::percpu::PercpuBlock::current().profiling else { + return; + }; + if !IS_PROFILING.load(Ordering::Relaxed) { + return; + } + if stack.iret.cs & 0b00 == 0b11 { + profiling.nmi_ucount.store(profiling.nmi_ucount.load(Ordering::Relaxed) + 1, Ordering::Relaxed); + return; + } else if stack.iret.rflags & (1 << 9) != 0 { + // Interrupts were enabled, i.e. we were in kmain, so ignore. + return; + } else { + profiling.nmi_kcount.store(profiling.nmi_kcount.load(Ordering::Relaxed) + 1, Ordering::Relaxed); + }; + + let mut buf = [0_usize; 32]; + buf[0] = stack.iret.rip & !(1<<63); + buf[1] = x86::time::rdtsc() as usize; + + let mut bp = stack.preserved.rbp; + + let mut len = 2; + + for i in 2..32 { + if bp.saturating_add(16) < crate::KERNEL_HEAP_OFFSET || bp >= crate::KERNEL_HEAP_OFFSET + crate::PML4_SIZE { + break; + } + let ip = ((bp + 8) as *const usize).read(); + bp = (bp as *const usize).read(); + + if ip < crate::kernel_executable_offsets::__text_start() || ip >= crate::kernel_executable_offsets::__text_end() { + break; + } + buf[i] = ip; + + len = i + 1; + } + + let _ = profiling.extend(&buf[..len]); +} +pub unsafe fn init() { + let percpu = PercpuBlock::current(); + + if percpu.cpu_id == PROFILER_CPU { return } + + let profiling = RingBuffer::create(); + + BUFS[percpu.cpu_id.get() as usize].store(profiling as *const _ as *mut _, core::sync::atomic::Ordering::SeqCst); + (core::ptr::addr_of!(percpu.profiling) as *mut Option<&'static RingBuffer>).write(Some(profiling)); +} + +static ACK: AtomicU32 = AtomicU32::new(0); + +pub fn ready_for_profiling() { + ACK.fetch_add(1, Ordering::Relaxed); +} + +pub fn maybe_run_profiling_helper_forever(cpu_id: LogicalCpuId) { + if cpu_id != PROFILER_CPU { + return; + } + unsafe { + for i in 33..255 { + crate::idt::IDTS.write().as_mut().unwrap().get_mut(&cpu_id).unwrap().entries[i].set_func(crate::interrupt::ipi::wakeup); + } + + let apic = &mut crate::device::local_apic::LOCAL_APIC; + apic.set_lvt_timer((0b01 << 17) | 32); + apic.set_div_conf(0b1011); + apic.set_init_count(0xffff_f); + + while ACK.load(Ordering::Relaxed) < HARDCODED_CPU_COUNT { + core::hint::spin_loop(); + } + assert_eq!(crate::cpu_count(), HARDCODED_CPU_COUNT + 1); + + interrupt::enable_and_nop(); + loop { + interrupt::halt(); + } + } +} + +pub fn maybe_setup_timer(idt: &mut Idt, cpu_id: LogicalCpuId) { + if cpu_id != PROFILER_CPU { + return; + } + idt.entries[32].set_func(aux_timer); + idt.set_reserved(32, true); +} diff --git a/src/scheme/debug.rs b/src/scheme/debug.rs index acec527664..e2cbbd6c31 100644 --- a/src/scheme/debug.rs +++ b/src/scheme/debug.rs @@ -1,9 +1,9 @@ -use core::sync::atomic::{AtomicUsize, Ordering, AtomicPtr}; +use core::sync::atomic::{AtomicUsize, Ordering}; use spin::RwLock; +use crate::LogicalCpuId; use crate::arch::debug::Writer; use crate::event; -use crate::percpu::RingBuffer; use crate::scheme::*; use crate::sync::WaitQueue; use crate::syscall::flag::{EventFlags, EVENT_READ, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK}; @@ -45,7 +45,9 @@ impl KernelScheme for DebugScheme { let num = match path { "" => !0, - "profiling" => flags & 0xffff, + p if p.starts_with("profiling-") => { + path[10..].parse().map_err(|_| Error::new(ENOENT))? + } _ => return Err(Error::new(ENOENT)), }; @@ -112,32 +114,18 @@ impl KernelScheme for DebugScheme { INPUT .receive_into_user(buf, handle.flags & O_NONBLOCK != O_NONBLOCK, "DebugScheme::read") } else { - unsafe { - let Some(src) = BUFS.get(handle.num).ok_or(Error::new(EBADFD))?.load(Ordering::Relaxed).as_ref() else { - return Ok(0); - }; - let byte_slices = src.peek().map(|words| core::slice::from_raw_parts(words.as_ptr().cast::(), words.len() * 8)); - - let copied_1 = buf.copy_common_bytes_from_slice(byte_slices[0])?; - src.advance(copied_1 / 8); - - let copied_2 = if let Some(remaining) = buf.advance(copied_1) { - remaining.copy_common_bytes_from_slice(byte_slices[1])? - } else { - 0 - }; - src.advance(copied_2 / 8); - - Ok(copied_1 + copied_2) - } + crate::profiling::drain_buffer(LogicalCpuId::new(handle.num as u32), buf) } } fn kwrite(&self, id: usize, buf: UserSliceRo) -> Result { - let _handle = { + let handle = { let handles = HANDLES.read(); *handles.get(&id).ok_or(Error::new(EBADF))? }; + if handle.num != !0 { + return Err(Error::new(EBADF)); + } let mut tmp = [0_u8; 512]; @@ -154,10 +142,13 @@ impl KernelScheme for DebugScheme { Ok(buf.len()) } fn kfpath(&self, id: usize, buf: UserSliceWo) -> Result { - let _handle = { + let handle = { let handles = HANDLES.read(); *handles.get(&id).ok_or(Error::new(EBADF))? }; + if handle.num != !0 { + return Err(Error::new(EBADF)); + } // TODO: Copy elsewhere in the kernel? const SRC: &[u8] = b"debug:"; @@ -167,6 +158,3 @@ impl KernelScheme for DebugScheme { Ok(byte_count) } } - -const NULL: AtomicPtr = AtomicPtr::new(core::ptr::null_mut()); -pub static BUFS: [AtomicPtr; 4] = [NULL; 4]; diff --git a/src/scheme/serio.rs b/src/scheme/serio.rs index b46595d7f2..679c53a6f1 100644 --- a/src/scheme/serio.rs +++ b/src/scheme/serio.rs @@ -1,7 +1,7 @@ //! PS/2 unfortunately requires a kernel driver to prevent race conditions due //! to how status is utilized use core::str; -use core::sync::atomic::{AtomicUsize, Ordering, AtomicBool}; +use core::sync::atomic::{AtomicUsize, Ordering}; use spin::RwLock; @@ -25,20 +25,10 @@ struct Handle { // Using BTreeMap as hashbrown doesn't have a const constructor. static HANDLES: RwLock> = RwLock::new(BTreeMap::new()); -pub const PROFILE_TOGGLEABLE: bool = true; -pub static IS_PROFILING: AtomicBool = AtomicBool::new(false); - /// Add to the input queue pub fn serio_input(index: usize, data: u8) { - if PROFILE_TOGGLEABLE { - if index == 0 && data == 30 { - log::info!("Enabling profiling"); - IS_PROFILING.store(true, Ordering::SeqCst); - } else if index == 0 && data == 48 { - log::info!("Disabling profiling"); - IS_PROFILING.store(false, Ordering::SeqCst); - } - } + crate::profiling::serio_command(index, data); + INPUT[index].send(data); for (id, _handle) in HANDLES.read().iter() {