Clean up code and fix unwrap/expect lints

This commit is contained in:
pjht 2024-11-24 16:21:17 -06:00
parent f0c6432740
commit ea4d9a7784
Signed by: pjht
GPG Key ID: 7B5F6AFBEC7EE78E
6 changed files with 445 additions and 337 deletions

49
Cargo.lock generated
View File

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 4
[[package]] [[package]]
name = "ahash" name = "ahash"
@ -16,9 +16,9 @@ dependencies = [
[[package]] [[package]]
name = "allocator-api2" name = "allocator-api2"
version = "0.2.18" version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9"
[[package]] [[package]]
name = "autocfg" name = "autocfg"
@ -52,9 +52,9 @@ checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]] [[package]]
name = "bootloader_api" name = "bootloader_api"
version = "0.11.7" version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a35ba5100c2431e20b924c8103c2cf8adb919ed9880f625e8770c3cb9d1b06aa" checksum = "99adba6d383d3b4b367b9ae41e8347ffe4d88efe247af76d00fd029e4fbb3076"
[[package]] [[package]]
name = "buddy_system_allocator" name = "buddy_system_allocator"
@ -174,9 +174,9 @@ dependencies = [
[[package]] [[package]]
name = "libm" name = "libm"
version = "0.2.8" version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa"
[[package]] [[package]]
name = "linked_list_allocator" name = "linked_list_allocator"
@ -229,12 +229,9 @@ dependencies = [
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.20.1" version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
dependencies = [
"portable-atomic",
]
[[package]] [[package]]
name = "pic8259" name = "pic8259"
@ -245,17 +242,11 @@ dependencies = [
"x86_64", "x86_64",
] ]
[[package]]
name = "portable-atomic"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.86" version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -286,9 +277,9 @@ checksum = "e3a8614ee435691de62bcffcf4a66d91b3594bf1428a5722e79103249a095690"
[[package]] [[package]]
name = "rustversion" name = "rustversion"
version = "1.0.17" version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248"
[[package]] [[package]]
name = "saturating_cast" name = "saturating_cast"
@ -348,9 +339,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.79" version = "2.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -377,9 +368,9 @@ dependencies = [
[[package]] [[package]]
name = "uart_16550" name = "uart_16550"
version = "0.3.1" version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4922792855b1bce30997fbaa5418597902c278a92d20dfe348e6f062c3bd861d" checksum = "e492212ac378a5e00da953718dafb1340d9fbaf4f27d6f3c5cab03d931d1c049"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.6.0",
"rustversion", "rustversion",
@ -388,9 +379,9 @@ dependencies = [
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.13" version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
[[package]] [[package]]
name = "unsigned-varint" name = "unsigned-varint"
@ -457,5 +448,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.79", "syn 2.0.89",
] ]

View File

@ -1,2 +1,2 @@
[toolchain] [toolchain]
channel = "nightly" channel = "nightly-2024-11-21"

View File

@ -1,8 +1,8 @@
use crate::{ use crate::{
bootinfo::BOOTINFO, bootinfo::BOOTINFO,
print, println, print, println,
tasking::SleepReason, tasking::{InvalidPid, SleepReason},
virtual_memory::{ASpaceMutex, AddressSpace, ACTIVE_SPACE, KERNEL_SPACE}, virtual_memory::{ASpaceMutex, AddressSpace, PagingError, ACTIVE_SPACE, KERNEL_SPACE},
TASKING, TASKING,
}; };
use alloc::{boxed::Box, vec::Vec}; use alloc::{boxed::Box, vec::Vec};
@ -64,43 +64,53 @@ extern "x86-interrupt" fn page_fault_handler(
error_code: PageFaultErrorCode, error_code: PageFaultErrorCode,
) { ) {
#[warn(clippy::expect_used, reason = "FIXME")] #[warn(clippy::expect_used, reason = "FIXME")]
let faulting_addr = if let Ok(faulting_addr) = Cr2::read() {
Cr2::read().expect("Cannot handle page faults caused by non-canonical addresses"); if faulting_addr.p4_index() >= PageTableIndex::new(256)
if faulting_addr.p4_index() >= PageTableIndex::new(256) && !ACTIVE_SPACE.lock().level_4_table()[faulting_addr.p4_index()]
&& !ACTIVE_SPACE.lock().level_4_table()[faulting_addr.p4_index()] .flags()
.flags() .contains(PageTableFlags::PRESENT)
.contains(PageTableFlags::PRESENT) && KERNEL_SPACE.lock().level_4_table()[faulting_addr.p4_index()]
&& KERNEL_SPACE.lock().level_4_table()[faulting_addr.p4_index()] .flags()
.flags() .contains(PageTableFlags::PRESENT)
.contains(PageTableFlags::PRESENT) {
{ ACTIVE_SPACE.lock().level_4_table_mut()[faulting_addr.p4_index()] =
ACTIVE_SPACE.lock().level_4_table_mut()[faulting_addr.p4_index()] = KERNEL_SPACE.lock().level_4_table()[faulting_addr.p4_index()].clone();
KERNEL_SPACE.lock().level_4_table()[faulting_addr.p4_index()].clone(); return;
return; }
} if let Some(current_pid) = TASKING.current_pid() {
if let Some(current_pid) = TASKING.current_pid() { print!("PID {current_pid} ");
print!("PID {current_pid} "); } else {
print!("Kernel init ");
}
if error_code.contains(PageFaultErrorCode::PROTECTION_VIOLATION) {
println!(
"page faulted {error_code:#?} at {:#x}\nEntry flags: {:#?}\n{stack_frame:#?}",
faulting_addr,
match ACTIVE_SPACE.lock().translate(faulting_addr) {
TranslateResult::Mapped { flags, .. } => flags,
_ =>
{
#![allow(
clippy::panic,
reason = "A protection violation only happends on mapped addresses. If we get here, something has gone VERY wrong."
)]
panic!();
}
},
);
} else {
println!("page faulted {error_code:#?} at {:#x}\n{stack_frame:#?}", faulting_addr);
}
} else { } else {
print!("Kernel init "); if let Some(current_pid) = TASKING.current_pid() {
} print!("PID {current_pid} ");
if error_code.contains(PageFaultErrorCode::PROTECTION_VIOLATION) { } else {
print!("Kernel init ");
}
println!( println!(
"page faulted {error_code:#?} at {:#x}\nEntry flags: {:#?}\n{stack_frame:#?}", "page faulted {error_code:#?} at non-caonical address {:#x}\n{stack_frame:#?}",
faulting_addr, Cr2::read_raw()
match ACTIVE_SPACE.lock().translate(faulting_addr) {
TranslateResult::Mapped { flags, .. } => flags,
_ =>
{
#![allow(
clippy::panic,
reason = "A protection violation only happends on mapped addresses. If we get here, something has gone VERY wrong."
)]
panic!();
}
},
); );
} else {
println!("page faulted {error_code:#?} at {:#x}\n{stack_frame:#?}", faulting_addr);
} }
TASKING.exit(254); TASKING.exit(254);
} }
@ -130,7 +140,30 @@ impl Drop for EoiGuard {
} }
} }
pub fn send_ipc_to(pid: usize, buffer: Box<[u8], &'static ASpaceMutex>, len: usize) { #[derive(Copy, Clone, Debug)]
pub enum SendIpcError {
InvalidPid,
#[expect(unused, reason = "Useful in debug logs")]
PagingError(PagingError),
}
impl From<InvalidPid> for SendIpcError {
fn from(_v: InvalidPid) -> Self {
Self::InvalidPid
}
}
impl From<PagingError> for SendIpcError {
fn from(v: PagingError) -> Self {
Self::PagingError(v)
}
}
pub fn send_ipc_to(
pid: usize,
buffer: Box<[u8], &'static ASpaceMutex>,
len: usize,
) -> Result<(), SendIpcError> {
#[cfg(feature = "log-rpc")] #[cfg(feature = "log-rpc")]
{ {
#[expect( #[expect(
@ -172,43 +205,35 @@ pub fn send_ipc_to(pid: usize, buffer: Box<[u8], &'static ASpaceMutex>, len: usi
]); ]);
} }
assert!(len <= buffer.len()); assert!(len <= buffer.len());
if TASKING.message_queue_mut(pid, |_| ()).is_ok() { TASKING.process_mut(pid, |process| {
let buf_num_pages = buffer.len() / 4096; let buf_num_pages = buffer.len() / 4096;
let buffer = Box::into_raw(buffer); let buffer = Box::into_raw(buffer);
let buf_start_page =
Page::from_start_address(VirtAddr::new(u64(buffer.expose_provenance()))).unwrap();
let dest_buffer = TASKING
.address_space_mut(pid, |aspace| {
// This is None only if the destiniation is the current process. If so,
// no remapping is necessary so just return the old buffer.
let Some(aspace) = aspace else {
return buffer;
};
let page = ACTIVE_SPACE
.lock()
.move_mappings_free(buf_start_page, buf_num_pages, aspace)
.unwrap();
ptr::slice_from_raw_parts_mut::<u8>(page.start_address().as_mut_ptr(), buffer.len())
})
.unwrap();
#[expect( #[expect(
clippy::unwrap_used, clippy::unwrap_used,
reason = "The PID is known valid due to using it in message_queue_mut in the if-let condition" reason = "ASpaceMutex is guaranteed to only return page-aligned allocations, so the address passed to Page::from_start_address is always valid"
)] )]
let new_buffer_key = TASKING.proc_data_buffers_mut(pid, |x| x.insert(dest_buffer)).unwrap(); let buf_start_page = Page::from_start_address(VirtAddr::new(u64(buffer.expose_provenance()))).unwrap();
#[expect( // This is None only if the destiniation is the current process. If so,
clippy::unwrap_used, // no remapping is necessary so just return the old buffer.
reason = "The option was already checked at the start of the if-let" let dest_buffer = if let Some(aspace) = process.address_space_mut() {
)] let page = ACTIVE_SPACE.lock().move_mappings_free(buf_start_page, buf_num_pages, aspace)?;
TASKING.message_queue_mut(pid, |x| x.push((new_buffer_key, len))).unwrap(); ptr::slice_from_raw_parts_mut::<u8>(
#[expect( page.start_address().as_mut_ptr(),
clippy::unwrap_used, buffer.len(),
reason = "The PID is known valid due to using it in message_queue_mut in the if-let condition" )
)] } else {
TASKING.wake(pid, SleepReason::WaitingForIPC).unwrap(); buffer
} else { };
println!("irq 1 msg: Bad PID ({})", pid); let new_buffer_key = process.data_buffers().lock().insert(dest_buffer);
} process.message_queue().lock().push((new_buffer_key, len));
Ok::<_, PagingError>(())
})??;
#[expect(
clippy::unwrap_used,
reason = "The PID is known valid due to using it in process_mut above"
)]
TASKING.wake(pid, SleepReason::WaitingForIPC).unwrap();
Ok(())
} }
fn irq_handler(_stack_frame: InterruptStackFrame, index: u8, _error_code: Option<u64>) { fn irq_handler(_stack_frame: InterruptStackFrame, index: u8, _error_code: Option<u64>) {
@ -234,7 +259,19 @@ fn irq_handler(_stack_frame: InterruptStackFrame, index: u8, _error_code: Option
buffer[0..8].copy_from_slice(&u64::MAX.to_le_bytes()); buffer[0..8].copy_from_slice(&u64::MAX.to_le_bytes());
buffer[8..10].copy_from_slice(&2u16.to_le_bytes()); buffer[8..10].copy_from_slice(&2u16.to_le_bytes());
buffer[10] = irq_num; buffer[10] = irq_num;
send_ipc_to(pid, buffer, len); match send_ipc_to(pid, buffer, len) {
Ok(()) => (),
Err(SendIpcError::InvalidPid) => {
IRQ_TASKS.write()[usize(irq_num)] = None;
}
#[expect(
clippy::panic,
reason = "If an IRQ message fails to deliver, driver code can easify malfunction, so treat this as fatal."
)]
Err(e) => {
panic!("Failed to send IRQ message: {e:?}");
}
}
} }
} }
@ -305,8 +342,12 @@ extern "x86-interrupt" fn syscall_handler_header(stack_frame: InterruptStackFram
} }
fn get_buffer(id: u64) -> Option<Box<[u8], &'static ASpaceMutex>> { fn get_buffer(id: u64) -> Option<Box<[u8], &'static ASpaceMutex>> {
TASKING.data_buffers_mut(|x| { TASKING.current_process(|process| {
x.try_remove(usize(id)).map(|buf| unsafe { Box::from_raw_in(buf, &*ACTIVE_SPACE) }) process
.data_buffers()
.lock()
.try_remove(usize(id))
.map(|buf| unsafe { Box::from_raw_in(buf, &*ACTIVE_SPACE) })
}) })
} }
@ -314,7 +355,7 @@ pub static REGISTERD_PIDS: Lazy<RwLock<HashMap<u64, u64>>> =
Lazy::new(|| RwLock::new(HashMap::new())); Lazy::new(|| RwLock::new(HashMap::new()));
static INITRD_BUF: Lazy<&'static [u8]> = Lazy::new(|| { static INITRD_BUF: Lazy<&'static [u8]> = Lazy::new(|| {
#[warn(clippy::expect_used, reason = "FIXME")] #[expect(clippy::expect_used, reason = "Boot cannot happen without an initrd")]
let ramdisk_start = BOOTINFO.ramdisk_addr.into_option().expect("initrd not present"); let ramdisk_start = BOOTINFO.ramdisk_addr.into_option().expect("initrd not present");
let ramdisk_len = BOOTINFO.ramdisk_len; let ramdisk_len = BOOTINFO.ramdisk_len;
let initrd = unsafe { let initrd = unsafe {
@ -326,6 +367,14 @@ static INITRD_BUF: Lazy<&'static [u8]> = Lazy::new(|| {
let initrd_start_page = Page::containing_address(VirtAddr::new(ramdisk_start)); let initrd_start_page = Page::containing_address(VirtAddr::new(ramdisk_start));
let initrd_num_pages = usize(ramdisk_len.div_ceil(4096)); let initrd_num_pages = usize(ramdisk_len.div_ceil(4096));
unsafe { unsafe {
#[expect(
clippy::unwrap_used,
reason = "
This can only fail if the initrd is not at the address the bootloder says or if it
uses huge pages. The first is a violatin of the contract between the bootloader and
the kernel, and the second can't happen because the bootloader does not use huge pages.
"
)]
KERNEL_SPACE KERNEL_SPACE
.lock() .lock()
.update_flags( .update_flags(
@ -367,12 +416,13 @@ extern "C" fn syscall_handler() {
.map_free(usize(regs.rdx), PageTableFlags::from_bits_truncate(regs.rsi)) .map_free(usize(regs.rdx), PageTableFlags::from_bits_truncate(regs.rsi))
.map_or(0, |x| u64(x.expose_provenance())) .map_or(0, |x| u64(x.expose_provenance()))
} else { } else {
TASKING.address_spaces_mut(|x| { TASKING.current_process(|process| {
let mut address_spaces = process.address_spaces().lock();
#[warn( #[warn(
clippy::arithmetic_side_effects, clippy::arithmetic_side_effects,
reason = "FIXME: The current address space should be usize::MAX as that is an invalid index, instead of 0." reason = "FIXME: The current address space should be usize::MAX as that is an invalid index, instead of 0."
)] )]
if let Some(space) = x.get_mut(usize(regs.rcx - 1)) { if let Some(space) = address_spaces.get_mut(usize(regs.rcx - 1)) {
space space
.map_free(usize(regs.rdx), PageTableFlags::from_bits_truncate(regs.rsi)) .map_free(usize(regs.rdx), PageTableFlags::from_bits_truncate(regs.rsi))
.map_or(0, |x| u64(x.expose_provenance())) .map_or(0, |x| u64(x.expose_provenance()))
@ -392,8 +442,10 @@ extern "C" fn syscall_handler() {
clippy::arithmetic_side_effects, clippy::arithmetic_side_effects,
reason = "usize::MAX will never be returned as an index, and so incrementing can never overflow." reason = "usize::MAX will never be returned as an index, and so incrementing can never overflow."
)] )]
let address_space = u64(TASKING.address_spaces_mut(|x| { let address_space = u64(TASKING.current_process(|process| {
x.insert(AddressSpace::new().expect("Failed to create address space")) + 1 let mut address_spaces = process.address_spaces().lock();
address_spaces.insert(AddressSpace::new().expect("Failed to create address space"))
+ 1
})); }));
retval = address_space; retval = address_space;
} }
@ -402,7 +454,9 @@ extern "C" fn syscall_handler() {
clippy::arithmetic_side_effects, clippy::arithmetic_side_effects,
reason = "FIXME: The current address space should be usize::MAX as that is an invalid index, instead of 0." reason = "FIXME: The current address space should be usize::MAX as that is an invalid index, instead of 0."
)] )]
TASKING.address_spaces_mut(|x| x.remove(usize(regs.rcx - 1))); TASKING.current_process(|process| {
process.address_spaces().lock().remove(usize(regs.rcx - 1))
});
} }
6 => 'call6: { 6 => 'call6: {
let Ok(page) = Page::from_start_address(VirtAddr::new(regs.rdx)) else { let Ok(page) = Page::from_start_address(VirtAddr::new(regs.rdx)) else {
@ -414,12 +468,13 @@ extern "C" fn syscall_handler() {
let failed = if regs.rcx == 0 { let failed = if regs.rcx == 0 {
ACTIVE_SPACE.lock().map_assert_unused(page, num_pages, flags).is_err() ACTIVE_SPACE.lock().map_assert_unused(page, num_pages, flags).is_err()
} else { } else {
TASKING.address_spaces_mut(|x| { TASKING.current_process(|process| {
let mut address_spaces = process.address_spaces().lock();
#[warn( #[warn(
clippy::arithmetic_side_effects, clippy::arithmetic_side_effects,
reason = "FIXME: The current address space should be usize::MAX as that is an invalid index, instead of 0." reason = "FIXME: The current address space should be usize::MAX as that is an invalid index, instead of 0."
)] )]
if let Some(space) = x.get_mut(usize(regs.rcx - 1)) { if let Some(space) = address_spaces.get_mut(usize(regs.rcx - 1)) {
space.map_assert_unused(page, num_pages, flags).is_err() space.map_assert_unused(page, num_pages, flags).is_err()
} else { } else {
true true
@ -432,35 +487,38 @@ extern "C" fn syscall_handler() {
if let Some(buffer) = get_buffer(regs.rdx) { if let Some(buffer) = get_buffer(regs.rdx) {
let len = usize(regs.rdi); let len = usize(regs.rdi);
assert!(len <= buffer.len()); assert!(len <= buffer.len());
TASKING.address_spaces_mut(|x| { let err = TASKING.current_process(|process| {
let mut address_spaces = process.address_spaces().lock();
#[warn( #[warn(
clippy::arithmetic_side_effects, clippy::arithmetic_side_effects,
reason = "FIXME: The current address space should be usize::MAX as that is an invalid index, instead of 0." reason = "FIXME: The current address space should be usize::MAX as that is an invalid index, instead of 0."
)] )]
if let Some(space) = x.get_mut(usize(regs.rcx - 1)) { if let Some(space) = address_spaces.get_mut(usize(regs.rcx - 1)) {
let buffer_num_pages = buffer.len() / 4096; let buffer_num_pages = buffer.len() / 4096;
let buffer_raw = Box::into_raw(buffer); let buffer_raw = Box::into_raw(buffer);
let page = ACTIVE_SPACE let page = ACTIVE_SPACE
.lock() .lock()
.move_mappings_free( .move_mappings_free(
Page::from_start_address(VirtAddr::new(u64( Page::from_start_address(VirtAddr::new(u64(
buffer_raw.expose_provenance() buffer_raw.expose_provenance()
))) ))).map_err(|_| ())?,
.unwrap(), buffer_num_pages,
buffer_num_pages, space,
space, ).map_err(|_| ())?;
)
.unwrap();
space.run(|| unsafe { space.run(|| unsafe {
(ptr::with_exposed_provenance_mut::<u8>(usize(regs.rsi))) (ptr::with_exposed_provenance_mut::<u8>(usize(regs.rsi)))
.copy_from(page.start_address().as_mut_ptr::<u8>(), len); .copy_from(page.start_address().as_mut_ptr::<u8>(), len);
}); });
space.unmap(page, buffer_num_pages).unwrap(); space.unmap(page, buffer_num_pages).map_err(|_| ())?;
retval = 0; Ok(())
} else { } else {
retval = 1; Err(())
} }
}); }).is_err();
#[expect(clippy::as_conversions, reason = "Needed to convert bool to u64")]
{
retval = err as u64;
}
} else { } else {
retval = 1; retval = 1;
} }
@ -470,7 +528,9 @@ extern "C" fn syscall_handler() {
clippy::arithmetic_side_effects, clippy::arithmetic_side_effects,
reason = "FIXME: The current address space should be usize::MAX as that is an invalid index, instead of 0." reason = "FIXME: The current address space should be usize::MAX as that is an invalid index, instead of 0."
)] )]
let space = TASKING.address_spaces_mut(|x| x.remove(usize(regs.rdx - 1))); let space = TASKING.current_process(|process| {
process.address_spaces().lock().remove(usize(regs.rdx - 1))
});
let res = TASKING.new_process(ptr::with_exposed_provenance(usize(regs.rcx)), space); let res = TASKING.new_process(ptr::with_exposed_provenance(usize(regs.rcx)), space);
if let Ok(pid) = res { if let Ok(pid) = res {
retval = 0; retval = 0;
@ -500,12 +560,12 @@ extern "C" fn syscall_handler() {
if let Some(buffer) = get_buffer(regs.rdx) { if let Some(buffer) = get_buffer(regs.rdx) {
let len = usize(regs.rsi); let len = usize(regs.rsi);
assert!(len <= buffer.len()); assert!(len <= buffer.len());
if TASKING.message_queue_mut(pid, |_| ()).is_ok() { match send_ipc_to(pid, buffer, len) {
send_ipc_to(pid, buffer, len); Ok(()) => retval = 0,
retval = 0; Err(e) => {
} else { println!("ipc_send: Error {e:?}");
println!("ipc_send: Bad PID ({})", pid); retval = 1;
retval = 1; }
} }
} else { } else {
println!("ipc_send: Bad buffer ({})", regs.rdx); println!("ipc_send: Bad buffer ({})", regs.rdx);
@ -513,13 +573,16 @@ extern "C" fn syscall_handler() {
} }
} }
12 => { 12 => {
if let Some(msg) = TASKING.current_message_queue_mut(|x| x.pop()) { if let Some(msg) =
TASKING.current_process(|process| process.message_queue().lock().pop())
{
#[expect( #[expect(
clippy::unwrap_used, clippy::unwrap_used,
reason = "The message queue only contains valid buffer IDs" reason = "The message queue only contains valid buffer IDs"
)] )]
let buffer_addr = let buffer_addr = u64(TASKING
u64(TASKING.data_buffers_mut(|x| *x.get(msg.0).unwrap()).expose_provenance()); .current_process(|process| *process.data_buffers().lock().get(msg.0).unwrap())
.expose_provenance());
retval2 = u64(msg.1); retval2 = u64(msg.1);
retval = buffer_addr; retval = buffer_addr;
retval3 = u64(msg.0); retval3 = u64(msg.0);
@ -545,12 +608,13 @@ extern "C" fn syscall_handler() {
let failed = if regs.rcx == 0 { let failed = if regs.rcx == 0 {
ACTIVE_SPACE.lock().map_only_unused(page, num_pages, flags).is_err() ACTIVE_SPACE.lock().map_only_unused(page, num_pages, flags).is_err()
} else { } else {
TASKING.address_spaces_mut(|x| { TASKING.current_process(|process| {
let mut address_spaces = process.address_spaces().lock();
#[warn( #[warn(
clippy::arithmetic_side_effects, clippy::arithmetic_side_effects,
reason = "FIXME: The current address space should be usize::MAX as that is an invalid index, instead of 0." reason = "FIXME: The current address space should be usize::MAX as that is an invalid index, instead of 0."
)] )]
if let Some(space) = x.get_mut(usize(regs.rcx - 1)) { if let Some(space) = address_spaces.get_mut(usize(regs.rcx - 1)) {
space.map_only_unused(page, num_pages, flags).is_err() space.map_only_unused(page, num_pages, flags).is_err()
} else { } else {
true true
@ -569,7 +633,9 @@ extern "C" fn syscall_handler() {
buffer.resize(rounded_size, 0); buffer.resize(rounded_size, 0);
let buffer = buffer.into_boxed_slice(); let buffer = buffer.into_boxed_slice();
let buffer = Box::into_raw(buffer); let buffer = Box::into_raw(buffer);
retval = u64(TASKING.data_buffers_mut(|x| x.insert(buffer))); retval = u64(
TASKING.current_process(|process| process.data_buffers().lock().insert(buffer))
);
retval2 = u64(buffer.cast::<u8>().expose_provenance()); retval2 = u64(buffer.cast::<u8>().expose_provenance());
retval3 = u64(rounded_size); retval3 = u64(rounded_size);
} }
@ -579,45 +645,56 @@ extern "C" fn syscall_handler() {
clippy::arithmetic_side_effects, clippy::arithmetic_side_effects,
reason = "FIXME: The current address space should be usize::MAX as that is an invalid index, instead of 0." reason = "FIXME: The current address space should be usize::MAX as that is an invalid index, instead of 0."
)] )]
TASKING.address_spaces_mut(|x| { let err = TASKING
let space = x.get_mut(usize(regs.rcx - 1)).expect("Invalid address space"); .current_process(|process| {
let slice_start: *mut u8 = ptr::with_exposed_provenance_mut(usize(regs.rdx)); let mut address_spaces = process.address_spaces().lock();
space.run(|| unsafe { let space = address_spaces.get_mut(usize(regs.rcx - 1)).ok_or(())?;
slice::from_raw_parts_mut(slice_start, usize(regs.rsi)).fill(0); let slice_start: *mut u8 = ptr::with_exposed_provenance_mut(usize(regs.rdx));
}); space.run(|| unsafe {
}); slice::from_raw_parts_mut(slice_start, usize(regs.rsi)).fill(0);
});
retval = 0; Ok::<_, ()>(())
})
.is_err();
#[expect(clippy::as_conversions, reason = "Needed to convert bool to u64")]
{
retval = err as u64;
}
} }
18 => { 18 => {
if TASKING.current_message_queue_mut(|x| x.is_empty()) { if TASKING.current_process(|process| process.message_queue().lock().is_empty()) {
TASKING.sleep(SleepReason::WaitingForIPC); TASKING.sleep(SleepReason::WaitingForIPC);
} }
} }
19 => (), 19 => (),
20 => { 20 => 'call20: {
let Ok(frame) = PhysFrame::from_start_address(PhysAddr::new(regs.rdx)) else {
retval = 0;
break 'call20;
};
retval = if regs.rcx == 0 { retval = if regs.rcx == 0 {
unsafe { unsafe {
ACTIVE_SPACE ACTIVE_SPACE
.lock() .lock()
.map_free_to( .map_free_to(
PhysFrame::from_start_address(PhysAddr::new(regs.rdx)).unwrap(), frame,
usize(regs.rsi), usize(regs.rsi),
PageTableFlags::from_bits_truncate(regs.rdi), PageTableFlags::from_bits_truncate(regs.rdi),
) )
.map_or(0, |x| u64(x.expose_provenance())) .map_or(0, |x| u64(x.expose_provenance()))
} }
} else { } else {
TASKING.address_spaces_mut(|x| { TASKING.current_process(|process| {
let mut address_spaces = process.address_spaces().lock();
#[warn( #[warn(
clippy::arithmetic_side_effects, clippy::arithmetic_side_effects,
reason = "FIXME: The current address space should be usize::MAX as that is an invalid index, instead of 0." reason = "FIXME: The current address space should be usize::MAX as that is an invalid index, instead of 0."
)] )]
if let Some(space) = x.get_mut(usize(regs.rcx - 1)) { if let Some(space) = address_spaces.get_mut(usize(regs.rcx - 1)) {
unsafe { unsafe {
space space
.map_free_to( .map_free_to(
PhysFrame::from_start_address(PhysAddr::new(regs.rdx)).unwrap(), frame,
usize(regs.rsi), usize(regs.rsi),
PageTableFlags::from_bits_truncate(regs.rdi), PageTableFlags::from_bits_truncate(regs.rdi),
) )
@ -641,12 +718,13 @@ extern "C" fn syscall_handler() {
retval2 = start_phys; retval2 = start_phys;
start_virt start_virt
} else { } else {
TASKING.address_spaces_mut(|x| { TASKING.current_process(|process| {
let mut address_spaces = process.address_spaces().lock();
#[warn( #[warn(
clippy::arithmetic_side_effects, clippy::arithmetic_side_effects,
reason = "FIXME: The current address space should be usize::MAX as that is an invalid index, instead of 0." reason = "FIXME: The current address space should be usize::MAX as that is an invalid index, instead of 0."
)] )]
if let Some(space) = x.get_mut(usize(regs.rcx - 1)) { if let Some(space) = address_spaces.get_mut(usize(regs.rcx - 1)) {
let (start_virt, start_phys) = space let (start_virt, start_phys) = space
.map_free_cont_phys( .map_free_cont_phys(
usize(regs.rdx), usize(regs.rdx),
@ -671,12 +749,13 @@ extern "C" fn syscall_handler() {
retval = if regs.rcx == 0 { retval = if regs.rcx == 0 {
u64::from(ACTIVE_SPACE.lock().unmap(page, usize(regs.rsi)).is_err()) u64::from(ACTIVE_SPACE.lock().unmap(page, usize(regs.rsi)).is_err())
} else { } else {
TASKING.address_spaces_mut(|x| { TASKING.current_process(|process| {
let mut address_spaces = process.address_spaces().lock();
#[warn( #[warn(
clippy::arithmetic_side_effects, clippy::arithmetic_side_effects,
reason = "FIXME: The current address space should be usize::MAX as that is an invalid index, instead of 0." reason = "FIXME: The current address space should be usize::MAX as that is an invalid index, instead of 0."
)] )]
if let Some(space) = x.get_mut(usize(regs.rcx - 1)) { if let Some(space) = address_spaces.get_mut(usize(regs.rcx - 1)) {
u64::from(space.unmap(page, usize(regs.rsi)).is_err()) u64::from(space.unmap(page, usize(regs.rsi)).is_err())
} else { } else {
1 1
@ -687,7 +766,17 @@ extern "C" fn syscall_handler() {
23 => { 23 => {
let irq_num = regs.rcx; let irq_num = regs.rcx;
if irq_num < 16 { if irq_num < 16 {
IRQ_TASKS.write()[usize(irq_num)] = Some(TASKING.current_pid().unwrap()); #[expect(
clippy::indexing_slicing,
reason = "The index has been checked to be in bounds above"
)]
IRQ_TASKS.write()[usize(irq_num)] = Some(
#[expect(
clippy::unwrap_used,
reason = "Syscalls cannot be called during early boot, the only time when there is no current PID"
)]
TASKING.current_pid().unwrap(),
);
retval = 0; retval = 0;
} else { } else {
retval = 1; retval = 1;

View File

@ -96,28 +96,33 @@ impl FrameDeallocator<Size4KiB> for PhysicalMemory {
impl PhysicalMemory { impl PhysicalMemory {
pub fn allocate_frame_range(&mut self, len: usize) -> Option<PhysFrameRange> { pub fn allocate_frame_range(&mut self, len: usize) -> Option<PhysFrameRange> {
self.bytes_used = self.bytes_used.saturating_add(4096 * len);
if self.bytes_used > self.peak_used {
self.peak_used = self.bytes_used;
}
if len >= 0x10_0000_0000_0000 { if len >= 0x10_0000_0000_0000 {
return None; return None;
} }
#[expect(clippy::arithmetic_side_effects, reason = "The check above makes sure the multiplication cannot overflow.")] #[expect(
clippy::arithmetic_side_effects,
reason = "The check above makes sure the multiplication cannot overflow."
)]
let byte_len = 4096 * len;
self.bytes_used = self.bytes_used.saturating_add(byte_len);
if self.bytes_used > self.peak_used {
self.peak_used = self.bytes_used;
}
#[expect(clippy::unwrap_used, reason = "4096 is a nonzero power of two, and len is already a multiple of 4096 so rounding cannot overflow.")] #[expect(clippy::unwrap_used, reason = "4096 is a nonzero power of two, and len is already a multiple of 4096 so rounding cannot overflow.")]
self.alloc.allocate_first_fit(Layout::from_size_align(4096 * len, 4096).unwrap()).ok().map(|(ptr, _)| { self.alloc.allocate_first_fit(Layout::from_size_align(byte_len, 4096).unwrap()).ok().map(|(ptr, _)| {
#[expect(clippy::unwrap_used, reason = "PhysFrame requires its argument to be 4k aligned, which is guaranteed by the allocator")] #[expect(clippy::unwrap_used, reason = "PhysFrame requires its argument to be 4k aligned, which is guaranteed by the allocator")]
#[expect(clippy::arithmetic_side_effects, reason = "All addresses passed to the allocator are > PHYS_OFFSET, so this cannot underflow")] #[expect(clippy::arithmetic_side_effects, reason = "All addresses passed to the allocator are > PHYS_OFFSET, so this cannot underflow")]
let start = PhysFrame::from_start_address(PhysAddr::new( let start = PhysFrame::from_start_address(PhysAddr::new(
(u64(ptr.as_ptr().expose_provenance())) - PHYS_OFFSET.as_u64(), (u64(ptr.as_ptr().expose_provenance())) - PHYS_OFFSET.as_u64(),
)) ))
.unwrap(); .unwrap();
#[expect(clippy::unwrap_used, reason = "PhysFrame requires its argument to be 4k aligned, which is guaranteed by the allocator")] #[expect(clippy::arithmetic_side_effects, reason = "
#[expect(clippy::arithmetic_side_effects, reason = "All addresses passed to the allocator are > PHYS_OFFSET, so this cannot underflow")] The pointer returned by the allocator is guaranteed to be a pointer to a contiguous block of len frames,
let end = PhysFrame::from_start_address(PhysAddr::new( so this could only overflow if the range included the last physical frame. But since the allocator gets
(u64(ptr.as_ptr().expose_provenance()) + (u64(len) * 4096)) - PHYS_OFFSET.as_u64(), passed regions from PhysFrameRanges, which can't include the last frame without overflow, that can't
)) happen and thus this can't overflow.
.unwrap(); ")]
let end = start + u64(len);
PhysFrameRange { PhysFrameRange {
start, start,
end end

View File

@ -12,7 +12,6 @@ use core::{
sync::atomic::{AtomicBool, Ordering}, sync::atomic::{AtomicBool, Ordering},
}; };
use crossbeam_queue::SegQueue; use crossbeam_queue::SegQueue;
//use humansize::{SizeFormatter, BINARY};
use slab::Slab; use slab::Slab;
use spin::{Lazy, Mutex, RwLock}; use spin::{Lazy, Mutex, RwLock};
use x86_64::{ use x86_64::{
@ -86,7 +85,7 @@ pub enum SleepReason {
} }
#[derive(Debug)] #[derive(Debug)]
struct Process { pub struct Process {
address_space: Option<AddressSpace>, address_space: Option<AddressSpace>,
kernel_stack: Box<[usize], &'static ASpaceMutex>, kernel_stack: Box<[usize], &'static ASpaceMutex>,
kernel_esp: *mut usize, kernel_esp: *mut usize,
@ -97,6 +96,24 @@ struct Process {
sleeping: RwLock<Option<SleepReason>>, sleeping: RwLock<Option<SleepReason>>,
} }
impl Process {
pub fn address_spaces(&self) -> &Mutex<Slab<AddressSpace>> {
&self.address_spaces
}
pub fn data_buffers(&self) -> &Mutex<Slab<*mut [u8]>> {
&self.data_buffers
}
pub fn message_queue(&self) -> &Mutex<SegQueue<(usize, usize)>> {
&self.message_queue
}
pub fn address_space_mut(&mut self) -> Option<&mut AddressSpace> {
self.address_space.as_mut()
}
}
unsafe impl Send for Process {} unsafe impl Send for Process {}
unsafe impl Sync for Process {} unsafe impl Sync for Process {}
@ -165,36 +182,33 @@ impl Tasking {
sleeping: RwLock::new(Some(SleepReason::NewProcess)), sleeping: RwLock::new(Some(SleepReason::NewProcess)),
}); });
if let Some(&proc_man_pid) = REGISTERD_PIDS.read().get(&3) { if let Some(&proc_man_pid) = REGISTERD_PIDS.read().get(&3) {
let mut len: usize; let mut varint_buf = unsigned_varint::encode::u64_buffer();
let rounded_size = 32usize.next_multiple_of(4096); let mut buffer = Vec::new_in(&*ACTIVE_SPACE);
let mut buffer = Vec::with_capacity_in(rounded_size, &*ACTIVE_SPACE); buffer.extend_from_slice(&u64::MAX.to_le_bytes());
buffer.resize(rounded_size, 0); buffer.extend_from_slice(&0u16.to_le_bytes());
let mut buffer = buffer.into_boxed_slice(); buffer.push(0);
buffer[0..8].copy_from_slice(&u64::MAX.to_le_bytes()); buffer.extend_from_slice(&0u64.to_le_bytes());
buffer[8..10].copy_from_slice(&0u16.to_le_bytes()); buffer.extend_from_slice(&8u16.to_le_bytes());
buffer[10] = 0; buffer.extend_from_slice(&6u16.to_le_bytes());
buffer[11..19].copy_from_slice(&0u64.to_le_bytes()); buffer.extend_from_slice(unsigned_varint::encode::u64(u64(pid), &mut varint_buf));
buffer[19..21].copy_from_slice(&8u16.to_le_bytes());
buffer[21..23].copy_from_slice(&6u16.to_le_bytes());
len = 23;
len += unsigned_varint::encode::u64(
u64(pid),
(&mut buffer[len..len + 10]).try_into().unwrap(),
)
.len();
if let Some(current_pid) = *(self.current_pid.read()) { if let Some(current_pid) = *(self.current_pid.read()) {
buffer[len] = 1; buffer.push(1);
len += 1; buffer.extend_from_slice(unsigned_varint::encode::u64(
len += unsigned_varint::encode::u64(
u64(current_pid), u64(current_pid),
(&mut buffer[len..len + 10]).try_into().unwrap(), &mut varint_buf,
) ));
.len();
} else { } else {
buffer[len] = 0; buffer.push(0);
len += 1;
} }
send_ipc_to(usize(proc_man_pid), buffer, len); let len = buffer.len();
buffer.resize(len.next_multiple_of(4096), 0);
let buffer = buffer.into_boxed_slice();
#[expect(
clippy::expect_used,
reason = "The tasking code in the kernel and proc_man CANNOT lose sync. Failure to communicate is fatal."
)]
send_ipc_to(usize(proc_man_pid), buffer, len)
.expect("Failed to send exit message to proc_man");
} else { } else {
println!("[TASKING] No process manager when creating PID {pid}"); println!("[TASKING] No process manager when creating PID {pid}");
} }
@ -215,51 +229,47 @@ impl Tasking {
pub fn task_yield(&self) { pub fn task_yield(&self) {
loop { loop {
self.freeable_kstacks.lock().clear(); self.freeable_kstacks.lock().clear();
let Some(current_pid) = *self.current_pid.read() else { let Some(current_pid) = self.current_pid() else {
self.wfi_loop.store(false, Ordering::Relaxed); self.wfi_loop.store(false, Ordering::Relaxed);
break; break;
}; };
let next_process_pid = self.ready_to_run.lock().pop_front(); let next_process_pid = self.ready_to_run.lock().pop_front();
if let Some(next_process_pid) = next_process_pid { if let Some(next_process_pid) = next_process_pid {
self.wfi_loop.store(false, Ordering::Relaxed); self.wfi_loop.store(false, Ordering::Relaxed);
if next_process_pid == self.current_pid().unwrap() { if Some(next_process_pid) == self.current_pid() {
println!("Yielding to currect process! Returning"); println!("Yielding to current process! Returning");
break; break;
} }
#[expect( #[warn(clippy::unwrap_used, reason = "FIXME(?)")]
clippy::expect_used, let current_address_space = self
reason = "This expect checks a critical invariant. If this fails, the kernel MUST panic" .process_mut(next_process_pid, |process| {
)] #[expect(
#[warn(clippy::indexing_slicing, reason = "FIXME(?)")] clippy::expect_used,
let current_address_space = self.processes.write()[next_process_pid] reason = "This expect checks a critical invariant. If this fails, the kernel MUST panic"
.address_space )]
.take() process
.expect("Non-current process has active page table") .address_space
.activate(); .take()
#[warn(clippy::indexing_slicing, reason = "FIXME(?)")] .expect("Non-current process has active page table")
self.processes.write()[current_pid].address_space = Some(current_address_space); .activate()
let processes = self.processes.read(); })
#[warn(clippy::indexing_slicing, reason = "FIXME(?)")] .unwrap();
let current_process = &processes[current_pid]; self.current_process_mut(|process| {
#[warn(clippy::indexing_slicing, reason = "FIXME(?)")] process.address_space = Some(current_address_space);
let next_process = &processes[next_process_pid]; });
gdt::set_tss_stack(next_process.kernel_esp_top); if self.current_process(|process| process.sleeping.read().is_none()) {
if current_process.sleeping.read().is_none() {
self.ready_to_run.lock().push_back(current_pid); self.ready_to_run.lock().push_back(current_pid);
} }
let kernel_esp = next_process.kernel_esp; let curr_stack =
let previous_process = current_pid; self.current_process_mut(|process| addr_of_mut!(process.kernel_esp));
*self.current_pid.write() = Some(next_process_pid); *self.current_pid.write() = Some(next_process_pid);
core::mem::drop(processes); let kernel_esp = self.current_process(|process| {
let mut processes = self.processes.write(); gdt::set_tss_stack(process.kernel_esp_top);
#[warn(clippy::indexing_slicing, reason = "FIXME(?)")] process.kernel_esp
let curr_stack = addr_of_mut!(processes[previous_process].kernel_esp); });
core::mem::drop(processes);
switch_to_asm(curr_stack, kernel_esp); switch_to_asm(curr_stack, kernel_esp);
break; break;
} else if #[warn(clippy::indexing_slicing, reason = "FIXME(?)")] } else if self.current_process(|process| process.sleeping.read().is_some()) {
self.processes.read()[current_pid].sleeping.read().is_some()
{
self.wfi_loop.store(true, Ordering::Relaxed); self.wfi_loop.store(true, Ordering::Relaxed);
x86_64::instructions::interrupts::enable_and_hlt(); x86_64::instructions::interrupts::enable_and_hlt();
x86_64::instructions::interrupts::disable(); x86_64::instructions::interrupts::disable();
@ -275,28 +285,30 @@ impl Tasking {
} }
pub fn exit(&self, code: u8) -> ! { pub fn exit(&self, code: u8) -> ! {
if let Some(current_pid) = *self.current_pid.read() { if let Some(current_pid) = self.current_pid() {
if let Some(&proc_man_pid) = REGISTERD_PIDS.read().get(&3) { if let Some(&proc_man_pid) = REGISTERD_PIDS.read().get(&3) {
let mut len: usize; let mut varint_buf = unsigned_varint::encode::u64_buffer();
let rounded_size = 32usize.next_multiple_of(4096); let mut buffer = Vec::new_in(&*ACTIVE_SPACE);
let mut buffer = Vec::with_capacity_in(rounded_size, &*ACTIVE_SPACE); buffer.extend_from_slice(&u64::MAX.to_le_bytes());
buffer.resize(rounded_size, 0); buffer.extend_from_slice(&0u16.to_le_bytes());
let mut buffer = buffer.into_boxed_slice(); buffer.push(0);
buffer[0..8].copy_from_slice(&u64::MAX.to_le_bytes()); buffer.extend_from_slice(&0u64.to_le_bytes());
buffer[8..10].copy_from_slice(&0u16.to_le_bytes()); buffer.extend_from_slice(&8u16.to_le_bytes());
buffer[10] = 0; buffer.extend_from_slice(&4u16.to_le_bytes());
buffer[11..19].copy_from_slice(&0u64.to_le_bytes()); buffer.extend_from_slice(unsigned_varint::encode::u64(
buffer[19..21].copy_from_slice(&8u16.to_le_bytes());
buffer[21..23].copy_from_slice(&4u16.to_le_bytes());
len = 23;
len += unsigned_varint::encode::u64(
u64(current_pid), u64(current_pid),
(&mut buffer[len..len + 10]).try_into().unwrap(), &mut varint_buf,
) ));
.len(); buffer.push(code);
buffer[len] = code; let len = buffer.len();
len += 1; buffer.resize(len.next_multiple_of(4096), 0);
send_ipc_to(usize(proc_man_pid), buffer, len); let buffer = buffer.into_boxed_slice();
#[expect(
clippy::expect_used,
reason = "The tasking code in the kernel and proc_man CANNOT lose sync. Failure to communicate is fatal."
)]
send_ipc_to(usize(proc_man_pid), buffer, len)
.expect("Failed to send exit message to proc_man");
} else { } else {
println!( println!(
"[TASKING] No process manager when PID {} exited with code {code}", "[TASKING] No process manager when PID {} exited with code {code}",
@ -309,25 +321,26 @@ impl Tasking {
if let Some(next_process_pid) = next_process_pid { if let Some(next_process_pid) = next_process_pid {
self.wfi_loop.store(false, Ordering::Relaxed); self.wfi_loop.store(false, Ordering::Relaxed);
#[warn(clippy::indexing_slicing, reason = "FIXME(?)")] #[warn(clippy::indexing_slicing, reason = "FIXME(?)")]
let mut processes = self.processes.write(); if self.current_pid.read().is_some() {
if let Some(current_pid) = *self.current_pid.read() { self.current_process(|process| {
*processes[current_pid].sleeping.write() = Some(SleepReason::Exited); *process.sleeping.write() = Some(SleepReason::Exited);
});
} }
#[warn(clippy::indexing_slicing, reason = "FIXME(?)")]
let next_process = &mut processes[next_process_pid];
#[expect(
clippy::expect_used,
reason = "This expect checks a critical invariant. If this fails, the kernel MUST panic"
)]
next_process
.address_space
.take()
.expect("Non-current process has active page table")
.activate();
gdt::set_tss_stack(next_process.kernel_esp_top);
let kernel_esp = next_process.kernel_esp;
*self.current_pid.write() = Some(next_process_pid); *self.current_pid.write() = Some(next_process_pid);
core::mem::drop(processes); let kernel_esp = self
.current_process_mut(|process| {
#[expect(
clippy::expect_used,
reason = "This expect checks a critical invariant. If this fails, the kernel MUST panic"
)]
process
.address_space
.take()
.expect("Non-current process has active page table")
.activate();
gdt::set_tss_stack(process.kernel_esp_top);
process.kernel_esp
});
switch_to_asm_exit(kernel_esp); switch_to_asm_exit(kernel_esp);
unreachable!() unreachable!()
} else { } else {
@ -351,67 +364,36 @@ impl Tasking {
Ok(()) Ok(())
} }
pub fn address_spaces_mut<F: FnOnce(&mut Slab<AddressSpace>) -> T, T>(&self, func: F) -> T { pub fn current_process<F: FnOnce(&Process) -> T, T>(&self, func: F) -> T {
let processes = self.processes.read(); let processes = self.processes.read();
#[warn(clippy::unwrap_used, reason = "FIXME")] #[warn(clippy::unwrap_used, reason = "FIXME")]
#[warn(clippy::indexing_slicing, reason = "FIXME(?)")] #[warn(clippy::indexing_slicing, reason = "FIXME(?)")]
let mut aspaces = processes[self.current_pid.read().unwrap()].address_spaces.lock(); func(&processes[self.current_pid().unwrap()])
func(&mut aspaces)
} }
pub fn data_buffers_mut<F: FnOnce(&mut Slab<*mut [u8]>) -> T, T>(&self, func: F) -> T { pub fn current_process_mut<F: FnOnce(&mut Process) -> T, T>(&self, func: F) -> T {
let processes = self.processes.read(); let mut processes = self.processes.write();
#[warn(clippy::unwrap_used, reason = "FIXME")] #[warn(clippy::unwrap_used, reason = "FIXME")]
#[warn(clippy::indexing_slicing, reason = "FIXME(?)")] #[warn(clippy::indexing_slicing, reason = "FIXME(?)")]
let mut dbufs = processes[self.current_pid.read().unwrap()].data_buffers.lock(); func(&mut processes[self.current_pid().unwrap()])
func(&mut dbufs)
} }
pub fn proc_data_buffers_mut<F: FnOnce(&mut Slab<*mut [u8]>) -> T, T>( pub fn process_mut<F: FnOnce(&mut Process) -> T, T>(
&self,
pid: usize,
func: F,
) -> Result<T, InvalidPid> {
let processes = self.processes.read();
let mut dbufs = processes.get(pid).ok_or(InvalidPid)?.data_buffers.lock();
Ok(func(&mut dbufs))
}
pub fn current_message_queue_mut<F: FnOnce(&mut SegQueue<(usize, usize)>) -> T, T>(
&self,
func: F,
) -> T {
let processes = self.processes.read();
#[warn(clippy::unwrap_used, reason = "FIXME")]
#[warn(clippy::indexing_slicing, reason = "FIXME(?)")]
let mut queue = processes[self.current_pid.read().unwrap()].message_queue.lock();
func(&mut queue)
}
pub fn message_queue_mut<F: FnOnce(&mut SegQueue<(usize, usize)>) -> T, T>(
&self,
pid: usize,
func: F,
) -> Result<T, InvalidPid> {
let processes = self.processes.read();
let mut queue = processes.get(pid).ok_or(InvalidPid)?.message_queue.lock();
Ok(func(&mut queue))
}
pub fn address_space_mut<F: FnOnce(Option<&mut AddressSpace>) -> T, T>(
&self, &self,
pid: usize, pid: usize,
func: F, func: F,
) -> Result<T, InvalidPid> { ) -> Result<T, InvalidPid> {
let mut processes = self.processes.write(); let mut processes = self.processes.write();
let aspace = processes.get_mut(pid).ok_or(InvalidPid)?.address_space.as_mut(); #[warn(clippy::unwrap_used, reason = "FIXME")]
Ok(func(aspace)) Ok(func(processes.get_mut(pid).ok_or(InvalidPid)?))
} }
pub fn sleep(&self, reason: SleepReason) { pub fn sleep(&self, reason: SleepReason) {
#[warn(clippy::unwrap_used, reason = "FIXME")] #[warn(clippy::unwrap_used, reason = "FIXME")]
#[warn(clippy::indexing_slicing, reason = "FIXME(?)")] #[warn(clippy::indexing_slicing, reason = "FIXME(?)")]
*self.processes.read()[self.current_pid.read().unwrap()].sleeping.write() = Some(reason); self.current_process(|process| {
*process.sleeping.write() = Some(reason);
});
self.task_yield(); self.task_yield();
} }

View File

@ -45,7 +45,7 @@ impl fmt::Debug for AddressSpace {
} }
} }
#[derive(Debug)] #[derive(Debug, Copy, Clone)]
pub enum PagingError { pub enum PagingError {
RequestInvalid, RequestInvalid,
ParentEntryHugePage, ParentEntryHugePage,
@ -171,6 +171,10 @@ impl<'a> PmemCountingWrapper<'a> {
} }
unsafe impl FrameAllocator<Size4KiB> for PmemCountingWrapper<'_> { unsafe impl FrameAllocator<Size4KiB> for PmemCountingWrapper<'_> {
#[expect(
clippy::arithmetic_side_effects,
reason = "This can never overflow as there are a theoretical maximum of usize::MAX/4096 physical frames."
)]
fn allocate_frame(&mut self) -> Option<PhysFrame> { fn allocate_frame(&mut self) -> Option<PhysFrame> {
if let Some(frame) = self.pmem.allocate_frame() { if let Some(frame) = self.pmem.allocate_frame() {
self.count += 1; self.count += 1;
@ -382,8 +386,13 @@ impl AddressSpace {
PhysFrame::from_start_address_unchecked(PhysAddr::new(0x000F_FFFF_FFFF_F000)) PhysFrame::from_start_address_unchecked(PhysAddr::new(0x000F_FFFF_FFFF_F000))
}; };
self.check_request_valid(page, num_pages)?; self.check_request_valid(page, num_pages)?;
if self.bump_base < page + u64(num_pages) { #[expect(
self.bump_base = page + u64(num_pages); clippy::arithmetic_side_effects,
reason = "check_request_valid guarentees this won't overflow"
)]
let req_end = page + u64(num_pages);
if self.bump_base < req_end {
self.bump_base = req_end;
} }
#[expect( #[expect(
clippy::arithmetic_side_effects, clippy::arithmetic_side_effects,
@ -428,6 +437,10 @@ impl AddressSpace {
&mut pmem_wrap, &mut pmem_wrap,
)? )?
.flush(); .flush();
#[expect(
clippy::arithmetic_side_effects,
reason = "This can never overflow, as there are a theoretical maximum of usize::MAX/4096 frames."
)]
self.record_alloc(pmem_wrap.count * 4096); self.record_alloc(pmem_wrap.count * 4096);
} }
} }
@ -461,14 +474,15 @@ impl AddressSpace {
flags: PageTableFlags, flags: PageTableFlags,
) -> Result<*mut u8, PagingError> { ) -> Result<*mut u8, PagingError> {
self.check_request_valid(page, num_pages)?; self.check_request_valid(page, num_pages)?;
if self.bump_base < page + u64(num_pages) {
self.bump_base = page + u64(num_pages);
}
#[expect( #[expect(
clippy::arithmetic_side_effects, clippy::arithmetic_side_effects,
reason = "check_request_valid guarentees this won't overflow" reason = "check_request_valid guarentees this won't overflow"
)] )]
for page in (PageRange { start: page, end: page + u64(num_pages) }) { let req_end = page + u64(num_pages);
if self.bump_base < req_end {
self.bump_base = req_end;
}
for page in (PageRange { start: page, end: req_end }) {
unsafe { unsafe {
let mut phys_mem = PHYSICAL_MEMORY.lock(); let mut phys_mem = PHYSICAL_MEMORY.lock();
let frame = phys_mem.allocate_frame().ok_or(PagingError::FrameAllocationFailed)?; let frame = phys_mem.allocate_frame().ok_or(PagingError::FrameAllocationFailed)?;
@ -493,6 +507,10 @@ impl AddressSpace {
&mut pmem_wrap, &mut pmem_wrap,
)? )?
.flush(); .flush();
#[expect(
clippy::arithmetic_side_effects,
reason = "This can never overflow, as there are a theoretical maximum of usize::MAX/4096 frames."
)]
self.record_alloc(pmem_wrap.count * 4096); self.record_alloc(pmem_wrap.count * 4096);
} }
} }
@ -532,10 +550,19 @@ impl AddressSpace {
.allocate_frame_range(num_pages) .allocate_frame_range(num_pages)
.ok_or(PagingError::FrameAllocationFailed)?; .ok_or(PagingError::FrameAllocationFailed)?;
let phys_start = frame_range.start.start_address().as_u64(); let phys_start = frame_range.start.start_address().as_u64();
unsafe { let res = unsafe {
self.map_to(page, frame_range.start, num_pages, flags | PageTableFlags::WRITABLE) self.map_to(page, frame_range.start, num_pages, flags | PageTableFlags::WRITABLE)
.map(|ptr| (ptr, phys_start)) .map(|ptr| (ptr, phys_start))?
} };
#[expect(
clippy::arithmetic_side_effects,
reason = "
This can never overflow, as there are a theoretical maximum of usize::MAX/4096 pages,
and check_request_valid makes sure that num_pages is below that max.
"
)]
self.record_alloc(num_pages * 4096);
Ok(res)
} }
/// Maps new virtual pages and returns the starting addresss /// Maps new virtual pages and returns the starting addresss
@ -569,7 +596,6 @@ impl AddressSpace {
// SAFETY: &mut aliasing is prevented by using free physical frames, and uninitialized // SAFETY: &mut aliasing is prevented by using free physical frames, and uninitialized
// values are prevented by using free virtual pages. // values are prevented by using free virtual pages.
let ptr = unsafe { self.map(start_page, num_pages, flags)? }; let ptr = unsafe { self.map(start_page, num_pages, flags)? };
self.record_alloc(num_pages * 4096);
Ok(ptr) Ok(ptr)
} }
@ -586,7 +612,6 @@ impl AddressSpace {
// SAFETY: &mut aliasing is prevented by using free physical frames, and uninitialized // SAFETY: &mut aliasing is prevented by using free physical frames, and uninitialized
// values are prevented by using free virtual pages. // values are prevented by using free virtual pages.
let ptr = unsafe { self.map_cont_phys(start_page, num_pages, flags)? }; let ptr = unsafe { self.map_cont_phys(start_page, num_pages, flags)? };
self.record_alloc(num_pages * 4096);
Ok(ptr) Ok(ptr)
} }
@ -600,7 +625,6 @@ impl AddressSpace {
) -> Result<*mut u8, PagingError> { ) -> Result<*mut u8, PagingError> {
self.check_request_unmapped(page, num_pages)?; self.check_request_unmapped(page, num_pages)?;
let ptr = unsafe { self.map(page, num_pages, flags)? }; let ptr = unsafe { self.map(page, num_pages, flags)? };
self.record_alloc(num_pages * 4096);
Ok(ptr) Ok(ptr)
} }
@ -612,16 +636,16 @@ impl AddressSpace {
num_pages: usize, num_pages: usize,
flags: PageTableFlags, flags: PageTableFlags,
) -> Result<*mut u8, PagingError> { ) -> Result<*mut u8, PagingError> {
self.check_request_valid(page, num_pages)?;
if self.bump_base < page + u64(num_pages) {
self.bump_base = page + u64(num_pages);
}
assert!(!self.alloc_force_user);
#[expect( #[expect(
clippy::arithmetic_side_effects, clippy::arithmetic_side_effects,
reason = "check_request_valid guarentees this won't overflow" reason = "check_request_valid guarentees this won't overflow"
)] )]
for page in (PageRange { start: page, end: page + u64(num_pages) }) { let req_end = page + u64(num_pages);
if self.bump_base < req_end {
self.bump_base = req_end;
}
assert!(!self.alloc_force_user);
for page in (PageRange { start: page, end: req_end }) {
if self.translate_addr(page.start_address()).is_some() { if self.translate_addr(page.start_address()).is_some() {
continue; continue;
} }
@ -645,6 +669,10 @@ impl AddressSpace {
&mut pmem_wrap, &mut pmem_wrap,
)? )?
.flush(); .flush();
#[expect(
clippy::arithmetic_side_effects,
reason = "This can never overflow, as there are a theoretical maximum of usize::MAX/4096 frames."
)]
self.record_alloc(pmem_wrap.count * 4096); self.record_alloc(pmem_wrap.count * 4096);
} }
} }
@ -775,12 +803,25 @@ impl AddressSpace {
}; };
} }
Err(PagingError::PageAllocationFailed) Err(PagingError::PageAllocationFailed)
} else if USER_PAGE_RANGE.end - self.bump_base < u64(num_pages) {
Err(PagingError::PageAllocationFailed)
} else { } else {
let old_base = self.bump_base; #[expect(
self.bump_base += u64(num_pages); clippy::arithmetic_side_effects,
Ok(old_base) reason = "bump_base can never be greater than USER_PAGE_RANGE.end"
)]
let num_pages_free = USER_PAGE_RANGE.end - self.bump_base;
if num_pages_free < u64(num_pages) {
Err(PagingError::PageAllocationFailed)
} else {
let old_base = self.bump_base;
#[expect(
clippy::arithmetic_side_effects,
reason = "bump_base can never be greater than USER_PAGE_RANGE.end, and num_pages can never push it over that due to the check above"
)]
{
self.bump_base += u64(num_pages);
}
Ok(old_base)
}
} }
} }