Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic userspace #228

Merged
merged 21 commits into from
Sep 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Changelog

## Unreleased
- Add basic userspace (#228)
- Bump acpi from 3.1.0 to 4.0.0 (#243)
- Bump sha2 from 0.9.6 to 0.9.8 (#244)
- Bump x86_64 from 0.14.4 to 0.14.5 (#245)
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ nic = rtl8139

export MOROS_KEYBOARD = $(keyboard)

# Build userspace binaries
nasm:
basename -s .s dsk/src/bin/*.s | xargs -I {} nasm dsk/src/bin/{}.s -o dsk/bin/{}

bin = target/x86_64-moros/release/bootimage-moros.bin
img = disk.img

Expand Down
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,8 @@ This project started from the [seventh post][1] of the second edition of
- [x] Basic text editor
- [x] Basic lisp interpreter
- [x] Basic file and network commands
- [x] A LOT OF UGLY SHORTCUTS TO GET EVERYTHING WORKING
- [ ] Processes
- [x] Basic userspace for nasm binaries
- [ ] Multitasking
- [ ] A real userspace


## Setup
Expand Down
Binary file added dsk/bin/hello
Binary file not shown.
Binary file added dsk/bin/sleep
Binary file not shown.
14 changes: 14 additions & 0 deletions dsk/src/bin/hello.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[bits 64]

section .data
msg: db "Hello, World!", 10

global _start
section .text
_start:
mov rax, 5 ; syscall number for WRITE
mov rdi, 1 ; standard output
mov rsi, msg ; addr of string
mov rdx, 14 ; size of string
int 0x80
jmp _start
8 changes: 8 additions & 0 deletions dsk/src/bin/sleep.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[bits 64]
_start:
mov rax, 0 ; syscall number for SLEEP
mov rdi, __float64__(1.0) ; time to sleep in seconds
mov rsi, 0
mov rdx, 0
int 0x80
jmp _start
1 change: 1 addition & 0 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub mod console;
pub mod font;
pub mod fs;
pub mod io;
pub mod process;
pub mod prompt;
pub mod random;
pub mod regex;
Expand Down
10 changes: 10 additions & 0 deletions src/api/process.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use crate::sys::process::Process;
use crate::api::fs;

pub fn create(path: &str) -> Result<Process, ()> {
if let Ok(bin) = fs::read(path) {
Ok(Process::create(&bin))
} else {
Err(())
}
}
1 change: 0 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ fn main(boot_info: &'static BootInfo) -> ! {
println!("MFS is not mounted to '/'");
}
println!("Running console in diskless mode");

usr::shell::main(&["shell"]);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/sys/fs/block_device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ pub fn mount_mem() {
}

pub fn format_mem() {
assert!(is_mounted());
debug_assert!(is_mounted());
let root = Dir::root();
BlockBitmap::alloc(root.addr());
}
Expand Down Expand Up @@ -115,7 +115,7 @@ pub fn format_ata(bus: u8, dsk: u8) {
}

// Allocate root dir
assert!(is_mounted());
debug_assert!(is_mounted());
let root = Dir::root();
BlockBitmap::alloc(root.addr());
}
Expand Down
2 changes: 1 addition & 1 deletion src/sys/fs/dir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ impl Dir {

entries.block.write();

Some(DirEntry::new(*self, kind, entry_addr, entry_size, entry_time, name))
Some(DirEntry::new(*self, kind, entry_addr, entry_size, entry_time, &entry_name))
}

// Deleting an entry is done by setting the entry address to 0
Expand Down
54 changes: 36 additions & 18 deletions src/sys/gdt.rs
Original file line number Diff line number Diff line change
@@ -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 = 8192;
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
};
Expand All @@ -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);
}
}
38 changes: 35 additions & 3 deletions src/sys/idt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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
};
}
Expand Down Expand Up @@ -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)]
Expand Down
7 changes: 5 additions & 2 deletions src/sys/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ use bootloader::bootinfo::{BootInfo, MemoryMap, MemoryRegionType};
use x86_64::structures::paging::{FrameAllocator, OffsetPageTable, PageTable, PhysFrame, Size4KiB, Translate};
use x86_64::{PhysAddr, VirtAddr};

// NOTE: This static is mutable but it'll be changed only once during initialization
static mut PHYS_MEM_OFFSET: u64 = 0;
// NOTE: mutable but changed only once during initialization
pub static mut PHYS_MEM_OFFSET: u64 = 0;
pub static mut MEMORY_MAP: Option<&MemoryMap> = None;

pub fn init(boot_info: &'static BootInfo) {
let mut memory_size = 0;
Expand All @@ -17,9 +18,11 @@ pub fn init(boot_info: &'static BootInfo) {
log!("MEM {} KB\n", memory_size >> 10);

unsafe { PHYS_MEM_OFFSET = boot_info.physical_memory_offset; }
unsafe { MEMORY_MAP.replace(&boot_info.memory_map) };

let mut mapper = unsafe { mapper(VirtAddr::new(PHYS_MEM_OFFSET)) };
let mut frame_allocator = unsafe { BootInfoFrameAllocator::init(&boot_info.memory_map) };

sys::allocator::init_heap(&mut mapper, &mut frame_allocator).expect("heap initialization failed");
}

Expand Down
Loading