Clean up code and fix unwrap/expect lints
This commit is contained in:
parent
f0c6432740
commit
ea4d9a7784
49
Cargo.lock
generated
49
Cargo.lock
generated
@ -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",
|
||||
]
|
||||
|
@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-11-21"
|
||||
|
@ -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,43 +64,53 @@ 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 faulting_addr.p4_index() >= PageTableIndex::new(256)
|
||||
&& !ACTIVE_SPACE.lock().level_4_table()[faulting_addr.p4_index()]
|
||||
.flags()
|
||||
.contains(PageTableFlags::PRESENT)
|
||||
&& KERNEL_SPACE.lock().level_4_table()[faulting_addr.p4_index()]
|
||||
.flags()
|
||||
.contains(PageTableFlags::PRESENT)
|
||||
{
|
||||
ACTIVE_SPACE.lock().level_4_table_mut()[faulting_addr.p4_index()] =
|
||||
KERNEL_SPACE.lock().level_4_table()[faulting_addr.p4_index()].clone();
|
||||
return;
|
||||
}
|
||||
if let Some(current_pid) = TASKING.current_pid() {
|
||||
print!("PID {current_pid} ");
|
||||
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()
|
||||
.contains(PageTableFlags::PRESENT)
|
||||
&& KERNEL_SPACE.lock().level_4_table()[faulting_addr.p4_index()]
|
||||
.flags()
|
||||
.contains(PageTableFlags::PRESENT)
|
||||
{
|
||||
ACTIVE_SPACE.lock().level_4_table_mut()[faulting_addr.p4_index()] =
|
||||
KERNEL_SPACE.lock().level_4_table()[faulting_addr.p4_index()].clone();
|
||||
return;
|
||||
}
|
||||
if let Some(current_pid) = TASKING.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 {
|
||||
print!("Kernel init ");
|
||||
}
|
||||
if error_code.contains(PageFaultErrorCode::PROTECTION_VIOLATION) {
|
||||
if let Some(current_pid) = TASKING.current_pid() {
|
||||
print!("PID {current_pid} ");
|
||||
} else {
|
||||
print!("Kernel init ");
|
||||
}
|
||||
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!();
|
||||
}
|
||||
},
|
||||
"page faulted {error_code:#?} at non-caonical address {:#x}\n{stack_frame:#?}",
|
||||
Cr2::read_raw()
|
||||
);
|
||||
} else {
|
||||
println!("page faulted {error_code:#?} at {:#x}\n{stack_frame:#?}", faulting_addr);
|
||||
}
|
||||
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| {
|
||||
// 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(
|
||||
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();
|
||||
#[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"
|
||||
)]
|
||||
TASKING.wake(pid, SleepReason::WaitingForIPC).unwrap();
|
||||
} else {
|
||||
println!("irq 1 msg: Bad PID ({})", pid);
|
||||
}
|
||||
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 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 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>) {
|
||||
@ -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,35 +487,38 @@ 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)) {
|
||||
let buffer_num_pages = buffer.len() / 4096;
|
||||
let buffer_raw = Box::into_raw(buffer);
|
||||
let page = ACTIVE_SPACE
|
||||
.lock()
|
||||
.move_mappings_free(
|
||||
Page::from_start_address(VirtAddr::new(u64(
|
||||
buffer_raw.expose_provenance()
|
||||
)))
|
||||
.unwrap(),
|
||||
buffer_num_pages,
|
||||
space,
|
||||
)
|
||||
.unwrap();
|
||||
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
|
||||
.lock()
|
||||
.move_mappings_free(
|
||||
Page::from_start_address(VirtAddr::new(u64(
|
||||
buffer_raw.expose_provenance()
|
||||
))).map_err(|_| ())?,
|
||||
buffer_num_pages,
|
||||
space,
|
||||
).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,12 +560,12 @@ 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);
|
||||
retval = 1;
|
||||
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);
|
||||
@ -513,13 +573,16 @@ extern "C" fn syscall_handler() {
|
||||
}
|
||||
}
|
||||
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 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;
|
||||
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);
|
||||
});
|
||||
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;
|
||||
|
@ -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
|
||||
|
260
src/tasking.rs
260
src/tasking.rs
@ -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;
|
||||
}
|
||||
#[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]
|
||||
.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() {
|
||||
#[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"
|
||||
)]
|
||||
process
|
||||
.address_space
|
||||
.take()
|
||||
.expect("Non-current process has active page table")
|
||||
.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];
|
||||
#[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);
|
||||
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);
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -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,12 +803,25 @@ impl AddressSpace {
|
||||
};
|
||||
}
|
||||
Err(PagingError::PageAllocationFailed)
|
||||
} else if USER_PAGE_RANGE.end - self.bump_base < u64(num_pages) {
|
||||
Err(PagingError::PageAllocationFailed)
|
||||
} else {
|
||||
let old_base = self.bump_base;
|
||||
self.bump_base += u64(num_pages);
|
||||
Ok(old_base)
|
||||
#[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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user