diff --git a/CHANGELOG.md b/CHANGELOG.md index d8628b001..60e45c6c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## Unreleased +- Add process table and exit syscall (#268) - Improve UTF-8 support (#267) - Bump acpi from 4.0.0 to 4.1.0 (#265) - Add shell redirections (#262) diff --git a/Makefile b/Makefile index 861f360e4..d1443d481 100644 --- a/Makefile +++ b/Makefile @@ -52,7 +52,7 @@ qemu: qemu-system-x86_64 $(opts) test: - cargo test --lib --no-default-features --features serial,$(nic) -- \ + cargo test --release --lib --no-default-features --features serial,$(nic) -- \ -m 32 -display none -serial stdio -device isa-debug-exit,iobase=0xf4,iosize=0x04 clean: diff --git a/dsk/bin/hello b/dsk/bin/hello index 7d84c1a3f..e76d47492 100755 Binary files a/dsk/bin/hello and b/dsk/bin/hello differ diff --git a/dsk/bin/sleep b/dsk/bin/sleep index 317582975..bf41f2ed3 100644 Binary files a/dsk/bin/sleep and b/dsk/bin/sleep differ diff --git a/dsk/src/bin/hello.s b/dsk/src/bin/hello.s index cc8c7d1b0..d4b59ea95 100644 --- a/dsk/src/bin/hello.s +++ b/dsk/src/bin/hello.s @@ -11,4 +11,6 @@ _start: mov rsi, msg ; addr of string mov rdx, 14 ; size of string int 0x80 - jmp _start + mov rax, 1 ; syscall number for EXIT + mov rdi, 0 ; no error + int 0x80 diff --git a/dsk/src/bin/sleep.s b/dsk/src/bin/sleep.s index b91a880d7..8e10abb4c 100644 --- a/dsk/src/bin/sleep.s +++ b/dsk/src/bin/sleep.s @@ -1,8 +1,10 @@ [bits 64] _start: mov rax, 9 ; syscall number for SLEEP - mov rdi, __float64__(1.0) ; time to sleep in seconds + mov rdi, __float64__(5.0) ; time to sleep in seconds mov rsi, 0 mov rdx, 0 int 0x80 - jmp _start + mov rax, 1 ; syscall number for EXIT + mov rdi, 0 ; no error + int 0x80 diff --git a/src/api/fs.rs b/src/api/fs.rs index 2974026bb..8b7823ec3 100644 --- a/src/api/fs.rs +++ b/src/api/fs.rs @@ -149,7 +149,8 @@ pub fn reopen(path: &str, handle: usize) -> Result { }; if let Some(old_handle) = res { syscall::dup(old_handle, handle); - return Ok(old_handle); + syscall::close(old_handle); + return Ok(handle); } Err(()) } diff --git a/src/api/regex.rs b/src/api/regex.rs index 471015eea..77cd101f8 100644 --- a/src/api/regex.rs +++ b/src/api/regex.rs @@ -3,16 +3,6 @@ use alloc::vec::Vec; use core::convert::From; use core::ops::RangeBounds; -// TODO: Remove this when tests are done -const DEBUG: bool = false; -macro_rules! debug { - ($($arg:tt)*) => ({ - if DEBUG { - println!("{}", format_args!($($arg)*)); - } - }); -} - // See "A Regular Expression Matcher" by Rob Pike and Brian Kernighan (2007) #[derive(Debug)] @@ -72,7 +62,6 @@ pub struct Regex(String); impl Regex { pub fn new(re: &str) -> Self { - debug!("debug: Regex::new({:?})", re); Self(re.to_string()) } pub fn is_match(&self, text: &str) -> bool { @@ -92,7 +81,6 @@ impl Regex { } fn is_match(re: &[char], text: &[char], start: &mut usize, end: &mut usize) -> bool { - debug!("debug: is_match({:?}, {:?})", re, text); if re.len() == 0 { return true; } @@ -116,7 +104,6 @@ fn is_match(re: &[char], text: &[char], start: &mut usize, end: &mut usize) -> b } fn is_match_here(re: &[char], text: &[char], end: &mut usize) -> bool { - debug!("debug: is_match_here({:?}, {:?})", re, text); if re.len() == 0 { return true; } @@ -148,22 +135,18 @@ fn is_match_here(re: &[char], text: &[char], end: &mut usize) -> bool { } fn is_match_star(lazy: bool, mc: MetaChar, re: &[char], text: &[char], end: &mut usize) -> bool { - debug!("debug: is_match_star({:?}, {:?}, {:?}", mc, re, text); is_match_char(lazy, mc, re, text, .., end) } fn is_match_plus(lazy: bool, mc: MetaChar, re: &[char], text: &[char], end: &mut usize) -> bool { - debug!("debug: is_match_plus({:?}, {:?}, {:?}", mc, re, text); is_match_char(lazy, mc, re, text, 1.., end) } fn is_match_ques(lazy: bool, mc: MetaChar, re: &[char], text: &[char], end: &mut usize) -> bool { - debug!("debug: is_match_ques({:?}, {:?}, {:?}", mc, re, text); is_match_char(lazy, mc, re, text, ..2, end) } fn is_match_char>(lazy: bool, mc: MetaChar, re: &[char], text: &[char], range: T, end: &mut usize) -> bool { - debug!("debug: is_match_char({:?}, {:?}, {:?}", mc, re, text); let mut i = 0; let n = text.len(); diff --git a/src/api/syscall.rs b/src/api/syscall.rs index 60974b4fe..7be6ac125 100644 --- a/src/api/syscall.rs +++ b/src/api/syscall.rs @@ -2,6 +2,10 @@ use crate::syscall; use crate::sys::syscall::number::*; use crate::sys::fs::FileStat; +pub fn exit(code: usize) -> usize { + unsafe { syscall!(EXIT, code as u64) } +} + pub fn sleep(seconds: f64) { unsafe { syscall!(SLEEP, seconds.to_bits()) }; } diff --git a/src/bin/hello.rs b/src/bin/hello.rs index 2b145475f..49493e8f0 100644 --- a/src/bin/hello.rs +++ b/src/bin/hello.rs @@ -11,7 +11,7 @@ fn panic(_info: &PanicInfo) -> ! { #[no_mangle] pub unsafe extern "sysv64" fn _start() -> ! { - loop { - syscall::write(1, b"Hello, World!\n"); - } + syscall::write(1, b"Hello, World!\n"); + syscall::exit(0); + loop {} } diff --git a/src/bin/sleep.rs b/src/bin/sleep.rs index 763682dbc..0138d23df 100644 --- a/src/bin/sleep.rs +++ b/src/bin/sleep.rs @@ -11,7 +11,7 @@ fn panic(_info: &PanicInfo) -> ! { #[no_mangle] pub unsafe extern "sysv64" fn _start() -> ! { - loop { - syscall::sleep(1.0); - } + syscall::sleep(5.0); + syscall::exit(0); + loop {} } diff --git a/src/sys/allocator.rs b/src/sys/allocator.rs index a3df1dd90..127e96369 100644 --- a/src/sys/allocator.rs +++ b/src/sys/allocator.rs @@ -43,6 +43,46 @@ pub fn init_heap(mapper: &mut impl Mapper, frame_allocator: &mut impl Ok(()) } +pub fn alloc_pages(addr: u64, size: u64) { + let mut mapper = unsafe { sys::mem::mapper(VirtAddr::new(sys::mem::PHYS_MEM_OFFSET)) }; + let mut frame_allocator = unsafe { sys::mem::BootInfoFrameAllocator::init(sys::mem::MEMORY_MAP.unwrap()) }; + let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::USER_ACCESSIBLE; + let pages = { + let start_page = Page::containing_address(VirtAddr::new(addr)); + let end_page = Page::containing_address(VirtAddr::new(addr + size)); + Page::range_inclusive(start_page, end_page) + }; + for page in pages { + let frame = frame_allocator.allocate_frame().unwrap(); + unsafe { + if let Ok(mapping) = mapper.map_to(page, frame, flags, &mut frame_allocator) { + mapping.flush(); + } else { + debug!("Could not map {:?}", page); + } + } + } +} + +use x86_64::structures::paging::page::PageRangeInclusive; + +// TODO: Replace `free` by `dealloc` +pub fn free_pages(addr: u64, size: u64) { + let mut mapper = unsafe { sys::mem::mapper(VirtAddr::new(sys::mem::PHYS_MEM_OFFSET)) }; + let pages: PageRangeInclusive = { + let start_page = Page::containing_address(VirtAddr::new(addr)); + let end_page = Page::containing_address(VirtAddr::new(addr + size)); + Page::range_inclusive(start_page, end_page) + }; + for page in pages { + if let Ok((_frame, mapping)) = mapper.unmap(page) { + mapping.flush(); + } else { + //debug!("Could not unmap {:?}", page); + } + } +} + #[derive(Clone)] pub struct PhysBuf { buf: Arc>>, diff --git a/src/sys/idt.rs b/src/sys/idt.rs index 649395025..67bfaa76e 100644 --- a/src/sys/idt.rs +++ b/src/sys/idt.rs @@ -1,9 +1,11 @@ use crate::sys; +use crate::sys::process::Registers; + use lazy_static::lazy_static; use spin::Mutex; use x86_64::instructions::interrupts; use x86_64::instructions::port::Port; -use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode}; +use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, InterruptStackFrameValue, PageFaultErrorCode}; const PIC1: u16 = 0x21; const PIC2: u16 = 0xA1; @@ -116,36 +118,14 @@ extern "x86-interrupt" fn segment_not_present_handler(stack_frame: InterruptStac panic!("EXCEPTION: SEGMENT NOT PRESENT\n{:#?}", stack_frame); } -// See: https://github.com/xfoxfu/rust-xos/blob/8a07a69ef/kernel/src/interrupts/handlers.rs#L92 -#[repr(align(8), C)] -#[derive(Debug, Clone, Default)] -pub struct Registers { - r15: usize, - r14: usize, - r13: usize, - r12: usize, - r11: usize, - r10: usize, - r9: usize, - r8: usize, - rdi: usize, - rsi: usize, - rdx: usize, - rcx: usize, - rbx: usize, - rax: usize, - rbp: usize, -} - -// See: https://github.com/xfoxfu/rust-xos/blob/8a07a69ef/kernel/src/interrupts/handlers.rs#L112 +// Naked function wrapper saving all scratch registers to the stack +// See: https://os.phil-opp.com/returning-from-exceptions/#a-naked-wrapper-function macro_rules! wrap { ($fn: ident => $w:ident) => { #[naked] pub unsafe extern "sysv64" fn $w() { asm!( - "push rbp", "push rax", - "push rbx", "push rcx", "push rdx", "push rsi", @@ -154,18 +134,10 @@ macro_rules! wrap { "push r9", "push r10", "push r11", - "push r12", - "push r13", - "push r14", - "push r15", "mov rsi, rsp", // Arg #2: register list "mov rdi, rsp", // Arg #1: interupt frame - "add rdi, 15 * 8", + "add rdi, 9 * 8", "call {}", - "pop r15", - "pop r14", - "pop r13", - "pop r12", "pop r11", "pop r10", "pop r9", @@ -174,9 +146,7 @@ macro_rules! wrap { "pop rsi", "pop rdx", "pop rcx", - "pop rbx", "pop rax", - "pop rbp", "iretq", sym $fn, options(noreturn) @@ -190,13 +160,31 @@ wrap!(syscall_handler => wrapped_syscall_handler); // NOTE: We can't use "x86-interrupt" for syscall_handler because we need to // return a result in the RAX register and it will be overwritten when the // context of the caller is restored. -extern "sysv64" fn syscall_handler(_stack_frame: &mut InterruptStackFrame, regs: &mut Registers) { +extern "sysv64" fn syscall_handler(stack_frame: &mut InterruptStackFrame, regs: &mut Registers) { // The registers order follow the System V ABI convention let n = regs.rax; let arg1 = regs.rdi; let arg2 = regs.rsi; let arg3 = regs.rdx; - regs.rax = sys::syscall::dispatcher(n, arg1, arg2, arg3); + + if n == sys::syscall::number::SPAWN { // Backup CPU context + sys::process::set_stack_frame(stack_frame.clone()); + sys::process::set_registers(regs.clone()); + } + + let res = sys::syscall::dispatcher(n, arg1, arg2, arg3); + + if n == sys::syscall::number::EXIT { // Restore CPU context + let sf = sys::process::stack_frame(); + unsafe { + //stack_frame.as_mut().write(sf); + core::ptr::write_volatile(stack_frame.as_mut().extract_inner() as *mut InterruptStackFrameValue, sf); // FIXME + core::ptr::write_volatile(regs, sys::process::registers()); + } + } + + regs.rax = res; + unsafe { sys::pic::PICS.lock().notify_end_of_interrupt(0x80) }; } diff --git a/src/sys/mod.rs b/src/sys/mod.rs index b4c27c11d..21489d7a0 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -5,6 +5,17 @@ macro_rules! printk { }); } +#[macro_export] +macro_rules! debug { + ($($arg:tt)*) => ({ + let csi_color = $crate::api::console::Style::color("Yellow"); + let csi_reset = $crate::api::console::Style::reset(); + $crate::sys::console::print_fmt(format_args!("{}DEBUG: ", csi_color)); + $crate::sys::console::print_fmt(format_args!($($arg)*)); + $crate::sys::console::print_fmt(format_args!("{}\n", csi_reset)); + }); +} + #[macro_export] macro_rules! log { ($($arg:tt)*) => ({ @@ -14,6 +25,7 @@ macro_rules! log { let csi_reset = $crate::api::console::Style::reset(); $crate::sys::console::print_fmt(format_args!("{}[{:.6}]{} ", csi_color, uptime, csi_reset)); $crate::sys::console::print_fmt(format_args!($($arg)*)); + // TODO: Add newline } }); } diff --git a/src/sys/process.rs b/src/sys/process.rs index 3903624e8..6ed7298fb 100644 --- a/src/sys/process.rs +++ b/src/sys/process.rs @@ -2,83 +2,101 @@ use crate::sys::fs::{Resource, Device}; use crate::sys::console::Console; use alloc::collections::btree_map::BTreeMap; use alloc::string::{String, ToString}; -use alloc::vec; -use alloc::vec::Vec; use core::sync::atomic::{AtomicUsize, Ordering}; use lazy_static::lazy_static; use object::{Object, ObjectSegment}; -use spin::Mutex; +use spin::RwLock; +use x86_64::structures::idt::InterruptStackFrameValue; -const MAX_FILE_HANDLES: usize = 1024; +const MAX_FILE_HANDLES: usize = 16; // FIXME Increasing this cause boot crashes +const MAX_PROCS: usize = 2; // TODO: Update this when EXIT syscall is working lazy_static! { - pub static ref PIDS: AtomicUsize = AtomicUsize::new(0); - pub static ref PROCESS: Mutex = Mutex::new(ProcessData::new("/", None)); // TODO + pub static ref PID: AtomicUsize = AtomicUsize::new(0); + pub static ref MAX_PID: AtomicUsize = AtomicUsize::new(1); + pub static ref PROCESS_TABLE: RwLock<[Process; MAX_PROCS]> = RwLock::new([(); MAX_PROCS].map(|_| Process::new(0))); } +#[derive(Clone, Debug)] pub struct ProcessData { - id: usize, env: BTreeMap, dir: String, user: Option, - file_handles: Vec>, - code_addr: u64, + file_handles: [Option; MAX_FILE_HANDLES], } impl ProcessData { pub fn new(dir: &str, user: Option<&str>) -> Self { - let id = PIDS.fetch_add(1, Ordering::SeqCst); let env = BTreeMap::new(); let dir = dir.to_string(); let user = user.map(String::from); - let code_addr = 0; - let mut file_handles = vec![None; MAX_FILE_HANDLES]; + let mut file_handles = [(); MAX_FILE_HANDLES].map(|_| None); file_handles[0] = Some(Resource::Device(Device::Console(Console::new()))); file_handles[1] = Some(Resource::Device(Device::Console(Console::new()))); file_handles[2] = Some(Resource::Device(Device::Console(Console::new()))); - Self { id, env, dir, user, file_handles, code_addr } + Self { env, dir, user, file_handles } } } pub fn id() -> usize { - PROCESS.lock().id + PID.load(Ordering::SeqCst) +} + +pub fn set_id(id: usize) { + PID.store(id, Ordering::SeqCst) } pub fn env(key: &str) -> Option { - PROCESS.lock().env.get(key).cloned() + let table = PROCESS_TABLE.read(); + let proc = &table[id()]; + proc.data.env.get(key).cloned() } pub fn envs() -> BTreeMap { - PROCESS.lock().env.clone() + let table = PROCESS_TABLE.read(); + let proc = &table[id()]; + proc.data.env.clone() } pub fn dir() -> String { - PROCESS.lock().dir.clone() + let table = PROCESS_TABLE.read(); + let proc = &table[id()]; + proc.data.dir.clone() } pub fn user() -> Option { - PROCESS.lock().user.clone() + let table = PROCESS_TABLE.read(); + let proc = &table[id()]; + proc.data.user.clone() } pub fn set_env(key: &str, val: &str) { - PROCESS.lock().env.insert(key.into(), val.into()); + let mut table = PROCESS_TABLE.write(); + let proc = &mut table[id()]; + proc.data.env.insert(key.into(), val.into()); } pub fn set_dir(dir: &str) { - PROCESS.lock().dir = dir.into(); + let mut table = PROCESS_TABLE.write(); + let proc = &mut table[id()]; + proc.data.dir = dir.into(); } pub fn set_user(user: &str) { - PROCESS.lock().user = Some(user.into()) + let mut table = PROCESS_TABLE.write(); + let proc = &mut table[id()]; + proc.data.user = Some(user.into()) } pub fn create_file_handle(file: Resource) -> Result { + let mut table = PROCESS_TABLE.write(); + let proc = &mut table[id()]; + let min = 4; // The first 4 file handles are reserved let max = MAX_FILE_HANDLES; - let proc = &mut *PROCESS.lock(); for handle in min..max { - if proc.file_handles[handle].is_none() { - proc.file_handles[handle] = Some(file); + if proc.data.file_handles[handle].is_none() { + proc.data.file_handles[handle] = Some(file); return Ok(handle); } } @@ -86,30 +104,69 @@ pub fn create_file_handle(file: Resource) -> Result { } pub fn update_file_handle(handle: usize, file: Resource) { - let proc = &mut *PROCESS.lock(); - proc.file_handles[handle] = Some(file); + let mut table = PROCESS_TABLE.write(); + let proc = &mut table[id()]; + proc.data.file_handles[handle] = Some(file); } pub fn delete_file_handle(handle: usize) { - let proc = &mut *PROCESS.lock(); - proc.file_handles[handle] = None; + let mut table = PROCESS_TABLE.write(); + let proc = &mut table[id()]; + proc.data.file_handles[handle] = None; } pub fn file_handle(handle: usize) -> Option { - let proc = &mut *PROCESS.lock(); - proc.file_handles[handle].clone() + let table = PROCESS_TABLE.read(); + let proc = &table[id()]; + proc.data.file_handles[handle].clone() } pub fn code_addr() -> u64 { - PROCESS.lock().code_addr + let table = PROCESS_TABLE.read(); + let proc = &table[id()]; + proc.code_addr } pub fn set_code_addr(addr: u64) { - PROCESS.lock().code_addr = addr; + let mut table = PROCESS_TABLE.write(); + let mut proc = &mut table[id()]; + proc.code_addr = addr; } pub fn ptr_from_addr(addr: u64) -> *mut u8 { - (PROCESS.lock().code_addr + addr) as *mut u8 + (code_addr() + addr) as *mut u8 +} + +pub fn registers() -> Registers { + let table = PROCESS_TABLE.read(); + let proc = &table[id()]; + proc.registers.clone() +} + +pub fn set_registers(regs: Registers) { + let mut table = PROCESS_TABLE.write(); + let mut proc = &mut table[id()]; + proc.registers = regs +} + +pub fn stack_frame() -> InterruptStackFrameValue { + let table = PROCESS_TABLE.read(); + let proc = &table[id()]; + proc.stack_frame.clone() +} + +pub fn set_stack_frame(stack_frame: InterruptStackFrameValue) { + let mut table = PROCESS_TABLE.write(); + let mut proc = &mut table[id()]; + proc.stack_frame = stack_frame; +} + +pub fn exit() { + let table = PROCESS_TABLE.read(); + let proc = &table[id()]; + sys::allocator::free_pages(proc.code_addr, proc.code_size); + MAX_PID.fetch_sub(1, Ordering::SeqCst); + set_id(0); // FIXME: No process manager so we switch back to process 0 } /************************ @@ -123,66 +180,82 @@ use crate::sys; use crate::sys::gdt::GDT; use core::sync::atomic::AtomicU64; use x86_64::VirtAddr; -use x86_64::structures::paging::{Mapper, FrameAllocator}; -use x86_64::structures::paging::{Page, PageTableFlags}; -static STACK_ADDR: AtomicU64 = AtomicU64::new(0x200_0000); -static CODE_ADDR: AtomicU64 = AtomicU64::new(0x100_0000); +static CODE_ADDR: AtomicU64 = AtomicU64::new((sys::allocator::HEAP_START as u64) + (16 << 20)); // 16 MB const PAGE_SIZE: u64 = 4 * 1024; +#[repr(align(8), C)] +#[derive(Debug, Clone, Copy, Default)] +pub struct Registers { + pub r11: usize, + pub r10: usize, + pub r9: usize, + pub r8: usize, + pub rdi: usize, + pub rsi: usize, + pub rdx: usize, + pub rcx: usize, + pub rax: usize, +} + +const ELF_MAGIC: [u8; 4] = [0x74, b'E', b'L', b'F']; + +#[derive(Clone, Debug)] pub struct Process { - stack_addr: u64, - stack_size: u64, + id: usize, code_addr: u64, + code_size: u64, entry_point: u64, + stack_frame: InterruptStackFrameValue, + registers: Registers, + data: ProcessData, } impl Process { - pub fn create(bin: &[u8]) -> Result { - let mut mapper = unsafe { sys::mem::mapper(VirtAddr::new(sys::mem::PHYS_MEM_OFFSET)) }; - let mut frame_allocator = unsafe { sys::mem::BootInfoFrameAllocator::init(sys::mem::MEMORY_MAP.unwrap()) }; - - - let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::USER_ACCESSIBLE; - - let stack_size = 256 * PAGE_SIZE; - let stack_addr = STACK_ADDR.fetch_add(stack_size, Ordering::SeqCst); - let pages = { - let stack_start_page = Page::containing_address(VirtAddr::new(stack_addr)); - let stack_end_page = Page::containing_address(VirtAddr::new(stack_addr + stack_size)); - Page::range_inclusive(stack_start_page, stack_end_page) + pub fn new(id: usize) -> Self { + let isf = InterruptStackFrameValue { + instruction_pointer: VirtAddr::new(0), + code_segment: 0, + cpu_flags: 0, + stack_pointer: VirtAddr::new(0), + stack_segment: 0, }; - for page in pages { - let frame = frame_allocator.allocate_frame().unwrap(); - unsafe { - mapper.map_to(page, frame, flags, &mut frame_allocator).unwrap().flush(); - } + Self { + id, + code_addr: 0, + code_size: 0, + entry_point: 0, + stack_frame: isf, + registers: Registers::default(), + data: ProcessData::new("/", None), + } + } + + pub fn spawn(bin: &[u8]) { + if let Ok(pid) = Self::create(bin) { + let proc = { + let table = PROCESS_TABLE.read(); + table[pid].clone() + }; + proc.exec(); } + } + fn create(bin: &[u8]) -> Result { let code_size = 1024 * PAGE_SIZE; let code_addr = CODE_ADDR.fetch_add(code_size, Ordering::SeqCst); - let pages = { - let code_start_page = Page::containing_address(VirtAddr::new(code_addr)); - let code_end_page = Page::containing_address(VirtAddr::new(code_addr + code_size)); - Page::range_inclusive(code_start_page, code_end_page) - }; - for page in pages { - let frame = frame_allocator.allocate_frame().unwrap(); - unsafe { - mapper.map_to(page, frame, flags, &mut frame_allocator).unwrap().flush(); - } - } + sys::allocator::alloc_pages(code_addr, code_size); let mut entry_point = 0; let code_ptr = code_addr as *mut u8; - if &bin[1..4] == b"ELF" { // ELF binary + if &bin[0..4] == ELF_MAGIC { // ELF binary if let Ok(obj) = object::File::parse(bin) { entry_point = obj.entry(); for segment in obj.segments() { let addr = segment.address() as usize; if let Ok(data) = segment.data() { - unsafe { - for (i, op) in data.iter().enumerate() { + for (i, op) in data.iter().enumerate() { + unsafe { let ptr = code_ptr.add(addr + i); core::ptr::write(ptr, *op); } @@ -191,24 +264,31 @@ impl Process { } } } else { // Raw binary - unsafe { - for (i, op) in bin.iter().enumerate() { + for (i, op) in bin.iter().enumerate() { + unsafe { let ptr = code_ptr.add(i); core::ptr::write(ptr, *op); } } } - set_code_addr(code_addr); + let mut table = PROCESS_TABLE.write(); + let parent = &table[id()]; + + let data = parent.data.clone(); + let registers = parent.registers.clone(); + let stack_frame = parent.stack_frame.clone(); + + let id = MAX_PID.fetch_add(1, Ordering::SeqCst); + let proc = Process { id, code_addr, code_size, entry_point, data, stack_frame, registers }; + table[id] = proc; - Ok(Process { stack_addr, stack_size, code_addr, entry_point }) + Ok(id) } // Switch to user mode and execute the program - pub fn exec(&self) { - //x86_64::instructions::tlb::flush_all(); - let data = GDT.1.user_data.0; - let code = GDT.1.user_code.0; + fn exec(&self) { + set_id(self.id); // Change PID unsafe { asm!( "cli", // Disable interrupts @@ -218,9 +298,9 @@ impl Process { "push rdx", // Code segment (CS) "push rdi", // Instruction pointer (RIP) "iretq", - in("rax") data, - in("rsi") self.stack_addr + self.stack_size, - in("rdx") code, + in("rax") GDT.1.user_data.0, + in("rsi") self.code_addr + self.code_size, + in("rdx") GDT.1.user_code.0, in("rdi") self.code_addr + self.entry_point, ); } diff --git a/src/sys/syscall/mod.rs b/src/sys/syscall/mod.rs index ae1dc8dd5..f843656af 100644 --- a/src/sys/syscall/mod.rs +++ b/src/sys/syscall/mod.rs @@ -10,6 +10,9 @@ use crate::sys::fs::FileStat; pub fn dispatcher(n: usize, arg1: usize, arg2: usize, arg3: usize) -> usize { match n { + number::EXIT => { + service::exit(arg1) + } number::SLEEP => { service::sleep(f64::from_bits(arg1 as u64)); 0 diff --git a/src/sys/syscall/number.rs b/src/sys/syscall/number.rs index 1d58d8554..fc518cf71 100644 --- a/src/sys/syscall/number.rs +++ b/src/sys/syscall/number.rs @@ -1,4 +1,3 @@ -pub const NULL: usize = 0x0; pub const EXIT: usize = 0x1; pub const SPAWN: usize = 0x2; pub const READ: usize = 0x3; diff --git a/src/sys/syscall/service.rs b/src/sys/syscall/service.rs index dc850b478..0c11d665c 100644 --- a/src/sys/syscall/service.rs +++ b/src/sys/syscall/service.rs @@ -4,6 +4,11 @@ use crate::sys::fs::FileIO; use crate::sys::process::Process; use alloc::vec; +pub fn exit(_code: usize) -> usize { + sys::process::exit(); + 0 +} + pub fn sleep(seconds: f64) { sys::time::sleep(seconds); } @@ -71,10 +76,8 @@ pub fn spawn(path: &str) -> isize { let mut buf = vec![0; file.size()]; if let Ok(bytes) = file.read(&mut buf) { buf.resize(bytes, 0); - if let Ok(process) = Process::create(&buf) { - process.exec(); - return 0; - } + Process::spawn(&buf); + return 0; } } -1 diff --git a/src/usr/shell.rs b/src/usr/shell.rs index 7c521309e..62a74192e 100644 --- a/src/usr/shell.rs +++ b/src/usr/shell.rs @@ -181,6 +181,7 @@ pub fn exec(cmd: &str) -> ExitCode { let res = match args[0] { "" => ExitCode::CommandSuccessful, + "test" => { api::syscall::exit(0); ExitCode::CommandSuccessful }, "a" | "alias" => ExitCode::CommandUnknown, "b" => ExitCode::CommandUnknown, "c" | "copy" => usr::copy::main(&args),