Commit 4e98cbcc authored by Nifou's avatar Nifou

Syscall can return POSIX compatible errors

parent c2ed9c5f
/*
* Copyright (C) 2020 Nicolas Fouquet
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see https://www.gnu.org/licenses.
*/
//! This module defines the errors which can be used in the syscalls
/// An error happens during a syscall
pub enum Error {
/// Invalid value
EINVAL = 22,
/// Function not implemented
ENOSYS = 38,
}
/// A return type for all syscalls
pub type Result = core::result::Result<usize, Error>;
......@@ -18,7 +18,7 @@
use core::str::from_utf8;
use core::slice::from_raw_parts;
use super::Syscall;
use super::{Syscall, error::Result};
const STDIN: usize = 0;
const STDOUT: usize = 1;
......@@ -26,7 +26,7 @@ const STDERR: usize = 2;
impl Syscall {
/// Write to the corresponding file descriptor
pub fn write(&mut self, fd: usize, buf: usize, count: usize) -> usize {
pub fn write(&mut self, fd: usize, buf: usize, count: usize) -> Result {
match fd {
STDIN | STDOUT | STDERR => {
let content = unsafe { from_utf8(from_raw_parts(buf as *const u8, count)) }
......@@ -36,6 +36,6 @@ impl Syscall {
},
_ => println!("We can't write in files for now. Sorry!"),
}
count
Ok(count)
}
}
......@@ -19,7 +19,7 @@ use bitflags::bitflags;
use x86_64::structures::paging::page_table::PageTableFlags as Flags;
use crate::tasking::processor::{PROCESSOR, PROCESSES};
use super::Syscall;
use super::{Syscall, error::{Result, Error}};
bitflags! {
struct MmapFlags: u32 {
......@@ -64,7 +64,7 @@ impl From<MmapProt> for Flags {
impl Syscall {
/// Map files or devices into memory
pub fn mmap(&self, addr: usize, len: usize, prot: usize, flags: usize, fd: usize, offset: usize)
-> usize {
-> Result {
println!("mmap({:#x}, {}, {}, {}, {:#x}, {})", addr, len, prot, flags, fd, offset);
let prot = MmapProt::from_bits_truncate(prot as u32);
......@@ -83,19 +83,19 @@ impl Syscall {
processes.get_mut(&current_process).unwrap().memory.map(0x300000, 0x300000 + len as u64, Flags::from(prot), Flags::PRESENT);
processes.get_mut(&current_process).unwrap().memory.switch_page_table();
0x300000
Ok(0x300000)
}
else {
addr
Ok(addr)
}
}
else {
0
Err(Error::EINVAL)
}
}
/// Change data segment size
pub fn brk(&self, addr: usize) -> usize {
pub fn brk(&self, addr: usize) -> Result {
print!("brk({:#x}) = ", addr);
if addr == 0 {
......@@ -111,11 +111,11 @@ impl Syscall {
processes.get_mut(&current_process).unwrap().memory.map(0x10000000, 0x10004000, Flags::PRESENT | Flags::WRITABLE, Flags::PRESENT);
processes.get_mut(&current_process).unwrap().memory.switch_page_table();
0x10000000
Ok(0x10000000)
}
else {
println!("{:#x}", addr);
addr
Ok(addr)
}
}
}
......@@ -20,11 +20,11 @@ use x86_64::{
registers::model_specific::FsBase,
};
use super::Syscall;
use super::{Syscall, error::Result};
impl Syscall {
/// Set og get some architecture specific registers
pub fn arch_prctl(&mut self, code: usize, addr: usize) -> usize {
pub fn arch_prctl(&mut self, code: usize, addr: usize) -> Result {
println!("arch_prctl({:#x}, {:#x}) = 0", code, addr);
const ARCH_SET_FS: usize = 0x1002;
......@@ -34,6 +34,6 @@ impl Syscall {
},
_ => (),
}
0
Ok(0)
}
}
......@@ -22,11 +22,13 @@
use x86::msr;
use crate::tasking::context::Registers;
use self::error::Error;
pub mod process;
pub mod fs;
pub mod memory;
pub mod misc;
pub mod error;
/// Init the syscalls by setting some [model specific registers](https://en.wikipedia.org/wiki/Model-specific_register).
pub unsafe fn init() {
......@@ -50,7 +52,7 @@ pub unsafe fn init() {
/// * Restores the register's values
pub unsafe extern fn syscall() {
#[inline(never)]
unsafe fn inner(stack: &'static mut Registers) -> usize {
unsafe fn inner(stack: &'static mut Registers) -> isize {
Syscall::new(stack).syscall()
}
......@@ -113,8 +115,11 @@ pub unsafe extern fn syscall() {
const WRITE: usize = 1;
const MMAP: usize = 9;
const BRK: usize = 12;
const SIGACTION: usize = 13;
const SIGPROCMASK: usize = 14;
const EXIT: usize = 60;
const ARCH_PRCTL: usize = 158;
const TKILL: usize = 200;
/// A structure used to call the right handler for each syscall
pub struct Syscall {
......@@ -130,20 +135,28 @@ impl Syscall {
}
/// Call the handler which matchs the syscall's number
pub fn syscall(&mut self) -> usize {
pub fn syscall(&mut self) -> isize {
let num = self.stack.rax;
let args = [self.stack.rdi, self.stack.rsi, self.stack.rdx, self.stack.r10, self.stack.r8, 0];
match num {
let result = match num {
WRITE => self.write(args[0], args[1], args[2]),
MMAP => self.mmap(args[0], args[1], args[2], args[3], args[4], args[5]),
BRK => self.brk(args[0]),
EXIT => self.exit(args[0]),
SIGACTION => self.sigaction(args[0], args[1], args[2]),
SIGPROCMASK => self.sigprocmask(args[0], args[1], args[2], args[3]),
TKILL => self.tkill(args[0], args[1]),
ARCH_PRCTL => self.arch_prctl(args[0], args[1]),
_ => {
println!("Unknown syscall: {}", num);
0
Err(Error::ENOSYS)
},
};
match result {
Ok(code) => code as isize,
Err(code) => -(code as isize),
}
}
}
......@@ -16,11 +16,48 @@
*/
//! Syscalls used for tasking (exit, ...)
use crate::tasking::processor::PROCESSOR;
use super::Syscall;
use super::{Syscall, error::{Result, Error}};
// --- Signals (from libc) ---
/// Signals that the virtual terminal is closed
pub const SIGHUP: usize = 1;
/// Signals that the user wishes to interrupt the process
pub const SIGINT: usize = 2;
/// Signals that the process should quit and perform a core dump
pub const SIGQUIT: usize = 3;
/// Signals that the process attempts to execute an illegal, malformed, unknown, or privileged instruction
pub const SIGILL: usize = 4;
/// Signals that the process must abort
pub const SIGABRT: usize = 6;
/// Signals that the process attempts to execute an erroneous arithmetic operation
pub const SIGFPE: usize = 8;
/// Signals that the process MUST terminate immediately (without clean-up)
pub const SIGKILL: usize = 9;
/// Signals that the process attempts to use an invalid virtual memory reference
pub const SIGSEGV: usize = 11;
/// Signals that the process attempts to write to a pipe without a process connected to the other end
pub const SIGPIPE: usize = 13;
/// Signals that a time limit is ended
pub const SIGALRM: usize = 14;
/// Signals that the process should terminate (unlike SIGKILL, it can clean-up)
pub const SIGTERM: usize = 15;
impl Syscall {
/// Exit from the current process by switching to the next process
pub fn exit(&self, code: usize) -> usize {
/// Exit from the current thread by switching to the next thread
pub fn exit(&self, code: usize) -> Result {
// TODO: Only exit the process, use exit_group to remove all threads
match code {
0 => println!("Exit success"),
_ => println!("Error"),
......@@ -58,6 +95,58 @@ impl Syscall {
unsafe { llvm_asm!("sti; hlt; cli"); }
}
}
0
unreachable!();
}
/// Send a signal to a thread
pub fn tkill(&self, tid: usize, sig: usize) -> Result {
println!("tkill({:#x}, {})", tid, sig);
// TODO: Send a signal
if sig == SIGABRT {
// Use the kernel's page table
crate::memory::switch_to_kernel_page_table();
PROCESSOR.inner().scheduler.remove();
if let Some(thread) = PROCESSOR.inner().scheduler.choose() {
// Change the stack to use the new context
unsafe { llvm_asm!("mov rsp, rax" : : "{rax}"(thread.kstack) : : "intel", "volatile"); }
// Load the new context
unsafe {
llvm_asm!("pop r11
mov cr3, r11
pop r11
pop r10
pop r9
pop r8
pop rsi
pop rdi
pop rdx
pop rcx
pop rbx
pop rax
iretq"
: : : : "intel", "volatile");
}
}
else {
loop {
unsafe { llvm_asm!("sti; hlt; cli"); }
}
}
unreachable!();
}
Err(Error::EINVAL)
}
/// Set the function which will be executed when the signal `num` will be handled
pub fn sigaction(&self, _num: usize, _action: usize, _oldaction: usize) -> Result { /* TODO: Set signal action*/ Ok(0) }
/// Change the mask of blocked signals
pub fn sigprocmask(&self, _how: usize, _set: usize, _oldset: usize, _size: usize) -> Result { /* TODO: Set signal mask*/ Ok(0) }
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment