Skip to content

Commit

Permalink
#32 WIP - trying go to user land
Browse files Browse the repository at this point in the history
For now, this is raising an #GP exception for some reason :/
  • Loading branch information
gil0mendes committed Apr 25, 2017
1 parent 7d5893c commit 7b1ac37
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 9 deletions.
2 changes: 2 additions & 0 deletions arch/x86_64/src/consts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/// Offset to user TCB
pub const USER_TCB_OFFSET: usize = 0xB000_0000;
49 changes: 47 additions & 2 deletions arch/x86_64/src/interrupts/gdt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ use x86_64::structures::gdt::SegmentSelector;
use x86_64::PrivilegeLevel;

pub struct Gdt {
table: [u64; 8],
table: [u64; 9],
next_free: usize,
}

impl Gdt {
pub fn new() -> Gdt {
Gdt {
table: [0; 8],
table: [0; 9],
next_free: 1
}
}
Expand All @@ -33,6 +33,20 @@ impl Gdt {
SegmentSelector::new(index as u16, PrivilegeLevel::Ring0)
}

/// Add a new entry to the GDT
pub fn add_entry_user(&mut self, entry: Descriptor) -> SegmentSelector {
let index = match entry {
Descriptor::UserSegment(value) => self.push(value),
Descriptor::SystemSegment(value_low, value_high) => {
let index = self.push(value_low);
self.push(value_high);
index
}
};
let new_seg = SegmentSelector::new(index as u16, PrivilegeLevel::Ring3);
new_seg
}

/// This is used to control the number of entries on the GDT table.
fn push(&mut self, value: u64) -> usize {
if self.next_free < self.table.len() {
Expand Down Expand Up @@ -120,13 +134,44 @@ impl Descriptor {

Descriptor::SystemSegment(low, high)
}

/// Creates an user mode code segment
pub fn user_code_segment() -> Descriptor {
let flags = USER_SEGMENT | PRESENT | EXECUTABLE | LONG_MODE | RING_3;
Descriptor::UserSegment(flags.bits())
}

/// Creates an user mode data segment
pub fn user_data_segment() -> Descriptor {
let flags = USER_SEGMENT | PRESENT | LONG_MODE | RING_3;
Descriptor::UserSegment(flags.bits())
}

/// Creates an user mode TLS segment
pub fn user_thread_local_segment(offset: usize) -> Descriptor {
use bit_field::BitField;

// set the descriptor flags
let flags = USER_SEGMENT | PRESENT | LONG_MODE | RING_3;

// get the bytes
let mut bits = flags.bits();

// set the offset
let off = offset as u64;
bits.set_bits(16..40, off.get_bits(0..24));
bits.set_bits(56..64, off.get_bits(24..32));

Descriptor::UserSegment(bits)
}
}

bitflags! {
flags DescriptorFlags: u64 {
const CONFORMING = 1 << 42,
const EXECUTABLE = 1 << 43,
const USER_SEGMENT = 1 << 44,
const RING_3 = 3 << 5,
const PRESENT = 1 << 47,
const LONG_MODE = 1 << 53,
}
Expand Down
19 changes: 15 additions & 4 deletions arch/x86_64/src/interrupts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ lazy_static! {
// create a new IDT structure
let mut idt = Idt::new();

// Set up exceptions
// Set up exceptions
idt.divide_by_zero.set_handler_fn(exceptions::divide_by_zero);
idt.debug.set_handler_fn(exceptions::debug);
Expand Down Expand Up @@ -89,17 +90,27 @@ pub fn init(memory_controller: &mut MemoryController, tcb_offset: usize) {
let mut tss_selector = SegmentSelector(0);
let gdt = GDT.call_once(|| {
let mut gdt = gdt::Gdt::new();
// setup the kernel code segment
// 1. setup the kernel code segment
code_selector = gdt.add_entry(gdt::Descriptor::kernel_code_segment());

// setup the kernel data segment
// 2. setup the kernel data segment
data_selector = gdt.add_entry(gdt::Descriptor::kernel_data_segment());

// setup the thread local segment
// 3. setup the thread local segment
tls_selector = gdt.add_entry(gdt::Descriptor::thread_local_segment(tcb_offset));

// setup the TSS segment
// 4. User code
gdt.add_entry_user(gdt::Descriptor::user_code_segment());

// 5. User data
gdt.add_entry_user(gdt::Descriptor::user_data_segment());

// 6. User TLS
gdt.add_entry_user(gdt::Descriptor::user_thread_local_segment(::USER_TCB_OFFSET));

// 7/8. setup the TSS segment
tss_selector = gdt.add_entry(gdt::Descriptor::tss_segment(&tss));

gdt
});
gdt.load();
Expand Down
36 changes: 36 additions & 0 deletions arch/x86_64/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ extern crate collections;
#[macro_use]
extern crate once;

// Make constants public
pub use consts::*;

#[macro_use]
/// Console handling
pub mod vga_buffer;
Expand All @@ -36,6 +39,9 @@ pub mod kernel_messaging;
/// ACPI manager
pub mod acpi;

/// Architecture constants
pub mod consts;

/// Architecture context
pub mod context;

Expand Down Expand Up @@ -72,3 +78,33 @@ pub extern "C" fn panic_fmt(fmt: core::fmt::Arguments, file: &'static str, line:
pub extern "C" fn _Unwind_Resume() -> ! {
loop {}
}

/// Enter in usermode.
///
/// This functions never returns.
pub unsafe fn usermode(ip: usize, sp: usize) -> ! {
asm!("
mov ds, ax
mov es, ax
mov fs, bx
mov gs, ax
push rax
push rcx
push rdx
push rsi
push rdi
iretq"
:
: "{rax}"(5 << 3 | 3) // Data segment
"{rbx}"(6 << 3 | 3) // TLS segment
"{rcx}"(sp) // Stack pointer
"{rdx}"(3 << 12 | 1 << 9) // Flags - Set IOPL and interrupt enable flag
"{rsi}"(4 << 3 | 3) // Code segment
"{rdi}"(ip) // Instruction Pointer
:
: "intel", "volatile"
);
unreachable!();
}
2 changes: 1 addition & 1 deletion programs/init/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub fn main() {
printl!("Hellow from the userland!");
println!("Hello, from the userland!");
loop {}
}
4 changes: 2 additions & 2 deletions src/syscall/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use collections::Vec;
use core::{intrinsics, mem, str};
use spin::Mutex;

use arch::usermode;
use context;
use elf;
use elf::program_header;
Expand Down Expand Up @@ -152,6 +153,5 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
}

// TODO go to userland
// unsafe { arch::usermode(entry, sp); }
Err(Error::new(ENOEXEC))
unsafe { usermode(entry, sp); }
}

0 comments on commit 7b1ac37

Please sign in to comment.