Add process table and exit syscall (#268)

* Add process table

* Add exit syscall

* Update binaries

* Make pid mutable

* Use RW lock for the process table

* Change pid atomic ordering

* Fix return code

* Fix lock issue

* Add debug print

* Add exit to sleep binary

* Enable asm_sym feature

* Use the end of code area for stack area

* Add debug macro

* Use array instead of vec for process

* Refactor process data clone

* Increase max file handles to 32

* Increase sleep to 5 seconds

* Fix MAX_PID calculation

* Revert max file handle value to fix crash

* Close file handle after dup syscall

* Remove init

* Run the test in release mode

* Refactor debug

* Refactor debug output of syscall

* Remove NULL syscall

* Save and restore stack frame

* Fix install

* Save only scratch registers to the stack

* Add write volatile to registers

* Overwrite rax register on exit

* Set pid back to 0 after exit

* Add alloc_page function

* Remove debug output

* Unmap pages after exit

* Allocate memory after kernel heap

* Hide unmap error
This commit is contained in:
Vincent Ollivier 2021-11-27 09:56:52 +01:00 committed by GitHub
parent 35f03ee644
commit e75c287098
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 272 additions and 153 deletions

View File

@ -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)

View File

@ -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:

Binary file not shown.

Binary file not shown.

View File

@ -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

View File

@ -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

View File

@ -149,7 +149,8 @@ pub fn reopen(path: &str, handle: usize) -> Result<usize, ()> {
};
if let Some(old_handle) = res {
syscall::dup(old_handle, handle);
return Ok(old_handle);
syscall::close(old_handle);
return Ok(handle);
}
Err(())
}

View File

@ -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<T: RangeBounds<usize>>(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();

View File

@ -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()) };
}

View File

@ -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 {}
}

View File

@ -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 {}
}

View File

@ -43,6 +43,46 @@ pub fn init_heap(mapper: &mut impl Mapper<Size4KiB>, 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<Size4KiB> = {
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<Mutex<Vec<u8>>>,

View File

@ -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) };
}

View File

@ -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
}
});
}

View File

@ -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<ProcessData> = 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<String, String>,
dir: String,
user: Option<String>,
file_handles: Vec<Option<Resource>>,
code_addr: u64,
file_handles: [Option<Resource>; 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<String> {
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<String, String> {
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<String> {
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<usize, ()> {
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<usize, ()> {
}
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<Resource> {
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<Process, ()> {
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<usize, ()> {
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()];
Ok(Process { stack_addr, stack_size, code_addr, entry_point })
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(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,
);
}

View File

@ -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

View File

@ -1,4 +1,3 @@
pub const NULL: usize = 0x0;
pub const EXIT: usize = 0x1;
pub const SPAWN: usize = 0x2;
pub const READ: usize = 0x3;

View File

@ -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

View File

@ -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),