uCore 32bit user program is runnable!

master
WangRunji 7 years ago
parent 5a1dc423e0
commit 8c64b2abb2

@ -35,6 +35,8 @@ pub fn init() {
gdt.add_entry(UCODE); gdt.add_entry(UCODE);
gdt.add_entry(KDATA); gdt.add_entry(KDATA);
gdt.add_entry(UDATA); gdt.add_entry(UDATA);
gdt.add_entry(UCODE32);
gdt.add_entry(UDATA32);
gdt.add_entry(Descriptor::tss_segment(&tss)); gdt.add_entry(Descriptor::tss_segment(&tss));
gdt gdt
}); });
@ -70,23 +72,29 @@ const KCODE: Descriptor = Descriptor::UserSegment(0x0020980000000000); // EXECU
const UCODE: Descriptor = Descriptor::UserSegment(0x0020F80000000000); // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT | LONG_MODE const UCODE: Descriptor = Descriptor::UserSegment(0x0020F80000000000); // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT | LONG_MODE
const KDATA: Descriptor = Descriptor::UserSegment(0x0000920000000000); // DATA_WRITABLE | USER_SEGMENT | PRESENT const KDATA: Descriptor = Descriptor::UserSegment(0x0000920000000000); // DATA_WRITABLE | USER_SEGMENT | PRESENT
const UDATA: Descriptor = Descriptor::UserSegment(0x0000F20000000000); // DATA_WRITABLE | USER_SEGMENT | USER_MODE | PRESENT const UDATA: Descriptor = Descriptor::UserSegment(0x0000F20000000000); // DATA_WRITABLE | USER_SEGMENT | USER_MODE | PRESENT
// Copied from xv6
const UCODE32: Descriptor = Descriptor::UserSegment(0x00cffa00_0000ffff);
// EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT
const UDATA32: Descriptor = Descriptor::UserSegment(0x00cff200_0000ffff); // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT
pub const KCODE_SELECTOR: SegmentSelector = SegmentSelector::new(1, PrivilegeLevel::Ring0); pub const KCODE_SELECTOR: SegmentSelector = SegmentSelector::new(1, PrivilegeLevel::Ring0);
pub const UCODE_SELECTOR: SegmentSelector = SegmentSelector::new(2, PrivilegeLevel::Ring3); pub const UCODE_SELECTOR: SegmentSelector = SegmentSelector::new(2, PrivilegeLevel::Ring3);
pub const KDATA_SELECTOR: SegmentSelector = SegmentSelector::new(3, PrivilegeLevel::Ring0); pub const KDATA_SELECTOR: SegmentSelector = SegmentSelector::new(3, PrivilegeLevel::Ring0);
pub const UDATA_SELECTOR: SegmentSelector = SegmentSelector::new(4, PrivilegeLevel::Ring3); pub const UDATA_SELECTOR: SegmentSelector = SegmentSelector::new(4, PrivilegeLevel::Ring3);
pub const TSS_SELECTOR: SegmentSelector = SegmentSelector::new(5, PrivilegeLevel::Ring0); pub const UCODE32_SELECTOR: SegmentSelector = SegmentSelector::new(5, PrivilegeLevel::Ring3);
pub const UDATA32_SELECTOR: SegmentSelector = SegmentSelector::new(6, PrivilegeLevel::Ring3);
pub const TSS_SELECTOR: SegmentSelector = SegmentSelector::new(7, PrivilegeLevel::Ring0);
pub struct Gdt { pub struct Gdt {
table: [u64; 8], table: [u64; 10],
next_free: usize, next_free: usize,
} }
impl Gdt { impl Gdt {
pub fn new() -> Gdt { pub fn new() -> Gdt {
Gdt { Gdt {
table: [0; 8], table: [0; 10],
next_free: 1, next_free: 1,
} }
} }

@ -25,6 +25,8 @@ pub fn init() {
.set_flags(IdtFlags::PRESENT | IdtFlags::RING_3 | IdtFlags::INTERRUPT); .set_flags(IdtFlags::PRESENT | IdtFlags::RING_3 | IdtFlags::INTERRUPT);
idt[T_SYSCALL].set_handler_fn(syscall) idt[T_SYSCALL].set_handler_fn(syscall)
.set_flags(IdtFlags::PRESENT | IdtFlags::RING_3 | IdtFlags::TRAP); .set_flags(IdtFlags::PRESENT | IdtFlags::RING_3 | IdtFlags::TRAP);
idt[0x80].set_handler_fn(syscall32)
.set_flags(IdtFlags::PRESENT | IdtFlags::RING_3 | IdtFlags::TRAP);
unsafe { unsafe {
idt[T_DBLFLT].set_handler_fn(double_fault) idt[T_DBLFLT].set_handler_fn(double_fault)

@ -18,7 +18,7 @@ interrupt_error_p!(double_fault, stack, {
interrupt_error_p!(page_fault, stack, { interrupt_error_p!(page_fault, stack, {
use x86_64::registers::control_regs::cr2; use x86_64::registers::control_regs::cr2;
let addr = cr2().0; let addr = cr2().0;
println!("\nEXCEPTION: Page Fault @ {:#x}", addr); println!("\nEXCEPTION: Page Fault @ {:#x}, code: {:#x}", addr, stack.code);
use memory::page_fault_handler; use memory::page_fault_handler;
if page_fault_handler(addr) { if page_fault_handler(addr) {
@ -108,7 +108,15 @@ interrupt_stack_p!(to_kernel, stack, {
}); });
interrupt_stack_p!(syscall, stack, { interrupt_stack_p!(syscall, stack, {
println!("\nInterupt: Syscall {}", stack.scratch.rax); println!("\nInterupt: Syscall {:#x?}", stack.scratch.rax);
use syscall::syscall; use syscall::syscall;
syscall(stack); let ret = syscall(stack, false);
stack.scratch.rax = ret as usize;
});
interrupt_stack_p!(syscall32, stack, {
println!("\nInterupt: Syscall {:#x?}", stack.scratch.rax);
use syscall::syscall;
let ret = syscall(stack, true);
stack.scratch.rax = ret as usize;
}); });

@ -17,14 +17,14 @@ impl TrapFrame {
tf.iret.rflags = 0x282; tf.iret.rflags = 0x282;
tf tf
} }
pub fn new_user_thread(entry_addr: usize, rsp: usize) -> Self { pub fn new_user_thread(entry_addr: usize, rsp: usize, is32: bool) -> Self {
use arch::gdt; use arch::gdt;
let mut tf = TrapFrame::default(); let mut tf = TrapFrame::default();
tf.iret.cs = gdt::UCODE_SELECTOR.0 as usize; tf.iret.cs = if is32 { gdt::UCODE32_SELECTOR.0 } else { gdt::UCODE_SELECTOR.0 } as usize;
tf.iret.rip = entry_addr; tf.iret.rip = entry_addr;
tf.iret.ss = gdt::UDATA_SELECTOR.0 as usize; tf.iret.ss = if is32 { gdt::UDATA32_SELECTOR.0 } else { gdt::UDATA_SELECTOR.0 } as usize;
tf.iret.rsp = rsp; tf.iret.rsp = rsp;
tf.iret.rflags = 0x3282; tf.iret.rflags = 0x282;
tf tf
} }
} }

@ -339,7 +339,7 @@ macro_rules! interrupt_switch {
use arch::gdt; use arch::gdt;
use core::mem::size_of; use core::mem::size_of;
let tf = &mut *(rsp as *mut TrapFrame); let tf = &mut *(rsp as *mut TrapFrame);
if tf.iret.cs == gdt::UCODE_SELECTOR.0 as usize { if tf.iret.cs & 0x3 == 3 {
gdt::set_ring0_rsp(rsp + size_of::<TrapFrame>()); gdt::set_ring0_rsp(rsp + size_of::<TrapFrame>());
} }

@ -34,6 +34,8 @@ use arch::interrupt::TrapFrame;
extern { extern {
fn _binary_user_forktest_start(); fn _binary_user_forktest_start();
fn _binary_user_forktest_end(); fn _binary_user_forktest_end();
fn _binary_hello_start();
fn _binary_hello_end();
} }
@ -42,12 +44,14 @@ pub fn init(mut mc: MemoryController) {
let initproc = Process::new_init(&mut mc); let initproc = Process::new_init(&mut mc);
let idleproc = Process::new("idle", idle_thread, &mut mc); let idleproc = Process::new("idle", idle_thread, &mut mc);
#[cfg(feature = "link_user_program")] #[cfg(feature = "link_user_program")]
let forktest = Process::new_user(_binary_user_forktest_start as usize, // let forktest = Process::new_user(_binary_user_forktest_start as usize,
_binary_user_forktest_end as usize, &mut mc); // _binary_user_forktest_end as usize, &mut mc);
let hello = Process::new_user(_binary_hello_start as usize,
_binary_hello_end as usize, &mut mc);
let mut processor = Processor::new(mc); let mut processor = Processor::new(mc);
processor.add(initproc); processor.add(initproc);
processor.add(idleproc); processor.add(idleproc);
processor.add(forktest); processor.add(hello);
processor processor
})}); })});
} }

@ -61,39 +61,60 @@ impl Process {
/// Make a new user thread /// Make a new user thread
/// The program elf data is placed at [begin, end) /// The program elf data is placed at [begin, end)
/// uCore x86 32bit program is planned to be supported.
pub fn new_user(begin: usize, end: usize, mc: &mut MemoryController) -> Self { pub fn new_user(begin: usize, end: usize, mc: &mut MemoryController) -> Self {
// Parse elf // Parse elf
let slice = unsafe{ slice::from_raw_parts(begin as *const u8, end - begin) }; let slice = unsafe{ slice::from_raw_parts(begin as *const u8, end - begin) };
let elf = ElfFile::new(slice).expect("failed to read elf"); let elf = ElfFile::new(slice).expect("failed to read elf");
let is32 = match elf.header.pt2 {
HeaderPt2::Header32(_) => true,
HeaderPt2::Header64(_) => false,
};
// User stack
use consts::{USER_STACK_OFFSET, USER_STACK_SIZE, USER_TCB_OFFSET};
let (user_stack_buttom, mut user_stack_top) = match is32 {
true => (USER_TCB_OFFSET, USER_TCB_OFFSET + USER_STACK_SIZE),
false => (USER_STACK_OFFSET, USER_STACK_OFFSET + USER_STACK_SIZE),
};
// Make page table // Make page table
use consts::{USER_STACK_OFFSET, USER_STACK_SIZE};
let mut memory_set = MemorySet::from(&elf); let mut memory_set = MemorySet::from(&elf);
memory_set.push(MemoryArea::new(USER_STACK_OFFSET, USER_STACK_OFFSET + USER_STACK_SIZE, memory_set.push(MemoryArea::new(user_stack_buttom, user_stack_top,
EntryFlags::WRITABLE | EntryFlags::NO_EXECUTE | EntryFlags::USER_ACCESSIBLE, "user_stack")); EntryFlags::WRITABLE | EntryFlags::NO_EXECUTE | EntryFlags::USER_ACCESSIBLE, "user_stack"));
let page_table = mc.make_page_table(&memory_set); let page_table = mc.make_page_table(&memory_set);
debug!("{:#x?}", memory_set); debug!("{:#x?}", memory_set);
let entry_addr = match elf.header.pt2 {
HeaderPt2::Header32(header) => header.entry_point as usize,
HeaderPt2::Header64(header) => header.entry_point as usize,
};
// Temporary switch to it, in order to copy data // Temporary switch to it, in order to copy data
let page_table = mc.with(page_table, || { let page_table = mc.with(page_table, || {
for ph in elf.program_iter() { for ph in elf.program_iter() {
let ph = match ph { let (virt_addr, offset, file_size) = match ph {
ProgramHeader::Ph64(ph) => ph, ProgramHeader::Ph32(ph) => (ph.virtual_addr as usize, ph.offset as usize, ph.file_size as usize),
_ => unimplemented!(), ProgramHeader::Ph64(ph) => (ph.virtual_addr as usize, ph.offset as usize, ph.file_size as usize),
}; };
unsafe { memcpy(ph.virtual_addr as *mut u8, (begin + ph.offset as usize) as *mut u8, ph.file_size as usize) }; unsafe { memcpy(virt_addr as *mut u8, (begin + offset) as *mut u8, file_size) };
}
if is32 {
unsafe {
// TODO: full argc & argv
*(user_stack_top as *mut u32).offset(-1) = 0; // argv
*(user_stack_top as *mut u32).offset(-2) = 0; // argc
user_stack_top -= 8;
}
} }
}); });
let entry_addr = match elf.header.pt2 {
HeaderPt2::Header64(header) => header.entry_point,
_ => unimplemented!(),
} as usize;
// Allocate kernel stack and push trap frame // Allocate kernel stack and push trap frame
let kstack = mc.alloc_stack(7).unwrap(); let kstack = mc.alloc_stack(7).unwrap();
let tf = TrapFrame::new_user_thread(entry_addr, USER_STACK_OFFSET + USER_STACK_SIZE); let tf = TrapFrame::new_user_thread(entry_addr, user_stack_top, is32);
let rsp = kstack.push_at_top(tf); let rsp = kstack.push_at_top(tf);
debug!("rsp = {:#x}", rsp);
Process { Process {
pid: 0, pid: 0,
@ -153,15 +174,11 @@ impl<'a> From<&'a ElfFile<'a>> for MemorySet {
fn from(elf: &'a ElfFile<'a>) -> Self { fn from(elf: &'a ElfFile<'a>) -> Self {
let mut set = MemorySet::new(); let mut set = MemorySet::new();
for ph in elf.program_iter() { for ph in elf.program_iter() {
let ph = match ph { let (virt_addr, mem_size, flags) = match ph {
ProgramHeader::Ph64(ph) => ph, ProgramHeader::Ph32(ph) => (ph.virtual_addr as usize, ph.mem_size as usize, ph.flags),
_ => unimplemented!(), ProgramHeader::Ph64(ph) => (ph.virtual_addr as usize, ph.mem_size as usize, ph.flags),
}; };
set.push(MemoryArea::new( set.push(MemoryArea::new(virt_addr, virt_addr + mem_size, EntryFlags::from(flags), ""));
ph.virtual_addr as usize,
(ph.virtual_addr + ph.mem_size) as usize,
EntryFlags::from(ph.flags),
""));
} }
set set
} }
@ -170,7 +187,9 @@ impl<'a> From<&'a ElfFile<'a>> for MemorySet {
impl From<Flags> for EntryFlags { impl From<Flags> for EntryFlags {
fn from(elf_flags: Flags) -> Self { fn from(elf_flags: Flags) -> Self {
let mut flags = EntryFlags::PRESENT | EntryFlags::USER_ACCESSIBLE; let mut flags = EntryFlags::PRESENT | EntryFlags::USER_ACCESSIBLE;
if elf_flags.is_write() { // if elf_flags.is_write() {
// TODO: handle readonly
if true {
flags = flags | EntryFlags::WRITABLE; flags = flags | EntryFlags::WRITABLE;
} }
if !elf_flags.is_execute() { if !elf_flags.is_execute() {

@ -2,12 +2,24 @@ use super::*;
use process; use process;
use arch::interrupt::TrapFrame; use arch::interrupt::TrapFrame;
pub unsafe fn syscall(tf: &TrapFrame) -> i32 { pub unsafe fn syscall(tf: &TrapFrame, is32: bool) -> i32 {
let id = tf.scratch.rax; let id = match is32 {
// For ucore: false => tf.scratch.rax,
// let args = [tf.scratch.rdx, tf.scratch.rcx, tf.preserved.rbx, tf.scratch.rdi, tf.scratch.rsi]; true => match tf.scratch.rax {
// For xv6 x86_64 UCORE_SYS_OPEN => SYS_OPEN,
let args = [tf.scratch.rdi, tf.scratch.rsi, tf.scratch.rdx, tf.scratch.rcx, tf.scratch.r8, tf.scratch.r9]; UCORE_SYS_CLOSE => SYS_CLOSE,
UCORE_SYS_WRITE => SYS_WRITE,
UCORE_SYS_READ => SYS_READ,
_ => 0,
}
};
let args = match is32 {
// For ucore x86
true => [tf.scratch.rdx, tf.scratch.rcx, tf.preserved.rbx, tf.scratch.rdi, tf.scratch.rsi, 0],
// For xv6 x86_64
false => [tf.scratch.rdi, tf.scratch.rsi, tf.scratch.rdx, tf.scratch.rcx, tf.scratch.r8, tf.scratch.r9],
};
debug!("id: {:#x}, args: {:#x?}", id, args);
match id { match id {
SYS_FORK => { SYS_FORK => {
@ -19,7 +31,7 @@ pub unsafe fn syscall(tf: &TrapFrame) -> i32 {
0 0
} }
_ => { _ => {
debug!("unknown syscall {}", id); debug!("unknown syscall {:#x}", id);
-1 -1
} }
} }
@ -47,3 +59,29 @@ const SYS_LINK: usize = 19;
const SYS_MKDIR: usize = 20; const SYS_MKDIR: usize = 20;
const SYS_CLOSE: usize = 21; const SYS_CLOSE: usize = 21;
const SYS_CHMOD: usize = 22; const SYS_CHMOD: usize = 22;
const UCORE_SYS_EXIT: usize = 1;
const UCORE_SYS_FORK: usize = 2;
const UCORE_SYS_WAIT: usize = 3;
const UCORE_SYS_EXEC: usize = 4;
const UCORE_SYS_CLONE: usize = 5;
const UCORE_SYS_YIELD: usize = 10;
const UCORE_SYS_SLEEP: usize = 11;
const UCORE_SYS_KILL: usize = 12;
const UCORE_SYS_GETTIME: usize = 17;
const UCORE_SYS_GETPID: usize = 18;
const UCORE_SYS_MMAP: usize = 20;
const UCORE_SYS_MUNMAP: usize = 21;
const UCORE_SYS_SHMEM: usize = 22;
const UCORE_SYS_PUTC: usize = 30;
const UCORE_SYS_PGDIR: usize = 31;
const UCORE_SYS_OPEN: usize = 100;
const UCORE_SYS_CLOSE: usize = 101;
const UCORE_SYS_READ: usize = 102;
const UCORE_SYS_WRITE: usize = 103;
const UCORE_SYS_SEEK: usize = 104;
const UCORE_SYS_FSTAT: usize = 110;
const UCORE_SYS_FSYNC: usize = 111;
const UCORE_SYS_GETCWD: usize = 121;
const UCORE_SYS_GETDIRENTRY: usize = 128;
const UCORE_SYS_DUP: usize = 130;

Binary file not shown.
Loading…
Cancel
Save