Commit 77ccd879 authored by Nifou's avatar Nifou

On the path of executing dynamically linked binary

*  Make the `open` and `read` syscalls working
*  Add a scheme of memory use
*  Save FSBASE
*  Rewrite the `rust-test` binary
parent 25ac97ad
Pipeline #194142238 failed with stages
in 6 minutes and 7 seconds
......@@ -119,7 +119,7 @@ set_up_page_tables:
mov [(p2_table - 0xc0000000) + ecx * 8], eax ; map ecx-th entry
inc ecx ; increase counter
cmp ecx, 9 ; the kernel size is 0x800000 (see memory/mod.rs:KERNEL_SIZE), so 0x1000000 / 0x200000 = 8. We need also to map the kernel heap, so 8 + 1 = 9
cmp ecx, 11 ; the kernel size is 0x1400000 (see memory/mod.rs:KERNEL_SIZE), so 0x1400000 / 0x200000 = 10. We need also to map the kernel heap, so 10 + 1 = 11
jne .map_p2_table ; else map the next entry
ret
......
......@@ -39,7 +39,7 @@ timer_interrupt_handler:
; Save the start of the registers' stack
mov rdi, rsp
sub rsp, 0x78
sub rsp, 0x88
; Switch to the next process
call next
......@@ -27,6 +27,9 @@ pub enum FileError {
/// The file is not found
NotFound,
/// The end is reached
EndReached,
/// The binary file cannot be translated into a String
Utf8Error,
}
......@@ -52,7 +55,11 @@ impl InitFS {
/// Get a file with a name among the files and return an array
pub fn get_binary_file(&self, name: String, offset: usize) -> Result<&'static [u8], FileError> {
return if let Some(content) = self.files.get(&name) {
Ok(&content.0[offset..])
if content.0.len() <= offset {
Err(FileError::EndReached)
} else {
Ok(&content.0[offset..])
}
} else {
Err(FileError::NotFound)
};
......
......@@ -144,7 +144,7 @@ pub extern "C" fn kmain(info_addr: usize) {
println!("ObsidianOS is ready!");
x86_64::instructions::interrupts::enable();
loop {}
unreachable!();
}
#[no_mangle]
......
......@@ -19,6 +19,22 @@
//! * Virtual memory management, such as mappings
//! * A frame allocator which allocate frames of physical memory memory which will be mapped
//! later to a page of virtual memory
//!
//! Virtual memory Physical memory
//!
//! 0xc140a000 |-------------------| 0x140a000 |-------------------|
//! | | | |
//! | Kernel heap | | Kernel heap |
//! | | | |
//! 0xc100a000 |-------------------| 0x100a000 |-------------------|
//! | | ----------------> | |
//! | Multiboot | ----------------> | Multiboot |
//! | | | |
//! 0xc1000000 |-------------------| 0x1000000 |-------------------|
//! | | | |
//! | Kernel | | Kernel |
//! | | | |
//! 0xc0000000 --------------------- 0x0 ---------------------
pub mod frame_allocator;
pub mod heap;
pub mod table;
......@@ -52,7 +68,7 @@ pub const KERNEL_START_VIRT: u64 = 0xc0000000;
pub const KERNEL_START_PHYS: u64 = 0;
/// The size of the kernel
pub const KERNEL_SIZE: u64 = 0x1000000;
pub const KERNEL_SIZE: u64 = 0x1400000;
/// The start of the multiboot information structure (Virtual)
pub const MULTIBOOT_START_VIRT: u64 = KERNEL_START_VIRT + KERNEL_SIZE;
......
......@@ -15,8 +15,11 @@
* along with this program. If not, see https://www.gnu.org/licenses.
*/
//! Syscalls used to manage the filesystem (open, read, write, close, ...)
use core::slice::from_raw_parts;
use core::str::from_utf8;
use core::{
slice::from_raw_parts,
str::from_utf8,
cmp,
};
use crate::initfs::{
FileError,
......@@ -86,11 +89,11 @@ impl Syscall {
///
/// If the pathname given in pathname is relative, then it is interpreted relative to the
/// directory referred to by the file descriptor `dirfd`.
pub fn openat(&self, dirfd: usize, path: usize, flags: usize, mode: usize) -> Result {
pub fn openat(&self, _dirfd: usize, path: usize, flags: usize, mode: usize) -> Result {
// TODO: `dirfd`, `flags` and `mode` are ignored for now
let path = unsafe { get_string(path).unwrap() };
print!("openat({}, {:?}, {}, {}) = ", dirfd, path, flags, mode);
print!("openat(AT_FDCWD, {:?}, {}, {}) = ", path, flags, mode);
if let Ok(_) = INITFS.perms(path.clone()) {
let mut processes = PROCESSES.write();
......@@ -123,11 +126,20 @@ impl Syscall {
match INITFS.get_binary_file(file.path.clone(), file.offset) {
Ok(content) => {
let src = content.as_ptr();
unsafe { src.copy_to(dest, count); }
let bytes_copied = cmp::min(content.len(), count);
unsafe { src.copy_to(dest, bytes_copied); }
file.offset += bytes_copied;
file.offset += count;
println!("{}", count);
Ok(count)
println!("{}", bytes_copied);
Ok(bytes_copied)
},
Err(FileError::EndReached) => {
println!("0");
Ok(0)
},
Err(FileError::NotFound) => {
println!("EINVAL");
Err(Error::EINVAL)
},
Err(_) => {
println!("EINVAL");
......@@ -197,6 +209,12 @@ impl Syscall {
Ok(0)
}
/// Do a file operation on a file descriptor
pub fn fcntl(&self, fd: usize, cmd: usize, arg: usize) -> Result {
println!("fcntl({:#x}, {:#x}, {:#x}) = 0", fd, cmd, arg);
Ok(0)
}
/// Create a pipe between two processes
pub fn pipe2(&self, pipefd: usize, flags: usize) -> Result {
/* TODO: Pipe2 syscall */
......
......@@ -177,11 +177,12 @@ impl Syscall {
.memory
.find_free_area(len);
let free_area = MemoryArea::new(
free_area_start,
free_area_start + 4069,
free_area_start + len as u64,
Flags::from(prot) | Flags::WRITABLE, // TODO: Remove it later
);
println!("{:#?}", free_area);
processes
.get_mut(&current_process)
.unwrap()
......
......@@ -142,6 +142,7 @@ const EXIT: usize = 60;
const WAIT4: usize = 61;
const KILL: usize = 62;
const UNAME: usize = 63;
const FCNTL: usize = 72;
const GETCWD: usize = 79;
const SIGALTSTACK: usize = 131;
const ARCH_PRCTL: usize = 158;
......@@ -195,6 +196,7 @@ impl Syscall {
WAIT4 => self.wait4(args[0], args[1], args[2], args[3]),
KILL => self.kill(args[0], args[1]),
UNAME => self.uname(args[0]),
FCNTL => self.fcntl(args[0], args[1], args[2]),
GETCWD => self.getcwd(args[0], args[1]),
SIGALTSTACK => self.sigaltstack(args[0], args[1]),
ARCH_PRCTL => self.arch_prctl(args[0], args[1]),
......
......@@ -20,6 +20,7 @@ use alloc::{
alloc::{GlobalAlloc, Layout},
};
use core::mem::{transmute, size_of};
use x86_64::{registers::model_specific::FsBase, VirtAddr};
use crate::memory::heap::HEAP_ALLOCATOR;
use super::{
......@@ -69,6 +70,7 @@ pub trait SchedulerAlgo {
/// Switch to the next process
fn switch(&mut self) {
println!("SWITCH");
// Choose the next thread
if let Some(mut thread) = self.choose() {
{
......@@ -187,6 +189,9 @@ pub trait SchedulerAlgo {
unsafe {
// --- Executes the thread ---
// Change fsbase
FsBase::write(VirtAddr::new(thread.fsbase));
// Change the stack to use the new context
llvm_asm!("mov rsp, rax" : : "{rax}"(thread.kstack) : : "intel", "volatile");
......
......@@ -19,6 +19,7 @@ use alloc::{collections::btree_map::BTreeMap, prelude::v1::Box};
use core::{cell::UnsafeCell, sync::atomic::{AtomicBool, Ordering}};
use lazy_static::lazy_static;
use spin::RwLock;
use x86_64::registers::model_specific::FsBase;
use crate::irq::{handlers, id};
use super::{
......@@ -60,6 +61,7 @@ unsafe impl Send for SchedulerCurrentAlgo {}
/// Else, remove all threads of the process of the current thread and switch to the next thread
/// (does the job of the `exit_group` syscall)
pub fn exit(all_threads: bool) {
println!("EXIT");
let mut processes = PROCESSES.write();
let pid = SCHEDULER
.get()
......@@ -107,30 +109,35 @@ pub fn exit(all_threads: bool) {
#[inline(never)]
/// Switch to the next process
pub fn next(regs: Registers) {
// Signals the end of the interrupt
handlers::end(id::IrqId::TIMER);
// If this is the first time, don't save registers because otherwise they will be saved in the
// first process which is not already running!
if !FIRST_TIME.load(Ordering::Relaxed) {
// Save the registers
match SCHEDULER.get().current_mut() {
Some(process) => *process.get_kstack() = regs,
None => {
// Signals the end of the interrupt
handlers::end(id::IrqId::TIMER);
Some(thread) => {
// Save the registers
*thread.get_kstack() = regs;
// Save fsbase
thread.fsbase = FsBase::read().as_u64();
// Save FX (we can save it now because the kernel does not mangle SSE registers)
Fx::save(SCHEDULER.get().current().unwrap().fx);
// Switch to the next process
SCHEDULER.get().switch();
},
None => {
// Switch to IDLE
SCHEDULER.get().idle();
},
}
// Save FX (we can save it now because the kernel does not mangle SSE registers)
Fx::save(SCHEDULER.get().current().unwrap().fx);
} else {
FIRST_TIME.store(false, Ordering::Relaxed);
}
// Signals the end of the interrupt
handlers::end(id::IrqId::TIMER);
// Switch to the next process
SCHEDULER.get().switch();
// Switch to the next process
SCHEDULER.get().switch();
}
}
......@@ -78,6 +78,9 @@ pub struct Thread {
/// The save of the SSE state
pub fx: u64,
/// The fs base
pub fsbase: u64,
// TODO: Signal mask?
}
......@@ -114,6 +117,7 @@ impl Thread {
process,
kstack: sp,
fx,
fsbase: 0x0,
}
}
......@@ -159,6 +163,7 @@ impl Thread {
process,
kstack: sp,
fx,
fsbase: 0x0,
},
mapping,
)
......
......@@ -6,3 +6,9 @@ edition = "2018"
[dependencies]
libc = "0.2.77"
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
use std::{
fs,
io::Read,
os::unix::io::AsRawFd,
};
use libc::*;
fn main() {
println!("Hello, world!");
println!("test-std mmap test");
println!("Rust-test, a series of tests!");
unsafe {
let ptr = "/README.md" as *const _ as *const i8;
let file = open(ptr, 0);
let mut buf = String::new();
println!("{:#?}", read(file, &mut buf as *mut _ as *mut c_void, 100usize));
}
println!("Read test ");
let mut buf = String::new();
let mut file = fs::File::open("/README.md").unwrap();
file.read_to_string(&mut buf).unwrap();
println!("Good ✔️");
println!("Mmap test ");
unsafe { mmap(0 as *mut c_void, 65536, PROT_READ, MAP_PRIVATE, file.as_raw_fd(), 0); }
println!("Good ✔️");
}
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