mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-12 07:44:18 +00:00
this is gated behind the feature "debug-proc" because this could leak attacker-useful information, and also it adds a primitive that causes the kernel to write the debug information into any page that the userspace already has access to. There are some checks to ensure that the page is actually in RAM (so you can't use this to trigger weird peripheral states, etc.) so hypothetically this should just cause corruption in the userspace process if it is abused, but still - more attack surface, more problems. however, the feature is useful enough and the risk is small enough that I think I'm going to leave it enabled for the foreseeable future. It's definitely helpful to be able to see how much free memory you have, and other resource allocation trackers like connection limits and interrupt handler allocations.
121 lines
4.5 KiB
Rust
121 lines
4.5 KiB
Rust
// SPDX-FileCopyrightText: 2020 Sean Cross <sean@xobs.io>
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
use xous_kernel::{MemoryAddress, PID};
|
|
|
|
use crate::arch;
|
|
|
|
static mut IRQ_HANDLERS: [Option<(PID, MemoryAddress, Option<MemoryAddress>)>; 32] = [None; 32];
|
|
|
|
#[cfg(baremetal)]
|
|
pub fn handle(irqs_pending: usize) -> Result<xous_kernel::Result, xous_kernel::Error> {
|
|
use crate::services::SystemServices;
|
|
// Unsafe is required here because we're accessing a static
|
|
// mutable value, and it could be modified from various threads.
|
|
// However, this is fine because this is run from an IRQ context
|
|
// with interrupts disabled.
|
|
// NOTE: This will become an issue when running with multiple cores,
|
|
// so this should be protected by a mutex.
|
|
unsafe {
|
|
for (irq_no, handler) in (&mut *(&raw mut IRQ_HANDLERS)).iter().enumerate() {
|
|
if irqs_pending & (1 << irq_no) != 0 {
|
|
if let Some((pid, f, arg)) = handler {
|
|
return SystemServices::with_mut(|ss| {
|
|
// Disable all other IRQs and redirect into userspace
|
|
arch::irq::disable_all_irqs();
|
|
klog!(
|
|
"Making a callback to PID{}: {:x?} ({:08x}, {:x?})",
|
|
pid,
|
|
f,
|
|
irq_no as usize,
|
|
arg
|
|
);
|
|
ss.make_callback_to(
|
|
*pid,
|
|
f.get() as *mut usize,
|
|
crate::services::CallbackType::Interrupt(
|
|
irq_no,
|
|
arg.map(|x| x.get() as *mut usize).unwrap_or(core::ptr::null_mut::<usize>()),
|
|
),
|
|
)
|
|
.map(|_| xous_kernel::Result::ResumeProcess)
|
|
});
|
|
} else {
|
|
klog!("[!] Masked an unhandled IRQ #{:?}", irq_no);
|
|
// If there is no handler, mask this interrupt
|
|
// to prevent an IRQ storm. This is considered
|
|
// an error.
|
|
arch::irq::disable_irq(irq_no);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Ok(xous_kernel::Result::ResumeProcess)
|
|
}
|
|
|
|
#[allow(dead_code)] // needed to silence a hosted mode warning
|
|
pub fn for_each_irq<F>(mut op: F)
|
|
where
|
|
F: FnMut(usize, &PID, MemoryAddress, Option<MemoryAddress>),
|
|
{
|
|
unsafe {
|
|
for (idx, handler) in (&mut *(&raw mut IRQ_HANDLERS)).iter().enumerate() {
|
|
// Ignore threads that have no PC, and ignore the ISR thread
|
|
if let Some(handler) = handler {
|
|
op(idx, &handler.0, handler.1, handler.2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn interrupt_claim(
|
|
irq: usize,
|
|
pid: PID,
|
|
f: MemoryAddress,
|
|
arg: Option<MemoryAddress>,
|
|
) -> Result<(), xous_kernel::Error> {
|
|
// Unsafe is required since we're accessing a static mut array.
|
|
// However, we disable interrupts to prevent contention on this array.
|
|
unsafe {
|
|
if irq > (&mut *(&raw mut IRQ_HANDLERS)).len() {
|
|
Err(xous_kernel::Error::InterruptNotFound)
|
|
} else if (&mut *(&raw mut IRQ_HANDLERS))[irq].is_some() {
|
|
Err(xous_kernel::Error::InterruptInUse)
|
|
} else {
|
|
(&mut *(&raw mut IRQ_HANDLERS))[irq] = Some((pid, f, arg));
|
|
arch::irq::enable_irq(irq);
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn interrupt_free(irq: usize, pid: PID) -> Result<(), xous_kernel::Error> {
|
|
// Unsafe is required since we're accessing a static mut array.
|
|
// However, we disable interrupts to prevent contention on this array.
|
|
unsafe {
|
|
if irq > (&mut *(&raw mut IRQ_HANDLERS)).len() {
|
|
Err(xous_kernel::Error::InterruptNotFound)
|
|
} else if !(&mut *(&raw mut IRQ_HANDLERS))[irq].map(|f| f.0 == pid).unwrap_or(false) {
|
|
Err(xous_kernel::Error::InterruptNotFound)
|
|
} else {
|
|
arch::irq::disable_irq(irq);
|
|
(&mut *(&raw mut IRQ_HANDLERS))[irq] = None;
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Iterate through the IRQ handlers and remove any handler that exists
|
|
/// for the given PID.
|
|
pub fn release_interrupts_for_pid(pid: PID) {
|
|
unsafe {
|
|
for (irq, handler) in (&mut *(&raw mut IRQ_HANDLERS)).iter_mut().enumerate() {
|
|
if let Some(h) = handler {
|
|
if h.0 == pid {
|
|
arch::irq::disable_irq(irq);
|
|
*handler = None;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|