2021-09-15 20:27:32 +00:00
|
|
|
use crate::sys::fs::{Resource, Device};
|
|
|
|
use crate::sys::console::Console;
|
2022-01-18 07:44:10 +00:00
|
|
|
|
2022-01-24 19:35:00 +00:00
|
|
|
use alloc::boxed::Box;
|
2020-02-10 20:29:07 +00:00
|
|
|
use alloc::collections::btree_map::BTreeMap;
|
|
|
|
use alloc::string::{String, ToString};
|
2022-01-18 07:44:10 +00:00
|
|
|
use alloc::vec::Vec;
|
2022-04-05 10:03:31 +00:00
|
|
|
use core::arch::asm;
|
2020-02-10 20:29:07 +00:00
|
|
|
use core::sync::atomic::{AtomicUsize, Ordering};
|
|
|
|
use lazy_static::lazy_static;
|
2021-10-14 07:49:30 +00:00
|
|
|
use object::{Object, ObjectSegment};
|
2021-11-27 08:56:52 +00:00
|
|
|
use spin::RwLock;
|
|
|
|
use x86_64::structures::idt::InterruptStackFrameValue;
|
2020-02-10 20:29:07 +00:00
|
|
|
|
2022-01-24 19:35:00 +00:00
|
|
|
const MAX_FILE_HANDLES: usize = 64;
|
|
|
|
const MAX_PROCS: usize = 2; // TODO: Update this when more than one process can run at once
|
2021-09-15 20:27:32 +00:00
|
|
|
|
2020-02-10 20:29:07 +00:00
|
|
|
lazy_static! {
|
2021-11-27 08:56:52 +00:00
|
|
|
pub static ref PID: AtomicUsize = AtomicUsize::new(0);
|
|
|
|
pub static ref MAX_PID: AtomicUsize = AtomicUsize::new(1);
|
2022-01-24 19:35:00 +00:00
|
|
|
pub static ref PROCESS_TABLE: RwLock<[Box<Process>; MAX_PROCS]> = RwLock::new([(); MAX_PROCS].map(|_| Box::new(Process::new(0))));
|
2020-02-10 20:29:07 +00:00
|
|
|
}
|
|
|
|
|
2021-11-27 08:56:52 +00:00
|
|
|
#[derive(Clone, Debug)]
|
2021-09-24 16:19:37 +00:00
|
|
|
pub struct ProcessData {
|
2020-02-10 20:29:07 +00:00
|
|
|
env: BTreeMap<String, String>,
|
|
|
|
dir: String,
|
2020-07-05 11:31:49 +00:00
|
|
|
user: Option<String>,
|
2022-01-24 19:35:00 +00:00
|
|
|
file_handles: [Option<Box<Resource>>; MAX_FILE_HANDLES],
|
2020-02-10 20:29:07 +00:00
|
|
|
}
|
|
|
|
|
2021-09-24 16:19:37 +00:00
|
|
|
impl ProcessData {
|
2020-07-05 11:31:49 +00:00
|
|
|
pub fn new(dir: &str, user: Option<&str>) -> Self {
|
2020-02-10 20:29:07 +00:00
|
|
|
let env = BTreeMap::new();
|
|
|
|
let dir = dir.to_string();
|
2020-07-05 11:31:49 +00:00
|
|
|
let user = user.map(String::from);
|
2021-11-27 08:56:52 +00:00
|
|
|
let mut file_handles = [(); MAX_FILE_HANDLES].map(|_| None);
|
2022-01-24 19:35:00 +00:00
|
|
|
file_handles[0] = Some(Box::new(Resource::Device(Device::Console(Console::new()))));
|
|
|
|
file_handles[1] = Some(Box::new(Resource::Device(Device::Console(Console::new()))));
|
|
|
|
file_handles[2] = Some(Box::new(Resource::Device(Device::Console(Console::new()))));
|
|
|
|
file_handles[3] = Some(Box::new(Resource::Device(Device::Null)));
|
2021-11-27 08:56:52 +00:00
|
|
|
Self { env, dir, user, file_handles }
|
2020-02-10 20:29:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn id() -> usize {
|
2021-11-27 08:56:52 +00:00
|
|
|
PID.load(Ordering::SeqCst)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_id(id: usize) {
|
|
|
|
PID.store(id, Ordering::SeqCst)
|
2020-02-10 20:29:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn env(key: &str) -> Option<String> {
|
2021-11-27 08:56:52 +00:00
|
|
|
let table = PROCESS_TABLE.read();
|
|
|
|
let proc = &table[id()];
|
|
|
|
proc.data.env.get(key).cloned()
|
2020-02-10 20:29:07 +00:00
|
|
|
}
|
|
|
|
|
2020-11-10 07:39:26 +00:00
|
|
|
pub fn envs() -> BTreeMap<String, String> {
|
2021-11-27 08:56:52 +00:00
|
|
|
let table = PROCESS_TABLE.read();
|
|
|
|
let proc = &table[id()];
|
|
|
|
proc.data.env.clone()
|
2020-11-10 07:39:26 +00:00
|
|
|
}
|
|
|
|
|
2020-02-10 20:29:07 +00:00
|
|
|
pub fn dir() -> String {
|
2021-11-27 08:56:52 +00:00
|
|
|
let table = PROCESS_TABLE.read();
|
|
|
|
let proc = &table[id()];
|
|
|
|
proc.data.dir.clone()
|
2020-02-10 20:29:07 +00:00
|
|
|
}
|
|
|
|
|
2020-07-05 11:31:49 +00:00
|
|
|
pub fn user() -> Option<String> {
|
2021-11-27 08:56:52 +00:00
|
|
|
let table = PROCESS_TABLE.read();
|
|
|
|
let proc = &table[id()];
|
|
|
|
proc.data.user.clone()
|
2020-02-10 20:29:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_env(key: &str, val: &str) {
|
2021-11-27 08:56:52 +00:00
|
|
|
let mut table = PROCESS_TABLE.write();
|
|
|
|
let proc = &mut table[id()];
|
|
|
|
proc.data.env.insert(key.into(), val.into());
|
2020-02-10 20:29:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_dir(dir: &str) {
|
2021-11-27 08:56:52 +00:00
|
|
|
let mut table = PROCESS_TABLE.write();
|
|
|
|
let proc = &mut table[id()];
|
|
|
|
proc.data.dir = dir.into();
|
2020-02-10 20:29:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_user(user: &str) {
|
2021-11-27 08:56:52 +00:00
|
|
|
let mut table = PROCESS_TABLE.write();
|
|
|
|
let proc = &mut table[id()];
|
|
|
|
proc.data.user = Some(user.into())
|
2020-02-10 20:29:07 +00:00
|
|
|
}
|
2021-09-15 20:27:32 +00:00
|
|
|
|
|
|
|
pub fn create_file_handle(file: Resource) -> Result<usize, ()> {
|
2021-11-27 08:56:52 +00:00
|
|
|
let mut table = PROCESS_TABLE.write();
|
|
|
|
let proc = &mut table[id()];
|
2021-09-15 20:27:32 +00:00
|
|
|
let min = 4; // The first 4 file handles are reserved
|
|
|
|
let max = MAX_FILE_HANDLES;
|
|
|
|
for handle in min..max {
|
2021-11-27 08:56:52 +00:00
|
|
|
if proc.data.file_handles[handle].is_none() {
|
2022-01-24 19:35:00 +00:00
|
|
|
proc.data.file_handles[handle] = Some(Box::new(file));
|
2021-09-15 20:27:32 +00:00
|
|
|
return Ok(handle);
|
|
|
|
}
|
|
|
|
}
|
2022-01-18 07:44:10 +00:00
|
|
|
debug!("Could not create file handle");
|
2021-09-15 20:27:32 +00:00
|
|
|
Err(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn update_file_handle(handle: usize, file: Resource) {
|
2021-11-27 08:56:52 +00:00
|
|
|
let mut table = PROCESS_TABLE.write();
|
|
|
|
let proc = &mut table[id()];
|
2022-01-24 19:35:00 +00:00
|
|
|
proc.data.file_handles[handle] = Some(Box::new(file));
|
2021-09-15 20:27:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn delete_file_handle(handle: usize) {
|
2021-11-27 08:56:52 +00:00
|
|
|
let mut table = PROCESS_TABLE.write();
|
|
|
|
let proc = &mut table[id()];
|
|
|
|
proc.data.file_handles[handle] = None;
|
2021-09-15 20:27:32 +00:00
|
|
|
}
|
|
|
|
|
2022-01-24 19:35:00 +00:00
|
|
|
pub fn file_handle(handle: usize) -> Option<Box<Resource>> {
|
2021-11-27 08:56:52 +00:00
|
|
|
let table = PROCESS_TABLE.read();
|
|
|
|
let proc = &table[id()];
|
|
|
|
proc.data.file_handles[handle].clone()
|
2021-09-15 20:27:32 +00:00
|
|
|
}
|
2021-09-24 16:19:37 +00:00
|
|
|
|
2022-01-24 19:35:00 +00:00
|
|
|
pub fn file_handles() -> Vec<Option<Box<Resource>>> {
|
2022-01-18 07:44:10 +00:00
|
|
|
let table = PROCESS_TABLE.read();
|
|
|
|
let proc = &table[id()];
|
|
|
|
proc.data.file_handles.to_vec()
|
|
|
|
}
|
|
|
|
|
2021-09-24 16:19:37 +00:00
|
|
|
pub fn code_addr() -> u64 {
|
2021-11-27 08:56:52 +00:00
|
|
|
let table = PROCESS_TABLE.read();
|
|
|
|
let proc = &table[id()];
|
|
|
|
proc.code_addr
|
2021-09-24 16:19:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_code_addr(addr: u64) {
|
2021-11-27 08:56:52 +00:00
|
|
|
let mut table = PROCESS_TABLE.write();
|
|
|
|
let mut proc = &mut table[id()];
|
|
|
|
proc.code_addr = addr;
|
2021-09-24 16:19:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn ptr_from_addr(addr: u64) -> *mut u8 {
|
2021-11-27 08:56:52 +00:00
|
|
|
(code_addr() + addr) as *mut u8
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn registers() -> Registers {
|
|
|
|
let table = PROCESS_TABLE.read();
|
|
|
|
let proc = &table[id()];
|
2021-12-22 19:49:17 +00:00
|
|
|
proc.registers
|
2021-11-27 08:56:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2021-09-24 16:19:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/************************
|
|
|
|
* Userspace experiment *
|
|
|
|
************************/
|
|
|
|
|
|
|
|
// See https://nfil.dev/kernel/rust/coding/rust-kernel-to-userspace-and-back/
|
|
|
|
// And https://github.com/WartaPoirier-corp/ananos/blob/dev/docs/notes/context-switch.md
|
|
|
|
|
|
|
|
use crate::sys;
|
|
|
|
use crate::sys::gdt::GDT;
|
|
|
|
use core::sync::atomic::AtomicU64;
|
|
|
|
use x86_64::VirtAddr;
|
|
|
|
|
2022-04-11 17:06:16 +00:00
|
|
|
static CODE_ADDR: AtomicU64 = AtomicU64::new((sys::allocator::HEAP_START as u64) + (16 << 20));
|
2021-09-26 20:50:45 +00:00
|
|
|
const PAGE_SIZE: u64 = 4 * 1024;
|
2021-09-24 16:19:37 +00:00
|
|
|
|
2021-11-27 08:56:52 +00:00
|
|
|
#[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)]
|
2021-09-24 16:19:37 +00:00
|
|
|
pub struct Process {
|
2021-11-27 08:56:52 +00:00
|
|
|
id: usize,
|
2021-09-24 16:19:37 +00:00
|
|
|
code_addr: u64,
|
2021-11-27 08:56:52 +00:00
|
|
|
code_size: u64,
|
2021-09-26 20:50:45 +00:00
|
|
|
entry_point: u64,
|
2021-11-27 08:56:52 +00:00
|
|
|
stack_frame: InterruptStackFrameValue,
|
|
|
|
registers: Registers,
|
|
|
|
data: ProcessData,
|
2021-09-24 16:19:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Process {
|
2021-11-27 08:56:52 +00:00
|
|
|
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,
|
2021-10-14 07:49:30 +00:00
|
|
|
};
|
2021-11-27 08:56:52 +00:00
|
|
|
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();
|
2021-09-24 16:19:37 +00:00
|
|
|
}
|
2021-11-27 08:56:52 +00:00
|
|
|
}
|
2021-09-24 16:19:37 +00:00
|
|
|
|
2021-11-27 08:56:52 +00:00
|
|
|
fn create(bin: &[u8]) -> Result<usize, ()> {
|
2022-04-11 17:06:16 +00:00
|
|
|
let code_size = 1 * PAGE_SIZE;
|
2021-10-14 07:49:30 +00:00
|
|
|
let code_addr = CODE_ADDR.fetch_add(code_size, Ordering::SeqCst);
|
2022-04-11 17:06:16 +00:00
|
|
|
|
2021-11-27 08:56:52 +00:00
|
|
|
sys::allocator::alloc_pages(code_addr, code_size);
|
2021-09-24 16:19:37 +00:00
|
|
|
|
2021-09-26 20:50:45 +00:00
|
|
|
let mut entry_point = 0;
|
|
|
|
let code_ptr = code_addr as *mut u8;
|
2021-12-22 19:49:17 +00:00
|
|
|
if bin[0..4] == ELF_MAGIC { // ELF binary
|
2021-09-26 20:50:45 +00:00
|
|
|
if let Ok(obj) = object::File::parse(bin) {
|
|
|
|
entry_point = obj.entry();
|
2021-10-14 07:49:30 +00:00
|
|
|
for segment in obj.segments() {
|
|
|
|
let addr = segment.address() as usize;
|
|
|
|
if let Ok(data) = segment.data() {
|
2021-11-27 08:56:52 +00:00
|
|
|
for (i, op) in data.iter().enumerate() {
|
|
|
|
unsafe {
|
2021-10-14 07:49:30 +00:00
|
|
|
let ptr = code_ptr.add(addr + i);
|
|
|
|
core::ptr::write(ptr, *op);
|
2021-09-26 20:50:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else { // Raw binary
|
2021-11-27 08:56:52 +00:00
|
|
|
for (i, op) in bin.iter().enumerate() {
|
|
|
|
unsafe {
|
2021-09-26 20:50:45 +00:00
|
|
|
let ptr = code_ptr.add(i);
|
|
|
|
core::ptr::write(ptr, *op);
|
|
|
|
}
|
2021-09-24 16:19:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-27 08:56:52 +00:00
|
|
|
let mut table = PROCESS_TABLE.write();
|
|
|
|
let parent = &table[id()];
|
|
|
|
|
|
|
|
let data = parent.data.clone();
|
2021-12-22 19:49:17 +00:00
|
|
|
let registers = parent.registers;
|
2021-11-27 08:56:52 +00:00
|
|
|
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 };
|
2022-01-24 19:35:00 +00:00
|
|
|
table[id] = Box::new(proc);
|
2021-09-24 16:19:37 +00:00
|
|
|
|
2021-11-27 08:56:52 +00:00
|
|
|
Ok(id)
|
2021-09-24 16:19:37 +00:00
|
|
|
}
|
|
|
|
|
2021-09-29 20:40:37 +00:00
|
|
|
// Switch to user mode and execute the program
|
2021-11-27 08:56:52 +00:00
|
|
|
fn exec(&self) {
|
|
|
|
set_id(self.id); // Change PID
|
2021-09-24 16:19:37 +00:00
|
|
|
unsafe {
|
|
|
|
asm!(
|
2021-09-26 20:50:45 +00:00
|
|
|
"cli", // Disable interrupts
|
|
|
|
"push rax", // Stack segment (SS)
|
|
|
|
"push rsi", // Stack pointer (RSP)
|
|
|
|
"push 0x200", // RFLAGS with interrupts enabled
|
|
|
|
"push rdx", // Code segment (CS)
|
|
|
|
"push rdi", // Instruction pointer (RIP)
|
2021-09-24 16:19:37 +00:00
|
|
|
"iretq",
|
2021-11-27 08:56:52 +00:00
|
|
|
in("rax") GDT.1.user_data.0,
|
|
|
|
in("rsi") self.code_addr + self.code_size,
|
|
|
|
in("rdx") GDT.1.user_code.0,
|
2021-09-26 20:50:45 +00:00
|
|
|
in("rdi") self.code_addr + self.entry_point,
|
2021-09-24 16:19:37 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|