Almost forking, UB

This commit is contained in:
2022-01-23 20:19:43 +02:00
parent a799b71326
commit 5113516b28
18 changed files with 797 additions and 547 deletions
+1 -1
View File
@@ -16,6 +16,6 @@
"os": "none",
"pre-link-args": {
"ld.lld": [ "-Tetc/aarch64-osdev5.ld" ]
"ld.lld": [ "-Tetc/x86_64-osdev5.ld" ]
}
}
+32
View File
@@ -0,0 +1,32 @@
ENTRY(_start);
PHDRS {
text PT_LOAD ;
rodata PT_LOAD ;
data PT_LOAD ;
}
SECTIONS {
. = 0x400000;
.text : {
*(.text._start)
*(.text*)
*(.eh_frame*)
} :text
. = ALIGN(0x1000);
.rodata : {
*(.rodata*)
} :rodata
. = ALIGN(0x1000);
.data : {
*(.data*)
} :data
.bss : {
*(COMMON)
*(.bss*)
} :data
}
+2 -1
View File
@@ -7,7 +7,7 @@ use crate::config::{ConfigKey, CONFIG};
use crate::debug;
use crate::dev::{display::FramebufferInfo, pseudo, Device};
use crate::font;
use crate::fs::{devfs, sysfs};
use crate::fs::{devfs::{self, CharDeviceType}, sysfs};
use crate::mem::{
self, heap,
phys::{self, MemoryRegion, PageUsage, ReservedRegion},
@@ -100,6 +100,7 @@ extern "C" fn __x86_64_bsp_main(mb_checksum: u32, mb_info_ptr: u32) -> ! {
devfs::init();
sysfs::init();
devfs::add_char_device(&x86_64::COM1, CharDeviceType::TtySerial).unwrap();
devfs::add_named_char_device(&pseudo::ZERO, "zero").unwrap();
devfs::add_named_char_device(&pseudo::RANDOM, "random").unwrap();
+2
View File
@@ -19,6 +19,8 @@ pub(self) mod gdt;
pub(self) mod idt;
pub(self) mod exception;
pub use syscall::SyscallFrame as ForkFrame;
/// Masks IRQs and returns previous IRQ mask state
///
/// # Safety
+57 -1
View File
@@ -1,4 +1,60 @@
.section .text
.global __x86_64_syscall_entry
__x86_64_syscall_entry:
jmp .
// Syscalls only happen from user space, so
// relying on TSS.RSP0 is safe here I guess
mov %rsp, scratch(%rip)
mov (4 + TSS)(%rip), %rsp
// Now on kernel stack
// Push the whole state
push %rcx // saved %rip
push %r11 // saved %rflags
mov scratch(%rip), %r11
push %r11 // saved %rsp
push %r12
push %r13
push %r14
push %r15
push %rbp
push %rbx
push %rax
push %r9
push %r8
push %r10
push %rdx
push %rsi
push %rdi
mov %rsp, %rdi
call __x86_64_syscall
pop %rdi
pop %rsi
pop %rdx
pop %r10
pop %r8
pop %r9
pop %rax
pop %rbx
pop %rbp
pop %r15
pop %r14
pop %r13
pop %r12
pop %rdi
pop %r11
pop %rcx
mov %rdi, %rsp
sysretq
.section .bss
scratch:
.skip 8
+36
View File
@@ -1,6 +1,17 @@
use crate::arch::x86_64::reg::{MSR_IA32_EFER, MSR_IA32_LSTAR, MSR_IA32_SFMASK, MSR_IA32_STAR};
use core::arch::global_asm;
use tock_registers::interfaces::{ReadWriteable, Writeable};
use libsys::abi::SystemCall;
use crate::syscall;
#[derive(Clone, Debug)]
pub struct SyscallFrame {
x: [usize; 13],
saved_rsp: usize,
saved_rflags: usize,
saved_rip: usize,
}
pub(super) fn init() {
extern "C" {
@@ -14,4 +25,29 @@ pub(super) fn init() {
MSR_IA32_EFER.modify(MSR_IA32_EFER::SCE::SET);
}
#[no_mangle]
extern "C" fn __x86_64_syscall(frame: &mut SyscallFrame) {
let num = SystemCall::from_repr(frame.x[6]);
if num.is_none() {
todo!();
}
let num = num.unwrap();
if num == SystemCall::Fork {
match unsafe { syscall::sys_fork(frame) } {
Ok(pid) => frame.x[6] = u32::from(pid) as usize,
Err(err) => {
frame.x[6] = err.to_negative_isize() as usize;
}
}
return;
}
match syscall::syscall(num, &frame.x[..6]) {
Ok(val) => frame.x[6] = val,
Err(err) => {
frame.x[6] = err.to_negative_isize() as usize;
}
}
}
global_asm!(include_str!("syscall.S"), options(att_syntax));
+52
View File
@@ -206,6 +206,58 @@ impl AddressSpace for Space {
Ok(())
}
}
/// Performs a copy of the address space, cloning data owned by it
fn fork(&mut self) -> Result<&'static mut Self, Errno> {
let res = Self::alloc_empty()?;
let pdpt0 = self.0.next_level_table(0).unwrap();
for pdpti in 0..512 {
if let Some(pd) = pdpt0.next_level_table(pdpti) {
for pdi in 0..512 {
if let Some(pt) = pd.next_level_table(pdi) {
for pti in 0..512 {
let entry = pt[pti];
if !entry.is_present() {
continue;
}
assert!(entry.is_table());
todo!();
// let src_phys = unsafe { entry.address_unchecked() };
// let virt_addr = (l0i << 30) | (l1i << 21) | (l2i << 12);
// let dst_phys = unsafe { phys::fork_page(src_phys)? };
// let mut flags = unsafe { entry.fork_flags() };
// if dst_phys != src_phys {
// todo!();
// // res.map(virt_addr, dst_phys, flags)?;
// } else {
// let writable = flags & MapAttributes::AP_BOTH_READONLY
// == MapAttributes::AP_BOTH_READWRITE;
// if writable {
// flags |=
// MapAttributes::AP_BOTH_READONLY | MapAttributes::EX_COW;
// l2_table[l2i].set_cow();
// unsafe {
// asm!("tlbi vaae1, {}", in(reg) virt_addr);
// }
// }
// res.map(virt_addr, dst_phys, flags)?;
// }
}
}
}
}
}
Ok(res)
}
}
impl Index<usize> for Table {
+17 -3
View File
@@ -1,9 +1,16 @@
use crate::dev::{Device, serial::SerialDevice};
use crate::arch::x86_64::PortIo;
use libsys::error::Errno;
use crate::dev::{
tty::{CharRing, TtyDevice},
irq::{IntController, IntSource},
serial::SerialDevice,
Device,
};
#[derive(TtyCharDevice)]
pub(super) struct Uart {
dr: PortIo<u8>
dr: PortIo<u8>,
ring: CharRing<16>
}
impl Device for Uart {
@@ -16,6 +23,12 @@ impl Device for Uart {
}
}
impl TtyDevice<16> for Uart {
fn ring(&self) -> &CharRing<16> {
&self.ring
}
}
impl SerialDevice for Uart {
fn send(&self, byte: u8) -> Result<(), Errno> {
self.dr.write(byte);
@@ -30,7 +43,8 @@ impl SerialDevice for Uart {
impl Uart {
pub const unsafe fn new(base: u16) -> Self {
Self {
dr: PortIo::new(base)
dr: PortIo::new(base),
ring: CharRing::new()
}
}
}
+1 -1
View File
@@ -13,7 +13,7 @@ pub mod display;
pub mod serial;
pub mod timer;
pub mod pseudo;
// pub mod tty;
pub mod tty;
/// Generic device trait
pub trait Device {
+2 -1
View File
@@ -126,7 +126,8 @@ pub trait TtyDevice<const N: usize>: SerialDevice {
// TODO send to pgid
let proc = Process::get(pgid);
if let Some(proc) = proc {
proc.set_signal(Signal::Interrupt);
// TODO
// proc.set_signal(Signal::Interrupt);
}
}
return;
+18 -18
View File
@@ -36,26 +36,26 @@ pub extern "C" fn init_fn(_arg: usize) -> ! {
proc.io.lock().set_ioctx(ioctx);
// // Open stdin/stdout/stderr
// {
// let devfs_root = devfs::root();
// let tty_node = if console.is_empty() {
// devfs_root.lookup("ttyS0")
// } else {
// devfs_root.lookup(console)
// }
// .expect("Failed to open stdout for init process");
// Open stdin/stdout/stderr
{
let devfs_root = devfs::root();
let tty_node = if console.is_empty() {
devfs_root.lookup("ttyS0")
} else {
devfs_root.lookup(console)
}
.expect("Failed to open stdout for init process");
// let mut io = proc.io.lock();
// let stdin = tty_node.open(OpenFlags::O_RDONLY).unwrap();
// let stdout = tty_node.open(OpenFlags::O_WRONLY).unwrap();
// let stderr = stdout.clone();
let mut io = proc.io.lock();
let stdin = tty_node.open(OpenFlags::O_RDONLY).unwrap();
let stdout = tty_node.open(OpenFlags::O_WRONLY).unwrap();
let stderr = stdout.clone();
// io.set_file(FileDescriptor::STDIN, stdin).unwrap();
// io.set_file(FileDescriptor::STDOUT, stdout).unwrap();
// io.set_file(FileDescriptor::STDERR, stderr).unwrap();
// io.set_ctty(tty_node);
// }
io.set_file(FileDescriptor::STDIN, stdin).unwrap();
io.set_file(FileDescriptor::STDOUT, stdout).unwrap();
io.set_file(FileDescriptor::STDERR, stderr).unwrap();
io.set_ctty(tty_node);
}
drop(cfg);
+29
View File
@@ -38,6 +38,7 @@ pub trait AddressSpace {
type Entry: Entry;
fn alloc_empty() -> Result<&'static mut Self, Errno>;
fn fork(&mut self) -> Result<&'static mut Self, Errno>;
fn release(space: &mut Self);
fn address_phys(&mut self) -> usize;
fn read_last_level_entry(&mut self, virt: usize) -> Result<Self::Entry, Errno>;
@@ -48,12 +49,40 @@ pub trait AddressSpace {
map_intermediate: bool,
) -> Result<(), Errno>;
#[inline(always)]
fn map(&mut self, virt: usize, phys: usize, attrs: MapAttributes) -> Result<(), Errno> {
let entry = Entry::from_parts(phys, attrs);
self.write_last_level_entry(virt, entry, true).map(|_| ())
}
#[inline(always)]
fn translate(&mut self, virt: usize) -> Result<usize, Errno> {
self.read_last_level_entry(virt).map(Entry::target)
}
/// Allocates a contiguous region from the address space and maps
/// physical pages to it
fn allocate(
&mut self,
start: usize,
end: usize,
len: usize,
flags: MapAttributes,
usage: PageUsage,
) -> Result<usize, Errno> {
'l0: for page in (start..end).step_by(0x1000) {
for i in 0..len {
if self.translate(page + i * 0x1000).is_ok() {
continue 'l0;
}
}
for i in 0..len {
let phys = phys::alloc_page(usage).unwrap();
self.map(page + i * 0x1000, phys, flags).unwrap();
}
return Ok(page);
}
Err(Errno::OutOfMemory)
}
}
+37 -34
View File
@@ -1,5 +1,5 @@
//! Process data and control
// use crate::arch::aarch64::exception::ExceptionFrame;
use crate::arch::platform::ForkFrame;
use crate::mem::{
self,
phys::{self, PageUsage},
@@ -55,7 +55,7 @@ pub struct Process {
impl Process {
const USTACK_VIRT_TOP: usize = 0x100000000;
const USTACK_PAGES: usize = 4;
const USTACK_PAGES: usize = 8;
/// Returns the process ID
#[inline]
@@ -229,45 +229,48 @@ impl Process {
// Ok(tid)
// }
// /// Creates a "fork" of the process, cloning its address space and
// /// resources
// pub fn fork(&self, frame: &mut ExceptionFrame) -> Result<Pid, Errno> {
// let src_io = self.io.lock();
// let mut src_inner = self.inner.lock();
/// Creates a "fork" of the process, cloning its address space and
/// resources
pub fn fork(&self, frame: &mut ForkFrame) -> Result<Pid, Errno> {
todo!();
let src_io = self.io.lock();
let mut src_inner = self.inner.lock();
// let dst_id = new_user_pid();
// let dst_space = src_inner.space.as_mut().unwrap().fork()?;
let dst_id = new_user_pid();
let dst_space = src_inner.space.as_mut().unwrap().fork()?;
// let dst_space_phys = (dst_space as *mut _ as usize) - mem::KERNEL_OFFSET;
// let dst_ttbr0 = dst_space_phys | ((dst_id.asid() as usize) << 48);
todo!()
// let mut threads = Vec::new();
// let tid = Thread::fork(Some(dst_id), frame, dst_ttbr0)?.id();
// threads.push(tid);
// let dst_space_phys = (dst_space as *mut _ as usize) - mem::KERNEL_OFFSET;
// let dst_ttbr0 = dst_space_phys | ((dst_id.asid() as usize) << 48);
// let dst = Rc::new(Self {
// exit_wait: Wait::new("process_exit"),
// io: IrqSafeSpinLock::new(src_io.fork()?),
// signal_state: AtomicU32::new(0),
// inner: IrqSafeSpinLock::new(ProcessInner {
// threads,
// exit: None,
// space: Some(dst_space),
// state: ProcessState::Active,
// id: dst_id,
// pgid: src_inner.pgid,
// ppid: Some(src_inner.id),
// sid: src_inner.sid,
// }),
// });
// let mut threads = Vec::new();
// let tid = Thread::fork(Some(dst_id), frame, dst_ttbr0)?.id();
// threads.push(tid);
// debugln!("Process {:?} forked into {:?}", src_inner.id, dst_id);
// assert!(PROCESSES.lock().insert(dst_id, dst).is_none());
// let dst = Rc::new(Self {
// exit_wait: Wait::new("process_exit"),
// io: IrqSafeSpinLock::new(src_io.fork()?),
// signal_state: AtomicU32::new(0),
// inner: IrqSafeSpinLock::new(ProcessInner {
// threads,
// exit: None,
// space: Some(dst_space),
// state: ProcessState::Active,
// id: dst_id,
// pgid: src_inner.pgid,
// ppid: Some(src_inner.id),
// sid: src_inner.sid,
// }),
// });
// SCHED.enqueue(tid);
// debugln!("Process {:?} forked into {:?}", src_inner.id, dst_id);
// assert!(PROCESSES.lock().insert(dst_id, dst).is_none());
// Ok(dst_id)
// }
// SCHED.enqueue(tid);
// Ok(dst_id)
}
/// Terminates a process.
pub fn exit(self: ProcessRef, status: ExitCode) {
+28 -16
View File
@@ -12,28 +12,39 @@ macro_rules! invalid_memory {
warnln!($($args)+);
#[cfg(feature = "aggressive_syscall")]
{
use libsys::signal::Signal;
use crate::proc::Thread;
todo!()
// use libsys::signal::Signal;
// use crate::proc::Thread;
let thread = Thread::current();
let proc = thread.owner().unwrap();
proc.enter_fault_signal(thread, Signal::SegmentationFault);
// let thread = Thread::current();
// let proc = thread.owner().unwrap();
// proc.enter_fault_signal(thread, Signal::SegmentationFault);
}
return Err(Errno::InvalidArgument);
}
}
#[inline(always)]
fn is_el0_accessible(virt: usize, write: bool) -> bool {
let mut res: usize;
unsafe {
if write {
asm!("at s1e0w, {}; mrs {}, par_el1", in(reg) virt, out(reg) res);
} else {
asm!("at s1e0r, {}; mrs {}, par_el1", in(reg) virt, out(reg) res);
cfg_if! {
if #[cfg(target_arch = "aarch64")] {
#[inline(always)]
fn is_el0_accessible(virt: usize, write: bool) -> bool {
let mut res: usize;
unsafe {
if write {
asm!("at s1e0w, {}; mrs {}, par_el1", in(reg) virt, out(reg) res);
} else {
asm!("at s1e0r, {}; mrs {}, par_el1", in(reg) virt, out(reg) res);
}
}
res & 1 == 0
}
} else {
#[inline(always)]
fn is_el0_accessible(virt: usize, write: bool) -> bool {
// TODO implement this
true
}
}
res & 1 == 0
}
/// Checks given argument and interprets it as a `T` reference
@@ -129,9 +140,10 @@ pub fn validate_ptr(base: usize, len: usize, write: bool) -> Result<(), Errno> {
// It's possible a CoW page hasn't yet been cloned when trying
// a write access
let res = if write {
todo!();
process.manipulate_space(|space| {
space.try_cow_copy(i * mem::PAGE_SIZE)?;
Process::invalidate_asid(asid);
// space.try_cow_copy(i * mem::PAGE_SIZE)?;
// Process::invalidate_asid(asid);
Ok(())
})
} else {
+416 -413
View File
@@ -1,10 +1,14 @@
//! System call implementation
// use crate::arch::{machine, platform::exception::ExceptionFrame};
// use crate::debug::Level;
use crate::arch::platform::ForkFrame;
use crate::debug::Level;
// use crate::dev::timer::TimestampSource;
// use crate::fs::create_filesystem;
// use crate::mem::{phys::PageUsage, virt::MapAttributes};
use crate::fs::create_filesystem;
use crate::mem::{
phys::PageUsage,
virt::table::{AddressSpace, MapAttributes},
};
use crate::proc::{self, elf, wait, Process, ProcessIo, Thread};
// use core::mem::size_of;
use core::ops::DerefMut;
@@ -24,18 +28,18 @@ use libsys::{
};
use vfs::VnodeRef;
// pub mod arg;
pub mod arg;
// /// Creates a "fork" process from current one using its register frame.
// /// See [Process::fork()].
// ///
// /// # Safety
// ///
// /// Unsafe: accepts and clones process states. Only legal to call
// /// from exception handlers.
// pub unsafe fn sys_fork(regs: &mut ExceptionFrame) -> Result<Pid, Errno> {
// Process::current().fork(regs)
// }
/// Creates a "fork" process from current one using its register frame.
/// See [Process::fork()].
///
/// # Safety
///
/// Unsafe: accepts and clones process states. Only legal to call
/// from exception handlers.
pub unsafe fn sys_fork(regs: &mut ForkFrame) -> Result<Pid, Errno> {
Process::current().fork(regs)
}
fn find_at_node<T: DerefMut<Target = ProcessIo>>(
io: &mut T,
@@ -57,407 +61,406 @@ fn find_at_node<T: DerefMut<Target = ProcessIo>>(
}
fn _syscall(num: SystemCall, args: &[usize]) -> Result<usize, Errno> {
loop {}
// match num {
// // I/O
// SystemCall::Read => {
// let proc = Process::current();
// let fd = FileDescriptor::from(args[0] as u32);
// let mut io = proc.io.lock();
// let buf = arg::buf_mut(args[1], args[2])?;
//
// io.file(fd)?.borrow_mut().read(buf)
// }
// SystemCall::Write => {
// let proc = Process::current();
// let fd = FileDescriptor::from(args[0] as u32);
// let mut io = proc.io.lock();
// let buf = arg::buf_ref(args[1], args[2])?;
//
// io.file(fd)?.borrow_mut().write(buf)
// }
// SystemCall::Open => {
// let at_fd = FileDescriptor::from_i32(args[0] as i32)?;
// let path = arg::str_ref(args[1], args[2])?;
// let mode = FileMode::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?;
// let opts = OpenFlags::from_bits(args[4] as u32).ok_or(Errno::InvalidArgument)?;
//
// let proc = Process::current();
// let mut io = proc.io.lock();
//
// let at = if let Some(fd) = at_fd {
// io.file(fd)?.borrow().node()
// } else {
// None
// };
//
// let file = io.ioctx().open(at, path, mode, opts)?;
// Ok(u32::from(io.place_file(file)?) as usize)
// }
// SystemCall::Close => {
// let proc = Process::current();
// let mut io = proc.io.lock();
// let fd = FileDescriptor::from(args[0] as u32);
//
// io.close_file(fd)?;
// Ok(0)
// }
// SystemCall::FileStatus => {
// let at_fd = FileDescriptor::from_i32(args[0] as i32)?;
// let filename = arg::str_ref(args[1], args[2])?;
// let buf = arg::struct_mut::<Stat>(args[3])?;
// let flags = args[4] as u32;
//
// let proc = Process::current();
// let mut io = proc.io.lock();
// let stat =
// find_at_node(&mut io, at_fd, filename, flags & AT_EMPTY_PATH != 0)?.stat()?;
// *buf = stat;
// Ok(0)
// }
// SystemCall::Ioctl => {
// let fd = FileDescriptor::from(args[0] as u32);
// let cmd = IoctlCmd::try_from(args[1] as u32)?;
//
// let proc = Process::current();
// let mut io = proc.io.lock();
//
// let node = io.file(fd)?.borrow().node().ok_or(Errno::InvalidFile)?;
// node.ioctl(cmd, args[2], args[3])
// }
// SystemCall::Select => {
// let rfds = arg::option_struct_mut::<FdSet>(args[0])?;
// let wfds = arg::option_struct_mut::<FdSet>(args[1])?;
// let timeout = if args[2] == 0 {
// None
// } else {
// Some(Duration::from_nanos(args[2] as u64))
// };
//
// wait::select(Thread::current(), rfds, wfds, timeout)
// }
// SystemCall::Access => {
// let at_fd = FileDescriptor::from_i32(args[0] as i32)?;
// let path = arg::str_ref(args[1], args[2])?;
// let mode = AccessMode::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?;
// let flags = args[4] as u32;
//
// let proc = Process::current();
// let mut io = proc.io.lock();
//
// find_at_node(&mut io, at_fd, path, flags & AT_EMPTY_PATH != 0)?
// .check_access(io.ioctx(), mode)?;
// Ok(0)
// }
// SystemCall::ReadDirectory => {
// let proc = Process::current();
// let fd = FileDescriptor::from(args[0] as u32);
// let mut io = proc.io.lock();
// let buf = arg::struct_buf_mut::<DirectoryEntry>(args[1], args[2])?;
//
// io.file(fd)?.borrow_mut().readdir(buf)
// }
// SystemCall::GetUserId => {
// let proc = Process::current();
// let uid = proc.io.lock().uid();
// Ok(u32::from(uid) as usize)
// }
// SystemCall::GetGroupId => {
// let proc = Process::current();
// let gid = proc.io.lock().gid();
// Ok(u32::from(gid) as usize)
// }
// SystemCall::DuplicateFd => {
// let src = FileDescriptor::from(args[0] as u32);
// let dst = FileDescriptor::from_i32(args[1] as i32)?;
//
// let proc = Process::current();
// let mut io = proc.io.lock();
//
// let res = io.duplicate_file(src, dst)?;
//
// Ok(u32::from(res) as usize)
// }
// SystemCall::SetUserId => {
// let uid = UserId::from(args[0] as u32);
// let proc = Process::current();
// proc.io.lock().set_uid(uid)?;
// Ok(0)
// }
// SystemCall::SetGroupId => {
// let gid = GroupId::from(args[0] as u32);
// let proc = Process::current();
// proc.io.lock().set_gid(gid)?;
// Ok(0)
// }
// SystemCall::SetCurrentDirectory => {
// let path = arg::str_ref(args[0], args[1])?;
// let proc = Process::current();
// proc.io.lock().ioctx().chdir(path)?;
// Ok(0)
// }
// SystemCall::GetCurrentDirectory => {
// todo!()
// }
// SystemCall::Seek => {
// todo!()
// }
// SystemCall::MapMemory => {
// let len = args[1];
// if len == 0 || (len & 0xFFF) != 0 {
// return Err(Errno::InvalidArgument);
// }
// let acc = MemoryAccess::from_bits(args[2] as u32).ok_or(Errno::InvalidArgument)?;
// let _flags = MemoryAccess::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?;
//
// let mut attrs =
// MapAttributes::NOT_GLOBAL | MapAttributes::SH_OUTER | MapAttributes::PXN;
// if !acc.contains(MemoryAccess::READ) {
// return Err(Errno::NotImplemented);
// }
// if acc.contains(MemoryAccess::WRITE) {
// if acc.contains(MemoryAccess::EXEC) {
// return Err(Errno::PermissionDenied);
// }
// attrs |= MapAttributes::AP_BOTH_READWRITE;
// } else {
// attrs |= MapAttributes::AP_BOTH_READONLY;
// }
// if !acc.contains(MemoryAccess::EXEC) {
// attrs |= MapAttributes::UXN;
// }
//
// // TODO don't ignore flags
// let usage = PageUsage::UserPrivate;
//
// let proc = Process::current();
//
// proc.manipulate_space(move |space| {
// space.allocate(0x100000000, 0xF00000000, len / 4096, attrs, usage)
// })
// }
// SystemCall::UnmapMemory => {
// let addr = args[0];
// let len = args[1];
//
// if addr == 0 || len == 0 || addr & 0xFFF != 0 || len & 0xFFF != 0 {
// return Err(Errno::InvalidArgument);
// }
//
// let proc = Process::current();
// proc.manipulate_space(move |space| space.free(addr, len / 4096))?;
// Ok(0)
// }
//
// // Process
// SystemCall::Clone => {
// let entry = args[0];
// let stack = args[1];
// let arg = args[2];
//
// Process::current()
// .new_user_thread(entry, stack, arg)
// .map(|e| u32::from(e) as usize)
// }
// SystemCall::Exec => {
// let filename = arg::str_ref(args[0], args[1])?;
// let argv = arg::struct_buf_ref::<&str>(args[2], args[3])?;
// // Validate each argument as well
// for item in argv.iter() {
// arg::validate_ptr(item.as_ptr() as usize, item.len(), false)?;
// }
// let node = {
// let proc = Process::current();
// let mut io = proc.io.lock();
// // TODO argv, envp array passing ABI?
// let node = io.ioctx().find(None, filename, true)?;
// drop(io);
// node
// };
// let file = node.open(OpenFlags::O_RDONLY)?;
// Process::execve(move |space| elf::load_elf(space, file), argv).unwrap();
// panic!();
// }
// SystemCall::Exit => {
// let status = ExitCode::from(args[0] as i32);
// let flags = args[1];
//
// if flags & (1 << 0) != 0 {
// Process::exit_thread(Thread::current(), status);
// } else {
// Process::current().exit(status);
// }
//
// unreachable!();
// }
// SystemCall::WaitPid => {
// // TODO special "pid" values
// let pid = Pid::try_from(args[0] as u32)?;
// let status = arg::struct_mut::<i32>(args[1])?;
//
// match Process::waitpid(pid) {
// Ok(exit) => {
// *status = i32::from(exit);
// Ok(0)
// }
// e => e.map(|e| i32::from(e) as usize),
// }
// }
// SystemCall::WaitTid => {
// let tid = Tid::from(args[0] as u32);
//
// match Thread::waittid(tid) {
// Ok(_) => Ok(0),
// _ => todo!(),
// }
// }
// SystemCall::GetPid => Ok(u32::from(Process::current().id()) as usize),
// SystemCall::GetTid => Ok(u32::from(Thread::current().id()) as usize),
// SystemCall::Sleep => {
// let rem_buf = arg::option_buf_ref(args[1], size_of::<u64>() * 2)?;
// let mut rem = Duration::new(0, 0);
// let res = wait::sleep(Duration::from_nanos(args[0] as u64), &mut rem);
// if res == Err(Errno::Interrupt) {
// warnln!("Sleep interrupted, {:?} remaining", rem);
// if rem_buf.is_some() {
// todo!()
// }
// }
// res.map(|_| 0)
// }
// SystemCall::SetSignalEntry => {
// Thread::current().set_signal_entry(args[0], args[1]);
// Ok(0)
// }
// SystemCall::SignalReturn => {
// Thread::current().return_from_signal();
// unreachable!();
// }
// SystemCall::SendSignal => {
// let target = SignalDestination::from(args[0] as isize);
// let signal = Signal::try_from(args[1] as u32)?;
//
// match target {
// SignalDestination::This => Process::current().set_signal(signal),
// SignalDestination::Process(pid) => Process::get(pid)
// .ok_or(Errno::DoesNotExist)?
// .set_signal(signal),
// _ => todo!(),
// };
// Ok(0)
// }
// SystemCall::Yield => {
// proc::switch();
// Ok(0)
// }
// SystemCall::GetSid => {
// // TODO handle kernel processes here?
// let pid = Pid::to_option(args[0] as u32);
// let current = Process::current();
// let proc = if let Some(pid) = pid {
// let proc = Process::get(pid).ok_or(Errno::DoesNotExist)?;
// if proc.sid() != current.sid() {
// return Err(Errno::PermissionDenied);
// }
// proc
// } else {
// current
// };
//
// Ok(u32::from(proc.sid()) as usize)
// }
// SystemCall::GetPgid => {
// // TODO handle kernel processes here?
// let pid = Pid::to_option(args[0] as u32);
// let current = Process::current();
// let proc = if let Some(pid) = pid {
// Process::get(pid).ok_or(Errno::DoesNotExist)?
// } else {
// current
// };
//
// Ok(u32::from(proc.pgid()) as usize)
// }
// SystemCall::GetPpid => Ok(u32::from(Process::current().ppid().unwrap()) as usize),
// SystemCall::SetSid => {
// let proc = Process::current();
// let mut io = proc.io.lock();
//
// if let Some(_ctty) = io.ctty() {
// todo!();
// }
//
// let id = proc.id();
// proc.set_sid(id);
// Ok(u32::from(id) as usize)
// }
// SystemCall::SetPgid => {
// let pid = Pid::to_option(args[0] as u32);
// let pgid = Pid::to_option(args[1] as u32);
//
// let current = Process::current();
// let proc = if let Some(_pid) = pid {
// todo!()
// } else {
// current
// };
//
// if let Some(_pgid) = pgid {
// todo!();
// } else {
// proc.set_pgid(proc.id());
// }
//
// Ok(u32::from(proc.pgid()) as usize)
// }
//
// // System
// SystemCall::GetCpuTime => {
// let time = machine::local_timer().timestamp()?;
// Ok(time.as_nanos() as usize)
// }
// SystemCall::Mount => {
// let target = arg::str_ref(args[0], args[1])?;
// let options = arg::struct_ref::<MountOptions>(args[2])?;
//
// let proc = Process::current();
// let mut io = proc.io.lock();
//
// debugln!("mount(target={:?}, options={:#x?})", target, options);
//
// let target_node = io.ioctx().find(None, target, true)?;
// let root = create_filesystem(options)?;
//
// target_node.mount(root)?;
//
// Ok(0)
// }
//
// // Debugging
// SystemCall::DebugTrace => {
// let level = TraceLevel::from_repr(args[0])
// .map(Level::from)
// .ok_or(Errno::InvalidArgument)?;
// let buf = arg::str_ref(args[1], args[2])?;
// let thread = Thread::current();
// let proc = thread.owner().unwrap();
// println!(level, "[trace {:?}:{:?}] {}", proc.id(), thread.id(), buf);
// Ok(args[1])
// }
//
// // Handled elsewhere
// SystemCall::Fork => unreachable!(),
// }
match num {
// I/O
SystemCall::Read => {
let proc = Process::current();
let fd = FileDescriptor::from(args[0] as u32);
let mut io = proc.io.lock();
let buf = arg::buf_mut(args[1], args[2])?;
io.file(fd)?.borrow_mut().read(buf)
}
SystemCall::Write => {
let proc = Process::current();
let fd = FileDescriptor::from(args[0] as u32);
let mut io = proc.io.lock();
let buf = arg::buf_ref(args[1], args[2])?;
io.file(fd)?.borrow_mut().write(buf)
}
// SystemCall::Open => {
// let at_fd = FileDescriptor::from_i32(args[0] as i32)?;
// let path = arg::str_ref(args[1], args[2])?;
// let mode = FileMode::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?;
// let opts = OpenFlags::from_bits(args[4] as u32).ok_or(Errno::InvalidArgument)?;
//
// let proc = Process::current();
// let mut io = proc.io.lock();
//
// let at = if let Some(fd) = at_fd {
// io.file(fd)?.borrow().node()
// } else {
// None
// };
//
// let file = io.ioctx().open(at, path, mode, opts)?;
// Ok(u32::from(io.place_file(file)?) as usize)
// }
// SystemCall::Close => {
// let proc = Process::current();
// let mut io = proc.io.lock();
// let fd = FileDescriptor::from(args[0] as u32);
//
// io.close_file(fd)?;
// Ok(0)
// }
// SystemCall::FileStatus => {
// let at_fd = FileDescriptor::from_i32(args[0] as i32)?;
// let filename = arg::str_ref(args[1], args[2])?;
// let buf = arg::struct_mut::<Stat>(args[3])?;
// let flags = args[4] as u32;
//
// let proc = Process::current();
// let mut io = proc.io.lock();
// let stat =
// find_at_node(&mut io, at_fd, filename, flags & AT_EMPTY_PATH != 0)?.stat()?;
// *buf = stat;
// Ok(0)
// }
// SystemCall::Ioctl => {
// let fd = FileDescriptor::from(args[0] as u32);
// let cmd = IoctlCmd::try_from(args[1] as u32)?;
//
// let proc = Process::current();
// let mut io = proc.io.lock();
//
// let node = io.file(fd)?.borrow().node().ok_or(Errno::InvalidFile)?;
// node.ioctl(cmd, args[2], args[3])
// }
// SystemCall::Select => {
// let rfds = arg::option_struct_mut::<FdSet>(args[0])?;
// let wfds = arg::option_struct_mut::<FdSet>(args[1])?;
// let timeout = if args[2] == 0 {
// None
// } else {
// Some(Duration::from_nanos(args[2] as u64))
// };
//
// wait::select(Thread::current(), rfds, wfds, timeout)
// }
// SystemCall::Access => {
// let at_fd = FileDescriptor::from_i32(args[0] as i32)?;
// let path = arg::str_ref(args[1], args[2])?;
// let mode = AccessMode::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?;
// let flags = args[4] as u32;
//
// let proc = Process::current();
// let mut io = proc.io.lock();
//
// find_at_node(&mut io, at_fd, path, flags & AT_EMPTY_PATH != 0)?
// .check_access(io.ioctx(), mode)?;
// Ok(0)
// }
// SystemCall::ReadDirectory => {
// let proc = Process::current();
// let fd = FileDescriptor::from(args[0] as u32);
// let mut io = proc.io.lock();
// let buf = arg::struct_buf_mut::<DirectoryEntry>(args[1], args[2])?;
//
// io.file(fd)?.borrow_mut().readdir(buf)
// }
// SystemCall::GetUserId => {
// let proc = Process::current();
// let uid = proc.io.lock().uid();
// Ok(u32::from(uid) as usize)
// }
// SystemCall::GetGroupId => {
// let proc = Process::current();
// let gid = proc.io.lock().gid();
// Ok(u32::from(gid) as usize)
// }
// SystemCall::DuplicateFd => {
// let src = FileDescriptor::from(args[0] as u32);
// let dst = FileDescriptor::from_i32(args[1] as i32)?;
//
// let proc = Process::current();
// let mut io = proc.io.lock();
//
// let res = io.duplicate_file(src, dst)?;
//
// Ok(u32::from(res) as usize)
// }
// SystemCall::SetUserId => {
// let uid = UserId::from(args[0] as u32);
// let proc = Process::current();
// proc.io.lock().set_uid(uid)?;
// Ok(0)
// }
// SystemCall::SetGroupId => {
// let gid = GroupId::from(args[0] as u32);
// let proc = Process::current();
// proc.io.lock().set_gid(gid)?;
// Ok(0)
// }
// SystemCall::SetCurrentDirectory => {
// let path = arg::str_ref(args[0], args[1])?;
// let proc = Process::current();
// proc.io.lock().ioctx().chdir(path)?;
// Ok(0)
// }
// SystemCall::GetCurrentDirectory => {
// todo!()
// }
// SystemCall::Seek => {
// todo!()
// }
SystemCall::MapMemory => {
let len = args[1];
if len == 0 || (len & 0xFFF) != 0 {
return Err(Errno::InvalidArgument);
}
let acc = MemoryAccess::from_bits(args[2] as u32).ok_or(Errno::InvalidArgument)?;
let _flags = MemoryAccess::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?;
let mut attrs =
MapAttributes::NOT_GLOBAL | MapAttributes::SHARE_OUTER | MapAttributes::USER_READ;
if !acc.contains(MemoryAccess::READ) {
return Err(Errno::NotImplemented);
}
if acc.contains(MemoryAccess::WRITE) {
if acc.contains(MemoryAccess::EXEC) {
return Err(Errno::PermissionDenied);
}
attrs |= MapAttributes::USER_WRITE | MapAttributes::KERNEL_WRITE;
} else {
attrs |= MapAttributes::USER_READ;
}
if !acc.contains(MemoryAccess::EXEC) {
attrs |= MapAttributes::USER_EXEC;
}
// TODO don't ignore flags
let usage = PageUsage::UserPrivate;
let proc = Process::current();
proc.manipulate_space(move |space| {
space.allocate(0x100000000, 0xF00000000, len / 4096, attrs, usage)
})
}
// SystemCall::UnmapMemory => {
// let addr = args[0];
// let len = args[1];
//
// if addr == 0 || len == 0 || addr & 0xFFF != 0 || len & 0xFFF != 0 {
// return Err(Errno::InvalidArgument);
// }
//
// let proc = Process::current();
// proc.manipulate_space(move |space| space.free(addr, len / 4096))?;
// Ok(0)
// }
//
// // Process
// SystemCall::Clone => {
// let entry = args[0];
// let stack = args[1];
// let arg = args[2];
//
// Process::current()
// .new_user_thread(entry, stack, arg)
// .map(|e| u32::from(e) as usize)
// }
// SystemCall::Exec => {
// let filename = arg::str_ref(args[0], args[1])?;
// let argv = arg::struct_buf_ref::<&str>(args[2], args[3])?;
// // Validate each argument as well
// for item in argv.iter() {
// arg::validate_ptr(item.as_ptr() as usize, item.len(), false)?;
// }
// let node = {
// let proc = Process::current();
// let mut io = proc.io.lock();
// // TODO argv, envp array passing ABI?
// let node = io.ioctx().find(None, filename, true)?;
// drop(io);
// node
// };
// let file = node.open(OpenFlags::O_RDONLY)?;
// Process::execve(move |space| elf::load_elf(space, file), argv).unwrap();
// panic!();
// }
// SystemCall::Exit => {
// let status = ExitCode::from(args[0] as i32);
// let flags = args[1];
//
// if flags & (1 << 0) != 0 {
// Process::exit_thread(Thread::current(), status);
// } else {
// Process::current().exit(status);
// }
//
// unreachable!();
// }
// SystemCall::WaitPid => {
// // TODO special "pid" values
// let pid = Pid::try_from(args[0] as u32)?;
// let status = arg::struct_mut::<i32>(args[1])?;
//
// match Process::waitpid(pid) {
// Ok(exit) => {
// *status = i32::from(exit);
// Ok(0)
// }
// e => e.map(|e| i32::from(e) as usize),
// }
// }
// SystemCall::WaitTid => {
// let tid = Tid::from(args[0] as u32);
//
// match Thread::waittid(tid) {
// Ok(_) => Ok(0),
// _ => todo!(),
// }
// }
// SystemCall::GetPid => Ok(u32::from(Process::current().id()) as usize),
// SystemCall::GetTid => Ok(u32::from(Thread::current().id()) as usize),
// SystemCall::Sleep => {
// let rem_buf = arg::option_buf_ref(args[1], size_of::<u64>() * 2)?;
// let mut rem = Duration::new(0, 0);
// let res = wait::sleep(Duration::from_nanos(args[0] as u64), &mut rem);
// if res == Err(Errno::Interrupt) {
// warnln!("Sleep interrupted, {:?} remaining", rem);
// if rem_buf.is_some() {
// todo!()
// }
// }
// res.map(|_| 0)
// }
// SystemCall::SetSignalEntry => {
// Thread::current().set_signal_entry(args[0], args[1]);
// Ok(0)
// }
// SystemCall::SignalReturn => {
// Thread::current().return_from_signal();
// unreachable!();
// }
// SystemCall::SendSignal => {
// let target = SignalDestination::from(args[0] as isize);
// let signal = Signal::try_from(args[1] as u32)?;
//
// match target {
// SignalDestination::This => Process::current().set_signal(signal),
// SignalDestination::Process(pid) => Process::get(pid)
// .ok_or(Errno::DoesNotExist)?
// .set_signal(signal),
// _ => todo!(),
// };
// Ok(0)
// }
// SystemCall::Yield => {
// proc::switch();
// Ok(0)
// }
// SystemCall::GetSid => {
// // TODO handle kernel processes here?
// let pid = Pid::to_option(args[0] as u32);
// let current = Process::current();
// let proc = if let Some(pid) = pid {
// let proc = Process::get(pid).ok_or(Errno::DoesNotExist)?;
// if proc.sid() != current.sid() {
// return Err(Errno::PermissionDenied);
// }
// proc
// } else {
// current
// };
//
// Ok(u32::from(proc.sid()) as usize)
// }
// SystemCall::GetPgid => {
// // TODO handle kernel processes here?
// let pid = Pid::to_option(args[0] as u32);
// let current = Process::current();
// let proc = if let Some(pid) = pid {
// Process::get(pid).ok_or(Errno::DoesNotExist)?
// } else {
// current
// };
//
// Ok(u32::from(proc.pgid()) as usize)
// }
// SystemCall::GetPpid => Ok(u32::from(Process::current().ppid().unwrap()) as usize),
// SystemCall::SetSid => {
// let proc = Process::current();
// let mut io = proc.io.lock();
//
// if let Some(_ctty) = io.ctty() {
// todo!();
// }
//
// let id = proc.id();
// proc.set_sid(id);
// Ok(u32::from(id) as usize)
// }
// SystemCall::SetPgid => {
// let pid = Pid::to_option(args[0] as u32);
// let pgid = Pid::to_option(args[1] as u32);
//
// let current = Process::current();
// let proc = if let Some(_pid) = pid {
// todo!()
// } else {
// current
// };
//
// if let Some(_pgid) = pgid {
// todo!();
// } else {
// proc.set_pgid(proc.id());
// }
//
// Ok(u32::from(proc.pgid()) as usize)
// }
//
// // System
// SystemCall::GetCpuTime => {
// let time = machine::local_timer().timestamp()?;
// Ok(time.as_nanos() as usize)
// }
SystemCall::Mount => {
let target = arg::str_ref(args[0], args[1])?;
let options = arg::struct_ref::<MountOptions>(args[2])?;
let proc = Process::current();
let mut io = proc.io.lock();
debugln!("mount(target={:?}, options={:#x?})", target, options);
let target_node = io.ioctx().find(None, target, true)?;
let root = create_filesystem(options)?;
target_node.mount(root)?;
Ok(0)
},
// Debugging
SystemCall::DebugTrace => {
let level = TraceLevel::from_repr(args[0])
.map(Level::from)
.ok_or(Errno::InvalidArgument)?;
let buf = arg::str_ref(args[1], args[2])?;
let thread = Thread::current();
let proc = thread.owner().unwrap();
println!(level, "[trace {:?}:{:?}] {}", proc.id(), thread.id(), buf);
Ok(args[1])
}
// // Handled elsewhere
// SystemCall::Fork => unreachable!(),
_ => panic!("Unimplemented: {:?}", num),
}
}
/// Main system call dispatcher function
pub fn syscall(num: SystemCall, args: &[usize]) -> Result<usize, Errno> {
todo!()
// let thread = Thread::current();
// let process = thread.owner().unwrap();
// let result = _syscall(num, args);
// if !thread.is_handling_signal() {
// process.handle_pending_signals();
// }
// result
let thread = Thread::current();
let process = thread.owner().unwrap();
let result = _syscall(num, args);
if !thread.is_handling_signal() {
// process.handle_pending_signals();
}
result
}
+38 -36
View File
@@ -15,57 +15,59 @@ use core::arch::asm;
// TODO document the syscall ABI
// rax
//
// rdi
// rsi
// rdx
// r10
// r8
// r9
// TODO move this to libusr
#[cfg(target_arch = "x86_64")]
macro_rules! syscall {
($num:expr) => {{
// let mut res: usize;
// asm!("svc #0", out("x0") res, in("x8") $num.repr(), options(nostack));
// res
loop {}
0
let mut res: usize = $num.repr();
asm!("syscall",
inout("rax") res,
options(nostack));
res
}};
($num:expr, $a0:expr) => {{
// let mut res: usize = $a0;
// asm!("svc #0",
// inout("x0") res,
// in("x8") $num.repr(), options(nostack));
// res
loop {}
0
let mut res: usize = $num.repr();
asm!("syscall",
inout("rax") res, in("rdi") $a0,
options(nostack));
res
}};
($num:expr, $a0:expr, $a1:expr) => {{
// let mut res: usize = $a0;
// asm!("svc #0",
// inout("x0") res, in("x1") $a1,
// in("x8") $num.repr(), options(nostack));
// res
loop {}
0
let mut res: usize = $num.repr();
asm!("syscall",
inout("rax") res, in("rdi") $a0, in("rsi") $a1,
options(nostack));
res
}};
($num:expr, $a0:expr, $a1:expr, $a2:expr) => {{
let mut res: usize = $a0;
let mut res: usize = $num.repr();
asm!("syscall",
inout("rax") res, in("rdi") $a1, in("rsi") $a2,
in("rdx") $num.repr(), options(nostack));
inout("rax") res, in("rdi") $a0, in("rsi") $a1,
in("rdx") $a2, options(nostack));
res
}};
($num:expr, $a0:expr, $a1:expr, $a2:expr, $a3:expr) => {{
// let mut res: usize = $a0;
// asm!("svc #0",
// inout("x0") res, in("x1") $a1, in("x2") $a2,
// in("x3") $a3, in("x8") $num.repr(), options(nostack));
// res
loop {}
0
let mut res: usize = $num.repr();
asm!("syscall",
inout("rax") res, in("rdi") $a0, in("rsi") $a1,
in("rdx") $a2, in("r10") $a3, options(nostack));
res
}};
($num:expr, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => {{
// let mut res: usize = $a0;
// asm!("svc #0",
// inout("x0") res, in("x1") $a1, in("x2") $a2,
// in("x3") $a3, in("x4") $a4, in("x8") $num.repr(), options(nostack));
// res
loop {}
0
let mut res: usize = $num.repr();
asm!("syscall",
inout("rax") res, in("rdi") $a0, in("rsi") $a1,
in("rdx") $a2, in("r10") $a3, in("r8") $a4, options(nostack));
res
}};
}
+9 -11
View File
@@ -26,14 +26,11 @@ extern "C" fn _start(arg: &'static ProgramArgs) -> ! {
fn main() -> i32;
}
trace!(TraceLevel::Debug, "Test!");
loop {}
// unsafe {
// allocator::init();
// thread::init_main();
// env::setup_env(arg);
// }
unsafe {
allocator::init();
thread::init_main();
env::setup_env(arg);
}
let res = unsafe { main() };
sys::sys_exit(ExitCode::from(res));
@@ -43,7 +40,8 @@ extern "C" fn _start(arg: &'static ProgramArgs) -> ! {
fn panic_handler(pi: &PanicInfo) -> ! {
// TODO unwind to send panic argument back to parent thread
// TODO print to stdout/stderr (if available)
let thread = thread::current();
trace!(TraceLevel::Error, "{:?} panicked: {:?}", thread, pi);
sys::sys_exit(ExitCode::from(-1));
// let thread = thread::current();
// trace!(TraceLevel::Error, "{:?} panicked: {:?}", thread, pi);
loop {}
// sys::sys_exit(ExitCode::from(-1));
}
+20 -11
View File
@@ -9,7 +9,8 @@ use libusr::sys::{stat::MountOptions, sys_execve, sys_fork, sys_mount, sys_waitp
#[no_mangle]
fn main() -> i32 {
loop {}
println!("Test");
trace_debug!("test!");
sys_mount(
"/dev",
@@ -28,15 +29,23 @@ fn main() -> i32 {
)
.expect("Failed to mount sysfs");
if let Some(pid) = unsafe { sys_fork().unwrap() } {
let mut status = 0;
sys_waitpid(pid, &mut status).unwrap();
println!("Process {:?} exited with status {}", pid, status);
let pid = unsafe { sys_fork().unwrap() };
loop {
}
} else {
sys_execve("/sbin/login", &["/sbin/login", "/dev/ttyS0"]).unwrap();
unreachable!();
}
trace_debug!("fork returned {:?}", pid);
loop {}
// loop {}
// if let Some(pid) = unsafe { sys_fork().unwrap() } {
// let mut status = 0;
// sys_waitpid(pid, &mut status).unwrap();
// println!("Process {:?} exited with status {}", pid, status);
// loop {
// }
// } else {
// sys_execve("/sbin/login", &["/sbin/login", "/dev/ttyS0"]).unwrap();
// unreachable!();
// }
}