2021-09-15 20:27:32 +00:00
|
|
|
use crate::sys::fs::{Resource, Device};
|
|
|
|
use crate::sys::console::Console;
|
2020-02-10 20:29:07 +00:00
|
|
|
use alloc::collections::btree_map::BTreeMap;
|
|
|
|
use alloc::string::{String, ToString};
|
2021-09-15 20:27:32 +00:00
|
|
|
use alloc::vec;
|
|
|
|
use alloc::vec::Vec;
|
2020-02-10 20:29:07 +00:00
|
|
|
use core::sync::atomic::{AtomicUsize, Ordering};
|
|
|
|
use lazy_static::lazy_static;
|
2021-09-26 20:50:45 +00:00
|
|
|
use object::{Object, ObjectSection};
|
2020-02-10 20:29:07 +00:00
|
|
|
use spin::Mutex;
|
|
|
|
|
2021-09-15 20:27:32 +00:00
|
|
|
const MAX_FILE_HANDLES: usize = 1024;
|
|
|
|
|
2020-02-10 20:29:07 +00:00
|
|
|
lazy_static! {
|
|
|
|
pub static ref PIDS: AtomicUsize = AtomicUsize::new(0);
|
2021-09-24 16:19:37 +00:00
|
|
|
pub static ref PROCESS: Mutex<ProcessData> = Mutex::new(ProcessData::new("/", None)); // TODO
|
2020-02-10 20:29:07 +00:00
|
|
|
}
|
|
|
|
|
2021-09-24 16:19:37 +00:00
|
|
|
pub struct ProcessData {
|
2020-02-10 20:29:07 +00:00
|
|
|
id: usize,
|
|
|
|
env: BTreeMap<String, String>,
|
|
|
|
dir: String,
|
2020-07-05 11:31:49 +00:00
|
|
|
user: Option<String>,
|
2021-09-15 20:27:32 +00:00
|
|
|
file_handles: Vec<Option<Resource>>,
|
2021-09-24 16:19:37 +00:00
|
|
|
code_addr: u64,
|
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 id = PIDS.fetch_add(1, Ordering::SeqCst);
|
|
|
|
let env = BTreeMap::new();
|
|
|
|
let dir = dir.to_string();
|
2020-07-05 11:31:49 +00:00
|
|
|
let user = user.map(String::from);
|
2021-09-24 16:19:37 +00:00
|
|
|
let code_addr = 0;
|
2021-09-15 20:27:32 +00:00
|
|
|
let mut file_handles = vec![None; MAX_FILE_HANDLES];
|
|
|
|
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())));
|
2021-09-24 16:19:37 +00:00
|
|
|
Self { id, env, dir, user, file_handles, code_addr }
|
2020-02-10 20:29:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn id() -> usize {
|
|
|
|
PROCESS.lock().id
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn env(key: &str) -> Option<String> {
|
2021-07-25 10:41:44 +00:00
|
|
|
PROCESS.lock().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> {
|
|
|
|
PROCESS.lock().env.clone()
|
|
|
|
}
|
|
|
|
|
2020-02-10 20:29:07 +00:00
|
|
|
pub fn dir() -> String {
|
|
|
|
PROCESS.lock().dir.clone()
|
|
|
|
}
|
|
|
|
|
2020-07-05 11:31:49 +00:00
|
|
|
pub fn user() -> Option<String> {
|
2020-02-10 20:29:07 +00:00
|
|
|
PROCESS.lock().user.clone()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_env(key: &str, val: &str) {
|
|
|
|
PROCESS.lock().env.insert(key.into(), val.into());
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_dir(dir: &str) {
|
|
|
|
PROCESS.lock().dir = dir.into();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_user(user: &str) {
|
2020-07-05 11:31:49 +00:00
|
|
|
PROCESS.lock().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, ()> {
|
|
|
|
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);
|
|
|
|
return Ok(handle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn update_file_handle(handle: usize, file: Resource) {
|
|
|
|
let proc = &mut *PROCESS.lock();
|
|
|
|
proc.file_handles[handle] = Some(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn delete_file_handle(handle: usize) {
|
|
|
|
let proc = &mut *PROCESS.lock();
|
|
|
|
proc.file_handles[handle] = None;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn file_handle(handle: usize) -> Option<Resource> {
|
|
|
|
let proc = &mut *PROCESS.lock();
|
|
|
|
proc.file_handles[handle].clone()
|
|
|
|
}
|
2021-09-24 16:19:37 +00:00
|
|
|
|
|
|
|
pub fn code_addr() -> u64 {
|
|
|
|
PROCESS.lock().code_addr
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_code_addr(addr: u64) {
|
|
|
|
PROCESS.lock().code_addr = addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn ptr_from_addr(addr: u64) -> *mut u8 {
|
|
|
|
(PROCESS.lock().code_addr + addr) as *mut u8
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************
|
|
|
|
* 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;
|
|
|
|
use x86_64::structures::paging::{Mapper, FrameAllocator};
|
|
|
|
use x86_64::structures::paging::{Page, PageTableFlags};
|
|
|
|
|
2021-09-26 20:50:45 +00:00
|
|
|
static CODE_ADDR: AtomicU64 = AtomicU64::new(0x40_0000);
|
|
|
|
static STACK_ADDR: AtomicU64 = AtomicU64::new(0x80_0000);
|
|
|
|
const PAGE_SIZE: u64 = 4 * 1024;
|
2021-09-24 16:19:37 +00:00
|
|
|
|
|
|
|
pub struct Process {
|
|
|
|
stack_addr: u64,
|
|
|
|
code_addr: u64,
|
2021-09-26 20:50:45 +00:00
|
|
|
entry_point: u64,
|
2021-09-24 16:19:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Process {
|
|
|
|
pub fn create(bin: &[u8]) -> 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_addr = STACK_ADDR.fetch_add(PAGE_SIZE, Ordering::SeqCst);
|
|
|
|
let frame = frame_allocator.allocate_frame().unwrap();
|
|
|
|
let page = Page::containing_address(VirtAddr::new(stack_addr));
|
|
|
|
unsafe {
|
|
|
|
mapper.map_to(page, frame, flags, &mut frame_allocator).unwrap().flush();
|
|
|
|
}
|
|
|
|
|
|
|
|
let code_addr = CODE_ADDR.fetch_add(PAGE_SIZE, Ordering::SeqCst);
|
|
|
|
let frame = frame_allocator.allocate_frame().unwrap();
|
2021-09-26 20:50:45 +00:00
|
|
|
for i in 0..1024 {
|
|
|
|
let addr = code_addr + i * PAGE_SIZE;
|
|
|
|
let page = Page::containing_address(VirtAddr::new(addr));
|
|
|
|
unsafe {
|
|
|
|
mapper.map_to(page, frame, flags, &mut frame_allocator).unwrap().flush();
|
|
|
|
}
|
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;
|
|
|
|
if &bin[1..4] == b"ELF" { // ELF binary
|
|
|
|
if let Ok(obj) = object::File::parse(bin) {
|
|
|
|
entry_point = obj.entry();
|
|
|
|
for section in obj.sections() {
|
|
|
|
if let Ok(name) = section.name() {
|
|
|
|
let addr = section.address() as usize;
|
|
|
|
if name.is_empty() || addr == 0 {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if let Ok(data) = section.data() {
|
|
|
|
unsafe {
|
|
|
|
for (i, op) in data.iter().enumerate() {
|
|
|
|
let ptr = code_ptr.add(addr + i);
|
|
|
|
core::ptr::write(ptr, *op);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else { // Raw binary
|
|
|
|
unsafe {
|
|
|
|
for (i, op) in bin.iter().enumerate() {
|
|
|
|
let ptr = code_ptr.add(i);
|
|
|
|
core::ptr::write(ptr, *op);
|
|
|
|
}
|
2021-09-24 16:19:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
set_code_addr(code_addr);
|
|
|
|
|
2021-09-26 20:50:45 +00:00
|
|
|
Process { stack_addr, code_addr, entry_point }
|
2021-09-24 16:19:37 +00:00
|
|
|
}
|
|
|
|
|
2021-09-26 20:50:45 +00:00
|
|
|
// Switch to user mode
|
2021-09-24 16:19:37 +00:00
|
|
|
pub fn switch(&self) {
|
2021-09-26 20:50:45 +00:00
|
|
|
//x86_64::instructions::tlb::flush_all();
|
2021-09-24 16:19:37 +00:00
|
|
|
let data = GDT.1.user_data.0;
|
|
|
|
let code = GDT.1.user_code.0;
|
|
|
|
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",
|
|
|
|
in("rax") data,
|
|
|
|
in("rsi") self.stack_addr,
|
|
|
|
in("rdx") code,
|
2021-09-26 20:50:45 +00:00
|
|
|
in("rdi") self.code_addr + self.entry_point,
|
2021-09-24 16:19:37 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|