mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-15 08:30:02 +00:00
kernel: get process termination "working" on risc-v
This successfully allows a process to call `terminate_process(val)`. Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
eb7895d601
commit
09b8242bb2
7 changed files with 110 additions and 39 deletions
|
|
@ -22,7 +22,7 @@ debug-print = []
|
|||
print-panics = []
|
||||
report-memory = ["stats_alloc"]
|
||||
wrap-print = []
|
||||
# default = ["print-panics", "debug-print"]
|
||||
# default = ["print-panics", "debug-print", "wrap-print"]
|
||||
default = ["print-panics"]
|
||||
|
||||
[target.'cfg(any(windows, unix))'.dependencies]
|
||||
|
|
|
|||
|
|
@ -477,6 +477,16 @@ pub fn move_page_inner(
|
|||
result
|
||||
}
|
||||
|
||||
/// Determine if a page has been lent.
|
||||
pub fn page_is_lent(src_addr: *mut u8) -> bool {
|
||||
let entry = if let Ok(val) = pagetable_entry(src_addr as usize) {
|
||||
val
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
*entry & MMUFlags::S.bits() != 0
|
||||
}
|
||||
|
||||
/// Mark the given virtual address as being lent. If `writable`, clear the
|
||||
/// `valid` bit so that this process can't accidentally write to this page while
|
||||
/// it is lent.
|
||||
|
|
|
|||
|
|
@ -70,16 +70,13 @@ struct ProcessTable {
|
|||
/// The process upon which the current syscall is operating
|
||||
current: PID,
|
||||
|
||||
/// The number of processes that exist
|
||||
// total: usize,
|
||||
|
||||
/// The actual table contents
|
||||
/// The actual table contents. `true` if a process is allocated,
|
||||
/// `false` if it is free.
|
||||
table: [bool; MAX_PROCESS_COUNT],
|
||||
}
|
||||
|
||||
static mut PROCESS_TABLE: ProcessTable = ProcessTable {
|
||||
current: unsafe { PID::new_unchecked(1) },
|
||||
// total: 0,
|
||||
table: [false; MAX_PROCESS_COUNT],
|
||||
};
|
||||
|
||||
|
|
@ -432,17 +429,14 @@ impl Process {
|
|||
todo!();
|
||||
}
|
||||
|
||||
pub fn destroy(_pid: PID) -> Result<(), xous_kernel::Error> {
|
||||
todo!();
|
||||
// let mut process_table = unsafe { &mut *PROCESS };
|
||||
// let pid_idx = pid.get() as usize - 1;
|
||||
// if pid_idx >= process_table.table.len() {
|
||||
// panic!("attempted to destroy PID that exceeds table index: {}", pid);
|
||||
// }
|
||||
// let process = process_table.table[pid_idx].as_mut().unwrap();
|
||||
// process_table.table[pid_idx] = None;
|
||||
// process_table.total -= 1;
|
||||
// Ok(())
|
||||
pub fn destroy(pid: PID) -> Result<(), xous_kernel::Error> {
|
||||
let mut process_table = unsafe { &mut PROCESS_TABLE };
|
||||
let pid_idx = pid.get() as usize - 1;
|
||||
if pid_idx >= process_table.table.len() {
|
||||
panic!("attempted to destroy PID that exceeds table index: {}", pid);
|
||||
}
|
||||
process_table.table[pid_idx] = false;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,3 +65,18 @@ pub fn interrupt_claim(
|
|||
result
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 IRQ_HANDLERS.iter_mut().enumerate() {
|
||||
if let Some(h) = handler {
|
||||
if h.0 == pid {
|
||||
arch::irq::disable_irq(irq).unwrap();
|
||||
*handler = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,8 @@
|
|||
|
||||
use core::fmt;
|
||||
use core::slice;
|
||||
use core::str;
|
||||
|
||||
pub use crate::arch::mem::{MemoryMapping, PAGE_SIZE};
|
||||
pub use crate::arch::mem::{page_is_lent, MemoryMapping, PAGE_SIZE};
|
||||
use crate::arch::process::Process;
|
||||
|
||||
use xous_kernel::{MemoryFlags, MemoryRange, PID};
|
||||
|
|
@ -27,18 +26,13 @@ pub struct MemoryRangeExtra {
|
|||
|
||||
impl fmt::Display for MemoryRangeExtra {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let tag_name_bytes = self.mem_tag.to_le_bytes();
|
||||
let s = unsafe {
|
||||
// First, we build a &[u8]...
|
||||
let slice = slice::from_raw_parts(tag_name_bytes.as_ptr(), 4);
|
||||
// ... and then convert that slice into a string slice
|
||||
str::from_utf8_unchecked(slice)
|
||||
};
|
||||
|
||||
write!(
|
||||
f,
|
||||
"{} ({:08x}) {:08x} - {:08x} {} bytes",
|
||||
s,
|
||||
"{}{}{}{} - ({:08x}) {:08x} - {:08x} {} bytes",
|
||||
((self.mem_tag >> 0) & 0xff) as u8 as char,
|
||||
((self.mem_tag >> 8) & 0xff) as u8 as char,
|
||||
((self.mem_tag >> 16) & 0xff) as u8 as char,
|
||||
((self.mem_tag >> 24) & 0xff) as u8 as char,
|
||||
self.mem_tag,
|
||||
self.mem_start,
|
||||
self.mem_start + self.mem_size,
|
||||
|
|
@ -699,4 +693,55 @@ impl MemoryManager {
|
|||
fn release_page(&mut self, addr: *mut usize, pid: PID) -> Result<(), xous_kernel::Error> {
|
||||
self.claim_release_move(addr, pid, ClaimReleaseMove::Release)
|
||||
}
|
||||
|
||||
/// Convert an offset in the `MEMORY_ALLOCATIONS` array into a physical address.
|
||||
fn allocation_offset_to_address(&self, offset: usize) -> Option<usize> {
|
||||
// If the offset is within the RAM size, simply turn it into
|
||||
// an address.
|
||||
if offset < self.ram_size as usize / PAGE_SIZE {
|
||||
Some(self.ram_start as usize + offset * PAGE_SIZE)
|
||||
} else {
|
||||
// The offset is not within RAM, so it must be in the extra
|
||||
// regions list. Loop through all regions looking for the
|
||||
// address. NOTE: This needs to be linear because each memory
|
||||
// region has a different length.
|
||||
let mut offset_in_region = offset - (self.ram_size as usize / PAGE_SIZE);
|
||||
unsafe {
|
||||
for region in EXTRA_REGIONS {
|
||||
// If the offset exceeds the current region, skip to the
|
||||
// next region.
|
||||
if offset_in_region >= (region.mem_size as usize / PAGE_SIZE) {
|
||||
offset_in_region -= region.mem_size as usize / PAGE_SIZE;
|
||||
continue;
|
||||
}
|
||||
return Some(region.mem_start as usize + (offset_in_region * PAGE_SIZE));
|
||||
}
|
||||
}
|
||||
|
||||
// No region was found.
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Free all memory that belongs to a process. This does not unmap the
|
||||
/// memory from the process, it only marks it as free.
|
||||
/// This is very unsafe because the memory can immediately be re-allocated
|
||||
/// to another process, so only call this as part of destroying a process.
|
||||
pub unsafe fn release_all_memory_for_process(&mut self, pid: PID) {
|
||||
for (idx, owner) in MEMORY_ALLOCATIONS.iter_mut().enumerate() {
|
||||
// If this address has been allocated to this process, consider
|
||||
// freeing it or reparenting it.
|
||||
if owner == &mut Some(pid) {
|
||||
let phys_addr = self.allocation_offset_to_address(idx).unwrap();
|
||||
if page_is_lent(phys_addr as *mut u8) {
|
||||
// If the page is lent, reparent it to PID 1 so it will
|
||||
// get freed when it is returned.
|
||||
*owner = PID::new(1);
|
||||
} else {
|
||||
// Mark this page as free, which allows it to be re-allocated.
|
||||
*owner = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -194,11 +194,15 @@ impl Process {
|
|||
return Err(xous_kernel::Error::ProcessNotFound);
|
||||
}
|
||||
|
||||
// TODO: Free all pages
|
||||
// Free all associated memory pages
|
||||
unsafe {
|
||||
crate::mem::MemoryManager::with_mut(|mm| mm.release_all_memory_for_process(self.pid))
|
||||
};
|
||||
|
||||
// TODO: Free all IRQs
|
||||
// Free all claimed IRQs
|
||||
crate::irq::release_interrupts_for_pid(self.pid);
|
||||
|
||||
// TODO: Free memory mapping
|
||||
// Remove this PID from the process table
|
||||
crate::arch::process::Process::destroy(self.pid)?;
|
||||
self.state = ProcessState::Free;
|
||||
Ok(())
|
||||
|
|
@ -582,12 +586,12 @@ impl SystemServices {
|
|||
tid: Option<TID>,
|
||||
) -> Result<(), xous_kernel::Error> {
|
||||
let process = self.get_process_mut(pid)?;
|
||||
// println!(
|
||||
// klog!(
|
||||
// "switch_to_thread({}:{:?}): Old state was {:?}",
|
||||
// pid, tid, process.state
|
||||
// );
|
||||
|
||||
// Determine which context number to switch to
|
||||
// Determine which thread to switch to
|
||||
process.state = match process.state {
|
||||
ProcessState::Free => return Err(xous_kernel::Error::ProcessNotFound),
|
||||
ProcessState::Sleeping => return Err(xous_kernel::Error::ProcessNotFound),
|
||||
|
|
@ -1841,6 +1845,8 @@ impl SystemServices {
|
|||
}
|
||||
}
|
||||
|
||||
let process = self.processes[(server.pid.get() - 1) as usize];
|
||||
process.activate().unwrap();
|
||||
// Look through this server's memory space to determine if this process
|
||||
// is mentioned there as having some memory lent out.
|
||||
server.discard_messages_for_pid(target_pid);
|
||||
|
|
@ -1850,10 +1856,8 @@ impl SystemServices {
|
|||
process.activate()?;
|
||||
let parent_pid = process.ppid;
|
||||
process.terminate()?;
|
||||
// println!("KERNEL({}): Terminated", target_pid);
|
||||
|
||||
let process = self.get_process(parent_pid)?;
|
||||
process.activate().unwrap();
|
||||
self.switch_to_thread(parent_pid, None).unwrap();
|
||||
|
||||
Ok(parent_pid)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -718,7 +718,8 @@ pub fn handle_inner(pid: PID, tid: TID, in_irq: bool, call: SysCall) -> SysCallR
|
|||
unsafe {
|
||||
assert!(
|
||||
SWITCHTO_CALLER.is_none(),
|
||||
"SWITCHTO_CALLER was not None, indicating SwitchTo was called twice"
|
||||
"SWITCHTO_CALLER was {:?} and not None, indicating SwitchTo was called twice",
|
||||
SWITCHTO_CALLER,
|
||||
);
|
||||
SWITCHTO_CALLER = Some((pid, tid));
|
||||
}
|
||||
|
|
@ -802,7 +803,9 @@ pub fn handle_inner(pid: PID, tid: TID, in_irq: bool, call: SysCall) -> SysCallR
|
|||
SysCall::TerminateProcess(_ret) => SystemServices::with_mut(|ss| {
|
||||
ss.switch_from_thread(pid, tid)?;
|
||||
ss.terminate_process(pid)?;
|
||||
Ok(xous_kernel::Result::Ok)
|
||||
// Clear out `SWITCHTO_CALLER` since we're resuming the parent process.
|
||||
unsafe { SWITCHTO_CALLER = None };
|
||||
Ok(xous_kernel::Result::ResumeProcess)
|
||||
}),
|
||||
SysCall::Shutdown => {
|
||||
SystemServices::with_mut(|ss| ss.shutdown().map(|_| xous_kernel::Result::Ok))
|
||||
|
|
|
|||
Loading…
Reference in a new issue