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

View File

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

View File

@ -1,8 +1,8 @@
use crate::{
bootinfo::BOOTINFO,
print, println,
tasking::SleepReason,
virtual_memory::{ASpaceMutex, AddressSpace, ACTIVE_SPACE, KERNEL_SPACE},
tasking::{InvalidPid, SleepReason},
virtual_memory::{ASpaceMutex, AddressSpace, PagingError, ACTIVE_SPACE, KERNEL_SPACE},
TASKING,
};
use alloc::{boxed::Box, vec::Vec};
@ -64,8 +64,7 @@ extern "x86-interrupt" fn page_fault_handler(
error_code: PageFaultErrorCode,
) {
#[warn(clippy::expect_used, reason = "FIXME")]
let faulting_addr =
Cr2::read().expect("Cannot handle page faults caused by non-canonical addresses");
if let Ok(faulting_addr) = Cr2::read() {
if faulting_addr.p4_index() >= PageTableIndex::new(256)
&& !ACTIVE_SPACE.lock().level_4_table()[faulting_addr.p4_index()]
.flags()
@ -102,6 +101,17 @@ extern "x86-interrupt" fn page_fault_handler(
} else {
println!("page faulted {error_code:#?} at {:#x}\n{stack_frame:#?}", faulting_addr);
}
} else {
if let Some(current_pid) = TASKING.current_pid() {
print!("PID {current_pid} ");
} else {
print!("Kernel init ");
}
println!(
"page faulted {error_code:#?} at non-caonical address {:#x}\n{stack_frame:#?}",
Cr2::read_raw()
);
}
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")]
{
#[expect(
@ -172,43 +205,35 @@ pub fn send_ipc_to(pid: usize, buffer: Box<[u8], &'static ASpaceMutex>, len: usi
]);
}
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 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| {
#[expect(
clippy::unwrap_used,
reason = "ASpaceMutex is guaranteed to only return page-aligned allocations, so the address passed to Page::from_start_address is always valid"
)]
let buf_start_page = Page::from_start_address(VirtAddr::new(u64(buffer.expose_provenance()))).unwrap();
// 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 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)?;
ptr::slice_from_raw_parts_mut::<u8>(
page.start_address().as_mut_ptr(),
buffer.len(),
)
} else {
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();
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 message_queue_mut in the if-let condition"
)]
let new_buffer_key = TASKING.proc_data_buffers_mut(pid, |x| x.insert(dest_buffer)).unwrap();
#[expect(
clippy::unwrap_used,
reason = "The option was already checked at the start of the if-let"
)]
TASKING.message_queue_mut(pid, |x| x.push((new_buffer_key, len))).unwrap();
#[expect(
clippy::unwrap_used,
reason = "The PID is known valid due to using it in message_queue_mut in the if-let condition"
reason = "The PID is known valid due to using it in process_mut above"
)]
TASKING.wake(pid, SleepReason::WaitingForIPC).unwrap();
} else {
println!("irq 1 msg: Bad PID ({})", pid);
}
Ok(())
}
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[8..10].copy_from_slice(&2u16.to_le_bytes());
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>> {
TASKING.data_buffers_mut(|x| {
x.try_remove(usize(id)).map(|buf| unsafe { Box::from_raw_in(buf, &*ACTIVE_SPACE) })
TASKING.current_process(|process| {
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()));
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_len = BOOTINFO.ramdisk_len;
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_num_pages = usize(ramdisk_len.div_ceil(4096));
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
.lock()
.update_flags(
@ -367,12 +416,13 @@ extern "C" fn syscall_handler() {
.map_free(usize(regs.rdx), PageTableFlags::from_bits_truncate(regs.rsi))
.map_or(0, |x| u64(x.expose_provenance()))
} else {
TASKING.address_spaces_mut(|x| {
TASKING.current_process(|process| {
let mut address_spaces = process.address_spaces().lock();
#[warn(
clippy::arithmetic_side_effects,
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_free(usize(regs.rdx), PageTableFlags::from_bits_truncate(regs.rsi))
.map_or(0, |x| u64(x.expose_provenance()))
@ -392,8 +442,10 @@ extern "C" fn syscall_handler() {
clippy::arithmetic_side_effects,
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| {
x.insert(AddressSpace::new().expect("Failed to create address space")) + 1
let address_space = u64(TASKING.current_process(|process| {
let mut address_spaces = process.address_spaces().lock();
address_spaces.insert(AddressSpace::new().expect("Failed to create address space"))
+ 1
}));
retval = address_space;
}
@ -402,7 +454,9 @@ extern "C" fn syscall_handler() {
clippy::arithmetic_side_effects,
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: {
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 {
ACTIVE_SPACE.lock().map_assert_unused(page, num_pages, flags).is_err()
} else {
TASKING.address_spaces_mut(|x| {
TASKING.current_process(|process| {
let mut address_spaces = process.address_spaces().lock();
#[warn(
clippy::arithmetic_side_effects,
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()
} else {
true
@ -432,12 +487,13 @@ extern "C" fn syscall_handler() {
if let Some(buffer) = get_buffer(regs.rdx) {
let len = usize(regs.rdi);
assert!(len <= buffer.len());
TASKING.address_spaces_mut(|x| {
let err = TASKING.current_process(|process| {
let mut address_spaces = process.address_spaces().lock();
#[warn(
clippy::arithmetic_side_effects,
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_raw = Box::into_raw(buffer);
let page = ACTIVE_SPACE
@ -445,22 +501,24 @@ extern "C" fn syscall_handler() {
.move_mappings_free(
Page::from_start_address(VirtAddr::new(u64(
buffer_raw.expose_provenance()
)))
.unwrap(),
))).map_err(|_| ())?,
buffer_num_pages,
space,
)
.unwrap();
).map_err(|_| ())?;
space.run(|| unsafe {
(ptr::with_exposed_provenance_mut::<u8>(usize(regs.rsi)))
.copy_from(page.start_address().as_mut_ptr::<u8>(), len);
});
space.unmap(page, buffer_num_pages).unwrap();
retval = 0;
space.unmap(page, buffer_num_pages).map_err(|_| ())?;
Ok(())
} else {
retval = 1;
Err(())
}
}).is_err();
#[expect(clippy::as_conversions, reason = "Needed to convert bool to u64")]
{
retval = err as u64;
}
});
} else {
retval = 1;
}
@ -470,7 +528,9 @@ extern "C" fn syscall_handler() {
clippy::arithmetic_side_effects,
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);
if let Ok(pid) = res {
retval = 0;
@ -500,26 +560,29 @@ extern "C" fn syscall_handler() {
if let Some(buffer) = get_buffer(regs.rdx) {
let len = usize(regs.rsi);
assert!(len <= buffer.len());
if TASKING.message_queue_mut(pid, |_| ()).is_ok() {
send_ipc_to(pid, buffer, len);
retval = 0;
} else {
println!("ipc_send: Bad PID ({})", pid);
match send_ipc_to(pid, buffer, len) {
Ok(()) => retval = 0,
Err(e) => {
println!("ipc_send: Error {e:?}");
retval = 1;
}
}
} else {
println!("ipc_send: Bad buffer ({})", regs.rdx);
retval = 1;
}
}
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(
clippy::unwrap_used,
reason = "The message queue only contains valid buffer IDs"
)]
let buffer_addr =
u64(TASKING.data_buffers_mut(|x| *x.get(msg.0).unwrap()).expose_provenance());
let buffer_addr = u64(TASKING
.current_process(|process| *process.data_buffers().lock().get(msg.0).unwrap())
.expose_provenance());
retval2 = u64(msg.1);
retval = buffer_addr;
retval3 = u64(msg.0);
@ -545,12 +608,13 @@ extern "C" fn syscall_handler() {
let failed = if regs.rcx == 0 {
ACTIVE_SPACE.lock().map_only_unused(page, num_pages, flags).is_err()
} else {
TASKING.address_spaces_mut(|x| {
TASKING.current_process(|process| {
let mut address_spaces = process.address_spaces().lock();
#[warn(
clippy::arithmetic_side_effects,
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()
} else {
true
@ -569,7 +633,9 @@ extern "C" fn syscall_handler() {
buffer.resize(rounded_size, 0);
let buffer = buffer.into_boxed_slice();
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());
retval3 = u64(rounded_size);
}
@ -579,45 +645,56 @@ extern "C" fn syscall_handler() {
clippy::arithmetic_side_effects,
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 space = x.get_mut(usize(regs.rcx - 1)).expect("Invalid address space");
let err = TASKING
.current_process(|process| {
let mut address_spaces = process.address_spaces().lock();
let space = address_spaces.get_mut(usize(regs.rcx - 1)).ok_or(())?;
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 => {
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);
}
}
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 {
unsafe {
ACTIVE_SPACE
.lock()
.map_free_to(
PhysFrame::from_start_address(PhysAddr::new(regs.rdx)).unwrap(),
frame,
usize(regs.rsi),
PageTableFlags::from_bits_truncate(regs.rdi),
)
.map_or(0, |x| u64(x.expose_provenance()))
}
} else {
TASKING.address_spaces_mut(|x| {
TASKING.current_process(|process| {
let mut address_spaces = process.address_spaces().lock();
#[warn(
clippy::arithmetic_side_effects,
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 {
space
.map_free_to(
PhysFrame::from_start_address(PhysAddr::new(regs.rdx)).unwrap(),
frame,
usize(regs.rsi),
PageTableFlags::from_bits_truncate(regs.rdi),
)
@ -641,12 +718,13 @@ extern "C" fn syscall_handler() {
retval2 = start_phys;
start_virt
} else {
TASKING.address_spaces_mut(|x| {
TASKING.current_process(|process| {
let mut address_spaces = process.address_spaces().lock();
#[warn(
clippy::arithmetic_side_effects,
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
.map_free_cont_phys(
usize(regs.rdx),
@ -671,12 +749,13 @@ extern "C" fn syscall_handler() {
retval = if regs.rcx == 0 {
u64::from(ACTIVE_SPACE.lock().unmap(page, usize(regs.rsi)).is_err())
} else {
TASKING.address_spaces_mut(|x| {
TASKING.current_process(|process| {
let mut address_spaces = process.address_spaces().lock();
#[warn(
clippy::arithmetic_side_effects,
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())
} else {
1
@ -687,7 +766,17 @@ extern "C" fn syscall_handler() {
23 => {
let irq_num = regs.rcx;
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;
} else {
retval = 1;

View File

@ -96,28 +96,33 @@ impl FrameDeallocator<Size4KiB> for PhysicalMemory {
impl PhysicalMemory {
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 {
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.")]
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::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(
(u64(ptr.as_ptr().expose_provenance())) - PHYS_OFFSET.as_u64(),
))
.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 = "All addresses passed to the allocator are > PHYS_OFFSET, so this cannot underflow")]
let end = PhysFrame::from_start_address(PhysAddr::new(
(u64(ptr.as_ptr().expose_provenance()) + (u64(len) * 4096)) - PHYS_OFFSET.as_u64(),
))
.unwrap();
#[expect(clippy::arithmetic_side_effects, reason = "
The pointer returned by the allocator is guaranteed to be a pointer to a contiguous block of len frames,
so this could only overflow if the range included the last physical frame. But since the allocator gets
passed regions from PhysFrameRanges, which can't include the last frame without overflow, that can't
happen and thus this can't overflow.
")]
let end = start + u64(len);
PhysFrameRange {
start,
end

View File

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

View File

@ -45,7 +45,7 @@ impl fmt::Debug for AddressSpace {
}
}
#[derive(Debug)]
#[derive(Debug, Copy, Clone)]
pub enum PagingError {
RequestInvalid,
ParentEntryHugePage,
@ -171,6 +171,10 @@ impl<'a> PmemCountingWrapper<'a> {
}
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> {
if let Some(frame) = self.pmem.allocate_frame() {
self.count += 1;
@ -382,8 +386,13 @@ impl AddressSpace {
PhysFrame::from_start_address_unchecked(PhysAddr::new(0x000F_FFFF_FFFF_F000))
};
self.check_request_valid(page, num_pages)?;
if self.bump_base < page + u64(num_pages) {
self.bump_base = page + u64(num_pages);
#[expect(
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(
clippy::arithmetic_side_effects,
@ -428,6 +437,10 @@ impl AddressSpace {
&mut pmem_wrap,
)?
.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);
}
}
@ -461,14 +474,15 @@ impl AddressSpace {
flags: PageTableFlags,
) -> 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);
}
#[expect(
clippy::arithmetic_side_effects,
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 {
let mut phys_mem = PHYSICAL_MEMORY.lock();
let frame = phys_mem.allocate_frame().ok_or(PagingError::FrameAllocationFailed)?;
@ -493,6 +507,10 @@ impl AddressSpace {
&mut pmem_wrap,
)?
.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);
}
}
@ -532,10 +550,19 @@ impl AddressSpace {
.allocate_frame_range(num_pages)
.ok_or(PagingError::FrameAllocationFailed)?;
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)
.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
@ -569,7 +596,6 @@ impl AddressSpace {
// SAFETY: &mut aliasing is prevented by using free physical frames, and uninitialized
// values are prevented by using free virtual pages.
let ptr = unsafe { self.map(start_page, num_pages, flags)? };
self.record_alloc(num_pages * 4096);
Ok(ptr)
}
@ -586,7 +612,6 @@ impl AddressSpace {
// SAFETY: &mut aliasing is prevented by using free physical frames, and uninitialized
// values are prevented by using free virtual pages.
let ptr = unsafe { self.map_cont_phys(start_page, num_pages, flags)? };
self.record_alloc(num_pages * 4096);
Ok(ptr)
}
@ -600,7 +625,6 @@ impl AddressSpace {
) -> Result<*mut u8, PagingError> {
self.check_request_unmapped(page, num_pages)?;
let ptr = unsafe { self.map(page, num_pages, flags)? };
self.record_alloc(num_pages * 4096);
Ok(ptr)
}
@ -612,16 +636,16 @@ impl AddressSpace {
num_pages: usize,
flags: PageTableFlags,
) -> 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(
clippy::arithmetic_side_effects,
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() {
continue;
}
@ -645,6 +669,10 @@ impl AddressSpace {
&mut pmem_wrap,
)?
.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);
}
}
@ -775,14 +803,27 @@ impl AddressSpace {
};
}
Err(PagingError::PageAllocationFailed)
} else if USER_PAGE_RANGE.end - self.bump_base < u64(num_pages) {
} else {
#[expect(
clippy::arithmetic_side_effects,
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)
}
}
}
pub fn record_alloc(&self, size: usize) {
self.bytes_allocated.fetch_add(size, Ordering::Relaxed);