diff --git a/src/main.rs b/src/main.rs
index 585e43e..8fbcf4e 100644
@@ -11,6 +11,28 @@ entry_point!(main);
fn main(boot_info: &'static BootInfo) -> ! {
moros::init(boot_info);
+
+ use x86_64::VirtAddr;
+ let mut mapper = unsafe { sys::mem::mapper(VirtAddr::new(boot_info.physical_memory_offset)) };
+ let mut frame_allocator = unsafe { sys::mem::BootInfoFrameAllocator::init(&boot_info.memory_map) };
+ let process = sys::process::Process::create(
+ &mut mapper,
+ &mut frame_allocator,
+ &[
+ // Infinite nop
+ // 0x90, 0x90, 0x90, 0xEB, 0xFB
+
+ // Infinite syscall to sleep (1.0 second at a time)
+ 0xb8, 0x00, 0x00, 0x00, 0x00,
+ 0x48, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f,
+ 0xbe, 0x00, 0x00, 0x00, 0x00,
+ 0xba, 0x00, 0x00, 0x00, 0x00,
+ 0xcd, 0x80,
+ 0xeb, 0xe3,
+ ]
+ );
+ process.switch();
+
loop {
let bootrc = "/ini/boot.sh";
if sys::fs::File::open(bootrc).is_some() {
diff --git a/src/sys/gdt.rs b/src/sys/gdt.rs
index e1cce94..32cb956 100644
@@ -1,17 +1,31 @@
use lazy_static::lazy_static;
use x86_64::VirtAddr;
-use x86_64::instructions::segmentation::{CS, Segment};
+use x86_64::instructions::segmentation::{CS, DS, Segment};
use x86_64::instructions::tables::load_tss;
-use x86_64::structures::gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector};
+use x86_64::structures::gdt::{Descriptor, DescriptorFlags, GlobalDescriptorTable, SegmentSelector};
use x86_64::structures::tss::TaskStateSegment;
+const STACK_SIZE: usize = 4096;
pub const DOUBLE_FAULT_IST_INDEX: u16 = 0;
+pub const PAGE_FAULT_IST_INDEX: u16 = 1;
+pub const GENERAL_PROTECTION_FAULT_IST_INDEX: u16 = 2;
lazy_static! {
static ref TSS: TaskStateSegment = {
let mut tss = TaskStateSegment::new();
+ tss.privilege_stack_table[0] = {
+ static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
+ VirtAddr::from_ptr(unsafe { &STACK }) + STACK_SIZE
+ };
tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX as usize] = {
- const STACK_SIZE: usize = 4096;
+ static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
+ VirtAddr::from_ptr(unsafe { &STACK }) + STACK_SIZE
+ };
+ tss.interrupt_stack_table[PAGE_FAULT_IST_INDEX as usize] = {
+ static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
+ VirtAddr::from_ptr(unsafe { &STACK }) + STACK_SIZE
+ };
+ tss.interrupt_stack_table[GENERAL_PROTECTION_FAULT_IST_INDEX as usize] = {
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
VirtAddr::from_ptr(unsafe { &STACK }) + STACK_SIZE
};
@@ -20,29 +34,33 @@ lazy_static! {
}
lazy_static! {
- static ref GDT: (GlobalDescriptorTable, Selectors) = {
+ pub static ref GDT: (GlobalDescriptorTable, Selectors) = {
let mut gdt = GlobalDescriptorTable::new();
- let code_selector = gdt.add_entry(Descriptor::kernel_code_segment());
- let tss_selector = gdt.add_entry(Descriptor::tss_segment(&TSS));
- (
- gdt,
- Selectors {
- code_selector,
- tss_selector,
- },
- )
+ let kernel_data_flags = DescriptorFlags::USER_SEGMENT | DescriptorFlags::PRESENT | DescriptorFlags::WRITABLE;
+
+ let code = gdt.add_entry(Descriptor::kernel_code_segment());
+ let data = gdt.add_entry(Descriptor::UserSegment(kernel_data_flags.bits()));
+ let tss = gdt.add_entry(Descriptor::tss_segment(&TSS));
+ let user_code = gdt.add_entry(Descriptor::user_code_segment());
+ let user_data = gdt.add_entry(Descriptor::user_data_segment());
+
+ (gdt, Selectors { code, data, tss, user_code, user_data })
};
}
-struct Selectors {
- code_selector: SegmentSelector,
- tss_selector: SegmentSelector,
+pub struct Selectors {
+ code: SegmentSelector,
+ data: SegmentSelector,
+ tss: SegmentSelector,
+ pub user_code: SegmentSelector,
+ pub user_data: SegmentSelector,
}
pub fn init() {
GDT.0.load();
unsafe {
- CS::set_reg(GDT.1.code_selector);
- load_tss(GDT.1.tss_selector);
+ CS::set_reg(GDT.1.code);
+ DS::set_reg(GDT.1.data);
+ load_tss(GDT.1.tss);
}
}
diff --git a/src/sys/idt.rs b/src/sys/idt.rs
index 58f18f3..9060344 100644
@@ -3,7 +3,7 @@ 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};
+use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode};
const PIC1: u16 = 0x21;
const PIC2: u16 = 0xA1;
@@ -27,7 +27,19 @@ lazy_static! {
let mut idt = InterruptDescriptorTable::new();
idt.breakpoint.set_handler_fn(breakpoint_handler);
unsafe {
- idt.double_fault.set_handler_fn(double_fault_handler).set_stack_index(sys::gdt::DOUBLE_FAULT_IST_INDEX);
+ idt.double_fault.
+ set_handler_fn(double_fault_handler).
+ set_stack_index(sys::gdt::DOUBLE_FAULT_IST_INDEX);
+ idt.page_fault.
+ set_handler_fn(page_fault_handler).
+ set_stack_index(sys::gdt::PAGE_FAULT_IST_INDEX);
+ idt.general_protection_fault.
+ set_handler_fn(general_protection_fault_handler).
+ set_stack_index(sys::gdt::GENERAL_PROTECTION_FAULT_IST_INDEX);
+ idt[0x80].
+ set_handler_fn(core::mem::transmute(wrapped_syscall_handler as *mut fn())).
+ set_stack_index(sys::gdt::DOUBLE_FAULT_IST_INDEX).
+ set_privilege_level(x86_64::PrivilegeLevel::Ring3);
}
idt[interrupt_index(0) as usize].set_handler_fn(irq0_handler);
idt[interrupt_index(1) as usize].set_handler_fn(irq1_handler);
@@ -45,7 +57,8 @@ lazy_static! {
idt[interrupt_index(13) as usize].set_handler_fn(irq13_handler);
idt[interrupt_index(14) as usize].set_handler_fn(irq14_handler);
idt[interrupt_index(15) as usize].set_handler_fn(irq15_handler);
- idt[0x80].set_handler_fn(unsafe { core::mem::transmute(wrapped_syscall_handler as *mut fn()) });
+ idt.stack_segment_fault.set_handler_fn(stack_segment_fault_handler);
+ idt.segment_not_present.set_handler_fn(segment_not_present_handler);
idt
};
}
@@ -85,6 +98,25 @@ extern "x86-interrupt" fn double_fault_handler(stack_frame: InterruptStackFrame,
panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
}
+extern "x86-interrupt" fn page_fault_handler(stack_frame: InterruptStackFrame, error_code: PageFaultErrorCode) {
+ let ip = stack_frame.instruction_pointer.as_ptr();
+ let inst: [u8; 8] = unsafe { core::ptr::read(ip) };
+ println!("Code: {:?}", inst);
+ panic!("EXCEPTION: PAGE FAULT\n{:#?}\n{:#?}", stack_frame, error_code);
+}
+
+extern "x86-interrupt" fn general_protection_fault_handler(stack_frame: InterruptStackFrame, _error_code: u64) {
+ panic!("EXCEPTION: GENERAL PROTECTION FAULT\n{:#?}", stack_frame);
+}
+
+extern "x86-interrupt" fn stack_segment_fault_handler(stack_frame: InterruptStackFrame, _error_code: u64) {
+ panic!("EXCEPTION: STACK SEGMENT FAULT\n{:#?}", stack_frame);
+}
+
+extern "x86-interrupt" fn segment_not_present_handler(stack_frame: InterruptStackFrame, _error_code: u64) {
+ 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)]
@@ -167,6 +199,7 @@ extern "sysv64" fn syscall_handler(_stack_frame: &mut InterruptStackFrame, regs:
let arg1 = regs.rdi;
let arg2 = regs.rsi;
let arg3 = regs.rdx;
+ printk!("DEBUG: syscall({}, {}, {}, {})\n", n, arg1, arg2, arg3);
regs.rax = sys::syscall::dispatcher(n, arg1, arg2, arg3);
unsafe { sys::pic::PICS.lock().notify_end_of_interrupt(0x80) };
}
diff --git a/src/sys/process.rs b/src/sys/process.rs
index d7fd2ae..8c92de1 100644
@@ -6,17 +6,17 @@ use spin::Mutex;
lazy_static! {
pub static ref PIDS: AtomicUsize = AtomicUsize::new(0);
- pub static ref PROCESS: Mutex<Process> = Mutex::new(Process::new("/", None)); // TODO
+ pub static ref PROCESS: Mutex<ProcessData> = Mutex::new(ProcessData::new("/", None)); // TODO
}
-pub struct Process {
+pub struct ProcessData {
id: usize,
env: BTreeMap<String, String>,
dir: String,
user: Option<String>,
}
-impl Process {
+impl ProcessData {
pub fn new(dir: &str, user: Option<&str>) -> Self {
let id = PIDS.fetch_add(1, Ordering::SeqCst);
let env = BTreeMap::new();
@@ -57,3 +57,96 @@ pub fn set_dir(dir: &str) {
pub fn set_user(user: &str) {
PROCESS.lock().user = Some(user.into())
}
+
+
+
+use x86_64::VirtAddr;
+use x86_64::instructions::interrupts;
+use x86_64::structures::paging::{
+ Page, PageTableFlags,
+};
+use x86_64::structures::{
+ paging::{Mapper, FrameAllocator, Size4KiB},
+};
+use core::sync::atomic::AtomicU64;
+use crate::sys::gdt::GDT;
+
+// TODO: use virtual memory better, i.e don't map all
+// processes in the same page table directory
+static STACK_ADDR: AtomicU64 = AtomicU64::new(0x600_000);
+static CODE_ADDR: AtomicU64 = AtomicU64::new(0x400_000);
+
+pub struct Process {
+ stack_addr: u64,
+ code_addr: u64,
+}
+
+impl Process {
+ pub fn create(mapper: &mut impl Mapper<Size4KiB>, frame_alloc: &mut impl FrameAllocator<Size4KiB>, asm: &[u8]) -> Process {
+ const PAGE_SIZE: u64 = 1024 * 4;
+ let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::USER_ACCESSIBLE;
+
+ let stack = STACK_ADDR.fetch_add(PAGE_SIZE, Ordering::SeqCst);
+ let frame = frame_alloc.allocate_frame().unwrap();
+ let page = Page::containing_address(VirtAddr::new(stack));
+ unsafe {
+ mapper.map_to(page, frame, flags, frame_alloc).unwrap().flush();
+ }
+
+ let code = CODE_ADDR.fetch_add(PAGE_SIZE, Ordering::SeqCst);
+ let frame = frame_alloc.allocate_frame().unwrap();
+ let page = Page::containing_address(VirtAddr::new(code));
+ unsafe {
+ mapper.map_to(page, frame, flags, frame_alloc).unwrap().flush();
+ }
+
+ unsafe {
+ let code = code as *mut u8;
+ for (i, op) in asm.iter().enumerate() {
+ core::ptr::write(code.add(i), *op);
+ }
+ }
+
+ Process {
+ stack_addr: stack,
+ code_addr: code,
+ }
+ }
+
+ pub fn switch(&self) {
+ crate::println!("DEBUG: switching to userspace");
+ let data = GDT.1.user_data.0;
+ let code = GDT.1.user_code.0;
+
+ unsafe {
+ interrupts::disable();
+
+ asm!(
+ //"mov ds, ax",
+ //"mov es, ax",
+ //"mov fs, ax",
+ //"mov gs, ax",
+
+ "push rax",
+ "push rsi",
+ "push 0x200",
+
+ // Reenable interrupts in userspace
+ //"pushf", // Get EFLAGS
+ //"pop rax",
+ //"or rax, 0x200", // Set IF
+ //"push rax",
+
+ //"push rcx",
+ "push rdx",
+ "push rdi",
+ "iretq",
+ in("rax") data,
+ in("rsi") self.stack_addr,
+ in("rdx") code,
+ in("rdi") self.code_addr,
+ );
+ }
+ }
+}
+
diff --git a/src/sys/syscall/service.rs b/src/sys/syscall/service.rs
index ea6204d..9a6f24f 100644
@@ -2,6 +2,7 @@ use crate::sys;
pub fn sleep(seconds: f64) {
unsafe { asm!("sti") }; // Restore interrupts
+ printk!("DEBUG: sleep({:.2})\n", seconds);
sys::time::sleep(seconds);
unsafe { asm!("cli") }; // Disable interrupts
}