694 lines
27 KiB
Rust
694 lines
27 KiB
Rust
use crate::{
|
|
bootinfo::BOOTINFO,
|
|
print, println,
|
|
serial::SECOND_PORT,
|
|
tasking::SleepReason,
|
|
virtual_memory::{ASpaceMutex, AddressSpace, ACTIVE_SPACE, KERNEL_SPACE},
|
|
TASKING,
|
|
};
|
|
use alloc::{boxed::Box, vec::Vec};
|
|
use az::WrappingCast;
|
|
use cast::{u64, usize};
|
|
use core::{arch::asm, ffi::CStr, ptr, slice};
|
|
use hashbrown::HashMap;
|
|
use pic8259::ChainedPics;
|
|
use saturating_cast::SaturatingCast;
|
|
use spin::{Lazy, Mutex, RwLock};
|
|
use tap::Tap;
|
|
use x86_64::{
|
|
registers::control::Cr2,
|
|
set_general_handler,
|
|
structures::{
|
|
idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
|
|
paging::{mapper::TranslateResult, Page, PageTableFlags, PhysFrame, Translate},
|
|
},
|
|
PhysAddr, PrivilegeLevel, VirtAddr,
|
|
};
|
|
|
|
const IRQ_BASE: u8 = 32;
|
|
|
|
static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
|
|
let mut idt = InterruptDescriptorTable::new();
|
|
set_general_handler!(&mut idt, general_handler);
|
|
set_general_handler!(&mut idt, exc_handler, 0..32);
|
|
set_general_handler!(&mut idt, irq_handler, 32..48);
|
|
idt[0x80].set_handler_fn(syscall_handler_header).set_privilege_level(PrivilegeLevel::Ring3);
|
|
idt.page_fault.set_handler_fn(page_fault_handler);
|
|
idt
|
|
});
|
|
static PICS: Mutex<ChainedPics> = Mutex::new(unsafe { ChainedPics::new(IRQ_BASE, IRQ_BASE + 8) });
|
|
static IRQ_HANDLERS: RwLock<[Option<IrqHandler>; 16]> = RwLock::new([None; 16]);
|
|
|
|
pub type IrqHandler = fn(irq_num: u8, eoi_guard: EoiGuard);
|
|
|
|
#[derive(Debug)]
|
|
pub struct InvalidIrq;
|
|
|
|
pub fn init() {
|
|
IDT.load();
|
|
unsafe { PICS.lock().initialize() };
|
|
unsafe { PICS.lock().write_masks(0, 0) };
|
|
x86_64::instructions::interrupts::enable();
|
|
}
|
|
|
|
extern "x86-interrupt" fn page_fault_handler(
|
|
stack_frame: InterruptStackFrame,
|
|
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 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);
|
|
}
|
|
TASKING.exit();
|
|
}
|
|
|
|
#[expect(clippy::needless_pass_by_value, reason = "Signature dictated by external crate")]
|
|
fn general_handler(stack_frame: InterruptStackFrame, index: u8, _error_code: Option<u64>) {
|
|
println!("Other interrupt {index}\n{stack_frame:#?}");
|
|
}
|
|
|
|
#[expect(clippy::needless_pass_by_value, reason = "Signature dictated by external crate")]
|
|
fn exc_handler(_stack_frame: InterruptStackFrame, _index: u8, _error_code: Option<u64>) {
|
|
if let Some(current_pid) = TASKING.current_pid() {
|
|
print!("PID {current_pid} ");
|
|
} else {
|
|
print!("Kernel init ");
|
|
}
|
|
println!("had exception, exiting");
|
|
TASKING.exit();
|
|
}
|
|
|
|
pub struct EoiGuard(u8);
|
|
|
|
impl Drop for EoiGuard {
|
|
fn drop(&mut self) {
|
|
unsafe {
|
|
PICS.lock().notify_end_of_interrupt(self.0);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[expect(clippy::needless_pass_by_value, reason = "Signature dictated by external crate")]
|
|
fn irq_handler(_stack_frame: InterruptStackFrame, index: u8, _error_code: Option<u64>) {
|
|
#[expect(
|
|
clippy::arithmetic_side_effects,
|
|
reason = "This function is only called for irqs, which are always above the base index."
|
|
)]
|
|
let irq_num = index - IRQ_BASE;
|
|
let eoi_guard = EoiGuard(index);
|
|
#[expect(
|
|
clippy::indexing_slicing,
|
|
reason = "This function is only called for 16 irqs, which are all valid indexes"
|
|
)]
|
|
if let Some(handler) = IRQ_HANDLERS.read()[usize(irq_num)] {
|
|
handler(irq_num, eoi_guard);
|
|
};
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Debug, Clone, Copy)]
|
|
struct SyscallRegs {
|
|
rax: u64,
|
|
rbx: u64,
|
|
rcx: u64,
|
|
rdx: u64,
|
|
rsi: u64,
|
|
rdi: u64,
|
|
rsp: u64,
|
|
rbp: u64,
|
|
r8: u64,
|
|
r9: u64,
|
|
r10: u64,
|
|
r11: u64,
|
|
r12: u64,
|
|
r13: u64,
|
|
r14: u64,
|
|
r15: u64,
|
|
}
|
|
|
|
#[no_mangle]
|
|
static mut SYSCALL_REGS: SyscallRegs = SyscallRegs {
|
|
rax: 0,
|
|
rbx: 0,
|
|
rcx: 0,
|
|
rdx: 0,
|
|
rsi: 0,
|
|
rdi: 0,
|
|
rsp: 0,
|
|
rbp: 0,
|
|
r8: 0,
|
|
r9: 0,
|
|
r10: 0,
|
|
r11: 0,
|
|
r12: 0,
|
|
r13: 0,
|
|
r14: 0,
|
|
r15: 0,
|
|
};
|
|
|
|
#[naked]
|
|
extern "x86-interrupt" fn syscall_handler_header(stack_frame: InterruptStackFrame) {
|
|
unsafe {
|
|
asm!(
|
|
"mov [rip+SYSCALL_REGS], rax",
|
|
"mov [rip+SYSCALL_REGS+8], rbx",
|
|
"mov [rip+SYSCALL_REGS+16], rcx",
|
|
"mov [rip+SYSCALL_REGS+24], rdx",
|
|
"mov [rip+SYSCALL_REGS+32], rsi",
|
|
"mov [rip+SYSCALL_REGS+40], rdi",
|
|
"mov [rip+SYSCALL_REGS+48], rsp",
|
|
"mov [rip+SYSCALL_REGS+56], rbp",
|
|
"mov [rip+SYSCALL_REGS+64], r8",
|
|
"mov [rip+SYSCALL_REGS+72], r9",
|
|
"mov [rip+SYSCALL_REGS+80], r10",
|
|
"mov [rip+SYSCALL_REGS+88], r11",
|
|
"mov [rip+SYSCALL_REGS+96], r12",
|
|
"mov [rip+SYSCALL_REGS+104], r13",
|
|
"mov [rip+SYSCALL_REGS+112], r14",
|
|
"mov [rip+SYSCALL_REGS+120], r15",
|
|
"jmp syscall_handler",
|
|
options(noreturn)
|
|
)
|
|
}
|
|
}
|
|
|
|
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) })
|
|
})
|
|
}
|
|
|
|
static REGISTERD_PIDS: Lazy<RwLock<HashMap<u64, u64>>> = Lazy::new(|| RwLock::new(HashMap::new()));
|
|
|
|
static INITRD_BUF: Lazy<&'static [u8]> = Lazy::new(|| {
|
|
let initrd = unsafe {
|
|
#[warn(clippy::expect_used, reason = "FIXME")]
|
|
let ramdisk_start = BOOTINFO.ramdisk_addr.into_option().expect("initrd not present");
|
|
let ramdisk_len = BOOTINFO.ramdisk_len;
|
|
slice::from_raw_parts(
|
|
ptr::with_exposed_provenance::<u8>(usize(ramdisk_start)),
|
|
usize(ramdisk_len),
|
|
)
|
|
};
|
|
KERNEL_SPACE.lock().alloc_force_user = true;
|
|
let initrd = Box::leak(
|
|
Vec::with_capacity_in(initrd.len(), &*KERNEL_SPACE)
|
|
.tap_mut(|v| v.extend_from_slice(initrd))
|
|
.into_boxed_slice(),
|
|
);
|
|
KERNEL_SPACE.lock().alloc_force_user = false;
|
|
initrd
|
|
});
|
|
|
|
#[no_mangle]
|
|
extern "C" fn syscall_handler() {
|
|
let regs = unsafe { SYSCALL_REGS };
|
|
let mut retval = 0;
|
|
let mut retval2 = regs.rcx;
|
|
let mut retval3 = regs.rdx;
|
|
match regs.rax {
|
|
0 => {
|
|
let rval = if let Some(chr) = char::from_u32(regs.rcx.wrapping_cast()) {
|
|
if chr == '\n' {
|
|
print!("\r\n");
|
|
} else {
|
|
print!("{}", chr);
|
|
}
|
|
0
|
|
} else {
|
|
1
|
|
};
|
|
retval = rval;
|
|
}
|
|
1 => TASKING.exit(),
|
|
2 => {
|
|
retval = if regs.rcx == 0 {
|
|
ACTIVE_SPACE
|
|
.lock()
|
|
.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| {
|
|
#[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)) {
|
|
space
|
|
.map_free(usize(regs.rdx), PageTableFlags::from_bits_truncate(regs.rsi))
|
|
.map_or(0, |x| u64(x.expose_provenance()))
|
|
} else {
|
|
0
|
|
}
|
|
})
|
|
};
|
|
}
|
|
3 => {
|
|
retval = u64(INITRD_BUF.as_ptr().expose_provenance());
|
|
retval2 = u64(INITRD_BUF.len());
|
|
}
|
|
4 => {
|
|
#[warn(clippy::expect_used, reason = "FIXME")]
|
|
#[expect(
|
|
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
|
|
}));
|
|
retval = address_space;
|
|
}
|
|
5 => {
|
|
#[warn(
|
|
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)));
|
|
}
|
|
6 => 'call6: {
|
|
let Ok(page) = Page::from_start_address(VirtAddr::new(regs.rdx)) else {
|
|
retval = 1;
|
|
break 'call6;
|
|
};
|
|
let num_pages = usize(regs.rsi);
|
|
let flags = PageTableFlags::from_bits_truncate(regs.rdi);
|
|
let failed = if regs.rcx == 0 {
|
|
ACTIVE_SPACE.lock().map_assert_unused(page, num_pages, flags).is_err()
|
|
} else {
|
|
TASKING.address_spaces_mut(|x| {
|
|
#[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)) {
|
|
space.map_assert_unused(page, num_pages, flags).is_err()
|
|
} else {
|
|
true
|
|
}
|
|
})
|
|
};
|
|
retval = failed.into();
|
|
}
|
|
7 => {
|
|
if let Some(mut buffer) = get_buffer(regs.rdx) {
|
|
let len = usize(regs.rdi);
|
|
assert!(len <= buffer.len());
|
|
TASKING.address_spaces_mut(|x| {
|
|
#[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();
|
|
space.run(|| unsafe {
|
|
(ptr::with_exposed_provenance_mut::<u8>(usize(regs.rsi)))
|
|
.copy_from(page.start_address().as_mut_ptr::<u8>(), len);
|
|
});
|
|
space.unmap_and_free(page, buffer_num_pages).unwrap();
|
|
retval = 0;
|
|
} else {
|
|
retval = 1;
|
|
}
|
|
});
|
|
} else {
|
|
retval = 1;
|
|
}
|
|
}
|
|
8 => {
|
|
let args = unsafe {
|
|
let argc = usize(regs.rsi);
|
|
let argv: &[&[u8]] =
|
|
slice::from_raw_parts(ptr::with_exposed_provenance(usize(regs.rdi)), argc);
|
|
argv.iter().map(|arg| CStr::from_bytes_with_nul_unchecked(arg)).collect::<Vec<_>>()
|
|
};
|
|
#[warn(
|
|
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 res = TASKING.new_process(
|
|
ptr::with_exposed_provenance(usize(regs.rcx)),
|
|
space,
|
|
args.as_slice(),
|
|
);
|
|
if let Ok(pid) = res {
|
|
retval = 0;
|
|
retval2 = u64(pid);
|
|
} else {
|
|
retval = 1;
|
|
}
|
|
}
|
|
9 => {
|
|
#[expect(
|
|
clippy::unwrap_used,
|
|
reason = "Syscalls cannot be called during early boot, the only time when there is no current PID"
|
|
)]
|
|
REGISTERD_PIDS.write().insert(regs.rcx, u64(TASKING.current_pid().unwrap()));
|
|
}
|
|
10 => {
|
|
let id = REGISTERD_PIDS.read().get(®s.rcx).copied();
|
|
if let Some(id) = id {
|
|
retval = 0;
|
|
retval2 = id;
|
|
} else {
|
|
retval = 1;
|
|
}
|
|
}
|
|
11 => {
|
|
let pid = usize(regs.rcx);
|
|
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() {
|
|
#[expect(
|
|
clippy::unwrap_used,
|
|
reason = "The min call guarantees that the value is in the range of a u32 before the cast"
|
|
)]
|
|
let trunc_len: u32 = usize::min(len, 4096).try_into().unwrap();
|
|
#[expect(
|
|
clippy::arithmetic_side_effects,
|
|
reason = "Can't underflow, as x % 4 < 4 no matter the x"
|
|
)]
|
|
let padding = if (trunc_len % 4) != 0 { 4 - (trunc_len % 4) } else { 0 };
|
|
#[expect(
|
|
clippy::arithmetic_side_effects,
|
|
reason = "Can't overflow, as padding is no more than 4 and trunc_len is no more than 4096."
|
|
)]
|
|
let padded_len = trunc_len + padding;
|
|
#[expect(
|
|
clippy::arithmetic_side_effects,
|
|
reason = "Can't overflow, as padded_len is no more than 4096 and 4096+24 < u32::MAX"
|
|
)]
|
|
let total_len = padded_len + 8 + (4 * 4);
|
|
SECOND_PORT.write_u32s(&[
|
|
0x3, // SPB type
|
|
total_len, // Total block length
|
|
len.saturating_cast::<u32>().saturating_add(8), // Packet length
|
|
]);
|
|
SECOND_PORT.write_bytes(&pid.to_ne_bytes());
|
|
#[expect(
|
|
clippy::indexing_slicing,
|
|
reason = "The truncated length is always <= the buffer's length"
|
|
)]
|
|
SECOND_PORT.write_bytes(&buffer[0..usize(trunc_len)]);
|
|
for _ in 0..padding {
|
|
SECOND_PORT.write_bytes(&[0]);
|
|
}
|
|
SECOND_PORT.write_u32s(&[
|
|
total_len, // Total block length
|
|
]);
|
|
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 retyurn 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"
|
|
)]
|
|
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"
|
|
)]
|
|
let sleep_status = TASKING.proc_sleeping(pid).unwrap();
|
|
if sleep_status == Some(SleepReason::WaitingForIPC) {
|
|
#[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).unwrap();
|
|
}
|
|
retval = 0;
|
|
} else {
|
|
println!("ipc_send: Bad PID ({})", pid);
|
|
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()) {
|
|
#[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());
|
|
retval2 = u64(msg.1);
|
|
retval = buffer_addr;
|
|
retval3 = u64(msg.0);
|
|
} else {
|
|
retval = 0;
|
|
}
|
|
}
|
|
13 => {
|
|
#[expect(
|
|
clippy::unwrap_used,
|
|
reason = "Syscalls cannot be called during early boot, the only time when there is no current PID"
|
|
)]
|
|
let pid = u64(TASKING.current_pid().unwrap());
|
|
retval = pid;
|
|
}
|
|
14 => 'call14: {
|
|
let Ok(page) = Page::from_start_address(VirtAddr::new(regs.rdx)) else {
|
|
retval = 1;
|
|
break 'call14;
|
|
};
|
|
let num_pages = usize(regs.rsi);
|
|
let flags = PageTableFlags::from_bits_truncate(regs.rdi);
|
|
let failed = if regs.rcx == 0 {
|
|
ACTIVE_SPACE.lock().map_only_unused(page, num_pages, flags).is_err()
|
|
} else {
|
|
TASKING.address_spaces_mut(|x| {
|
|
#[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)) {
|
|
space.map_only_unused(page, num_pages, flags).is_err()
|
|
} else {
|
|
true
|
|
}
|
|
})
|
|
};
|
|
retval = failed.into();
|
|
}
|
|
15 => {
|
|
get_buffer(regs.rcx);
|
|
}
|
|
16 => {
|
|
let size = usize(regs.rcx);
|
|
let rounded_size = size.next_multiple_of(4096);
|
|
let mut buffer = Vec::with_capacity_in(rounded_size, &*ACTIVE_SPACE);
|
|
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)));
|
|
retval2 = u64(buffer.cast::<u8>().expose_provenance());
|
|
retval3 = u64(rounded_size);
|
|
}
|
|
17 => {
|
|
#[warn(clippy::expect_used, reason = "FIXME")]
|
|
#[warn(
|
|
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;
|
|
}
|
|
18 => {
|
|
if TASKING.current_message_queue_mut(|x| x.is_empty()) {
|
|
TASKING.sleep(SleepReason::WaitingForIPC);
|
|
}
|
|
}
|
|
19 => {
|
|
let args = TASKING.arguments();
|
|
retval = u64(args.0.expose_provenance());
|
|
retval2 = u64(args.1);
|
|
}
|
|
20 => {
|
|
retval = if regs.rcx == 0 {
|
|
unsafe {
|
|
ACTIVE_SPACE
|
|
.lock()
|
|
.map_free_to(
|
|
PhysFrame::from_start_address(PhysAddr::new(regs.rdx)).unwrap(),
|
|
usize(regs.rsi),
|
|
PageTableFlags::from_bits_truncate(regs.rdi),
|
|
)
|
|
.map_or(0, |x| u64(x.expose_provenance()))
|
|
}
|
|
} else {
|
|
TASKING.address_spaces_mut(|x| {
|
|
#[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)) {
|
|
unsafe {
|
|
space
|
|
.map_free_to(
|
|
PhysFrame::from_start_address(PhysAddr::new(regs.rdx)).unwrap(),
|
|
usize(regs.rsi),
|
|
PageTableFlags::from_bits_truncate(regs.rdi),
|
|
)
|
|
.map_or(0, |x| u64(x.expose_provenance()))
|
|
}
|
|
} else {
|
|
0
|
|
}
|
|
})
|
|
}
|
|
}
|
|
21 => {
|
|
retval = if regs.rcx == 0 {
|
|
let (start_virt, start_phys) = ACTIVE_SPACE
|
|
.lock()
|
|
.map_free_cont_phys(
|
|
usize(regs.rdx),
|
|
PageTableFlags::from_bits_truncate(regs.rsi),
|
|
)
|
|
.map_or((0, 0), |(ptr, start_phys)| (u64(ptr.expose_provenance()), start_phys));
|
|
retval2 = start_phys;
|
|
start_virt
|
|
} else {
|
|
TASKING.address_spaces_mut(|x| {
|
|
#[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 (start_virt, start_phys) = space
|
|
.map_free_cont_phys(
|
|
usize(regs.rdx),
|
|
PageTableFlags::from_bits_truncate(regs.rsi),
|
|
)
|
|
.map_or((0, 0), |(ptr, start_phys)| {
|
|
(u64(ptr.expose_provenance()), start_phys)
|
|
});
|
|
retval2 = start_phys;
|
|
start_virt
|
|
} else {
|
|
0
|
|
}
|
|
})
|
|
};
|
|
}
|
|
22 => 'call22: {
|
|
let Ok(page) = Page::from_start_address(VirtAddr::new(regs.rdx)) else {
|
|
retval = 1;
|
|
break 'call22;
|
|
};
|
|
retval = if regs.rcx == 0 {
|
|
u64::from(ACTIVE_SPACE.lock().unmap_and_free(page, usize(regs.rsi)).is_err())
|
|
} else {
|
|
TASKING.address_spaces_mut(|x| {
|
|
#[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)) {
|
|
u64::from(space.unmap_and_free(page, usize(regs.rsi)).is_err())
|
|
} else {
|
|
1
|
|
}
|
|
})
|
|
}
|
|
}
|
|
_ => (),
|
|
};
|
|
unsafe { SYSCALL_REGS = regs };
|
|
unsafe {
|
|
asm!(
|
|
"mov rbx, [rip+SYSCALL_REGS+8]",
|
|
"mov rsi, [rip+SYSCALL_REGS+32]",
|
|
"mov rdi, [rip+SYSCALL_REGS+40]",
|
|
"mov rsp, [rip+SYSCALL_REGS+48]",
|
|
"mov rbp, [rip+SYSCALL_REGS+56]",
|
|
"mov r8, [rip+SYSCALL_REGS+64]",
|
|
"mov r9, [rip+SYSCALL_REGS+72]",
|
|
"mov r10, [rip+SYSCALL_REGS+80]",
|
|
"mov r11, [rip+SYSCALL_REGS+88]",
|
|
"mov r12, [rip+SYSCALL_REGS+96]",
|
|
"mov r13, [rip+SYSCALL_REGS+104]",
|
|
"mov r14, [rip+SYSCALL_REGS+112]",
|
|
"mov r15, [rip+SYSCALL_REGS+120]",
|
|
"iretq",
|
|
in("rax") retval, in("rcx") retval2, in("rdx") retval3, options(noreturn)
|
|
)
|
|
}
|
|
}
|
|
|
|
pub fn register_handler(irq: u8, handler: IrqHandler) -> Result<(), InvalidIrq> {
|
|
*(IRQ_HANDLERS.write().get_mut(usize(irq)).ok_or(InvalidIrq)?) = Some(handler);
|
|
Ok(())
|
|
}
|