This commit is contained in:
parent
f0b4236407
commit
a6a88e7f3b
4 changed files with 75 additions and 20 deletions
|
@ -36,9 +36,10 @@ static PHYSICAL_FRAMES: Spinlock<OnceCell<BitVec<u64>>> = Spinlock::new(OnceCell
|
|||
static HEAP_PHYS_MAPPING: Spinlock<Vec<u64>> = Spinlock::new(Vec::new());
|
||||
const KERNEL_MAPPINGS_START: u64 = 0xfffffffd00000000;
|
||||
const KERNEL_MAPPINGS_END: u64 = 0xfffffffe00000000;
|
||||
pub const USER_END: u64 = 0x800000000000 - 0x1000; // Avoid accidentally jumping to non-canonical address
|
||||
|
||||
impl AddressSpace {
|
||||
fn get_page(&mut self, virt: u64) -> Option<&mut PageEntry> {
|
||||
pub fn get_page(&mut self, virt: u64) -> Option<&mut PageEntry> {
|
||||
let virt_page = virt as usize / 0x1000;
|
||||
let table_i = virt_page % 512;
|
||||
let directory_i = virt_page / 512 % 512;
|
||||
|
|
|
@ -4,12 +4,13 @@ use elf::{abi::PT_LOAD, endian::LittleEndian, ElfBytes};
|
|||
use log::info;
|
||||
|
||||
use crate::{
|
||||
cpu::cpu::{disable_user_memory_access, enable_user_memory_access},
|
||||
cpu::{
|
||||
cpu::{disable_user_memory_access, enable_user_memory_access},
|
||||
paging::USER_END,
|
||||
},
|
||||
sys::{lapic::get_current_lapic_id, task::CURRENT_TASKS},
|
||||
};
|
||||
|
||||
const USER_END: u64 = 0x800000000000 - 0x1000; // Avoid accidentally jumping to non-canonical address
|
||||
|
||||
extern "C" {
|
||||
fn jump_usermode(address: u64) -> !;
|
||||
}
|
||||
|
@ -33,11 +34,9 @@ pub fn load_binary() {
|
|||
}
|
||||
let write = i.p_flags & 2 != 0;
|
||||
let exec = i.p_flags & 1 != 0;
|
||||
assert!(i.p_vaddr + i.p_memsz < USER_END);
|
||||
assert!(i.p_vaddr + i.p_memsz >= i.p_vaddr);
|
||||
assert!(i.p_vaddr.checked_add(i.p_memsz).unwrap_or(USER_END + 1) <= USER_END);
|
||||
assert!(i.p_filesz <= i.p_memsz);
|
||||
assert!(i.p_offset + i.p_filesz <= binary.len() as u64);
|
||||
assert!(i.p_offset + i.p_filesz >= i.p_offset);
|
||||
assert!(i.p_offset.checked_add(i.p_filesz).unwrap_or(binary.len() as u64 + 1) <= binary.len() as u64);
|
||||
assert!(!write || !exec);
|
||||
let start = i.p_vaddr / 0x1000 * 0x1000;
|
||||
let end = (i.p_vaddr + i.p_memsz + 0xfff) / 0x1000 * 0x1000;
|
||||
|
|
|
@ -1,21 +1,70 @@
|
|||
use log::debug;
|
||||
use core::{error::Error, ptr::copy};
|
||||
|
||||
use super::task::terminate_current_task;
|
||||
use alloc::{boxed::Box, string::String, vec::Vec};
|
||||
use log::{debug, trace};
|
||||
|
||||
use crate::cpu::{
|
||||
cpu::{disable_user_memory_access, enable_user_memory_access},
|
||||
paging::USER_END,
|
||||
};
|
||||
|
||||
use super::{
|
||||
lapic::get_current_lapic_id,
|
||||
task::{terminate_current_task, CURRENT_TASKS},
|
||||
};
|
||||
|
||||
struct SyscallArgs {
|
||||
_arg1: usize,
|
||||
_arg2: usize,
|
||||
arg1: usize,
|
||||
arg2: usize,
|
||||
_arg3: usize,
|
||||
_arg4: usize,
|
||||
_arg5: usize,
|
||||
}
|
||||
|
||||
const SYSCALL_TABLE: [fn(SyscallArgs) -> usize; 1] = [syscall_get_kernel_version];
|
||||
const SYSCALL_TABLE: [fn(SyscallArgs) -> Result<usize, Box<dyn Error>>; 3] = [syscall_get_kernel_version, syscall_exit, syscall_debug_print];
|
||||
|
||||
fn syscall_get_kernel_version(_args: SyscallArgs) -> usize {
|
||||
0
|
||||
fn copy_from_user(start: u64, size: usize) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
if size > 16 * 1024 * 1024 {
|
||||
return Err("Too large copy requested".into());
|
||||
}
|
||||
let end = start.checked_add(size as u64).ok_or("Invalid copy requested")?;
|
||||
if end > USER_END {
|
||||
return Err("Invalid copy requested".into());
|
||||
}
|
||||
let process;
|
||||
{
|
||||
let tasks = CURRENT_TASKS.lock();
|
||||
process = tasks[get_current_lapic_id()].as_ref().unwrap().process.clone();
|
||||
}
|
||||
let mut process = process.lock();
|
||||
for i in start / 0x1000..(end + 0xfff) / 0x1000 {
|
||||
let page = process.address_space.get_page(i * 0x1000);
|
||||
if page.is_none() || page.unwrap().present() == 0 {
|
||||
return Err("Invalid copy requested".into());
|
||||
}
|
||||
}
|
||||
let mut buffer = Vec::with_capacity(size);
|
||||
buffer.resize(size, 0);
|
||||
enable_user_memory_access();
|
||||
unsafe {
|
||||
copy(start as *const u8, buffer.as_mut_ptr(), size);
|
||||
}
|
||||
disable_user_memory_access();
|
||||
Ok(buffer)
|
||||
}
|
||||
fn syscall_get_kernel_version(_args: SyscallArgs) -> Result<usize, Box<dyn Error>> {
|
||||
Ok(0)
|
||||
}
|
||||
fn syscall_exit(_args: SyscallArgs) -> Result<usize, Box<dyn Error>> {
|
||||
// TODO: Also terminate other threads
|
||||
terminate_current_task();
|
||||
}
|
||||
fn syscall_debug_print(args: SyscallArgs) -> Result<usize, Box<dyn Error>> {
|
||||
let data = copy_from_user(args.arg1 as u64, args.arg2)?;
|
||||
let string = String::from_utf8(data)?;
|
||||
trace!("{}", string);
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn syscall_handler(syscall: u64, arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
|
||||
if syscall as usize >= SYSCALL_TABLE.len() {
|
||||
|
@ -23,12 +72,16 @@ extern "C" fn syscall_handler(syscall: u64, arg1: u64, arg2: u64, arg3: u64, arg
|
|||
terminate_current_task();
|
||||
}
|
||||
let args = SyscallArgs {
|
||||
_arg1: arg1 as usize,
|
||||
_arg2: arg2 as usize,
|
||||
arg1: arg1 as usize,
|
||||
arg2: arg2 as usize,
|
||||
_arg3: arg3 as usize,
|
||||
_arg4: arg4 as usize,
|
||||
_arg5: arg5 as usize,
|
||||
};
|
||||
let result = SYSCALL_TABLE[syscall as usize](args);
|
||||
result as u64
|
||||
if result.is_err() {
|
||||
debug!("Error during syscall: {}", result.err().unwrap());
|
||||
terminate_current_task();
|
||||
}
|
||||
result.unwrap() as u64
|
||||
}
|
||||
|
|
|
@ -146,7 +146,9 @@ fn create_idle_task() {
|
|||
}
|
||||
}
|
||||
pub fn terminate_current_task() -> ! {
|
||||
CURRENT_TASKS.lock()[get_current_lapic_id()].as_mut().unwrap().task_state = TaskState::Terminated;
|
||||
{
|
||||
CURRENT_TASKS.lock()[get_current_lapic_id()].as_mut().unwrap().task_state = TaskState::Terminated;
|
||||
}
|
||||
yield_task();
|
||||
panic!("Failed to terminate task");
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue