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 ELF loader #248

Merged
merged 16 commits into from
Sep 26, 2021
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 ELF loader (#248)
- 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)
Expand Down
16 changes: 16 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
libm = "0.2.1"
linked_list_allocator = "0.9.0"
littlewing = { version = "0.7.0", default-features = false }
object = { version = "0.26.2", default-features = false, features = ["read"] }
pbkdf2 = { version = "0.9.0", default-features = false }
pc-keyboard = "0.5.1"
pic8259 = "0.10.2"
Expand Down
Binary file modified dsk/bin/hello
100644 → 100755
Binary file not shown.
10 changes: 4 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,12 @@ pub fn init(boot_info: &'static BootInfo) {
sys::vga::init();
sys::gdt::init();
sys::idt::init();
unsafe { sys::pic::PICS.lock().initialize() };
x86_64::instructions::interrupts::enable();
sys::pic::init(); // Enable interrupts
sys::serial::init();
sys::keyboard::init();
sys::time::init();

log!("MOROS v{}\n", env!("CARGO_PKG_VERSION"));

sys::time::init();
sys::keyboard::init();
sys::serial::init();
sys::mem::init(boot_info);
sys::cpu::init();
sys::pci::init(); // Require MEM
Expand Down
2 changes: 1 addition & 1 deletion src/sys/allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use x86_64::structures::paging::mapper::MapToError;
use x86_64::structures::paging::{FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB};
use x86_64::VirtAddr;

pub const HEAP_START: usize = 0x_4444_4444_0000;
pub const HEAP_START: usize = 0x4444_4444_0000;
pub const HEAP_SIZE: usize = 16 << 20; // MB

#[global_allocator]
Expand Down
11 changes: 5 additions & 6 deletions src/sys/gdt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use lazy_static::lazy_static;
use x86_64::VirtAddr;
use x86_64::instructions::segmentation::{CS, DS, Segment};
use x86_64::instructions::tables::load_tss;
use x86_64::structures::gdt::{Descriptor, DescriptorFlags, GlobalDescriptorTable, SegmentSelector};
use x86_64::structures::gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector};
use x86_64::structures::tss::TaskStateSegment;

const STACK_SIZE: usize = 8192;
Expand Down Expand Up @@ -36,22 +36,21 @@ lazy_static! {
lazy_static! {
pub static ref GDT: (GlobalDescriptorTable, Selectors) = {
let mut gdt = GlobalDescriptorTable::new();
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 code = gdt.add_entry(Descriptor::kernel_code_segment());
let data = gdt.add_entry(Descriptor::kernel_data_segment());
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 })
(gdt, Selectors { tss, code, data, user_code, user_data })
};
}

pub struct Selectors {
tss: SegmentSelector,
code: SegmentSelector,
data: SegmentSelector,
tss: SegmentSelector,
pub user_code: SegmentSelector,
pub user_data: SegmentSelector,
}
Expand Down
75 changes: 36 additions & 39 deletions src/sys/idt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ fn interrupt_index(irq: u8) -> u8 {
sys::pic::PIC_1_OFFSET + irq
}

fn default_irq_handler() {
}
fn default_irq_handler() {}

lazy_static! {
pub static ref IRQ_HANDLERS: Mutex<[fn(); 16]> = Mutex::new([default_irq_handler; 16]);
Expand Down Expand Up @@ -144,43 +143,41 @@ macro_rules! wrap {
#[naked]
pub unsafe extern "sysv64" fn $w() {
asm!(
"
push rbp
push rax
push rbx
push rcx
push rdx
push rsi
push rdi
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
mov rsi, rsp // arg2: register list
mov rdi, rsp
add rdi, 15*8 // arg1: interupt frame
call {}
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rdi
pop rsi
pop rdx
pop rcx
pop rbx
pop rax
pop rbp
iretq
",
"push rbp",
"push rax",
"push rbx",
"push rcx",
"push rdx",
"push rsi",
"push rdi",
"push r8",
"push r9",
"push r10",
"push r11",
"push r12",
"push r13",
"push r14",
"push r15",
"mov rsi, rsp", // Arg #2: register list
"mov rdi, rsp", // Arg #1: interupt frame
"add rdi, 15 * 8",
"call {}",
"pop r15",
"pop r14",
"pop r13",
"pop r12",
"pop r11",
"pop r10",
"pop r9",
"pop r8",
"pop rdi",
"pop rsi",
"pop rdx",
"pop rcx",
"pop rbx",
"pop rax",
"pop rbp",
"iretq",
sym $fn,
options(noreturn)
);
Expand Down
1 change: 0 additions & 1 deletion src/sys/keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ pub fn set_keyboard(layout: &str) -> bool {

pub fn init() {
set_keyboard(option_env!("MOROS_KEYBOARD").unwrap_or("qwerty"));

sys::idt::set_irq_handler(1, interrupt_handler);
}

Expand Down
35 changes: 19 additions & 16 deletions src/sys/mem.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::sys;
use bootloader::bootinfo::{BootInfo, MemoryMap, MemoryRegionType};
use x86_64::instructions::interrupts;
use x86_64::structures::paging::{FrameAllocator, OffsetPageTable, PageTable, PhysFrame, Size4KiB, Translate};
use x86_64::{PhysAddr, VirtAddr};

Expand All @@ -8,22 +9,24 @@ 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;
for region in boot_info.memory_map.iter() {
let start_addr = region.range.start_addr();
let end_addr = region.range.end_addr();
memory_size += end_addr - start_addr;
log!("MEM [{:#016X}-{:#016X}] {:?}\n", start_addr, end_addr, region.region_type);
}
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");
interrupts::without_interrupts(|| {
let mut memory_size = 0;
for region in boot_info.memory_map.iter() {
let start_addr = region.range.start_addr();
let end_addr = region.range.end_addr();
memory_size += end_addr - start_addr;
log!("MEM [{:#016X}-{:#016X}] {:?}\n", start_addr, end_addr, region.region_type);
}
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");
});
}

pub fn phys_to_virt(addr: PhysAddr) -> VirtAddr {
Expand Down
7 changes: 7 additions & 0 deletions src/sys/pic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,10 @@ pub const PIC_1_OFFSET: u8 = 32;
pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8;

pub static PICS: Mutex<ChainedPics> = Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) });

pub fn init() {
unsafe {
PICS.lock().initialize();
}
x86_64::instructions::interrupts::enable();
}
69 changes: 49 additions & 20 deletions src/sys/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use alloc::vec;
use alloc::vec::Vec;
use core::sync::atomic::{AtomicUsize, Ordering};
use lazy_static::lazy_static;
use object::{Object, ObjectSection};
use spin::Mutex;

const MAX_FILE_HANDLES: usize = 1024;
Expand Down Expand Up @@ -122,17 +123,17 @@ use crate::sys;
use crate::sys::gdt::GDT;
use core::sync::atomic::AtomicU64;
use x86_64::VirtAddr;
use x86_64::instructions::interrupts;
use x86_64::structures::paging::{Mapper, FrameAllocator};
use x86_64::structures::paging::{Page, PageTableFlags};

static STACK_ADDR: AtomicU64 = AtomicU64::new(0x600_000);
static CODE_ADDR: AtomicU64 = AtomicU64::new(0x400_000);
const PAGE_SIZE: u64 = 1024 * 4;
static CODE_ADDR: AtomicU64 = AtomicU64::new(0x40_0000);
static STACK_ADDR: AtomicU64 = AtomicU64::new(0x80_0000);
const PAGE_SIZE: u64 = 4 * 1024;

pub struct Process {
stack_addr: u64,
code_addr: u64,
entry_point: u64,
}

impl Process {
Expand All @@ -151,40 +152,68 @@ impl Process {

let code_addr = CODE_ADDR.fetch_add(PAGE_SIZE, Ordering::SeqCst);
let frame = frame_allocator.allocate_frame().unwrap();
let page = Page::containing_address(VirtAddr::new(code_addr));
unsafe {
mapper.map_to(page, frame, flags, &mut frame_allocator).unwrap().flush();
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();
}
}

unsafe {
let code_addr = code_addr as *mut u8;
for (i, op) in bin.iter().enumerate() {
core::ptr::write(code_addr.add(i), *op);
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);
}
}
}

set_code_addr(code_addr);

Process { stack_addr, code_addr }
Process { stack_addr, code_addr, entry_point }
}

// Switch to userspace
// Switch to user mode
pub fn switch(&self) {
//x86_64::instructions::tlb::flush_all();
let data = GDT.1.user_data.0;
let code = GDT.1.user_code.0;
unsafe {
interrupts::disable();
asm!(
"push rax",
"push rsi",
"push 0x200",
"push rdx",
"push rdi",
"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)
"iretq",
in("rax") data,
in("rsi") self.stack_addr,
in("rdx") code,
in("rdi") self.code_addr,
in("rdi") self.code_addr + self.entry_point,
);
}
}
Expand Down
Loading