From 44e8b99b46f55fab11cad10812110bbd601e92c4 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 10 Sep 2016 22:06:09 -0600 Subject: [PATCH] Implement exec Implement brk --- Makefile | 12 ++--- arch/x86_64/src/lib.rs | 6 ++- bootloader/x86_64/harddrive.asm | 2 +- init/src/main.rs | 10 +++- kernel/context/mod.rs | 2 +- kernel/lib.rs | 46 +++-------------- kernel/scheme/debug.rs | 2 +- kernel/scheme/initfs.rs | 3 +- kernel/syscall/mod.rs | 6 +++ kernel/syscall/process.rs | 90 ++++++++++++++++++++++++++++++--- libstd | 2 +- 11 files changed, 122 insertions(+), 59 deletions(-) diff --git a/Makefile b/Makefile index 73a3879..e9f5233 100644 --- a/Makefile +++ b/Makefile @@ -37,10 +37,10 @@ ifeq ($(ARCH),arm) QEMUFLAGS+=-cpu arm1176 -machine integratorcp QEMUFLAGS+=-nographic -$(KBUILD)/kernel.list: $(KBUILD)/kernel.bin +build/%.list: build/% $(ARCH)-none-eabi-objdump -C -D $< > $@ -$(KBUILD)/harddrive.bin: $(KBUILD)/kernel.bin +$(KBUILD)/harddrive.bin: $(KBUILD)/kernel cp $< $@ qemu: $(KBUILD)/harddrive.bin @@ -60,11 +60,11 @@ endif QEMUFLAGS= endif -$(KBUILD)/kernel.list: $(KBUILD)/kernel.bin +build/%.list: build/% objdump -C -M intel -D $< > $@ -$(KBUILD)/harddrive.bin: $(KBUILD)/kernel.bin bootloader/$(ARCH)/** - nasm -f bin -o $@ -D ARCH_$(ARCH) -ibootloader/$(ARCH)/ -i$(KBUILD)/ bootloader/$(ARCH)/harddrive.asm +$(KBUILD)/harddrive.bin: $(KBUILD)/kernel bootloader/$(ARCH)/** + nasm -f bin -o $@ -D ARCH_$(ARCH) -ibootloader/$(ARCH)/ bootloader/$(ARCH)/harddrive.asm qemu: $(KBUILD)/harddrive.bin $(QEMU) $(QEMUFLAGS) -drive file=$<,format=raw,index=0,media=disk @@ -93,7 +93,7 @@ $(KBUILD)/libcollections.rlib: rust/src/libcollections/lib.rs $(KBUILD)/libcore. $(KBUILD)/libkernel.a: $(KBUILD)/libcore.rlib $(KBUILD)/liballoc.rlib $(KBUILD)/libcollections.rlib $(BUILD)/init kernel/** FORCE $(KCARGO) rustc $(KCARGOFLAGS) -o $@ -$(KBUILD)/kernel.bin: $(KBUILD)/libkernel.a +$(KBUILD)/kernel: $(KBUILD)/libkernel.a $(LD) --gc-sections -z max-page-size=0x1000 -T arch/$(ARCH)/src/linker.ld -o $@ $< # Userspace recipes diff --git a/arch/x86_64/src/lib.rs b/arch/x86_64/src/lib.rs index c72ccc2..8ace580 100644 --- a/arch/x86_64/src/lib.rs +++ b/arch/x86_64/src/lib.rs @@ -29,7 +29,11 @@ pub const BITMAP_OFFSET: usize = 0xffff_fe80_0000_0000; /// Offset to kernel heap pub const HEAP_OFFSET: usize = 0xffff_fe00_0000_0000; /// Size of heap -pub const HEAP_SIZE: usize = 64 * 1024 * 1024; // 128 MB +pub const HEAP_SIZE: usize = 64 * 1024 * 1024; // 64 MB +/// Offset to user heap +pub const USER_HEAP_OFFSET: usize = 0x0000_0080_0000_0000; +/// Size of user heap +pub const USER_HEAP_SIZE: usize = 64 * 1024 * 1024; // 64 MB /// Print to console #[macro_export] diff --git a/bootloader/x86_64/harddrive.asm b/bootloader/x86_64/harddrive.asm index 2a50fed..c0f228b 100644 --- a/bootloader/x86_64/harddrive.asm +++ b/bootloader/x86_64/harddrive.asm @@ -12,7 +12,7 @@ align 512, db 0 startup_end: kernel_file: - incbin "kernel.bin" + incbin "build/kernel/kernel" align 512, db 0 .end: .length equ kernel_file.end - kernel_file diff --git a/init/src/main.rs b/init/src/main.rs index dc90bf5..48b1c76 100644 --- a/init/src/main.rs +++ b/init/src/main.rs @@ -1,7 +1,15 @@ +use std::fs::File; +use std::io::{BufRead, BufReader}; use std::thread; pub fn main() { - println!("Hello, World!"); + let mut file = File::open("initfs:etc/init.rc").expect("failed to open init.rc"); + let mut reader = BufReader::new(file); + + for line in reader.lines() { + println!("{}", line.expect("failed to read init.rc")); + } + loop { thread::yield_now(); } diff --git a/kernel/context/mod.rs b/kernel/context/mod.rs index c0911cf..506dde6 100644 --- a/kernel/context/mod.rs +++ b/kernel/context/mod.rs @@ -71,7 +71,7 @@ impl ContextList { let context_lock = self.new_context()?; { let mut context = context_lock.write(); - let mut stack = Box::new([0; 4096]); + let mut stack = Box::new([0; 65536]); let offset = stack.len() - mem::size_of::(); unsafe { let offset = stack.len() - mem::size_of::(); diff --git a/kernel/lib.rs b/kernel/lib.rs index 836aa19..e32d088 100644 --- a/kernel/lib.rs +++ b/kernel/lib.rs @@ -116,14 +116,14 @@ pub mod syscall; #[cfg(test)] pub mod tests; -pub extern fn context_test() { - print!("Test\n"); - unsafe { context::switch(); } +pub extern fn userspace_init() { + assert_eq!(syscall::open(b"debug:", 0), Ok(0)); + assert_eq!(syscall::open(b"debug:", 0), Ok(1)); + assert_eq!(syscall::open(b"debug:", 0), Ok(2)); - print!("Test halt\n"); - loop { - unsafe { interrupt::enable_and_halt(); } - } + syscall::exec(b"initfs:bin/init", &[]).expect("failed to execute initfs:init"); + + panic!("initfs:init returned") } #[no_mangle] @@ -133,36 +133,10 @@ pub extern fn kmain() { let pid = syscall::getpid(); println!("BSP: {:?}", pid); - assert_eq!(syscall::open(b"debug:", 0), Ok(0)); - assert_eq!(syscall::open(b"debug:", 0), Ok(1)); - assert_eq!(syscall::open(b"debug:", 0), Ok(2)); + context::contexts_mut().spawn(userspace_init).expect("failed to spawn userspace_init"); - let init_file = syscall::open(b"initfs:init", 0).expect("failed to open initfs:init"); - let mut init_data = collections::Vec::new(); - loop { - let mut buf = [0; 65536]; - let count = syscall::read(init_file, &mut buf).expect("failed to read initfs:init"); - if count > 0 { - init_data.extend_from_slice(&buf[..count]); - } else { - break; - } - } - - let elf = elf::Elf::from(&init_data).expect("could not load elf"); - elf.run(); - - /* - if let Ok(_context_lock) = context::contexts_mut().spawn(context_test) { - print!("Spawned context\n"); - } - - print!("Main\n"); unsafe { context::switch(); } - print!("Main halt\n"); - */ - loop { unsafe { interrupt::enable_and_halt(); } } @@ -175,10 +149,6 @@ pub extern fn kmain_ap(id: usize) { let pid = syscall::getpid(); println!("AP {}: {:?}", id, pid); - assert_eq!(syscall::open(b"debug:", 0), Ok(0)); - assert_eq!(syscall::open(b"debug:", 0), Ok(1)); - assert_eq!(syscall::open(b"debug:", 0), Ok(2)); - loop { unsafe { interrupt::enable_and_halt() } } diff --git a/kernel/scheme/debug.rs b/kernel/scheme/debug.rs index 35979b3..942cc4a 100644 --- a/kernel/scheme/debug.rs +++ b/kernel/scheme/debug.rs @@ -6,7 +6,7 @@ use super::Scheme; pub struct DebugScheme; impl Scheme for DebugScheme { - fn open(&mut self, path: &[u8], _flags: usize) -> Result { + fn open(&mut self, _path: &[u8], _flags: usize) -> Result { Ok(0) } diff --git a/kernel/scheme/initfs.rs b/kernel/scheme/initfs.rs index 145f7f6..38fefc4 100644 --- a/kernel/scheme/initfs.rs +++ b/kernel/scheme/initfs.rs @@ -18,7 +18,8 @@ impl InitFsScheme { pub fn new() -> InitFsScheme { let mut files: BTreeMap<&'static [u8], &'static [u8]> = BTreeMap::new(); - files.insert(b"init", include_bytes!("../../build/userspace/init")); + files.insert(b"bin/init", include_bytes!("../../build/userspace/init")); + files.insert(b"etc/init.rc", b"echo testing\n"); InitFsScheme { next_id: 0, diff --git a/kernel/syscall/mod.rs b/kernel/syscall/mod.rs index 6696ffd..91f4388 100644 --- a/kernel/syscall/mod.rs +++ b/kernel/syscall/mod.rs @@ -30,6 +30,8 @@ pub enum Call { Exec = 11, /// Get process ID GetPid = 20, + /// Set process break + Brk = 45, /// Yield to scheduler SchedYield = 158 } @@ -46,6 +48,7 @@ impl Call { 6 => Ok(Call::Close), 11 => Ok(Call::Exec), 20 => Ok(Call::GetPid), + 45 => Ok(Call::Brk), 158 => Ok(Call::SchedYield), _ => Err(Error::NoCall) } @@ -63,6 +66,8 @@ pub enum Error { NoEntry = 2, /// No such process NoProcess = 3, + /// Invalid executable format + NoExec = 8, /// Bad file number BadFile = 9, /// Try again @@ -100,6 +105,7 @@ pub fn handle(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize) -> Re Call::Close => close(b), Call::Exec => exec(convert_slice(b as *const u8, c)?, convert_slice(d as *const [usize; 2], e)?), Call::GetPid => getpid(), + Call::Brk => brk(b), Call::SchedYield => sched_yield() } } diff --git a/kernel/syscall/process.rs b/kernel/syscall/process.rs index 0149aed..d15c239 100644 --- a/kernel/syscall/process.rs +++ b/kernel/syscall/process.rs @@ -1,10 +1,63 @@ ///! Process syscalls +use core::str; + +use arch; use arch::interrupt::halt; - +use arch::paging::{ActivePageTable, Page, VirtualAddress, entry}; use context; +use elf; +use syscall::{self, Error, Result}; -use super::{convert_slice, Error, Result}; +pub fn brk(address: usize) -> Result { + //TODO: Make this more efficient + let mut active_table = unsafe { ActivePageTable::new() }; + let mut current = arch::USER_HEAP_OFFSET; + { + let min_page = Page::containing_address(VirtualAddress::new(arch::USER_HEAP_OFFSET)); + let max_page = Page::containing_address(VirtualAddress::new(arch::USER_HEAP_OFFSET + arch::USER_HEAP_SIZE - 1)); + for page in Page::range_inclusive(min_page, max_page) { + if active_table.translate_page(page).is_none() { + break; + } + current = page.start_address().get() + 4096; + } + } + if address == 0 { + //println!("Brk query {:X}", current); + Ok(current) + } else if address > current { + let start_page = Page::containing_address(VirtualAddress::new(current)); + let end_page = Page::containing_address(VirtualAddress::new(address - 1)); + for page in Page::range_inclusive(start_page, end_page) { + //println!("Map {:X}", page.start_address().get()); + if active_table.translate_page(page).is_none() { + //println!("Not found - mapping"); + active_table.map(page, entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE | entry::USER_ACCESSIBLE); + } else { + //println!("Found - skipping"); + } + } + //let new = end_page.start_address().get() + 4096; + //println!("Brk increase {:X}: from {:X} to {:X}", address, current, new); + Ok(address) + } else { + let start_page = Page::containing_address(VirtualAddress::new(address)); + let end_page = Page::containing_address(VirtualAddress::new(current - 1)); + for page in Page::range_inclusive(start_page, end_page) { + //println!("Unmap {:X}", page.start_address().get()); + if active_table.translate_page(page).is_some() { + //println!("Found - unmapping"); + active_table.unmap(page); + } else { + //println!("Not found - skipping"); + } + } + //let new = start_page.start_address().get(); + //println!("Brk decrease {:X}: from {:X} to {:X}", address, current, new); + Ok(address) + } +} pub fn exit(status: usize) -> ! { println!("Exit {}", status); @@ -13,13 +66,34 @@ pub fn exit(status: usize) -> ! { } } -pub fn exec(path: &[u8], args: &[[usize; 2]]) -> Result { - print!("Exec {:?}", ::core::str::from_utf8(path)); - for arg in args { - print!(" {:?}", ::core::str::from_utf8(convert_slice(arg[0] as *const u8, arg[1])?)); +pub fn exec(path: &[u8], _args: &[[usize; 2]]) -> Result { + //TODO: Use args + //TODO: Unmap previous mappings + //TODO: Drop init_data + + let init_file = syscall::open(path, 0)?; + let mut init_data = vec![]; + loop { + let mut buf = [0; 4096]; + let count = syscall::read(init_file, &mut buf)?; + if count > 0 { + init_data.extend_from_slice(&buf[..count]); + } else { + break; + } + } + let _ = syscall::close(init_file); + + match elf::Elf::from(&init_data) { + Ok(elf) => { + elf.run(); + Ok(0) + }, + Err(err) => { + println!("failed to execute {}: {}", unsafe { str::from_utf8_unchecked(path) }, err); + Err(Error::NoExec) + } } - println!(""); - Ok(0) } pub fn getpid() -> Result { diff --git a/libstd b/libstd index 7b20e73..7ead704 160000 --- a/libstd +++ b/libstd @@ -1 +1 @@ -Subproject commit 7b20e739903a4877a10b64b875a3fd7a06cdcd16 +Subproject commit 7ead704d48411cc66ce71ffe4f1fbe86a6a4cbe4