From 850792bbf13614c517f4f3290bfa2f12ef23ddaf Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 7 Sep 2016 21:16:30 -0600 Subject: [PATCH 1/7] Load a very simple ELF and launch it in usermode --- arch/x86_64/src/idt.rs | 1 + arch/x86_64/src/interrupt/syscall.rs | 37 ++++--- arch/x86_64/src/lib.rs | 2 +- arch/x86_64/src/paging/mapper.rs | 9 ++ arch/x86_64/src/paging/table.rs | 2 +- arch/x86_64/src/start.rs | 44 ++++----- init/main | Bin 0 -> 512 bytes init/main.asm | 20 ++++ init/main.o | Bin 0 -> 880 bytes kernel/elf.rs | 140 +++++++++++++++++++++++---- kernel/lib.rs | 5 +- 11 files changed, 201 insertions(+), 59 deletions(-) create mode 100755 init/main create mode 100644 init/main.asm create mode 100644 init/main.o diff --git a/arch/x86_64/src/idt.rs b/arch/x86_64/src/idt.rs index 75f54f1..e53e259 100644 --- a/arch/x86_64/src/idt.rs +++ b/arch/x86_64/src/idt.rs @@ -60,6 +60,7 @@ pub unsafe fn init() { // Set syscall function IDT[0x80].set_func(syscall::syscall); + IDT[0x80].set_flags(IDT_PRESENT | IDT_RING_3 | IDT_INTERRUPT); dtables::lidt(&IDTR); } diff --git a/arch/x86_64/src/interrupt/syscall.rs b/arch/x86_64/src/interrupt/syscall.rs index 45eae6a..feac040 100644 --- a/arch/x86_64/src/interrupt/syscall.rs +++ b/arch/x86_64/src/interrupt/syscall.rs @@ -1,22 +1,29 @@ #[naked] pub unsafe extern fn syscall() { - extern { - fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> usize; + #[inline(never)] + unsafe fn inner() { + extern { + fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> usize; + } + + let mut a; + { + let b; + let c; + let d; + let e; + let f; + asm!("xchg bx, bx" : "={rax}"(a), "={rbx}"(b), "={rcx}"(c), "={rdx}"(d), "={rsi}"(e), "={rdi}"(f) + : : : "intel", "volatile"); + + a = syscall(a, b, c, d, e, f); + } + + asm!("xchg bx, bx" : : "{rax}"(a) : : "intel", "volatile"); } - let a; - let b; - let c; - let d; - let e; - let f; - asm!("" : "={rax}"(a), "={rbx}"(b), "={rcx}"(c), "={rdx}"(d), "={rsi}"(e), "={rdi}"(f) - : : : "intel", "volatile"); + inner(); - let a = syscall(a, b, c, d, e, f); - - asm!("" : : "{rax}"(a) : : "intel", "volatile"); - - // Pop scratch registers, error code, and return + // Interrupt return asm!("iretq" : : : : "intel", "volatile"); } diff --git a/arch/x86_64/src/lib.rs b/arch/x86_64/src/lib.rs index d54cb5d..bd18ee9 100644 --- a/arch/x86_64/src/lib.rs +++ b/arch/x86_64/src/lib.rs @@ -17,7 +17,7 @@ extern crate hole_list_allocator as allocator; extern crate bitflags; extern crate ransid; extern crate spin; -extern crate x86; +pub extern crate x86; /// Print to console #[macro_export] diff --git a/arch/x86_64/src/paging/mapper.rs b/arch/x86_64/src/paging/mapper.rs index 5ca7570..dbbaa60 100644 --- a/arch/x86_64/src/paging/mapper.rs +++ b/arch/x86_64/src/paging/mapper.rs @@ -46,6 +46,15 @@ impl Mapper { self.map_to(page, frame, flags) } + /// Update flags for a page + pub fn remap(&mut self, page: Page, flags: EntryFlags) { + let mut p3 = self.p4_mut().next_table_mut(page.p4_index()).expect("failed to remap: no p3"); + let mut p2 = p3.next_table_mut(page.p3_index()).expect("failed to remap: no p2"); + let mut p1 = p2.next_table_mut(page.p2_index()).expect("failed to remap: no p1"); + let frame = p1[page.p1_index()].pointed_frame().expect("failed to remap: not mapped"); + p1[page.p1_index()].set(frame, flags | entry::PRESENT); + } + /// Identity map a frame pub fn identity_map(&mut self, frame: Frame, flags: EntryFlags) { let page = Page::containing_address(VirtualAddress::new(frame.start_address().get())); diff --git a/arch/x86_64/src/paging/table.rs b/arch/x86_64/src/paging/table.rs index db2564f..956787b 100644 --- a/arch/x86_64/src/paging/table.rs +++ b/arch/x86_64/src/paging/table.rs @@ -66,7 +66,7 @@ impl Table where L: HierarchicalLevel { assert!(!self[index].flags().contains(HUGE_PAGE), "mapping code does not support huge pages"); let frame = allocate_frame().expect("no frames available"); - self[index].set(frame, PRESENT | WRITABLE); + self[index].set(frame, PRESENT | WRITABLE | USER_ACCESSIBLE /* Allow users to go down the page table, implement permissions at the page level */); self.next_table_mut(index).unwrap().zero(); } self.next_table_mut(index).unwrap() diff --git a/arch/x86_64/src/start.rs b/arch/x86_64/src/start.rs index 1b1047d..c99dd64 100644 --- a/arch/x86_64/src/start.rs +++ b/arch/x86_64/src/start.rs @@ -137,28 +137,6 @@ pub unsafe extern fn kstart() -> ! { kmain(); } -unsafe fn usermode(ip: usize, sp: usize) { - // Test usermode - asm!("xchg bx, bx - mov rax, 0x2B - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - - push rax - push rbx - pushfq - mov rax, 0x23 - push rax - push rcx - iretq" - : - : "{rbx}"(sp), "{rcx}"(ip) - : "rax", "rbx", "rcx", "sp" - : "intel", "volatile"); -} - /// Entry to rust for an AP pub unsafe extern fn kstart_ap(stack_start: usize, stack_end: usize) -> ! { { @@ -223,3 +201,25 @@ pub unsafe extern fn kstart_ap(stack_start: usize, stack_end: usize) -> ! { kmain_ap(ap_number); } + +pub unsafe fn usermode(ip: usize, sp: usize) { + // Test usermode + asm!("xchg bx, bx + mov rax, 0x2B + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + push rax + push rbx + pushfq + mov rax, 0x23 + push rax + push rcx + iretq" + : + : "{rbx}"(sp), "{rcx}"(ip) + : "rax", "rbx", "rcx", "sp" + : "intel", "volatile"); +} diff --git a/init/main b/init/main new file mode 100755 index 0000000000000000000000000000000000000000..872fc339dff51bc94418dfb899402b6aff7c415c GIT binary patch literal 512 zcmb<-^>JfjWMqH=CI&kO5N`v616T+`0+|RUKp6`LCLqbezzh~<1*?P+FdY#3DpVLo zGcYKCML@=}0r3qm4@4(`SumOpDh{Jz`qJ8O?*fT=?1ZV@4Kiv63y?V5umi+C+W;gy zQgd?hbrj0;i*iyFxft|{Gm1-!N)nS8^h#1IN*MG~5=#<+$|wfhKoeko0T~7hw+&E} xRiQMD5`ZzFv>=cM>1T%WVZMTe3&Q^p1t5PS17y9(;?JNQab!Ut8>Ai?008+ZBm@8e literal 0 HcmV?d00001 diff --git a/init/main.asm b/init/main.asm new file mode 100644 index 0000000..514295b --- /dev/null +++ b/init/main.asm @@ -0,0 +1,20 @@ +[bits 64] +section .text +global _start ;must be declared for linker (ld) + +_start: ;tell linker entry point + + xchg bx, bx + mov rdx,len ;message length + mov rcx,msg ;message to write + mov rbx,1 ;file descriptor (stdout) + mov rax,4 ;system call number (sys_write) + int 0x80 ;call kernel + + mov rax,1 ;system call number (sys_exit) + int 0x80 ;call kernel + +section .data + +msg db 'Hello, world!',0xa ;our dear string +len equ $ - msg ;length of our dear string diff --git a/init/main.o b/init/main.o new file mode 100644 index 0000000000000000000000000000000000000000..5c5b590756309e75462979c74c12c64a19f70f38 GIT binary patch literal 880 zcmb<-^>JfjWMqH=Mg}_u1P><4z~F#jLfH-s>CU=+Ij>OcvYnJ_gVIsmF4W)DaWNH0t+Ogydq_AXEudF%udV6Ypc zYzIi)*@hh;_Sps?0RtYXIXU?{3g!7lIVp- { pub data: &'a [u8], + header: &'a header::Header } impl<'a> Elf<'a> { @@ -25,29 +31,125 @@ impl<'a> Elf<'a> { } else if data.get(header::EI_CLASS) != Some(&header::ELFCLASS) { Err(format!("Elf: Invalid architecture: {:?} != {:?}", data.get(header::EI_CLASS), header::ELFCLASS)) } else { - Ok(Elf { data: data }) + Ok(Elf { + data: data, + header: unsafe { &*(data.as_ptr() as usize as *const header::Header) } + }) } } - pub unsafe fn load_segments(&self) -> Vec { - let mut segments = Vec::new(); - - let header = &*(self.data.as_ptr() as usize as *const header::Header); - - for i in 0..header.e_phnum { - let segment = ptr::read((self.data.as_ptr() as usize + header.e_phoff as usize + i as usize * header.e_phentsize as usize) as *const program_header::ProgramHeader); - - if segment.p_type == program_header::PT_LOAD || segment.p_type == program_header::PT_TLS { - segments.push(segment); - } + pub fn segments(&'a self) -> ElfSegments<'a> { + ElfSegments { + data: self.data, + header: self.header, + i: 0 } - - segments } /// Get the entry field of the header - pub unsafe fn entry(&self) -> usize { - let header = &*(self.data.as_ptr() as usize as *const header::Header); - header.e_entry as usize + pub fn entry(&self) -> usize { + self.header.e_entry as usize + } + + /// Test function to run. Remove and replace with proper syscall + pub fn run(self) { + let mut active_table = unsafe { ActivePageTable::new() }; + + for segment in self.segments() { + println!("Segment {:X} flags {:X} off {:X} virt {:X} phys {:X} file {} mem {} align {}", + segment.p_type, segment.p_flags, segment.p_offset, + segment.p_vaddr, segment.p_paddr, segment.p_filesz, + segment.p_memsz, segment.p_align); + + if segment.p_type == program_header::PT_LOAD { + let start_page = Page::containing_address(VirtualAddress::new(segment.p_vaddr as usize)); + let end_page = Page::containing_address(VirtualAddress::new((segment.p_vaddr + segment.p_memsz) as usize)); + + for page in Page::range_inclusive(start_page, end_page) { + active_table.map(page, entry::NO_EXECUTE | entry::WRITABLE); + } + + unsafe { + // Update the page table + tlb::flush_all(); + + // Copy file data + memcpy(segment.p_vaddr as *mut u8, + (self.data.as_ptr() as usize + segment.p_offset as usize) as *const u8, + segment.p_filesz as usize); + // Set BSS + memset((segment.p_vaddr + segment.p_filesz) as *mut u8, + 0, + (segment.p_memsz - segment.p_filesz) as usize); + } + + let mut flags = entry::NO_EXECUTE | entry::USER_ACCESSIBLE; + + if segment.p_flags & program_header::PF_R == program_header::PF_R { + flags.insert(entry::PRESENT); + } + + // W ^ X. If it is executable, do not allow it to be writable, even if requested + if segment.p_flags & program_header::PF_X == program_header::PF_X { + flags.remove(entry::NO_EXECUTE); + } else if segment.p_flags & program_header::PF_W == program_header::PF_W { + flags.insert(entry::WRITABLE); + } + + for page in Page::range_inclusive(start_page, end_page) { + println!("{:X}: {:?}", page.start_address().get(), flags); + active_table.remap(page, flags); + } + + unsafe { + // Update the page table + tlb::flush_all(); + } + } + } + + unsafe { + // Map stack + let start_page = Page::containing_address(VirtualAddress::new(0x80000000)); + let end_page = Page::containing_address(VirtualAddress::new(0x80000000 + 64*1024 - 1)); + + for page in Page::range_inclusive(start_page, end_page) { + active_table.map(page, entry::NO_EXECUTE | entry::WRITABLE | entry::USER_ACCESSIBLE); + } + + // Update the page table + tlb::flush_all(); + + // Clear stack + memset(0x80000000 as *mut u8, 0, 64 * 1024); + + // Go to usermode + usermode(self.entry(), 0x80000000 + 64*1024 - 256); + } + } +} + +pub struct ElfSegments<'a> { + data: &'a [u8], + header: &'a header::Header, + i: usize +} + +impl<'a> Iterator for ElfSegments<'a> { + type Item = &'a program_header::ProgramHeader; + fn next(&mut self) -> Option { + if self.i < self.header.e_phnum as usize { + let item = unsafe { + &* (( + self.data.as_ptr() as usize + + self.header.e_phoff as usize + + self.i * self.header.e_phentsize as usize + ) as *const program_header::ProgramHeader) + }; + self.i += 1; + Some(item) + } else { + None + } } } diff --git a/kernel/lib.rs b/kernel/lib.rs index 19d1a4e..d88d926 100644 --- a/kernel/lib.rs +++ b/kernel/lib.rs @@ -133,6 +133,9 @@ pub extern fn kmain() { let pid = syscall::getpid(); println!("BSP: {:?}", pid); + let elf = elf::Elf::from(include_bytes!("../init/main")).expect("could not load elf"); + elf.run(); + /* if let Ok(_context_lock) = context::contexts_mut().spawn(context_test) { print!("Spawned context\n"); @@ -143,7 +146,7 @@ pub extern fn kmain() { print!("Main halt\n"); */ - + loop { unsafe { interrupt::enable_and_halt(); } } From fb0df8530d6033a9bdab3771a9b1b34ee12cf1c6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 7 Sep 2016 21:32:09 -0600 Subject: [PATCH 2/7] Debug reads writes better, set up stdio for BSP --- arch/x86_64/src/lib.rs | 3 ++- kernel/lib.rs | 9 +++++++++ kernel/syscall/fs.rs | 4 ++-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/src/lib.rs b/arch/x86_64/src/lib.rs index bd18ee9..02a5ff3 100644 --- a/arch/x86_64/src/lib.rs +++ b/arch/x86_64/src/lib.rs @@ -89,7 +89,8 @@ macro_rules! interrupt_error { } // Push scratch registers - asm!("push rax + asm!("xchg bx, bx + push rax push rcx push rdx push rdi diff --git a/kernel/lib.rs b/kernel/lib.rs index d88d926..bc93fc5 100644 --- a/kernel/lib.rs +++ b/kernel/lib.rs @@ -133,6 +133,15 @@ pub extern fn kmain() { let pid = syscall::getpid(); println!("BSP: {:?}", pid); + let stdin = syscall::open("debug:".as_bytes(), 0); + println!("STDIN: {:?}", stdin); + + let stdout = syscall::open("debug:".as_bytes(), 0); + println!("STDOUT: {:?}", stdout); + + let stderr = syscall::open("debug:".as_bytes(), 0); + println!("STDERR: {:?}", stderr); + let elf = elf::Elf::from(include_bytes!("../init/main")).expect("could not load elf"); elf.run(); diff --git a/kernel/syscall/fs.rs b/kernel/syscall/fs.rs index 87fe2db..3a23b6c 100644 --- a/kernel/syscall/fs.rs +++ b/kernel/syscall/fs.rs @@ -7,7 +7,7 @@ use super::{Error, Result}; /// Read syscall pub fn read(fd: usize, buf: &mut [u8]) -> Result { - println!("Read {}: {}", fd, buf.len()); + println!("Read {}: {:X} {}", fd, buf.as_ptr() as usize, buf.len()); if let Some(context_lock) = context::contexts().current() { let context = context_lock.read(); if let Some(file) = context.files.get(fd) { @@ -23,7 +23,7 @@ pub fn read(fd: usize, buf: &mut [u8]) -> Result { /// Write syscall pub fn write(fd: usize, buf: &[u8]) -> Result { - println!("Write {}: {}", fd, buf.len()); + println!("Write {}: {:X} {}", fd, buf.as_ptr() as usize, buf.len()); if let Some(context_lock) = context::contexts().current() { let context = context_lock.read(); if let Some(file) = context.files.get(fd) { From a5d79d79579126e815ff3547e9f06fdd622d7973 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 8 Sep 2016 15:45:26 -0600 Subject: [PATCH 3/7] Nographic mode, fix userspace transition by setting kernel TLS back on syscall --- Makefile | 2 +- arch/x86_64/src/interrupt/exception.rs | 4 +++- arch/x86_64/src/interrupt/mod.rs | 20 ++++++++++++++------ arch/x86_64/src/interrupt/syscall.rs | 13 ++++++++++++- arch/x86_64/src/lib.rs | 21 ++++++++++++++++----- arch/x86_64/src/paging/mod.rs | 4 ++-- 6 files changed, 48 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index 0bf1ea1..d879ba5 100644 --- a/Makefile +++ b/Makefile @@ -13,8 +13,8 @@ ifeq ($(ARCH),arm) else LD=ld QEMUFLAGS+=-enable-kvm -cpu host -machine q35 -smp 4 + QEMUFLAGS+=-nographic -vga none #,int,pcall - #-nographic #-device intel-iommu UNAME := $(shell uname) diff --git a/arch/x86_64/src/interrupt/exception.rs b/arch/x86_64/src/interrupt/exception.rs index 40f54d5..369f448 100644 --- a/arch/x86_64/src/interrupt/exception.rs +++ b/arch/x86_64/src/interrupt/exception.rs @@ -71,7 +71,9 @@ interrupt_error!(protection, { }); interrupt_error!(page, { - print!("Page fault\n"); + let cr2: usize; + asm!("mov rax, cr2" : "={rax}"(cr2) : : : "intel", "volatile"); + println!("Page fault: {:>016X}", cr2); stack_trace(); loop { halt(); } }); diff --git a/arch/x86_64/src/interrupt/mod.rs b/arch/x86_64/src/interrupt/mod.rs index d7c6ddc..ad93b1a 100644 --- a/arch/x86_64/src/interrupt/mod.rs +++ b/arch/x86_64/src/interrupt/mod.rs @@ -52,13 +52,21 @@ pub unsafe fn stack_trace() { //Maximum 64 frames let active_table = ActivePageTable::new(); for _frame in 0..64 { - if active_table.translate(VirtualAddress::new(rbp)).is_some() && active_table.translate(VirtualAddress::new(rbp + mem::size_of::())).is_some() { - let rip = *(rbp as *const usize).offset(1); - println!(" {:>016X}: {:>016X}", rbp, rip); - rbp = *(rbp as *const usize); + if let Some(rip_rbp) = rbp.checked_add(mem::size_of::()) { + if active_table.translate(VirtualAddress::new(rbp)).is_some() && active_table.translate(VirtualAddress::new(rip_rbp)).is_some() { + let rip = *(rip_rbp as *const usize); + if rip == 0 { + println!(" {:>016X}: EMPTY RETURN", rbp); + break; + } + println!(" {:>016X}: {:>016X}", rbp, rip); + rbp = *(rbp as *const usize); + } else { + println!(" {:>016X}: GUARD PAGE", rbp); + break; + } } else { - println!(" {:>016X}: GUARD PAGE", rbp); - break; + println!(" {:>016X}: RBP OVERFLOW", rbp); } } } diff --git a/arch/x86_64/src/interrupt/syscall.rs b/arch/x86_64/src/interrupt/syscall.rs index feac040..7dfaf38 100644 --- a/arch/x86_64/src/interrupt/syscall.rs +++ b/arch/x86_64/src/interrupt/syscall.rs @@ -22,8 +22,19 @@ pub unsafe extern fn syscall() { asm!("xchg bx, bx" : : "{rax}"(a) : : "intel", "volatile"); } + asm!("xchg bx, bx + push fs + push rax + mov rax, 0x18 + mov fs, ax + pop rax" + : : : : "intel", "volatile"); + inner(); // Interrupt return - asm!("iretq" : : : : "intel", "volatile"); + asm!("xchg bx, bx + pop fs + iretq" + : : : : "intel", "volatile"); } diff --git a/arch/x86_64/src/lib.rs b/arch/x86_64/src/lib.rs index 02a5ff3..fdcea65 100644 --- a/arch/x86_64/src/lib.rs +++ b/arch/x86_64/src/lib.rs @@ -48,7 +48,8 @@ macro_rules! interrupt { } // Push scratch registers - asm!("push rax + asm!("xchg bx, bx + push rax push rcx push rdx push rdi @@ -56,14 +57,19 @@ macro_rules! interrupt { push r8 push r9 push r10 - push r11" + push r11 + push fs + mov rax, 0x18 + mov fs, ax" : : : : "intel", "volatile"); // Call inner rust function inner(); // Pop scratch registers and return - asm!("pop r11 + asm!("xchg bx, bx + pop fs + pop r11 pop r10 pop r9 pop r8 @@ -98,14 +104,19 @@ macro_rules! interrupt_error { push r8 push r9 push r10 - push r11" + push r11 + push fs + mov rax, 0x18 + mov fs, ax" : : : : "intel", "volatile"); // Call inner rust function inner(); // Pop scratch registers, error code, and return - asm!("pop r11 + asm!("xchg bx, bx + pop fs + pop r11 pop r10 pop r9 pop r8 diff --git a/arch/x86_64/src/paging/mod.rs b/arch/x86_64/src/paging/mod.rs index f55e015..0c48f7a 100644 --- a/arch/x86_64/src/paging/mod.rs +++ b/arch/x86_64/src/paging/mod.rs @@ -303,8 +303,8 @@ impl Page { } pub fn containing_address(address: VirtualAddress) -> Page { - assert!(address.get() < 0x0000_8000_0000_0000 || address.get() >= 0xffff_8000_0000_0000, - "invalid address: 0x{:x}", address.get()); + //TODO assert!(address.get() < 0x0000_8000_0000_0000 || address.get() >= 0xffff_8000_0000_0000, + // "invalid address: 0x{:x}", address.get()); Page { number: address.get() / PAGE_SIZE } } From fcec69efdc2e65ef10e6a295ffb0582bca42177b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 8 Sep 2016 15:53:45 -0600 Subject: [PATCH 4/7] remove bochs breaks --- arch/x86_64/src/interrupt/syscall.rs | 10 ++++------ arch/x86_64/src/lib.rs | 12 ++++-------- arch/x86_64/src/start.rs | 3 +-- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/arch/x86_64/src/interrupt/syscall.rs b/arch/x86_64/src/interrupt/syscall.rs index 7dfaf38..7133906 100644 --- a/arch/x86_64/src/interrupt/syscall.rs +++ b/arch/x86_64/src/interrupt/syscall.rs @@ -13,17 +13,16 @@ pub unsafe extern fn syscall() { let d; let e; let f; - asm!("xchg bx, bx" : "={rax}"(a), "={rbx}"(b), "={rcx}"(c), "={rdx}"(d), "={rsi}"(e), "={rdi}"(f) + asm!("" : "={rax}"(a), "={rbx}"(b), "={rcx}"(c), "={rdx}"(d), "={rsi}"(e), "={rdi}"(f) : : : "intel", "volatile"); a = syscall(a, b, c, d, e, f); } - asm!("xchg bx, bx" : : "{rax}"(a) : : "intel", "volatile"); + asm!("" : : "{rax}"(a) : : "intel", "volatile"); } - asm!("xchg bx, bx - push fs + asm!("push fs push rax mov rax, 0x18 mov fs, ax @@ -33,8 +32,7 @@ pub unsafe extern fn syscall() { inner(); // Interrupt return - asm!("xchg bx, bx - pop fs + asm!("pop fs iretq" : : : : "intel", "volatile"); } diff --git a/arch/x86_64/src/lib.rs b/arch/x86_64/src/lib.rs index fdcea65..61fb547 100644 --- a/arch/x86_64/src/lib.rs +++ b/arch/x86_64/src/lib.rs @@ -48,8 +48,7 @@ macro_rules! interrupt { } // Push scratch registers - asm!("xchg bx, bx - push rax + asm!("push rax push rcx push rdx push rdi @@ -67,8 +66,7 @@ macro_rules! interrupt { inner(); // Pop scratch registers and return - asm!("xchg bx, bx - pop fs + asm!("pop fs pop r11 pop r10 pop r9 @@ -95,8 +93,7 @@ macro_rules! interrupt_error { } // Push scratch registers - asm!("xchg bx, bx - push rax + asm!("push rax push rcx push rdx push rdi @@ -114,8 +111,7 @@ macro_rules! interrupt_error { inner(); // Pop scratch registers, error code, and return - asm!("xchg bx, bx - pop fs + asm!("pop fs pop r11 pop r10 pop r9 diff --git a/arch/x86_64/src/start.rs b/arch/x86_64/src/start.rs index c99dd64..d382f28 100644 --- a/arch/x86_64/src/start.rs +++ b/arch/x86_64/src/start.rs @@ -204,8 +204,7 @@ pub unsafe extern fn kstart_ap(stack_start: usize, stack_end: usize) -> ! { pub unsafe fn usermode(ip: usize, sp: usize) { // Test usermode - asm!("xchg bx, bx - mov rax, 0x2B + asm!("mov rax, 0x2B mov ds, ax mov es, ax mov fs, ax From 46f9f90e3c49abd4ca6da1a4c3ef37bdb93dba8b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 8 Sep 2016 19:09:58 -0600 Subject: [PATCH 5/7] Add syscall library, make init program Rust --- Makefile | 8 +- init/Cargo.toml | 10 ++ init/main | Bin 512 -> 0 bytes init/main.asm | 20 --- init/main.o | Bin 880 -> 0 bytes init/src/lib.rs | 97 +++++++++++++ kernel/lib.rs | 4 +- syscall/Cargo.toml | 3 + syscall/src/error.rs | 314 ++++++++++++++++++++++++++++++++++++++++++ syscall/src/lib.rs | 210 ++++++++++++++++++++++++++++ syscall/src/x86.rs | 61 ++++++++ syscall/src/x86_64.rs | 61 ++++++++ 12 files changed, 765 insertions(+), 23 deletions(-) create mode 100644 init/Cargo.toml delete mode 100755 init/main delete mode 100644 init/main.asm delete mode 100644 init/main.o create mode 100644 init/src/lib.rs create mode 100644 syscall/Cargo.toml create mode 100644 syscall/src/error.rs create mode 100644 syscall/src/lib.rs create mode 100644 syscall/src/x86.rs create mode 100644 syscall/src/x86_64.rs diff --git a/Makefile b/Makefile index d879ba5..eadb0d5 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,13 @@ build/libcollections.rlib: rust/src/libcollections/lib.rs build/libcore.rlib bui mkdir -p build ./rustc.sh $(RUSTCFLAGS) -o $@ $< -build/libkernel.a: build/libcore.rlib build/liballoc.rlib build/libcollections.rlib FORCE +build/libinit.a: init/src/*.rs + RUSTC="./rustc.sh" cargo rustc --manifest-path init/Cargo.toml $(CARGOFLAGS) -o $@ + +build/init: build/libinit.a + $(LD) -e _start --gc-sections -o $@ $< + +build/libkernel.a: build/libcore.rlib build/liballoc.rlib build/libcollections.rlib build/init FORCE mkdir -p build RUSTC="./rustc.sh" cargo rustc $(CARGOFLAGS) -o $@ diff --git a/init/Cargo.toml b/init/Cargo.toml new file mode 100644 index 0000000..1aeb3c2 --- /dev/null +++ b/init/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "init" +version = "0.1.0" + +[lib] +name = "init" +crate-type = ["staticlib"] + +[dependencies] +syscall = { path = "../syscall/" } diff --git a/init/main b/init/main deleted file mode 100755 index 872fc339dff51bc94418dfb899402b6aff7c415c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 512 zcmb<-^>JfjWMqH=CI&kO5N`v616T+`0+|RUKp6`LCLqbezzh~<1*?P+FdY#3DpVLo zGcYKCML@=}0r3qm4@4(`SumOpDh{Jz`qJ8O?*fT=?1ZV@4Kiv63y?V5umi+C+W;gy zQgd?hbrj0;i*iyFxft|{Gm1-!N)nS8^h#1IN*MG~5=#<+$|wfhKoeko0T~7hw+&E} xRiQMD5`ZzFv>=cM>1T%WVZMTe3&Q^p1t5PS17y9(;?JNQab!Ut8>Ai?008+ZBm@8e diff --git a/init/main.asm b/init/main.asm deleted file mode 100644 index 514295b..0000000 --- a/init/main.asm +++ /dev/null @@ -1,20 +0,0 @@ -[bits 64] -section .text -global _start ;must be declared for linker (ld) - -_start: ;tell linker entry point - - xchg bx, bx - mov rdx,len ;message length - mov rcx,msg ;message to write - mov rbx,1 ;file descriptor (stdout) - mov rax,4 ;system call number (sys_write) - int 0x80 ;call kernel - - mov rax,1 ;system call number (sys_exit) - int 0x80 ;call kernel - -section .data - -msg db 'Hello, world!',0xa ;our dear string -len equ $ - msg ;length of our dear string diff --git a/init/main.o b/init/main.o deleted file mode 100644 index 5c5b590756309e75462979c74c12c64a19f70f38..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 880 zcmb<-^>JfjWMqH=Mg}_u1P><4z~F#jLfH-s>CU=+Ij>OcvYnJ_gVIsmF4W)DaWNH0t+Ogydq_AXEudF%udV6Ypc zYzIi)*@hh;_Sps?0RtYXIXU?{3g!7lIVp- ! { + loop {} +} + +/// Memcpy +/// +/// Copy N bytes of memory from one location to another. +#[no_mangle] +pub unsafe extern fn memcpy(dest: *mut u8, src: *const u8, + n: usize) -> *mut u8 { + let mut i = 0; + while i < n { + *dest.offset(i as isize) = *src.offset(i as isize); + i += 1; + } + + dest +} + +/// Memmove +/// +/// Copy N bytes of memory from src to dest. The memory areas may overlap. +#[no_mangle] +pub unsafe extern fn memmove(dest: *mut u8, src: *const u8, + n: usize) -> *mut u8 { + if src < dest as *const u8 { + let mut i = n; + while i != 0 { + i -= 1; + *dest.offset(i as isize) = *src.offset(i as isize); + } + } else { + let mut i = 0; + while i < n { + *dest.offset(i as isize) = *src.offset(i as isize); + i += 1; + } + } + + dest +} + +/// Memset +/// +/// Fill a block of memory with a specified value. +#[no_mangle] +pub unsafe extern fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8 { + let mut i = 0; + while i < n { + *s.offset(i as isize) = c as u8; + i += 1; + } + + s +} + +/// Memcmp +/// +/// Compare two blocks of memory. +#[no_mangle] +pub unsafe extern fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { + let mut i = 0; + + while i < n { + let a = *s1.offset(i as isize); + let b = *s2.offset(i as isize); + if a != b { + return a as i32 - b as i32 + } + i += 1; + } + + 0 +} diff --git a/kernel/lib.rs b/kernel/lib.rs index bc93fc5..19731e1 100644 --- a/kernel/lib.rs +++ b/kernel/lib.rs @@ -135,14 +135,14 @@ pub extern fn kmain() { let stdin = syscall::open("debug:".as_bytes(), 0); println!("STDIN: {:?}", stdin); - + let stdout = syscall::open("debug:".as_bytes(), 0); println!("STDOUT: {:?}", stdout); let stderr = syscall::open("debug:".as_bytes(), 0); println!("STDERR: {:?}", stderr); - let elf = elf::Elf::from(include_bytes!("../init/main")).expect("could not load elf"); + let elf = elf::Elf::from(include_bytes!("../build/init")).expect("could not load elf"); elf.run(); /* diff --git a/syscall/Cargo.toml b/syscall/Cargo.toml new file mode 100644 index 0000000..e5b3417 --- /dev/null +++ b/syscall/Cargo.toml @@ -0,0 +1,3 @@ +[package] +name = "syscall" +version = "0.1.0" diff --git a/syscall/src/error.rs b/syscall/src/error.rs new file mode 100644 index 0000000..9af8f4a --- /dev/null +++ b/syscall/src/error.rs @@ -0,0 +1,314 @@ +use core::{fmt, result}; + +pub struct Error { + pub errno: isize, +} + +pub type Result = result::Result; + +impl Error { + pub fn new(errno: isize) -> Error { + Error { errno: errno } + } + + pub fn mux(result: Result) -> usize { + match result { + Ok(value) => value, + Err(error) => -error.errno as usize, + } + } + + pub fn demux(value: usize) -> Result { + let errno = -(value as isize); + if errno >= 1 && errno < STR_ERROR.len() as isize { + Err(Error::new(errno)) + } else { + Ok(value) + } + } + + pub fn text(&self) -> &str { + if let Some(description) = STR_ERROR.get(self.errno as usize) { + description + } else { + "Unknown Error" + } + } +} + +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { + f.write_str(self.text()) + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { + f.write_str(self.text()) + } +} + +pub const EPERM: isize = 1; /* Operation not permitted */ +pub const ENOENT: isize = 2; /* No such file or directory */ +pub const ESRCH: isize = 3; /* No such process */ +pub const EINTR: isize = 4; /* Interrupted system call */ +pub const EIO: isize = 5; /* I/O error */ +pub const ENXIO: isize = 6; /* No such device or address */ +pub const E2BIG: isize = 7; /* Argument list too long */ +pub const ENOEXEC: isize = 8; /* Exec format error */ +pub const EBADF: isize = 9; /* Bad file number */ +pub const ECHILD: isize = 10; /* No child processes */ +pub const EAGAIN: isize = 11; /* Try again */ +pub const ENOMEM: isize = 12; /* Out of memory */ +pub const EACCES: isize = 13; /* Permission denied */ +pub const EFAULT: isize = 14; /* Bad address */ +pub const ENOTBLK: isize = 15; /* Block device required */ +pub const EBUSY: isize = 16; /* Device or resource busy */ +pub const EEXIST: isize = 17; /* File exists */ +pub const EXDEV: isize = 18; /* Cross-device link */ +pub const ENODEV: isize = 19; /* No such device */ +pub const ENOTDIR: isize = 20; /* Not a directory */ +pub const EISDIR: isize = 21; /* Is a directory */ +pub const EINVAL: isize = 22; /* Invalid argument */ +pub const ENFILE: isize = 23; /* File table overflow */ +pub const EMFILE: isize = 24; /* Too many open files */ +pub const ENOTTY: isize = 25; /* Not a typewriter */ +pub const ETXTBSY: isize = 26; /* Text file busy */ +pub const EFBIG: isize = 27; /* File too large */ +pub const ENOSPC: isize = 28; /* No space left on device */ +pub const ESPIPE: isize = 29; /* Illegal seek */ +pub const EROFS: isize = 30; /* Read-only file system */ +pub const EMLINK: isize = 31; /* Too many links */ +pub const EPIPE: isize = 32; /* Broken pipe */ +pub const EDOM: isize = 33; /* Math argument out of domain of func */ +pub const ERANGE: isize = 34; /* Math result not representable */ +pub const EDEADLK: isize = 35; /* Resource deadlock would occur */ +pub const ENAMETOOLONG: isize = 36; /* File name too long */ +pub const ENOLCK: isize = 37; /* No record locks available */ +pub const ENOSYS: isize = 38; /* Function not implemented */ +pub const ENOTEMPTY: isize = 39; /* Directory not empty */ +pub const ELOOP: isize = 40; /* Too many symbolic links encountered */ +pub const EWOULDBLOCK: isize = 41; /* Operation would block */ +pub const ENOMSG: isize = 42; /* No message of desired type */ +pub const EIDRM: isize = 43; /* Identifier removed */ +pub const ECHRNG: isize = 44; /* Channel number out of range */ +pub const EL2NSYNC: isize = 45; /* Level 2 not synchronized */ +pub const EL3HLT: isize = 46; /* Level 3 halted */ +pub const EL3RST: isize = 47; /* Level 3 reset */ +pub const ELNRNG: isize = 48; /* Link number out of range */ +pub const EUNATCH: isize = 49; /* Protocol driver not attached */ +pub const ENOCSI: isize = 50; /* No CSI structure available */ +pub const EL2HLT: isize = 51; /* Level 2 halted */ +pub const EBADE: isize = 52; /* Invalid exchange */ +pub const EBADR: isize = 53; /* Invalid request descriptor */ +pub const EXFULL: isize = 54; /* Exchange full */ +pub const ENOANO: isize = 55; /* No anode */ +pub const EBADRQC: isize = 56; /* Invalid request code */ +pub const EBADSLT: isize = 57; /* Invalid slot */ +pub const EDEADLOCK: isize = 58; /* Resource deadlock would occur */ +pub const EBFONT: isize = 59; /* Bad font file format */ +pub const ENOSTR: isize = 60; /* Device not a stream */ +pub const ENODATA: isize = 61; /* No data available */ +pub const ETIME: isize = 62; /* Timer expired */ +pub const ENOSR: isize = 63; /* Out of streams resources */ +pub const ENONET: isize = 64; /* Machine is not on the network */ +pub const ENOPKG: isize = 65; /* Package not installed */ +pub const EREMOTE: isize = 66; /* Object is remote */ +pub const ENOLINK: isize = 67; /* Link has been severed */ +pub const EADV: isize = 68; /* Advertise error */ +pub const ESRMNT: isize = 69; /* Srmount error */ +pub const ECOMM: isize = 70; /* Communication error on send */ +pub const EPROTO: isize = 71; /* Protocol error */ +pub const EMULTIHOP: isize = 72; /* Multihop attempted */ +pub const EDOTDOT: isize = 73; /* RFS specific error */ +pub const EBADMSG: isize = 74; /* Not a data message */ +pub const EOVERFLOW: isize = 75; /* Value too large for defined data type */ +pub const ENOTUNIQ: isize = 76; /* Name not unique on network */ +pub const EBADFD: isize = 77; /* File descriptor in bad state */ +pub const EREMCHG: isize = 78; /* Remote address changed */ +pub const ELIBACC: isize = 79; /* Can not access a needed shared library */ +pub const ELIBBAD: isize = 80; /* Accessing a corrupted shared library */ +pub const ELIBSCN: isize = 81; /* .lib section in a.out corrupted */ +pub const ELIBMAX: isize = 82; /* Attempting to link in too many shared libraries */ +pub const ELIBEXEC: isize = 83; /* Cannot exec a shared library directly */ +pub const EILSEQ: isize = 84; /* Illegal byte sequence */ +pub const ERESTART: isize = 85; /* Interrupted system call should be restarted */ +pub const ESTRPIPE: isize = 86; /* Streams pipe error */ +pub const EUSERS: isize = 87; /* Too many users */ +pub const ENOTSOCK: isize = 88; /* Socket operation on non-socket */ +pub const EDESTADDRREQ: isize = 89; /* Destination address required */ +pub const EMSGSIZE: isize = 90; /* Message too long */ +pub const EPROTOTYPE: isize = 91; /* Protocol wrong type for socket */ +pub const ENOPROTOOPT: isize = 92; /* Protocol not available */ +pub const EPROTONOSUPPORT: isize = 93; /* Protocol not supported */ +pub const ESOCKTNOSUPPORT: isize = 94; /* Socket type not supported */ +pub const EOPNOTSUPP: isize = 95; /* Operation not supported on transport endpoint */ +pub const EPFNOSUPPORT: isize = 96; /* Protocol family not supported */ +pub const EAFNOSUPPORT: isize = 97; /* Address family not supported by protocol */ +pub const EADDRINUSE: isize = 98; /* Address already in use */ +pub const EADDRNOTAVAIL: isize = 99; /* Cannot assign requested address */ +pub const ENETDOWN: isize = 100; /* Network is down */ +pub const ENETUNREACH: isize = 101; /* Network is unreachable */ +pub const ENETRESET: isize = 102; /* Network dropped connection because of reset */ +pub const ECONNABORTED: isize = 103; /* Software caused connection abort */ +pub const ECONNRESET: isize = 104; /* Connection reset by peer */ +pub const ENOBUFS: isize = 105; /* No buffer space available */ +pub const EISCONN: isize = 106; /* Transport endpoint is already connected */ +pub const ENOTCONN: isize = 107; /* Transport endpoint is not connected */ +pub const ESHUTDOWN: isize = 108; /* Cannot send after transport endpoint shutdown */ +pub const ETOOMANYREFS: isize = 109; /* Too many references: cannot splice */ +pub const ETIMEDOUT: isize = 110; /* Connection timed out */ +pub const ECONNREFUSED: isize = 111; /* Connection refused */ +pub const EHOSTDOWN: isize = 112; /* Host is down */ +pub const EHOSTUNREACH: isize = 113; /* No route to host */ +pub const EALREADY: isize = 114; /* Operation already in progress */ +pub const EINPROGRESS: isize = 115; /* Operation now in progress */ +pub const ESTALE: isize = 116; /* Stale NFS file handle */ +pub const EUCLEAN: isize = 117; /* Structure needs cleaning */ +pub const ENOTNAM: isize = 118; /* Not a XENIX named type file */ +pub const ENAVAIL: isize = 119; /* No XENIX semaphores available */ +pub const EISNAM: isize = 120; /* Is a named type file */ +pub const EREMOTEIO: isize = 121; /* Remote I/O error */ +pub const EDQUOT: isize = 122; /* Quota exceeded */ +pub const ENOMEDIUM: isize = 123; /* No medium found */ +pub const EMEDIUMTYPE: isize = 124; /* Wrong medium type */ +pub const ECANCELED: isize = 125; /* Operation Canceled */ +pub const ENOKEY: isize = 126; /* Required key not available */ +pub const EKEYEXPIRED: isize = 127; /* Key has expired */ +pub const EKEYREVOKED: isize = 128; /* Key has been revoked */ +pub const EKEYREJECTED: isize = 129; /* Key was rejected by service */ +pub const EOWNERDEAD: isize = 130; /* Owner died */ +pub const ENOTRECOVERABLE: isize = 131; /* State not recoverable */ + +pub static STR_ERROR: [&'static str; 132] = ["Success", + "Operation not permitted", + "No such file or directory", + "No such process", + "Interrupted system call", + "I/O error", + "No such device or address", + "Argument list too long", + "Exec format error", + "Bad file number", + "No child processes", + "Try again", + "Out of memory", + "Permission denied", + "Bad address", + "Block device required", + "Device or resource busy", + "File exists", + "Cross-device link", + "No such device", + "Not a directory", + "Is a directory", + "Invalid argument", + "File table overflow", + "Too many open files", + "Not a typewriter", + "Text file busy", + "File too large", + "No space left on device", + "Illegal seek", + "Read-only file system", + "Too many links", + "Broken pipe", + "Math argument out of domain of func", + "Math result not representable", + "Resource deadlock would occur", + "File name too long", + "No record locks available", + "Function not implemented", + "Directory not empty", + "Too many symbolic links encountered", + "Operation would block", + "No message of desired type", + "Identifier removed", + "Channel number out of range", + "Level 2 not synchronized", + "Level 3 halted", + "Level 3 reset", + "Link number out of range", + "Protocol driver not attached", + "No CSI structure available", + "Level 2 halted", + "Invalid exchange", + "Invalid request descriptor", + "Exchange full", + "No anode", + "Invalid request code", + "Invalid slot", + "Resource deadlock would occur", + "Bad font file format", + "Device not a stream", + "No data available", + "Timer expired", + "Out of streams resources", + "Machine is not on the network", + "Package not installed", + "Object is remote", + "Link has been severed", + "Advertise error", + "Srmount error", + "Communication error on send", + "Protocol error", + "Multihop attempted", + "RFS specific error", + "Not a data message", + "Value too large for defined data type", + "Name not unique on network", + "File descriptor in bad state", + "Remote address changed", + "Can not access a needed shared library", + "Accessing a corrupted shared library", + ".lib section in a.out corrupted", + "Attempting to link in too many shared libraries", + "Cannot exec a shared library directly", + "Illegal byte sequence", + "Interrupted system call should be restarted", + "Streams pipe error", + "Too many users", + "Socket operation on non-socket", + "Destination address required", + "Message too long", + "Protocol wrong type for socket", + "Protocol not available", + "Protocol not supported", + "Socket type not supported", + "Operation not supported on transport endpoint", + "Protocol family not supported", + "Address family not supported by protocol", + "Address already in use", + "Cannot assign requested address", + "Network is down", + "Network is unreachable", + "Network dropped connection because of reset", + "Software caused connection abort", + "Connection reset by peer", + "No buffer space available", + "Transport endpoint is already connected", + "Transport endpoint is not connected", + "Cannot send after transport endpoint shutdown", + "Too many references: cannot splice", + "Connection timed out", + "Connection refused", + "Host is down", + "No route to host", + "Operation already in progress", + "Operation now in progress", + "Stale NFS file handle", + "Structure needs cleaning", + "Not a XENIX named type file", + "No XENIX semaphores available", + "Is a named type file", + "Remote I/O error", + "Quota exceeded", + "No medium found", + "Wrong medium type", + "Operation Canceled", + "Required key not available", + "Key has expired", + "Key has been revoked", + "Key was rejected by service", + "Owner died", + "State not recoverable"]; diff --git a/syscall/src/lib.rs b/syscall/src/lib.rs new file mode 100644 index 0000000..bb441de --- /dev/null +++ b/syscall/src/lib.rs @@ -0,0 +1,210 @@ +#![feature(asm)] +#![no_std] + +pub use self::arch::*; +pub use self::error::*; + +#[cfg(target_arch = "x86")] +#[path="x86.rs"] +pub mod arch; + +#[cfg(target_arch = "x86_64")] +#[path="x86_64.rs"] +pub mod arch; + +pub mod error; + +pub const SYS_BRK: usize = 45; +pub const SYS_CHDIR: usize = 12; +pub const SYS_CLONE: usize = 120; + pub const CLONE_VM: usize = 0x100; + pub const CLONE_FS: usize = 0x200; + pub const CLONE_FILES: usize = 0x400; + pub const CLONE_VFORK: usize = 0x4000; + /// Mark this clone as supervised. + /// + /// This means that the process can run in supervised mode, even not being connected to + /// a supervisor yet. In other words, the parent can later on supervise the process and handle + /// the potential blocking syscall. + /// + /// This is an important security measure, since otherwise the process would be able to fork it + /// self right after starting, making supervising it impossible. + pub const CLONE_SUPERVISE: usize = 0x400000; +pub const SYS_CLOSE: usize = 6; +pub const SYS_CLOCK_GETTIME: usize = 265; + pub const CLOCK_REALTIME: usize = 1; + pub const CLOCK_MONOTONIC: usize = 4; +pub const SYS_DUP: usize = 41; +pub const SYS_EXECVE: usize = 11; +pub const SYS_EXIT: usize = 1; +pub const SYS_FPATH: usize = 928; +pub const SYS_FSTAT: usize = 28; + pub const MODE_DIR: u16 = 0x4000; + pub const MODE_FILE: u16 = 0x8000; + pub const MODE_ALL: u16 = MODE_DIR | MODE_FILE; +pub const SYS_FSYNC: usize = 118; +pub const SYS_FTRUNCATE: usize = 93; +pub const SYS_FUTEX: usize = 240; + pub const FUTEX_WAIT: usize = 0; + pub const FUTEX_WAKE: usize = 1; + pub const FUTEX_REQUEUE: usize = 2; +pub const SYS_GETPID: usize = 20; +pub const SYS_IOPL: usize = 110; +pub const SYS_LINK: usize = 9; +pub const SYS_LSEEK: usize = 19; + pub const SEEK_SET: usize = 0; + pub const SEEK_CUR: usize = 1; + pub const SEEK_END: usize = 2; +pub const SYS_MKDIR: usize = 39; +pub const SYS_NANOSLEEP: usize = 162; +pub const SYS_OPEN: usize = 5; + pub const O_RDONLY: usize = 0; + pub const O_WRONLY: usize = 1; + pub const O_RDWR: usize = 2; + pub const O_NONBLOCK: usize = 4; + pub const O_APPEND: usize = 8; + pub const O_SHLOCK: usize = 0x10; + pub const O_EXLOCK: usize = 0x20; + pub const O_ASYNC: usize = 0x40; + pub const O_FSYNC: usize = 0x80; + pub const O_CREAT: usize = 0x200; + pub const O_TRUNC: usize = 0x400; + pub const O_EXCL: usize = 0x800; +pub const SYS_PIPE2: usize = 331; +pub const SYS_READ: usize = 3; +pub const SYS_RMDIR: usize = 84; +pub const SYS_UNLINK: usize = 10; +pub const SYS_WAITPID: usize = 7; +pub const SYS_WRITE: usize = 4; +pub const SYS_YIELD: usize = 158; + +#[derive(Copy, Clone, Debug, Default)] +#[repr(packed)] +pub struct Stat { + pub st_dev: u16, + pub st_ino: u16, + pub st_mode: u16, + pub st_nlink: u16, + pub st_uid: u16, + pub st_gid: u16, + pub st_rdev: u16, + pub st_size: u32, + pub st_atime: u32, + pub st_mtime: u32, + pub st_ctime: u32 +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(packed)] +pub struct TimeSpec { + pub tv_sec: i64, + pub tv_nsec: i32, +} + +pub unsafe fn brk(addr: usize) -> Result { + syscall1(SYS_BRK, addr) +} + +pub fn chdir(path: &str) -> Result { + unsafe { syscall2(SYS_CHDIR, path.as_ptr() as usize, path.len()) } +} + +pub unsafe fn clone(flags: usize) -> Result { + syscall1(SYS_CLONE, flags) +} + +pub fn close(fd: usize) -> Result { + unsafe { syscall1(SYS_CLOSE, fd) } +} + +pub fn clock_gettime(clock: usize, tp: &mut TimeSpec) -> Result { + unsafe { syscall2(SYS_CLOCK_GETTIME, clock, tp as *mut TimeSpec as usize) } +} + +pub fn dup(fd: usize) -> Result { + unsafe { syscall1(SYS_DUP, fd) } +} + +pub unsafe fn execve(path: *const u8, args: *const *const u8) -> Result { + syscall2(SYS_EXECVE, path as usize, args as usize) +} + +pub fn exit(status: usize) -> Result { + unsafe { syscall1(SYS_EXIT, status) } +} + +pub fn fpath(fd: usize, buf: &mut [u8]) -> Result { + unsafe { syscall3(SYS_FPATH, fd, buf.as_mut_ptr() as usize, buf.len()) } +} + +pub fn fstat(fd: usize, stat: &mut Stat) -> Result { + unsafe { syscall2(SYS_FSTAT, fd, stat as *mut Stat as usize) } +} + +pub fn fsync(fd: usize) -> Result { + unsafe { syscall1(SYS_FSYNC, fd) } +} + +pub fn ftruncate(fd: usize, len: usize) -> Result { + unsafe { syscall2(SYS_FTRUNCATE, fd, len) } +} + +pub unsafe fn futex(addr: *mut i32, op: usize, val: i32, val2: usize, addr2: *mut i32) -> Result { + syscall5(SYS_FUTEX, addr as usize, op, (val as isize) as usize, val2, addr2 as usize) +} + +pub fn getpid() -> Result { + unsafe { syscall0(SYS_GETPID) } +} + +pub unsafe fn iopl(level: usize) -> Result { + syscall1(SYS_IOPL, level) +} + +pub unsafe fn link(old: *const u8, new: *const u8) -> Result { + syscall2(SYS_LINK, old as usize, new as usize) +} + +pub fn lseek(fd: usize, offset: isize, whence: usize) -> Result { + unsafe { syscall3(SYS_LSEEK, fd, offset as usize, whence) } +} + +pub fn mkdir(path: &str, mode: usize) -> Result { + unsafe { syscall3(SYS_MKDIR, path.as_ptr() as usize, path.len(), mode) } +} + +pub fn nanosleep(req: &TimeSpec, rem: &mut TimeSpec) -> Result { + unsafe { syscall2(SYS_NANOSLEEP, req as *const TimeSpec as usize, rem as *mut TimeSpec as usize) } +} + +pub fn open(path: &str, flags: usize) -> Result { + unsafe { syscall3(SYS_OPEN, path.as_ptr() as usize, path.len(), flags) } +} + +pub fn pipe2(fds: &mut [usize; 2], flags: usize) -> Result { + unsafe { syscall2(SYS_PIPE2, fds.as_ptr() as usize, flags) } +} + +pub fn read(fd: usize, buf: &mut [u8]) -> Result { + unsafe { syscall3(SYS_READ, fd, buf.as_mut_ptr() as usize, buf.len()) } +} + +pub fn rmdir(path: &str) -> Result { + unsafe { syscall2(SYS_RMDIR, path.as_ptr() as usize, path.len()) } +} + +pub fn unlink(path: &str) -> Result { + unsafe { syscall2(SYS_UNLINK, path.as_ptr() as usize, path.len()) } +} + +pub fn waitpid(pid: usize, status: &mut usize, options: usize) -> Result { + unsafe { syscall3(SYS_WAITPID, pid, status as *mut usize as usize, options) } +} + +pub fn write(fd: usize, buf: &[u8]) -> Result { + unsafe { syscall3(SYS_WRITE, fd, buf.as_ptr() as usize, buf.len()) } +} + +pub fn sched_yield() -> Result { + unsafe { syscall0(SYS_YIELD) } +} diff --git a/syscall/src/x86.rs b/syscall/src/x86.rs new file mode 100644 index 0000000..d4b53e9 --- /dev/null +++ b/syscall/src/x86.rs @@ -0,0 +1,61 @@ +use error::{Error, Result}; + +pub unsafe fn syscall0(mut a: usize) -> Result { + asm!("int 0x80" + : "={eax}"(a) + : "{eax}"(a) + : "memory" + : "intel", "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall1(mut a: usize, b: usize) -> Result { + asm!("int 0x80" + : "={eax}"(a) + : "{eax}"(a), "{ebx}"(b) + : "memory" + : "intel", "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result { + asm!("int 0x80" + : "={eax}"(a) + : "{eax}"(a), "{ebx}"(b), "{ecx}"(c) + : "memory" + : "intel", "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result { + asm!("int 0x80" + : "={eax}"(a) + : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d) + : "memory" + : "intel", "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result { + asm!("int 0x80" + : "={eax}"(a) + : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d), "{esi}"(e) + : "memory" + : "intel", "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> Result { + asm!("int 0x80" + : "={eax}"(a) + : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d), "{esi}"(e), "{edi}"(f) + : "memory" + : "intel", "volatile"); + + Error::demux(a) +} diff --git a/syscall/src/x86_64.rs b/syscall/src/x86_64.rs new file mode 100644 index 0000000..3de2d5f --- /dev/null +++ b/syscall/src/x86_64.rs @@ -0,0 +1,61 @@ +use error::{Error, Result}; + +pub unsafe fn syscall0(mut a: usize) -> Result { + asm!("int 0x80" + : "={rax}"(a) + : "{rax}"(a) + : "memory" + : "intel", "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall1(mut a: usize, b: usize) -> Result { + asm!("int 0x80" + : "={rax}"(a) + : "{rax}"(a), "{rbx}"(b) + : "memory" + : "intel", "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result { + asm!("int 0x80" + : "={rax}"(a) + : "{rax}"(a), "{rbx}"(b), "{rcx}"(c) + : "memory" + : "intel", "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result { + asm!("int 0x80" + : "={rax}"(a) + : "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d) + : "memory" + : "intel", "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result { + asm!("int 0x80" + : "={rax}"(a) + : "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d), "{rsi}"(e) + : "memory" + : "intel", "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> Result { + asm!("int 0x80" + : "={rax}"(a) + : "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d), "{rsi}"(e), "{rdi}"(f) + : "memory" + : "intel", "volatile"); + + Error::demux(a) +} From afde5f5b5db3ad5880b46cf7cf06adfe85629fac Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 8 Sep 2016 19:13:52 -0600 Subject: [PATCH 6/7] rebuild init on cargo file change --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index eadb0d5..0b0ba17 100644 --- a/Makefile +++ b/Makefile @@ -51,8 +51,8 @@ build/libcollections.rlib: rust/src/libcollections/lib.rs build/libcore.rlib bui mkdir -p build ./rustc.sh $(RUSTCFLAGS) -o $@ $< -build/libinit.a: init/src/*.rs - RUSTC="./rustc.sh" cargo rustc --manifest-path init/Cargo.toml $(CARGOFLAGS) -o $@ +build/libinit.a: init/Cargo.toml init/src/*.rs + RUSTC="./rustc.sh" cargo rustc --manifest-path $< $(CARGOFLAGS) -o $@ build/init: build/libinit.a $(LD) -e _start --gc-sections -o $@ $< From 9afe0645e1e86b0943670bd3d22dd137df95f7a3 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 8 Sep 2016 19:31:26 -0600 Subject: [PATCH 7/7] Cleanup to use question mark --- kernel/syscall/fs.rs | 71 ++++++++++++++------------------------- kernel/syscall/process.rs | 10 +++--- 2 files changed, 29 insertions(+), 52 deletions(-) diff --git a/kernel/syscall/fs.rs b/kernel/syscall/fs.rs index 3a23b6c..353a1b4 100644 --- a/kernel/syscall/fs.rs +++ b/kernel/syscall/fs.rs @@ -8,33 +8,23 @@ use super::{Error, Result}; /// Read syscall pub fn read(fd: usize, buf: &mut [u8]) -> Result { println!("Read {}: {:X} {}", fd, buf.as_ptr() as usize, buf.len()); - if let Some(context_lock) = context::contexts().current() { - let context = context_lock.read(); - if let Some(file) = context.files.get(fd) { - println!("{:?}", file); - Ok(0) - } else { - Err(Error::BadFile) - } - } else { - Err(Error::NoProcess) - } + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::NoProcess)?; + let context = context_lock.read(); + let file = context.files.get(fd).ok_or(Error::BadFile)?; + println!("{:?}", file); + Ok(0) } /// Write syscall pub fn write(fd: usize, buf: &[u8]) -> Result { println!("Write {}: {:X} {}", fd, buf.as_ptr() as usize, buf.len()); - if let Some(context_lock) = context::contexts().current() { - let context = context_lock.read(); - if let Some(file) = context.files.get(fd) { - println!("{:?}: {:?}", file, ::core::str::from_utf8(buf)); - Ok(buf.len()) - } else { - Err(Error::BadFile) - } - } else { - Err(Error::NoProcess) - } + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::NoProcess)?; + let context = context_lock.read(); + let file = context.files.get(fd).ok_or(Error::BadFile); + println!("{:?}: {:?}", file, ::core::str::from_utf8(buf)); + Ok(buf.len()) } /// Open syscall @@ -45,31 +35,20 @@ pub fn open(path: &[u8], flags: usize) -> Result { println!("Open namespace {:?} reference {:?}: {:X}", namespace_opt.map(::core::str::from_utf8), reference_opt.map(::core::str::from_utf8), flags); let file = { - if let Some(namespace) = namespace_opt { - let schemes = scheme::schemes(); - if let Some(scheme_mutex) = schemes.get(namespace) { - scheme_mutex.lock().open(reference_opt.unwrap_or(b""), flags) - } else { - Err(Error::NoEntry) - } - } else { - Err(Error::NoEntry) - } - }?; + let namespace = namespace_opt.ok_or(Error::NoEntry)?; + let schemes = scheme::schemes(); + let scheme_mutex = schemes.get(namespace).ok_or(Error::NoEntry)?; + let file = scheme_mutex.lock().open(reference_opt.unwrap_or(b""), flags)?; + file + }; - if let Some(context_lock) = context::contexts().current() { - let mut context = context_lock.write(); - if let Some(fd) = context.add_file(::context::file::File { - scheme: 0, - number: file - }) { - Ok(fd) - } else { - Err(Error::TooManyFiles) - } - } else { - Err(Error::NoProcess) - } + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::NoProcess)?; + let mut context = context_lock.write(); + context.add_file(::context::file::File { + scheme: 0, + number: file + }).ok_or(Error::TooManyFiles) } /// Close syscall diff --git a/kernel/syscall/process.rs b/kernel/syscall/process.rs index 4f43aee..9db0bfa 100644 --- a/kernel/syscall/process.rs +++ b/kernel/syscall/process.rs @@ -23,10 +23,8 @@ pub fn exec(path: &[u8], args: &[[usize; 2]]) -> Result { } pub fn getpid() -> Result { - if let Some(context_lock) = context::contexts().current() { - let context = context_lock.read(); - Ok(context.id) - } else { - Err(Error::NoProcess) - } + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::NoProcess)?; + let context = context_lock.read(); + Ok(context.id) }