From c9a68634f5007e1c73495fcdaade3b5d0fff3d33 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Wed, 3 Apr 2019 17:41:54 +0800 Subject: [PATCH 01/28] simplify FdSet using bitvec crate --- kernel/Cargo.lock | 7 +++++ kernel/Cargo.toml | 1 + kernel/src/syscall/fs.rs | 65 ++++++++++++++++++++-------------------- 3 files changed, 40 insertions(+), 33 deletions(-) diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 603faef..c49497a 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -81,6 +81,11 @@ name = "bitvec" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bitvec" +version = "0.11.0" +source = "git+https://github.com/myrrlyn/bitvec.git#f6e1fbed95061955d96617dfed6c112ffba45a7e" + [[package]] name = "bootloader" version = "0.4.0" @@ -308,6 +313,7 @@ dependencies = [ "bit-allocator 0.1.0", "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bitvec 0.11.0 (git+https://github.com/myrrlyn/bitvec.git)", "bootloader 0.4.0 (git+https://github.com/rcore-os/bootloader)", "buddy_system_allocator 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", @@ -594,6 +600,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bcm2837 0.1.0 (git+https://github.com/rcore-os/bcm2837)" = "" "checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum bitvec 0.11.0 (git+https://github.com/myrrlyn/bitvec.git)" = "" "checksum bitvec 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cfadef5c4e2c2e64067b9ecc061179f12ac7ec65ba613b1f60f3972bbada1f5b" "checksum bootloader 0.4.0 (git+https://github.com/rcore-os/bootloader)" = "" "checksum buddy_system_allocator 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2ed828f1e227d6e32b998d6375b67fd63ac5389d50b23f258ce151d22b6cc595" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 1665f77..7aacfe2 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -42,6 +42,7 @@ bitflags = "1.0" bit_field = "0.9" volatile = "0.2" heapless = "0.4" +bitvec = { git = "https://github.com/myrrlyn/bitvec.git", default-features = false, features = ["alloc"] } console-traits = "0.3" buddy_system_allocator = "0.1" pci = { git = "https://github.com/rcore-os/pci-rs" } diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index b16fe73..a2636a2 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -10,6 +10,8 @@ use crate::fs::*; use crate::memory::MemorySet; use crate::sync::Condvar; +use bitvec::{BitSlice, BitVec, LittleEndian}; + use super::*; pub fn sys_read(fd: usize, base: *mut u8, len: usize) -> SysResult { @@ -160,30 +162,30 @@ pub fn sys_select( loop { let proc = process(); let mut events = 0; - for (fd, file_like) in proc.files.iter() { - if *fd < nfds { + for (&fd, file_like) in proc.files.iter() { + if fd < nfds { match file_like { FileLike::File(_) => { // FIXME: assume it is stdin for now if STDIN.can_read() { - if read_fds.is_set(*fd) { - read_fds.set(*fd); + if read_fds.contains(fd) { + read_fds.set(fd); events = events + 1; } } } FileLike::Socket(socket) => { let (input, output, err) = socket.poll(); - if err && err_fds.is_set(*fd) { - err_fds.set(*fd); + if err && err_fds.contains(fd) { + err_fds.set(fd); events = events + 1; } - if input && read_fds.is_set(*fd) { - read_fds.set(*fd); + if input && read_fds.contains(fd) { + read_fds.set(fd); events = events + 1; } - if output && write_fds.is_set(*fd) { - write_fds.set(*fd); + if output && write_fds.contains(fd) { + write_fds.set(fd); events = events + 1; } } @@ -1172,54 +1174,51 @@ const FD_PER_ITEM: usize = 8 * size_of::(); const MAX_FDSET_SIZE: usize = 1024 / FD_PER_ITEM; struct FdSet { - addr: *mut u32, - nfds: usize, - saved: [u32; MAX_FDSET_SIZE], + bitset: &'static mut BitSlice, + origin: BitVec, } impl FdSet { /// Initialize a `FdSet` from pointer and number of fds /// Check if the array is large enough fn new(vm: &MemorySet, addr: *mut u32, nfds: usize) -> Result { - let mut saved = [0u32; MAX_FDSET_SIZE]; - if addr as usize != 0 { + if addr.is_null() { + Ok(FdSet { + bitset: BitSlice::empty_mut(), + origin: BitVec::new(), + }) + } else { let len = (nfds + FD_PER_ITEM - 1) / FD_PER_ITEM; vm.check_write_array(addr, len)?; if len > MAX_FDSET_SIZE { return Err(SysError::EINVAL); } let slice = unsafe { slice::from_raw_parts_mut(addr, len) }; + let bitset: &'static mut BitSlice = slice.into(); // save the fdset, and clear it - for i in 0..len { - saved[i] = slice[i]; - slice[i] = 0; - } + use alloc::prelude::ToOwned; + let origin = bitset.to_owned(); + bitset.set_all(false); + Ok(FdSet { bitset, origin }) } - - Ok(FdSet { addr, nfds, saved }) } /// Try to set fd in `FdSet` /// Return true when `FdSet` is valid, and false when `FdSet` is bad (i.e. null pointer) /// Fd should be less than nfds fn set(&mut self, fd: usize) -> bool { - if self.addr as usize != 0 { - assert!(fd < self.nfds); - unsafe { - *self.addr.add(fd / 8 / size_of::()) |= 1 << (fd % (8 * size_of::())); - } - true - } else { - false + if self.bitset.is_empty() { + return false; } + self.bitset.set(fd, true); + true } - /// Check to see fd is see in original `FdSet` + /// Check to see whether `fd` is in original `FdSet` /// Fd should be less than nfds - fn is_set(&mut self, fd: usize) -> bool { - assert!(fd < self.nfds); - self.saved[fd / 8 / size_of::()] & (1 << (fd % (8 * size_of::()))) != 0 + fn contains(&self, fd: usize) -> bool { + self.origin[fd] } } From b77a52dccb2586260df2ad6a083e5a6759c6fd89 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Thu, 4 Apr 2019 12:45:55 +0800 Subject: [PATCH 02/28] move bit-allocator and rcore-thread crate to remote --- Cargo.toml | 2 - crate/bit-allocator/Cargo.toml | 7 - crate/bit-allocator/src/lib.rs | 221 -------------------- crate/thread/Cargo.toml | 11 - crate/thread/build.rs | 1 - crate/thread/example/Cargo.toml | 19 -- crate/thread/example/README.md | 5 - crate/thread/example/src/main.rs | 204 ------------------ crate/thread/example/x86_64-blog_os.json | 15 -- crate/thread/src/interrupt.rs | 63 ------ crate/thread/src/lib.rs | 19 -- crate/thread/src/processor.rs | 127 ----------- crate/thread/src/scheduler/mod.rs | 34 --- crate/thread/src/scheduler/o1.rs | 65 ------ crate/thread/src/scheduler/rr.rs | 109 ---------- crate/thread/src/scheduler/stride.rs | 113 ---------- crate/thread/src/scheduler/work_stealing.rs | 80 ------- crate/thread/src/std_thread.rs | 165 --------------- crate/thread/src/thread_pool.rs | 221 -------------------- crate/thread/src/timer.rs | 65 ------ kernel/Cargo.lock | 22 +- kernel/Cargo.toml | 4 +- kernel/src/arch/x86_64/memory.rs | 2 +- kernel/src/memory.rs | 8 +- 24 files changed, 20 insertions(+), 1562 deletions(-) delete mode 100644 crate/bit-allocator/Cargo.toml delete mode 100644 crate/bit-allocator/src/lib.rs delete mode 100644 crate/thread/Cargo.toml delete mode 100644 crate/thread/build.rs delete mode 100644 crate/thread/example/Cargo.toml delete mode 100644 crate/thread/example/README.md delete mode 100644 crate/thread/example/src/main.rs delete mode 100644 crate/thread/example/x86_64-blog_os.json delete mode 100644 crate/thread/src/interrupt.rs delete mode 100644 crate/thread/src/lib.rs delete mode 100644 crate/thread/src/processor.rs delete mode 100644 crate/thread/src/scheduler/mod.rs delete mode 100644 crate/thread/src/scheduler/o1.rs delete mode 100644 crate/thread/src/scheduler/rr.rs delete mode 100644 crate/thread/src/scheduler/stride.rs delete mode 100644 crate/thread/src/scheduler/work_stealing.rs delete mode 100644 crate/thread/src/std_thread.rs delete mode 100644 crate/thread/src/thread_pool.rs delete mode 100644 crate/thread/src/timer.rs diff --git a/Cargo.toml b/Cargo.toml index 00d2e95..68779bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,6 @@ [workspace] members = [ - "crate/bit-allocator", "crate/memory", "crate/sync", - "crate/thread", ] exclude = ["kernel", "bootloader", "user/rust"] diff --git a/crate/bit-allocator/Cargo.toml b/crate/bit-allocator/Cargo.toml deleted file mode 100644 index fb4d6dd..0000000 --- a/crate/bit-allocator/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "bit-allocator" -version = "0.1.0" -authors = ["WangRunji "] - -[dependencies] -bit_field = "0.9" diff --git a/crate/bit-allocator/src/lib.rs b/crate/bit-allocator/src/lib.rs deleted file mode 100644 index 6c30948..0000000 --- a/crate/bit-allocator/src/lib.rs +++ /dev/null @@ -1,221 +0,0 @@ -#![no_std] -#![feature(asm)] - -extern crate bit_field; - -use bit_field::BitField; -use core::ops::Range; - -/// Allocator of a bitmap, able to allocate / free bits. -/// -/// CAP: the bitmap has a total of CAP bits, numbered from 0 to CAP-1 inclusively. -/// -/// alloc: allocate a free bit. -/// dealloc: free an allocated bit. -/// -/// insert: mark bits in the range as allocated (available) -/// remove: reverse of insert -/// -/// any: whether there are free bits remaining -/// test: whether a specific bit is free -pub trait BitAlloc: Default { - const CAP: usize; - fn alloc(&mut self) -> Option; - fn dealloc(&mut self, key: usize); - fn insert(&mut self, range: Range); - fn remove(&mut self, range: Range); - fn any(&self) -> bool; - fn test(&self, key: usize) -> bool; -} - -pub type BitAlloc256 = BitAllocCascade16; -pub type BitAlloc4K = BitAllocCascade16; -pub type BitAlloc64K = BitAllocCascade16; -pub type BitAlloc1M = BitAllocCascade16; -pub type BitAlloc16M = BitAllocCascade16; -pub type BitAlloc256M = BitAllocCascade16; - -/// Implement the bit allocator by segment tree algorithm. -#[derive(Default)] -pub struct BitAllocCascade16 { - bitset: u16, // for each bit, 1 indicates available, 0 indicates inavailable - sub: [T; 16], -} - -impl BitAlloc for BitAllocCascade16 { - const CAP: usize = T::CAP * 16; - - fn alloc(&mut self) -> Option { - if self.any() { - let i = log2(self.bitset); - let res = self.sub[i].alloc().unwrap() + i * T::CAP; - self.bitset.set_bit(i, self.sub[i].any()); - Some(res) - } else { - None - } - } - fn dealloc(&mut self, key: usize) { - let i = key / T::CAP; - self.sub[i].dealloc(key % T::CAP); - self.bitset.set_bit(i, true); - } - fn insert(&mut self, range: Range) { - self.for_range(range, |sub: &mut T, range| sub.insert(range)); - } - fn remove(&mut self, range: Range) { - self.for_range(range, |sub: &mut T, range| sub.remove(range)); - } - fn any(&self) -> bool { - self.bitset != 0 - } - fn test(&self, key: usize) -> bool { - self.sub[key / T::CAP].test(key % T::CAP) - } -} - -impl BitAllocCascade16 { - fn for_range(&mut self, range: Range, f: impl Fn(&mut T, Range)) { - let Range { start, end } = range; - assert!(start <= end); - assert!(end <= Self::CAP); - for i in start / T::CAP..=(end - 1) / T::CAP { - let begin = if start / T::CAP == i { - start % T::CAP - } else { - 0 - }; - let end = if end / T::CAP == i { - end % T::CAP - } else { - T::CAP - }; - f(&mut self.sub[i], begin..end); - self.bitset.set_bit(i, self.sub[i].any()); - } - } -} - -#[derive(Default)] -pub struct BitAlloc16(u16); - -/// BitAlloc16 acts as the leaf (except the leaf bits of course) nodes -/// in the segment trees. -impl BitAlloc for BitAlloc16 { - const CAP: usize = 16; - - fn alloc(&mut self) -> Option { - if self.any() { - let i = log2(self.0); - self.0.set_bit(i, false); - Some(i) - } else { - None - } - } - fn dealloc(&mut self, key: usize) { - assert!(!self.test(key)); - self.0.set_bit(key, true); - } - fn insert(&mut self, range: Range) { - self.0.set_bits(range.clone(), 0xffff.get_bits(range)); - } - fn remove(&mut self, range: Range) { - self.0.set_bits(range, 0); - } - fn any(&self) -> bool { - self.0 != 0 - } - fn test(&self, key: usize) -> bool { - self.0.get_bit(key) - } -} - -#[inline(always)] -#[cfg(target_arch = "x86_64")] -fn log2(x: u16) -> usize { - assert_ne!(x, 0); - let pos: u16; - unsafe { asm!("bsrw $1, $0" :"=r"(pos) :"r"(x) : :"volatile") }; - pos as usize -} - -#[inline(always)] -#[cfg(not(target_arch = "x86_64"))] -fn log2(x: u16) -> usize { - log2_naive(x) -} - -#[cfg(not(target_arch = "x86_64"))] -#[inline(always)] -fn log2_naive(mut x: u16) -> usize { - //a naive implement - assert_ne!(x, 0); - let mut pos = -1; - while x != 0 { - pos += 1; - x >>= 1; - } - pos as usize -} - -#[cfg(test)] -mod tests { - use super::*; - - #[cfg(not(target_arch = "x86_64"))] - #[test] - fn log2_() { - for x in 1..=0xffff { - assert_eq!(log2(x), log2_naive(x), "log2 failed: {}", x); - } - } - - #[test] - fn bitalloc16() { - let mut ba = BitAlloc16::default(); - assert_eq!(BitAlloc16::CAP, 16); - ba.insert(0..16); - for i in 0..16 { - assert_eq!(ba.test(i), true); - } - ba.remove(8..14); - assert_eq!(ba.alloc(), Some(15)); - assert_eq!(ba.alloc(), Some(14)); - assert_eq!(ba.alloc(), Some(7)); - ba.dealloc(14); - ba.dealloc(15); - ba.dealloc(7); - - for _ in 0..10 { - assert!(ba.alloc().is_some()); - } - assert!(!ba.any()); - assert!(ba.alloc().is_none()); - } - - #[test] - fn bitalloc4k() { - let mut ba = BitAlloc4K::default(); - assert_eq!(BitAlloc4K::CAP, 4096); - ba.insert(0..4096); - for i in 0..4096 { - assert_eq!(ba.test(i), true); - } - ba.remove(8..4094); - for i in 0..4096 { - assert_eq!(ba.test(i), i < 8 || i >= 4094); - } - assert_eq!(ba.alloc(), Some(4095)); - assert_eq!(ba.alloc(), Some(4094)); - assert_eq!(ba.alloc(), Some(7)); - ba.dealloc(4095); - ba.dealloc(4094); - ba.dealloc(7); - - for _ in 0..10 { - assert!(ba.alloc().is_some()); - } - assert!(ba.alloc().is_none()); - } -} diff --git a/crate/thread/Cargo.toml b/crate/thread/Cargo.toml deleted file mode 100644 index e8aa1c3..0000000 --- a/crate/thread/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "rcore-thread" -version = "0.1.0" -authors = ["WangRunji "] -description = "Bare-metal thread scheduler and executor" -edition = "2018" - -[dependencies] -log = "0.4" -spin = "0.5" -deque = { git = "https://github.com/rcore-os/deque.git", branch = "no_std" } \ No newline at end of file diff --git a/crate/thread/build.rs b/crate/thread/build.rs deleted file mode 100644 index f328e4d..0000000 --- a/crate/thread/build.rs +++ /dev/null @@ -1 +0,0 @@ -fn main() {} diff --git a/crate/thread/example/Cargo.toml b/crate/thread/example/Cargo.toml deleted file mode 100644 index 0ecc867..0000000 --- a/crate/thread/example/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "example" -version = "0.1.0" -authors = ["WangRunji "] -edition = "2018" - -[dependencies] -log = "0.4" -linked_list_allocator = "0.6" -blog_os = { git = "https://github.com/phil-opp/blog_os.git" } -rcore-thread = { path = ".." } - -[package.metadata.bootimage] -default-target = "x86_64-blog_os.json" -run-command = ["qemu-system-x86_64", - "-drive", "format=raw,file={}", - "-serial", "mon:stdio", - "-device", "isa-debug-exit,iobase=0xf4,iosize=0x04" -] \ No newline at end of file diff --git a/crate/thread/example/README.md b/crate/thread/example/README.md deleted file mode 100644 index 2b14623..0000000 --- a/crate/thread/example/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Example of `rcore-thread` crate - -```bash -bootimage run --release -``` \ No newline at end of file diff --git a/crate/thread/example/src/main.rs b/crate/thread/example/src/main.rs deleted file mode 100644 index 2462998..0000000 --- a/crate/thread/example/src/main.rs +++ /dev/null @@ -1,204 +0,0 @@ -#![no_std] -#![no_main] -#![feature(asm)] -#![feature(alloc)] -#![feature(naked_functions)] -#![feature(lang_items)] - -extern crate alloc; - -use core::alloc::Layout; -use core::panic::PanicInfo; -use alloc::{boxed::Box, sync::Arc}; - -use blog_os::{exit_qemu, gdt, interrupts::init_idt, serial_println}; -use linked_list_allocator::LockedHeap; -use rcore_thread::{*, std_thread as thread}; - -const STACK_SIZE: usize = 0x2000; -const HEAP_SIZE: usize = 0x100000; -const MAX_CPU_NUM: usize = 1; -const MAX_PROC_NUM: usize = 32; - - -/// The entry of the kernel -#[no_mangle] -pub extern "C" fn _start() -> ! { - // init x86 - gdt::init(); - init_idt(); - // init log - init_log(); - // init heap - unsafe { HEAP_ALLOCATOR.lock().init(HEAP.as_ptr() as usize, HEAP_SIZE); } - // init processor - let scheduler = scheduler::RRScheduler::new(5); - let thread_pool = Arc::new(ThreadPool::new(scheduler, MAX_PROC_NUM)); - unsafe { processor().init(0, Thread::init(), thread_pool); } - // init threads - thread::spawn(|| { - let tid = processor().tid(); - serial_println!("[{}] yield", tid); - thread::yield_now(); - serial_println!("[{}] spawn", tid); - let t2 = thread::spawn(|| { - let tid = processor().tid(); - serial_println!("[{}] yield", tid); - thread::yield_now(); - serial_println!("[{}] return 8", tid); - 8 - }); - serial_println!("[{}] join", tid); - let ret = t2.join(); - serial_println!("[{}] get {:?}", tid, ret); - serial_println!("[{}] exit", tid); - }); - // run threads - processor().run(); -} - -fn init_log() { - use log::*; - struct SimpleLogger; - impl Log for SimpleLogger { - fn enabled(&self, _metadata: &Metadata) -> bool { - true - } - fn log(&self, record: &Record) { - serial_println!("[{:>5}] {}", record.level(), record.args()); - } - fn flush(&self) {} - } - static LOGGER: SimpleLogger = SimpleLogger; - set_logger(&LOGGER).unwrap(); - set_max_level(LevelFilter::Trace); -} - -/// The context of a thread. -/// -/// When a thread yield, its context will be stored at its stack. -#[derive(Debug, Default)] -#[repr(C)] -struct ContextData { - rdi: usize, // arg0 - r15: usize, - r14: usize, - r13: usize, - r12: usize, - rbp: usize, - rbx: usize, - rip: usize, -} - -impl ContextData { - fn new(entry: extern fn(usize) -> !, arg0: usize) -> Self { - ContextData { - rip: entry as usize, - rdi: arg0, - ..ContextData::default() - } - } -} - -#[repr(C)] -struct Thread { - rsp: usize, - stack: [u8; STACK_SIZE], -} - -impl Thread { - unsafe fn init() -> Box { - Box::new(core::mem::uninitialized()) - } - fn new(entry: extern fn(usize) -> !, arg0: usize) -> Box { - let mut thread = unsafe { Thread::init() }; - let rsp = thread.stack.as_ptr() as usize + STACK_SIZE - core::mem::size_of::(); - // push a Context at stack top - let init_context = ContextData::new(entry, arg0); - unsafe { (rsp as *mut ContextData).write(init_context); } - thread.rsp = rsp; - thread - } -} - -/// Implement `switch_to` for a thread -impl Context for Thread { - /// Switch to another thread. - unsafe fn switch_to(&mut self, target: &mut Context) { - let (to, _): (*mut Thread, usize) = core::mem::transmute(target); - inner(self, to); - - #[naked] - #[inline(never)] - unsafe extern "C" fn inner(_from: *mut Thread, _to: *mut Thread) { - asm!( - " - // push rip (by caller) - - // Save self callee-save registers - push rbx - push rbp - push r12 - push r13 - push r14 - push r15 - push rdi - - // Switch stacks - mov [rdi], rsp // *rdi = from_rsp - mov rsp, [rsi] // *rsi = to_rsp - - // Restore target callee-save registers - pop rdi - pop r15 - pop r14 - pop r13 - pop r12 - pop rbp - pop rbx - - // pop rip - ret" - : : : : "intel" "volatile" ) - } - } - - fn set_tid(&mut self, _tid: usize) { - } -} - -/// Define global `Processor` for each core. -static PROCESSORS: [Processor; MAX_CPU_NUM] = [Processor::new()]; - -/// Now we only have one core. -fn cpu_id() -> usize { 0 } - -/// Implement dependency for `rcore_thread::std_thread` -#[no_mangle] -pub fn processor() -> &'static Processor { - &PROCESSORS[cpu_id()] -} - -/// Implement dependency for `rcore_thread::std_thread` -#[no_mangle] -pub fn new_kernel_context(entry: extern fn(usize) -> !, arg0: usize) -> Box { - Thread::new(entry, arg0) -} - -#[panic_handler] -fn panic(info: &PanicInfo) -> ! { - serial_println!("\n{}", info); - - unsafe { exit_qemu(); } - loop {} -} - -#[global_allocator] -static HEAP_ALLOCATOR: LockedHeap = LockedHeap::empty(); - -static mut HEAP: [u8; HEAP_SIZE] = [0; HEAP_SIZE]; - -#[lang = "oom"] -fn oom(_: Layout) -> ! { - panic!("out of memory"); -} \ No newline at end of file diff --git a/crate/thread/example/x86_64-blog_os.json b/crate/thread/example/x86_64-blog_os.json deleted file mode 100644 index 7d2110d..0000000 --- a/crate/thread/example/x86_64-blog_os.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "llvm-target": "x86_64-unknown-none", - "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", - "arch": "x86_64", - "target-endian": "little", - "target-pointer-width": "64", - "target-c-int-width": "32", - "os": "none", - "executables": true, - "linker-flavor": "ld.lld", - "linker": "rust-lld", - "panic-strategy": "abort", - "disable-redzone": true, - "features": "-mmx,-sse,+soft-float" -} diff --git a/crate/thread/src/interrupt.rs b/crate/thread/src/interrupt.rs deleted file mode 100644 index d7c1d3c..0000000 --- a/crate/thread/src/interrupt.rs +++ /dev/null @@ -1,63 +0,0 @@ -//! Enable and disable interrupt for each architecture. - -#[inline(always)] -#[cfg(target_arch = "x86_64")] -pub unsafe fn disable_and_store() -> usize { - let rflags: usize; - asm!("pushfq; popq $0; cli" : "=r"(rflags) ::: "volatile"); - rflags & (1 << 9) -} - -#[inline(always)] -#[cfg(target_arch = "x86_64")] -pub unsafe fn restore(flags: usize) { - if flags != 0 { - asm!("sti" :::: "volatile"); - } -} - -#[inline(always)] -#[cfg(target_arch = "x86_64")] -pub unsafe fn enable_and_wfi() { - asm!("sti; hlt" :::: "volatile"); -} - -#[inline(always)] -#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] -pub unsafe fn disable_and_store() -> usize { - let sstatus: usize; - asm!("csrci sstatus, 1 << 1" : "=r"(sstatus) ::: "volatile"); - sstatus & (1 << 1) -} - -#[inline(always)] -#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] -pub unsafe fn restore(flags: usize) { - asm!("csrs sstatus, $0" :: "r"(flags) :: "volatile"); -} - -#[inline(always)] -#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] -pub unsafe fn enable_and_wfi() { - asm!("csrsi sstatus, 1 << 1; wfi" :::: "volatile"); -} - -#[inline(always)] -#[cfg(target_arch = "aarch64")] -pub unsafe fn disable_and_store() -> usize { - let daif: u32; - asm!("mrs $0, DAIF; msr daifset, #2": "=r"(daif) ::: "volatile"); - daif as usize -} - -#[inline(always)] -#[cfg(target_arch = "aarch64")] -pub unsafe fn restore(flags: usize) { - asm!("msr DAIF, $0" :: "r"(flags as u32) :: "volatile"); -} - -#[inline(always)] -#[cfg(target_arch = "aarch64")] -pub unsafe fn enable_and_wfi() { - asm!("msr daifclr, #2; wfi" :::: "volatile"); -} diff --git a/crate/thread/src/lib.rs b/crate/thread/src/lib.rs deleted file mode 100644 index 1a66d6a..0000000 --- a/crate/thread/src/lib.rs +++ /dev/null @@ -1,19 +0,0 @@ -#![cfg_attr(not(test), no_std)] -#![feature(alloc)] -#![feature(const_fn)] -#![feature(linkage)] -#![feature(vec_resize_default)] -#![feature(asm)] -#![feature(exact_size_is_empty)] - -extern crate alloc; - -mod interrupt; -mod processor; -pub mod scheduler; -pub mod std_thread; -mod thread_pool; -mod timer; - -pub use crate::processor::Processor; -pub use crate::thread_pool::*; diff --git a/crate/thread/src/processor.rs b/crate/thread/src/processor.rs deleted file mode 100644 index e935087..0000000 --- a/crate/thread/src/processor.rs +++ /dev/null @@ -1,127 +0,0 @@ -use crate::interrupt; -use crate::thread_pool::*; -use alloc::boxed::Box; -use alloc::sync::Arc; -use core::cell::UnsafeCell; -use log::*; - -/// Thread executor -/// -/// Per-CPU struct. Defined at global. -/// Only accessed by associated CPU with interrupt disabled. -#[derive(Default)] -pub struct Processor { - inner: UnsafeCell>, -} - -unsafe impl Sync for Processor {} - -struct ProcessorInner { - id: usize, - proc: Option<(Tid, Box)>, - loop_context: Box, - manager: Arc, -} - -impl Processor { - pub const fn new() -> Self { - Processor { - inner: UnsafeCell::new(None), - } - } - - pub unsafe fn init(&self, id: usize, context: Box, manager: Arc) { - *self.inner.get() = Some(ProcessorInner { - id, - proc: None, - loop_context: context, - manager, - }); - } - - fn inner(&self) -> &mut ProcessorInner { - unsafe { &mut *self.inner.get() } - .as_mut() - .expect("Processor is not initialized") - } - - /// Begin running processes after CPU setup. - /// - /// This function never returns. It loops, doing: - /// - choose a process to run - /// - switch to start running that process - /// - eventually that process transfers control - /// via switch back to the scheduler. - pub fn run(&self) -> ! { - let inner = self.inner(); - unsafe { - interrupt::disable_and_store(); - } - loop { - if let Some(proc) = inner.manager.run(inner.id) { - trace!("CPU{} begin running thread {}", inner.id, proc.0); - inner.proc = Some(proc); - unsafe { - inner - .loop_context - .switch_to(&mut *inner.proc.as_mut().unwrap().1); - } - let (tid, context) = inner.proc.take().unwrap(); - trace!("CPU{} stop running thread {}", inner.id, tid); - inner.manager.stop(tid, context); - } else { - trace!("CPU{} idle", inner.id); - unsafe { - interrupt::enable_and_wfi(); - } - // wait for a timer interrupt - unsafe { - interrupt::disable_and_store(); - } - } - } - } - - /// Called by process running on this Processor. - /// Yield and reschedule. - /// - /// The interrupt may be enabled. - pub fn yield_now(&self) { - let inner = self.inner(); - unsafe { - let flags = interrupt::disable_and_store(); - inner - .proc - .as_mut() - .unwrap() - .1 - .switch_to(&mut *inner.loop_context); - interrupt::restore(flags); - } - } - - pub fn tid(&self) -> Tid { - self.inner().proc.as_ref().unwrap().0 - } - - pub fn context(&self) -> &Context { - &*self.inner().proc.as_ref().unwrap().1 - } - - pub fn manager(&self) -> &ThreadPool { - &*self.inner().manager - } - - /// Called by timer interrupt handler. - /// - /// The interrupt should be disabled in the handler. - pub fn tick(&self) { - // If I'm idle, tid == None, need_reschedule == false. - // Will go back to `run()` after interrupt return. - let tid = self.inner().proc.as_ref().map(|p| p.0); - let need_reschedule = self.manager().tick(self.inner().id, tid); - if need_reschedule { - self.yield_now(); - } - } -} diff --git a/crate/thread/src/scheduler/mod.rs b/crate/thread/src/scheduler/mod.rs deleted file mode 100644 index bc42450..0000000 --- a/crate/thread/src/scheduler/mod.rs +++ /dev/null @@ -1,34 +0,0 @@ -use alloc::{collections::BinaryHeap, vec::Vec}; - -use log::*; -use spin::Mutex; - -pub use self::o1::O1Scheduler; -pub use self::rr::RRScheduler; -pub use self::stride::StrideScheduler; -pub use self::work_stealing::WorkStealingScheduler; - -mod o1; -mod rr; -mod stride; -mod work_stealing; - -type Tid = usize; - -/// The scheduler for a ThreadPool -pub trait Scheduler: 'static { - /// Push a thread to the back of ready queue. - fn push(&self, tid: Tid); - /// Select a thread to run, pop it from the queue. - fn pop(&self, cpu_id: usize) -> Option; - /// Got a tick from CPU. - /// Return true if need reschedule. - fn tick(&self, current_tid: Tid) -> bool; - /// Set priority of a thread. - fn set_priority(&self, tid: Tid, priority: u8); -} - -fn expand(vec: &mut Vec, id: usize) { - let len = vec.len(); - vec.resize(len.max(id + 1), T::default()); -} diff --git a/crate/thread/src/scheduler/o1.rs b/crate/thread/src/scheduler/o1.rs deleted file mode 100644 index f2e273c..0000000 --- a/crate/thread/src/scheduler/o1.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! O(1) scheduler introduced in Linux 2.6 -//! -//! Two queues are maintained, one is active, another is inactive. -//! Take the first task from the active queue to run. When it is empty, swap active and inactive queues. - -use super::*; - -pub struct O1Scheduler { - inner: Mutex, -} - -struct O1SchedulerInner { - active_queue: usize, - queues: [Vec; 2], -} - -impl Scheduler for O1Scheduler { - fn push(&self, tid: usize) { - self.inner.lock().push(tid); - } - fn pop(&self, _cpu_id: usize) -> Option { - self.inner.lock().pop() - } - fn tick(&self, current_tid: usize) -> bool { - self.inner.lock().tick(current_tid) - } - fn set_priority(&self, _tid: usize, _priority: u8) {} -} - -impl O1Scheduler { - pub fn new() -> Self { - let inner = O1SchedulerInner { - active_queue: 0, - queues: [Vec::new(), Vec::new()], - }; - O1Scheduler { - inner: Mutex::new(inner), - } - } -} - -impl O1SchedulerInner { - fn push(&mut self, tid: Tid) { - let inactive_queue = 1 - self.active_queue; - self.queues[inactive_queue].push(tid); - trace!("o1 push {}", tid - 1); - } - - fn pop(&mut self) -> Option { - let ret = match self.queues[self.active_queue].pop() { - Some(tid) => return Some(tid), - None => { - // active queue is empty, swap 'em - self.active_queue = 1 - self.active_queue; - self.queues[self.active_queue].pop() - } - }; - trace!("o1 pop {:?}", ret); - ret - } - - fn tick(&mut self, _current: Tid) -> bool { - true - } -} diff --git a/crate/thread/src/scheduler/rr.rs b/crate/thread/src/scheduler/rr.rs deleted file mode 100644 index d111dab..0000000 --- a/crate/thread/src/scheduler/rr.rs +++ /dev/null @@ -1,109 +0,0 @@ -use super::*; - -pub struct RRScheduler { - inner: Mutex, -} - -struct RRSchedulerInner { - max_time_slice: usize, - infos: Vec, -} - -#[derive(Debug, Default, Copy, Clone)] -struct RRProcInfo { - present: bool, - rest_slice: usize, - prev: Tid, - next: Tid, -} - -impl Scheduler for RRScheduler { - fn push(&self, tid: usize) { - self.inner.lock().push(tid); - } - fn pop(&self, _cpu_id: usize) -> Option { - self.inner.lock().pop() - } - fn tick(&self, current_tid: usize) -> bool { - self.inner.lock().tick(current_tid) - } - fn set_priority(&self, _tid: usize, _priority: u8) {} -} - -impl RRScheduler { - pub fn new(max_time_slice: usize) -> Self { - let inner = RRSchedulerInner { - max_time_slice, - infos: Vec::default(), - }; - RRScheduler { - inner: Mutex::new(inner), - } - } -} - -impl RRSchedulerInner { - fn push(&mut self, tid: Tid) { - let tid = tid + 1; - expand(&mut self.infos, tid); - { - let info = &mut self.infos[tid]; - assert!(!info.present); - info.present = true; - if info.rest_slice == 0 { - info.rest_slice = self.max_time_slice; - } - } - self._list_add_before(tid, 0); - trace!("rr push {}", tid - 1); - } - - fn pop(&mut self) -> Option { - let ret = match self.infos[0].next { - 0 => None, - tid => { - self.infos[tid].present = false; - self._list_remove(tid); - Some(tid - 1) - } - }; - trace!("rr pop {:?}", ret); - ret - } - - fn tick(&mut self, current: Tid) -> bool { - let current = current + 1; - expand(&mut self.infos, current); - assert!(!self.infos[current].present); - - let rest = &mut self.infos[current].rest_slice; - if *rest > 0 { - *rest -= 1; - } else { - warn!("current process rest_slice = 0, need reschedule") - } - *rest == 0 - } -} - -impl RRSchedulerInner { - fn _list_add_before(&mut self, i: Tid, at: Tid) { - let prev = self.infos[at].prev; - self.infos[i].next = at; - self.infos[i].prev = prev; - self.infos[prev].next = i; - self.infos[at].prev = i; - } - fn _list_add_after(&mut self, i: Tid, at: Tid) { - let next = self.infos[at].next; - self._list_add_before(i, next); - } - fn _list_remove(&mut self, i: Tid) { - let next = self.infos[i].next; - let prev = self.infos[i].prev; - self.infos[next].prev = prev; - self.infos[prev].next = next; - self.infos[i].next = 0; - self.infos[i].prev = 0; - } -} diff --git a/crate/thread/src/scheduler/stride.rs b/crate/thread/src/scheduler/stride.rs deleted file mode 100644 index 3ac0ffd..0000000 --- a/crate/thread/src/scheduler/stride.rs +++ /dev/null @@ -1,113 +0,0 @@ -//! Stride scheduler -//! -//! Each task is assigned a priority. Each task has a running stride. -//! The task with least stride is selected to run. -//! When a task is rescheduled, its stride is added to proportional to 1 / priority. - -use super::*; - -pub struct StrideScheduler { - inner: Mutex, -} - -pub struct StrideSchedulerInner { - max_time_slice: usize, - infos: Vec, - queue: BinaryHeap<(Stride, Tid)>, // It's max heap, so pass < 0 -} - -#[derive(Debug, Default, Copy, Clone)] -struct StrideProcInfo { - present: bool, - rest_slice: usize, - stride: Stride, - priority: u8, -} - -impl StrideProcInfo { - fn pass(&mut self) { - const BIG_STRIDE: Stride = 1 << 20; - let pass = if self.priority == 0 { - BIG_STRIDE - } else { - BIG_STRIDE / self.priority as Stride - }; - // FIXME: overflowing_add is not working ??? - // self.stride.overflowing_add(pass); - self.stride += pass; - } -} - -type Stride = i32; - -impl Scheduler for StrideScheduler { - fn push(&self, tid: usize) { - self.inner.lock().push(tid); - } - fn pop(&self, _cpu_id: usize) -> Option { - self.inner.lock().pop() - } - fn tick(&self, current_tid: usize) -> bool { - self.inner.lock().tick(current_tid) - } - fn set_priority(&self, tid: usize, priority: u8) { - self.inner.lock().set_priority(tid, priority); - } -} - -impl StrideScheduler { - pub fn new(max_time_slice: usize) -> Self { - let inner = StrideSchedulerInner { - max_time_slice, - infos: Vec::default(), - queue: BinaryHeap::default(), - }; - StrideScheduler { - inner: Mutex::new(inner), - } - } -} - -impl StrideSchedulerInner { - fn push(&mut self, tid: Tid) { - expand(&mut self.infos, tid); - let info = &mut self.infos[tid]; - assert!(!info.present); - info.present = true; - if info.rest_slice == 0 { - info.rest_slice = self.max_time_slice; - } - self.queue.push((-info.stride, tid)); - trace!("stride push {}", tid); - } - - fn pop(&mut self) -> Option { - let ret = self.queue.pop().map(|(_, tid)| tid); - if let Some(tid) = ret { - let old_stride = self.infos[tid].stride; - self.infos[tid].pass(); - let stride = self.infos[tid].stride; - trace!("stride {} {:#x} -> {:#x}", tid, old_stride, stride); - } - trace!("stride pop {:?}", ret); - ret - } - - fn tick(&mut self, current: Tid) -> bool { - expand(&mut self.infos, current); - assert!(!self.infos[current].present); - - let rest = &mut self.infos[current].rest_slice; - if *rest > 0 { - *rest -= 1; - } else { - warn!("current process rest_slice = 0, need reschedule") - } - *rest == 0 - } - - fn set_priority(&mut self, tid: Tid, priority: u8) { - self.infos[tid].priority = priority; - trace!("stride {} priority = {}", tid, priority); - } -} diff --git a/crate/thread/src/scheduler/work_stealing.rs b/crate/thread/src/scheduler/work_stealing.rs deleted file mode 100644 index b0cac58..0000000 --- a/crate/thread/src/scheduler/work_stealing.rs +++ /dev/null @@ -1,80 +0,0 @@ -//! Work stealing scheduler -//! -//! Each CPU has its own queue, and each CPU takes new jobs from its own queue. -//! When its queue is empty, steal jobs from other CPU's queue. - -use super::*; -use deque::{self, Stealer, Stolen, Worker}; - -pub struct WorkStealingScheduler { - /// The ready queue of each processors - workers: Vec>, - /// Stealers to all processors' queue - stealers: Vec>, -} - -impl WorkStealingScheduler { - pub fn new(core_num: usize) -> Self { - let (workers, stealers) = (0..core_num).map(|_| deque::new()).unzip(); - WorkStealingScheduler { workers, stealers } - } -} - -impl Scheduler for WorkStealingScheduler { - fn push(&self, tid: usize) { - // not random, but uniform - // no sync, because we don't need to - static mut WORKER_CPU: usize = 0; - let n = self.workers.len(); - let mut cpu = unsafe { - WORKER_CPU = WORKER_CPU + 1; - if WORKER_CPU >= n { - WORKER_CPU -= n; - } - WORKER_CPU - }; - - // potential racing, so we just check once more - if cpu >= n { - cpu -= n; - } - self.workers[cpu].push(tid); - trace!("work-stealing: cpu{} push thread {}", cpu, tid); - } - - fn pop(&self, cpu_id: usize) -> Option { - if let Some(tid) = self.workers[cpu_id].pop() { - trace!("work-stealing: cpu{} pop thread {}", cpu_id, tid); - return Some(tid); - } - let n = self.workers.len(); - for i in 1..n { - let mut other_id = cpu_id + i; - if other_id >= n { - other_id -= n; - } - loop { - match self.stealers[other_id].steal() { - Stolen::Abort => {} // retry - Stolen::Empty => break, - Stolen::Data(tid) => { - trace!( - "work-stealing: cpu{} steal thread {} from cpu{}", - cpu_id, - tid, - other_id - ); - return Some(tid); - } - } - } - } - None - } - - fn tick(&self, _current_tid: usize) -> bool { - true - } - - fn set_priority(&self, _tid: usize, _priority: u8) {} -} diff --git a/crate/thread/src/std_thread.rs b/crate/thread/src/std_thread.rs deleted file mode 100644 index 048f6d7..0000000 --- a/crate/thread/src/std_thread.rs +++ /dev/null @@ -1,165 +0,0 @@ -//! `std::thread`-like interface -//! -//! Based on Processor. Used in kernel. -//! -//! You need to implement the following functions before use: -//! - `processor`: Get a reference of the current `Processor` -//! - `new_kernel_context`: Construct a `Context` of the new kernel thread - -use crate::processor::*; -use crate::thread_pool::*; -use alloc::boxed::Box; -use core::marker::PhantomData; -use core::time::Duration; -use log::*; - -#[linkage = "weak"] -#[no_mangle] -/// Get a reference of the current `Processor` -fn processor() -> &'static Processor { - unimplemented!("thread: Please implement and export `processor`") -} - -#[linkage = "weak"] -#[no_mangle] -/// Construct a `Context` of the new kernel thread -fn new_kernel_context(_entry: extern "C" fn(usize) -> !, _arg: usize) -> Box { - unimplemented!("thread: Please implement and export `new_kernel_context`") -} - -/// Gets a handle to the thread that invokes it. -pub fn current() -> Thread { - Thread { - tid: processor().tid(), - } -} - -/// Puts the current thread to sleep for the specified amount of time. -pub fn sleep(dur: Duration) { - let time = dur_to_ticks(dur); - trace!("sleep: {:?} ticks", time); - processor().manager().sleep(current().id(), time); - park(); - - fn dur_to_ticks(dur: Duration) -> usize { - return dur.as_secs() as usize * 100 + dur.subsec_nanos() as usize / 10_000_000; - } -} - -/// Spawns a new thread, returning a JoinHandle for it. -/// -/// `F`: Type of the function `f` -/// `T`: Type of the return value of `f` -pub fn spawn(f: F) -> JoinHandle -where - F: Send + 'static + FnOnce() -> T, - T: Send + 'static, -{ - trace!("spawn:"); - - // 注意到下面的问题: - // Processor只能从入口地址entry+参数arg创建新线程 - // 而我们现在需要让它执行一个未知类型的(闭包)函数f - - // 首先把函数本体(代码数据)置于堆空间中 - let f = Box::into_raw(Box::new(f)); - - // 定义一个静态函数作为新线程的入口点 - // 其参数是函数f在堆上的指针 - // 这样我们就把函数f传到了一个静态函数内部 - // - // 注意到它具有泛型参数,因此对每一次spawn调用, - // 由于F类型是独特的,因此都会生成一个新的kernel_thread_entry - extern "C" fn kernel_thread_entry(f: usize) -> ! - where - F: Send + 'static + FnOnce() -> T, - T: Send + 'static, - { - // 在静态函数内部: - // 根据传进来的指针,恢复f - let f = unsafe { Box::from_raw(f as *mut F) }; - // 调用f,并将其返回值也放在堆上 - let ret = Box::new(f()); - // 让Processor退出当前线程 - // 把f返回值在堆上的指针,以线程返回码的形式传递出去 - let exit_code = Box::into_raw(ret) as usize; - processor().manager().exit(current().id(), exit_code); - processor().yield_now(); - // 再也不会被调度回来了 - unreachable!() - } - - // 在Processor中创建新的线程 - let context = new_kernel_context(kernel_thread_entry::, f as usize); - let tid = processor().manager().add(context); - - // 接下来看看`JoinHandle::join()`的实现 - // 了解是如何获取f返回值的 - return JoinHandle { - thread: Thread { tid }, - mark: PhantomData, - }; -} - -/// Cooperatively gives up a time slice to the OS scheduler. -pub fn yield_now() { - trace!("yield:"); - processor().yield_now(); -} - -/// Blocks unless or until the current thread's token is made available. -pub fn park() { - trace!("park:"); - processor().manager().sleep(current().id(), 0); - processor().yield_now(); -} - -/// Blocks unless or until the current thread's token is made available. -/// Calls `f` before thread yields. Can be used to avoid racing. -pub fn park_action(f: impl FnOnce()) { - trace!("park:"); - processor().manager().sleep(current().id(), 0); - f(); - processor().yield_now(); -} - -/// A handle to a thread. -pub struct Thread { - tid: usize, -} - -impl Thread { - /// Atomically makes the handle's token available if it is not already. - pub fn unpark(&self) { - processor().manager().wakeup(self.tid); - } - /// Gets the thread's unique identifier. - pub fn id(&self) -> usize { - self.tid - } -} - -/// An owned permission to join on a thread (block on its termination). -pub struct JoinHandle { - thread: Thread, - mark: PhantomData, -} - -impl JoinHandle { - /// Extracts a handle to the underlying thread. - pub fn thread(&self) -> &Thread { - &self.thread - } - /// Waits for the associated thread to finish. - pub fn join(self) -> Result { - loop { - trace!("try to join thread {}", self.thread.tid); - if let Some(exit_code) = processor().manager().try_remove(self.thread.tid) { - // Find return value on the heap from the exit code. - return Ok(unsafe { *Box::from_raw(exit_code as *mut T) }); - } - processor().manager().wait(current().id(), self.thread.tid); - processor().yield_now(); - } - } -} diff --git a/crate/thread/src/thread_pool.rs b/crate/thread/src/thread_pool.rs deleted file mode 100644 index 10d5471..0000000 --- a/crate/thread/src/thread_pool.rs +++ /dev/null @@ -1,221 +0,0 @@ -use crate::scheduler::Scheduler; -use crate::timer::Timer; -use alloc::boxed::Box; -use alloc::vec::Vec; -use log::*; -use spin::{Mutex, MutexGuard}; - -struct Thread { - status: Status, - status_after_stop: Status, - waiter: Option, - context: Option>, -} - -pub type Tid = usize; -type ExitCode = usize; - -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum Status { - Ready, - Running(usize), - Sleeping, - /// aka ZOMBIE. Its context was dropped. - Exited(ExitCode), -} - -#[derive(Eq, PartialEq)] -enum Event { - Wakeup(Tid), -} - -pub trait Context { - /// Switch to target context - unsafe fn switch_to(&mut self, target: &mut Context); - - /// A tid is allocated for this context - fn set_tid(&mut self, tid: Tid); -} - -pub struct ThreadPool { - threads: Vec>>, - scheduler: Box, - timer: Mutex>, -} - -impl ThreadPool { - pub fn new(scheduler: impl Scheduler, max_proc_num: usize) -> Self { - ThreadPool { - threads: new_vec_default(max_proc_num), - scheduler: Box::new(scheduler), - timer: Mutex::new(Timer::new()), - } - } - - fn alloc_tid(&self) -> (Tid, MutexGuard>) { - for (i, proc) in self.threads.iter().enumerate() { - let thread = proc.lock(); - if thread.is_none() { - return (i, thread); - } - } - panic!("Thread number exceeded"); - } - - /// Add a new thread - /// Calls action with tid and thread context - pub fn add(&self, mut context: Box) -> Tid { - let (tid, mut thread) = self.alloc_tid(); - context.set_tid(tid); - *thread = Some(Thread { - status: Status::Ready, - status_after_stop: Status::Ready, - waiter: None, - context: Some(context), - }); - self.scheduler.push(tid); - tid - } - - /// Make thread `tid` time slice -= 1. - /// Return true if time slice == 0. - /// Called by timer interrupt handler. - pub(crate) fn tick(&self, cpu_id: usize, tid: Option) -> bool { - if cpu_id == 0 { - let mut timer = self.timer.lock(); - timer.tick(); - while let Some(event) = timer.pop() { - match event { - Event::Wakeup(tid) => self.set_status(tid, Status::Ready), - } - } - } - match tid { - Some(tid) => self.scheduler.tick(tid), - None => false, - } - } - - /// Set the priority of thread `tid` - pub fn set_priority(&self, tid: Tid, priority: u8) { - self.scheduler.set_priority(tid, priority); - } - - /// Called by Processor to get a thread to run. - /// The manager first mark it `Running`, - /// then take out and return its Context. - pub(crate) fn run(&self, cpu_id: usize) -> Option<(Tid, Box)> { - self.scheduler.pop(cpu_id).map(|tid| { - let mut proc_lock = self.threads[tid].lock(); - let mut proc = proc_lock.as_mut().expect("thread not exist"); - proc.status = Status::Running(cpu_id); - (tid, proc.context.take().expect("context not exist")) - }) - } - - /// Called by Processor to finish running a thread - /// and give its context back. - pub(crate) fn stop(&self, tid: Tid, context: Box) { - let mut proc_lock = self.threads[tid].lock(); - let proc = proc_lock.as_mut().expect("thread not exist"); - proc.status = proc.status_after_stop.clone(); - proc.status_after_stop = Status::Ready; - proc.context = Some(context); - match proc.status { - Status::Ready => self.scheduler.push(tid), - Status::Exited(_) => self.exit_handler(proc), - _ => {} - } - } - - /// Called by `JoinHandle` to let thread `tid` wait for `target`. - /// The `tid` is going to sleep, and will be woke up when `target` exit. - /// (see `exit_handler()`) - pub(crate) fn wait(&self, tid: Tid, target: Tid) { - self.set_status(tid, Status::Sleeping); - let mut target_lock = self.threads[target].lock(); - let target = target_lock.as_mut().expect("thread not exist"); - target.waiter = Some(tid); - } - - /// Switch the status of a thread. - /// Insert/Remove it to/from scheduler if necessary. - fn set_status(&self, tid: Tid, status: Status) { - let mut proc_lock = self.threads[tid].lock(); - if let Some(mut proc) = proc_lock.as_mut() { - trace!("thread {} {:?} -> {:?}", tid, proc.status, status); - match (&proc.status, &status) { - (Status::Ready, Status::Ready) => return, - (Status::Ready, _) => panic!("can not remove a thread from ready queue"), - (Status::Exited(_), _) => panic!("can not set status for a exited thread"), - (Status::Sleeping, Status::Exited(_)) => self.timer.lock().stop(Event::Wakeup(tid)), - (Status::Running(_), Status::Ready) => {} // thread will be added to scheduler in stop() - (_, Status::Ready) => self.scheduler.push(tid), - _ => {} - } - match proc.status { - Status::Running(_) => proc.status_after_stop = status, - _ => proc.status = status, - } - match proc.status { - Status::Exited(_) => self.exit_handler(proc), - _ => {} - } - } - } - - /// Try to remove an exited thread `tid`. - /// Return its exit code if success. - pub fn try_remove(&self, tid: Tid) -> Option { - let mut proc_lock = self.threads[tid].lock(); - let proc = proc_lock.as_ref().expect("thread not exist"); - match proc.status { - Status::Exited(code) => { - // release the tid - *proc_lock = None; - Some(code) - } - _ => None, - } - } - - /// Sleep `tid` for `time` ticks. - /// `time` == 0 means sleep forever - pub fn sleep(&self, tid: Tid, time: usize) { - self.set_status(tid, Status::Sleeping); - if time != 0 { - self.timer.lock().start(time, Event::Wakeup(tid)); - } - } - - pub fn wakeup(&self, tid: Tid) { - let mut proc_lock = self.threads[tid].lock(); - if let Some(mut proc) = proc_lock.as_mut() { - trace!("thread {} {:?} -> {:?}", tid, proc.status, Status::Ready); - if let Status::Sleeping = proc.status { - proc.status = Status::Ready; - self.scheduler.push(tid); - } - } - } - - pub fn exit(&self, tid: Tid, code: ExitCode) { - // NOTE: if `tid` is running, status change will be deferred. - self.set_status(tid, Status::Exited(code)); - } - /// Called when a thread exit - fn exit_handler(&self, proc: &mut Thread) { - // wake up waiter - if let Some(waiter) = proc.waiter { - self.wakeup(waiter); - } - // drop its context - proc.context = None; - } -} - -fn new_vec_default(size: usize) -> Vec { - let mut vec = Vec::new(); - vec.resize_with(size, Default::default); - vec -} diff --git a/crate/thread/src/timer.rs b/crate/thread/src/timer.rs deleted file mode 100644 index 5917d72..0000000 --- a/crate/thread/src/timer.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! A simple timer - -use alloc::collections::VecDeque; - -type Time = usize; - -struct Event { - time: Time, - data: T, -} - -/// A simple timer using ordered dequeue -pub struct Timer { - tick: Time, - timers: VecDeque>, -} - -impl Timer { - /// Create a new timer. - pub fn new() -> Self { - Timer { - tick: 0, - timers: VecDeque::new(), - } - } - /// Called on each tick. - pub fn tick(&mut self) { - self.tick += 1; - } - /// Pop an expired timer after `tick`. - /// - /// This must be called after calling `tick`, - /// and should be called multiple times until return `None`. - pub fn pop(&mut self) -> Option { - match self.timers.front() { - None => return None, - Some(timer) if timer.time != self.tick => return None, - _ => {} - }; - self.timers.pop_front().map(|t| t.data) - } - /// Start a timer with given time interval - pub fn start(&mut self, time_after: Time, data: T) { - //debug!("{:?} {:?}", self.tick, time_after); - let time = self.tick + time_after; - let event = Event { time, data }; - let mut it = self.timers.iter(); - let mut i: usize = 0; - loop { - match it.next() { - None => break, - Some(e) if e.time >= time => break, - _ => {} - } - i += 1; - } - self.timers.insert(i, event); - } - /// Stop a timer - pub fn stop(&mut self, data: T) { - if let Some(i) = self.timers.iter().position(|t| t.data == data) { - self.timers.remove(i); - } - } -} diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index c49497a..18ff961 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -59,13 +59,6 @@ dependencies = [ "volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "bit-allocator" -version = "0.1.0" -dependencies = [ - "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "bit_field" version = "0.9.0" @@ -76,6 +69,14 @@ name = "bitflags" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bitmap-allocator" +version = "0.1.0" +source = "git+https://github.com/rcore-os/bitmap-allocator#891867c95bc81f2376ec6eca9e349c42dc26c7fb" +dependencies = [ + "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bitvec" version = "0.9.0" @@ -310,9 +311,9 @@ dependencies = [ "aarch64 2.2.2 (git+https://github.com/rcore-os/aarch64)", "apic 0.1.0 (git+https://github.com/rcore-os/apic-rs)", "bcm2837 0.1.0 (git+https://github.com/rcore-os/bcm2837)", - "bit-allocator 0.1.0", "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bitmap-allocator 0.1.0 (git+https://github.com/rcore-os/bitmap-allocator)", "bitvec 0.11.0 (git+https://github.com/myrrlyn/bitvec.git)", "bootloader 0.4.0 (git+https://github.com/rcore-os/bootloader)", "buddy_system_allocator 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -330,7 +331,7 @@ dependencies = [ "rcore-fs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)", "rcore-fs-sfs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)", "rcore-memory 0.1.0", - "rcore-thread 0.1.0", + "rcore-thread 0.1.0 (git+https://github.com/rcore-os/rcore-thread)", "riscv 0.5.0 (git+https://github.com/rcore-os/riscv)", "smoltcp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -367,6 +368,7 @@ dependencies = [ [[package]] name = "rcore-thread" version = "0.1.0" +source = "git+https://github.com/rcore-os/rcore-thread#470634bc15de1532ab255555ff71adf112fd52e8" dependencies = [ "deque 0.3.2 (git+https://github.com/rcore-os/deque.git?branch=no_std)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -600,6 +602,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bcm2837 0.1.0 (git+https://github.com/rcore-os/bcm2837)" = "" "checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum bitmap-allocator 0.1.0 (git+https://github.com/rcore-os/bitmap-allocator)" = "" "checksum bitvec 0.11.0 (git+https://github.com/myrrlyn/bitvec.git)" = "" "checksum bitvec 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cfadef5c4e2c2e64067b9ecc061179f12ac7ec65ba613b1f60f3972bbada1f5b" "checksum bootloader 0.4.0 (git+https://github.com/rcore-os/bootloader)" = "" @@ -635,6 +638,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d" "checksum rcore-fs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)" = "" "checksum rcore-fs-sfs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)" = "" +"checksum rcore-thread 0.1.0 (git+https://github.com/rcore-os/rcore-thread)" = "" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum register 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e10f31b6d2299e5620986ad9fcdd66463e125ad72af4f403f9aedf7592d5ccdb" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 7aacfe2..5c06128 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -50,9 +50,9 @@ device_tree = { git = "https://github.com/rcore-os/device_tree-rs" } isomorphic_drivers = { git = "https://github.com/rcore-os/isomorphic_drivers" } lazy_static = { version = "1.3", features = ["spin_no_std"] } smoltcp = { version = "0.5.0", default-features = false, features = ["alloc", "log", "proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw"] } -bit-allocator = { path = "../crate/bit-allocator" } +bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator" } rcore-memory = { path = "../crate/memory" } -rcore-thread = { path = "../crate/thread" } +rcore-thread = { git = "https://github.com/rcore-os/rcore-thread" } rcore-fs = { git = "https://github.com/rcore-os/rcore-fs" } rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs" } diff --git a/kernel/src/arch/x86_64/memory.rs b/kernel/src/arch/x86_64/memory.rs index 325b0b8..cadd738 100644 --- a/kernel/src/arch/x86_64/memory.rs +++ b/kernel/src/arch/x86_64/memory.rs @@ -1,5 +1,5 @@ use crate::consts::KERNEL_OFFSET; -use bit_allocator::BitAlloc; +use bitmap_allocator::BitAlloc; // Depends on kernel use super::{BootInfo, MemoryRegionType}; use crate::memory::{active_table, alloc_frame, init_heap, FRAME_ALLOCATOR}; diff --git a/kernel/src/memory.rs b/kernel/src/memory.rs index f48a625..a58efcd 100644 --- a/kernel/src/memory.rs +++ b/kernel/src/memory.rs @@ -3,7 +3,7 @@ pub use crate::arch::paging::*; use crate::consts::MEMORY_OFFSET; use crate::process::process_unsafe; use crate::sync::SpinNoIrqLock; -use bit_allocator::BitAlloc; +use bitmap_allocator::BitAlloc; use buddy_system_allocator::LockedHeap; use lazy_static::*; use log::*; @@ -14,15 +14,15 @@ pub type MemorySet = rcore_memory::memory_set::MemorySet; // x86_64 support up to 64G memory #[cfg(target_arch = "x86_64")] -pub type FrameAlloc = bit_allocator::BitAlloc16M; +pub type FrameAlloc = bitmap_allocator::BitAlloc16M; // RISCV has 8M memory #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] -pub type FrameAlloc = bit_allocator::BitAlloc4K; +pub type FrameAlloc = bitmap_allocator::BitAlloc4K; // Raspberry Pi 3 has 1G memory #[cfg(target_arch = "aarch64")] -pub type FrameAlloc = bit_allocator::BitAlloc1M; +pub type FrameAlloc = bitmap_allocator::BitAlloc1M; lazy_static! { pub static ref FRAME_ALLOCATOR: SpinNoIrqLock = From 99bb25fa7dfec28aef208b622f77308622386c3d Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Thu, 4 Apr 2019 13:02:57 +0800 Subject: [PATCH 03/28] Typo: bit_allocator => bitmap_allocator --- kernel/src/arch/aarch64/memory.rs | 2 +- kernel/src/arch/riscv32/memory.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/src/arch/aarch64/memory.rs b/kernel/src/arch/aarch64/memory.rs index 49bb094..3663596 100644 --- a/kernel/src/arch/aarch64/memory.rs +++ b/kernel/src/arch/aarch64/memory.rs @@ -16,7 +16,7 @@ pub fn init() { } fn init_frame_allocator() { - use bit_allocator::BitAlloc; + use bitmap_allocator::BitAlloc; use core::ops::Range; let end = super::board::probe_memory() diff --git a/kernel/src/arch/riscv32/memory.rs b/kernel/src/arch/riscv32/memory.rs index b10bb2d..a846c11 100644 --- a/kernel/src/arch/riscv32/memory.rs +++ b/kernel/src/arch/riscv32/memory.rs @@ -26,7 +26,7 @@ pub fn init_other() { } fn init_frame_allocator() { - use bit_allocator::BitAlloc; + use bitmap_allocator::BitAlloc; use core::ops::Range; let mut ba = FRAME_ALLOCATOR.lock(); From 025007c8bfecffcffa1a32b852c6f25fc9729cac Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Thu, 4 Apr 2019 13:12:36 +0800 Subject: [PATCH 04/28] Upgrade rcore-thread for riscv fixes --- kernel/Cargo.lock | 2 +- user | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 18ff961..bb74065 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -368,7 +368,7 @@ dependencies = [ [[package]] name = "rcore-thread" version = "0.1.0" -source = "git+https://github.com/rcore-os/rcore-thread#470634bc15de1532ab255555ff71adf112fd52e8" +source = "git+https://github.com/rcore-os/rcore-thread#765ea6c7b97de4b154fd8b9b8b4678deb7d7c93b" dependencies = [ "deque 0.3.2 (git+https://github.com/rcore-os/deque.git?branch=no_std)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/user b/user index b1e7a2d..b09e4e2 160000 --- a/user +++ b/user @@ -1 +1 @@ -Subproject commit b1e7a2d07e81ce5035a1cc25b0ade9367aee1a94 +Subproject commit b09e4e24ad1cfe3b6eae2b40231f389070cdb9e2 From d3a462e8a0d8b5a129b7e039207220a9bef2e6d1 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Thu, 4 Apr 2019 14:32:58 +0800 Subject: [PATCH 05/28] Implement hdrincl for raw socket --- kernel/src/net/structs.rs | 89 ++++++++++++++++++++++++++------------- kernel/src/syscall/net.rs | 13 ++++-- 2 files changed, 69 insertions(+), 33 deletions(-) diff --git a/kernel/src/net/structs.rs b/kernel/src/net/structs.rs index bc076fb..719cc48 100644 --- a/kernel/src/net/structs.rs +++ b/kernel/src/net/structs.rs @@ -31,6 +31,10 @@ pub trait Socket: Send + Sync { fn remote_endpoint(&self) -> Option { None } + fn setsockopt(&mut self, level: usize, opt: usize, data: &[u8]) -> SysResult { + warn!("setsockopt is unimplemented"); + Ok(0) + } fn box_clone(&self) -> Box; } @@ -65,6 +69,7 @@ pub struct UdpSocketState { #[derive(Debug, Clone)] pub struct RawSocketState { handle: GlobalSocketHandle, + header_included: bool, } /// A wrapper for `SocketHandle`. @@ -469,7 +474,10 @@ impl RawSocketState { ); let handle = GlobalSocketHandle(SOCKETS.lock().add(socket)); - RawSocketState { handle } + RawSocketState { + handle, + header_included: false, + } } } @@ -499,41 +507,51 @@ impl Socket for RawSocketState { } fn write(&self, data: &[u8], sendto_endpoint: Option) -> SysResult { - if let Some(endpoint) = sendto_endpoint { - // temporary solution - let iface = &*(NET_DRIVERS.read()[0]); - let v4_src = iface.ipv4_address().unwrap(); + if self.header_included { let mut sockets = SOCKETS.lock(); let mut socket = sockets.get::(self.handle.0); - if let IpAddress::Ipv4(v4_dst) = endpoint.addr { - let len = data.len(); - // using 20-byte IPv4 header - let mut buffer = vec![0u8; len + 20]; - let mut packet = Ipv4Packet::new_unchecked(&mut buffer); - packet.set_version(4); - packet.set_header_len(20); - packet.set_total_len((20 + len) as u16); - packet.set_protocol(socket.ip_protocol().into()); - packet.set_src_addr(v4_src); - packet.set_dst_addr(v4_dst); - let payload = packet.payload_mut(); - payload.copy_from_slice(data); - packet.fill_checksum(); - - socket.send_slice(&buffer).unwrap(); + match socket.send_slice(&data) { + Ok(()) => Ok(data.len()), + Err(_) => Err(SysError::ENOBUFS), + } + } else { + if let Some(endpoint) = sendto_endpoint { + // temporary solution + let iface = &*(NET_DRIVERS.read()[0]); + let v4_src = iface.ipv4_address().unwrap(); + let mut sockets = SOCKETS.lock(); + let mut socket = sockets.get::(self.handle.0); + + if let IpAddress::Ipv4(v4_dst) = endpoint.addr { + let len = data.len(); + // using 20-byte IPv4 header + let mut buffer = vec![0u8; len + 20]; + let mut packet = Ipv4Packet::new_unchecked(&mut buffer); + packet.set_version(4); + packet.set_header_len(20); + packet.set_total_len((20 + len) as u16); + packet.set_protocol(socket.ip_protocol().into()); + packet.set_src_addr(v4_src); + packet.set_dst_addr(v4_dst); + let payload = packet.payload_mut(); + payload.copy_from_slice(data); + packet.fill_checksum(); + + socket.send_slice(&buffer).unwrap(); - // avoid deadlock - drop(socket); - drop(sockets); - iface.poll(); + // avoid deadlock + drop(socket); + drop(sockets); + iface.poll(); - Ok(len) + Ok(len) + } else { + unimplemented!("ip type") + } } else { - unimplemented!("ip type") + Err(SysError::ENOTCONN) } - } else { - Err(SysError::ENOTCONN) } } @@ -548,6 +566,19 @@ impl Socket for RawSocketState { fn box_clone(&self) -> Box { Box::new(self.clone()) } + + fn setsockopt(&mut self, level: usize, opt: usize, data: &[u8]) -> SysResult { + match (level, opt) { + (IPPROTO_IP, IP_HDRINCL) => { + if let Some(arg) = data.first() { + self.header_included = *arg > 0; + debug!("hdrincl set to {}", self.header_included); + } + } + _ => {} + } + Ok(0) + } } fn get_ephemeral_port() -> u16 { diff --git a/kernel/src/syscall/net.rs b/kernel/src/syscall/net.rs index 2811f12..fd303f0 100644 --- a/kernel/src/syscall/net.rs +++ b/kernel/src/syscall/net.rs @@ -34,15 +34,18 @@ pub fn sys_setsockopt( fd: usize, level: usize, optname: usize, - _optval: *const u8, - _optlen: usize, + optval: *const u8, + optlen: usize, ) -> SysResult { info!( "setsockopt: fd: {}, level: {}, optname: {}", fd, level, optname ); - warn!("sys_setsockopt is unimplemented"); - Ok(0) + let mut proc = process(); + proc.vm.check_read_array(optval, optlen)?; + let data = unsafe { slice::from_raw_parts(optval, optlen) }; + let socket = proc.get_socket(fd)?; + socket.setsockopt(level, optname, data) } pub fn sys_getsockopt( @@ -387,3 +390,5 @@ const SO_RCVBUF: usize = 8; const SO_LINGER: usize = 13; const TCP_CONGESTION: usize = 13; + +const IP_HDRINCL: usize = 3; From f028823e5a8486765663b88522b565deb98a3e8a Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Thu, 4 Apr 2019 18:44:30 +0800 Subject: [PATCH 06/28] Assign different IP addresses for different nics --- kernel/src/drivers/bus/pci.rs | 3 ++- kernel/src/drivers/net/e1000.rs | 7 ++++--- kernel/src/net/structs.rs | 6 +++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/kernel/src/drivers/bus/pci.rs b/kernel/src/drivers/bus/pci.rs index 6a143c8..1f76b3e 100644 --- a/kernel/src/drivers/bus/pci.rs +++ b/kernel/src/drivers/bus/pci.rs @@ -118,7 +118,8 @@ pub fn init_driver(dev: &PCIDevice) { active_table().map_if_not_exists(KERNEL_OFFSET + current_addr, current_addr); current_addr = current_addr + PAGE_SIZE; } - e1000::e1000_init(name, irq, vaddr, len as usize); + let index = NET_DRIVERS.read().len(); + e1000::e1000_init(name, irq, vaddr, len as usize, index); } } (0x8086, 0x10fb) => { diff --git a/kernel/src/drivers/net/e1000.rs b/kernel/src/drivers/net/e1000.rs index fb32d8f..7461098 100644 --- a/kernel/src/drivers/net/e1000.rs +++ b/kernel/src/drivers/net/e1000.rs @@ -337,7 +337,7 @@ bitflags! { } // JudgeDuck-OS/kern/e1000.c -pub fn e1000_init(name: String, irq: Option, header: usize, size: usize) { +pub fn e1000_init(name: String, irq: Option, header: usize, size: usize, index: usize) { info!("Probing e1000 {}", name); assert_eq!(size_of::(), 16); assert_eq!(size_of::(), 16); @@ -357,7 +357,7 @@ pub fn e1000_init(name: String, irq: Option, header: usize, size: usize) { let mut recv_queue = unsafe { slice::from_raw_parts_mut(recv_page as *mut E1000RecvDesc, recv_queue_size) }; // randomly generated - let mac: [u8; 6] = [0x54, 0x51, 0x9F, 0x71, 0xC0, 0x3C]; + let mac: [u8; 6] = [0x54, 0x51, 0x9F, 0x71, 0xC0, index as u8]; let mut driver = E1000 { header, @@ -468,7 +468,7 @@ pub fn e1000_init(name: String, irq: Option, header: usize, size: usize) { let net_driver = E1000Driver(Arc::new(Mutex::new(driver))); let ethernet_addr = EthernetAddress::from_bytes(&mac); - let ip_addrs = [IpCidr::new(IpAddress::v4(10, 0, 0, 2), 24)]; + let ip_addrs = [IpCidr::new(IpAddress::v4(10, 0, index as u8, 2), 24)]; let neighbor_cache = NeighborCache::new(BTreeMap::new()); let iface = EthernetInterfaceBuilder::new(net_driver.clone()) .ethernet_addr(ethernet_addr) @@ -476,6 +476,7 @@ pub fn e1000_init(name: String, irq: Option, header: usize, size: usize) { .neighbor_cache(neighbor_cache) .finalize(); + info!("e1000 interface {} has addr 10.0.{}.2/24", name, index); let e1000_iface = E1000Interface { iface: Mutex::new(iface), driver: net_driver.clone(), diff --git a/kernel/src/net/structs.rs b/kernel/src/net/structs.rs index 719cc48..3238661 100644 --- a/kernel/src/net/structs.rs +++ b/kernel/src/net/structs.rs @@ -611,6 +611,6 @@ const UDP_METADATA_BUF: usize = 1024; const UDP_SENDBUF: usize = 64 * 1024; // 64K const UDP_RECVBUF: usize = 64 * 1024; // 64K -const RAW_METADATA_BUF: usize = 2; -const RAW_SENDBUF: usize = 2 * 1024; // 2K -const RAW_RECVBUF: usize = 2 * 1024; // 2K +const RAW_METADATA_BUF: usize = 1024; +const RAW_SENDBUF: usize = 64 * 1024; // 64K +const RAW_RECVBUF: usize = 64 * 1024; // 64K From 77f8afa30cba671f3fde3afac0d5a86da5418ae5 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Thu, 4 Apr 2019 20:01:59 +0800 Subject: [PATCH 07/28] Refactor network endpoint, and add basic support for sockaddr_ll --- kernel/src/lib.rs | 3 +- kernel/src/net/structs.rs | 234 +++++++++++++++++++++++++------------- kernel/src/syscall/net.rs | 116 +++++++++++++------ kernel/src/util/mod.rs | 55 +++++++++ 4 files changed, 293 insertions(+), 115 deletions(-) diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 20ff71a..53a9cc2 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -22,6 +22,8 @@ use rcore_thread::std_thread as thread; #[macro_use] // print! mod logging; +#[macro_use] +mod util; mod backtrace; mod consts; mod drivers; @@ -34,7 +36,6 @@ mod shell; mod sync; mod syscall; mod trap; -mod util; #[allow(dead_code)] #[cfg(target_arch = "x86_64")] diff --git a/kernel/src/net/structs.rs b/kernel/src/net/structs.rs index 3238661..6a9e569 100644 --- a/kernel/src/net/structs.rs +++ b/kernel/src/net/structs.rs @@ -7,13 +7,22 @@ use alloc::boxed::Box; use smoltcp::socket::*; use smoltcp::wire::*; -/// +#[derive(Clone, Debug)] +pub struct LinkLevelEndpoint {} + +#[derive(Clone, Debug)] +pub enum Endpoint { + Ip(IpEndpoint), + LinkLevel(LinkLevelEndpoint), +} + +/// Common methods that a socket must have pub trait Socket: Send + Sync { - fn read(&self, data: &mut [u8]) -> (SysResult, IpEndpoint); - fn write(&self, data: &[u8], sendto_endpoint: Option) -> SysResult; + fn read(&self, data: &mut [u8]) -> (SysResult, Endpoint); + fn write(&self, data: &[u8], sendto_endpoint: Option) -> SysResult; fn poll(&self) -> (bool, bool, bool); // (in, out, err) - fn connect(&mut self, endpoint: IpEndpoint) -> SysResult; - fn bind(&mut self, endpoint: IpEndpoint) -> SysResult { + fn connect(&mut self, endpoint: Endpoint) -> SysResult; + fn bind(&mut self, endpoint: Endpoint) -> SysResult { Err(SysError::EINVAL) } fn listen(&mut self) -> SysResult { @@ -22,13 +31,13 @@ pub trait Socket: Send + Sync { fn shutdown(&self) -> SysResult { Err(SysError::EINVAL) } - fn accept(&mut self) -> Result<(Box, IpEndpoint), SysError> { + fn accept(&mut self) -> Result<(Box, Endpoint), SysError> { Err(SysError::EINVAL) } - fn endpoint(&self) -> Option { + fn endpoint(&self) -> Option { None } - fn remote_endpoint(&self) -> Option { + fn remote_endpoint(&self) -> Option { None } fn setsockopt(&mut self, level: usize, opt: usize, data: &[u8]) -> SysResult { @@ -72,6 +81,12 @@ pub struct RawSocketState { header_included: bool, } +#[derive(Debug, Clone)] +pub struct PacketSocketState { + // no state +// only ethernet egress +} + /// A wrapper for `SocketHandle`. /// Auto increase and decrease reference count on Clone and Drop. #[derive(Debug)] @@ -112,7 +127,7 @@ impl TcpSocketState { } impl Socket for TcpSocketState { - fn read(&self, data: &mut [u8]) -> (SysResult, IpEndpoint) { + fn read(&self, data: &mut [u8]) -> (SysResult, Endpoint) { spin_and_wait(&[&SOCKET_ACTIVITY], move || { poll_ifaces(); let mut sockets = SOCKETS.lock(); @@ -127,17 +142,20 @@ impl Socket for TcpSocketState { drop(sockets); poll_ifaces(); - return Some((Ok(size), endpoint)); + return Some((Ok(size), Endpoint::Ip(endpoint))); } } } else { - return Some((Err(SysError::ENOTCONN), IpEndpoint::UNSPECIFIED)); + return Some(( + Err(SysError::ENOTCONN), + Endpoint::Ip(IpEndpoint::UNSPECIFIED), + )); } None }) } - fn write(&self, data: &[u8], sendto_endpoint: Option) -> SysResult { + fn write(&self, data: &[u8], sendto_endpoint: Option) -> SysResult { let mut sockets = SOCKETS.lock(); let mut socket = sockets.get::(self.handle.0); @@ -183,52 +201,60 @@ impl Socket for TcpSocketState { (input, output, err) } - fn connect(&mut self, endpoint: IpEndpoint) -> SysResult { + fn connect(&mut self, endpoint: Endpoint) -> SysResult { let mut sockets = SOCKETS.lock(); let mut socket = sockets.get::(self.handle.0); - let temp_port = get_ephemeral_port(); + if let Endpoint::Ip(ip) = endpoint { + let temp_port = get_ephemeral_port(); - match socket.connect(endpoint, temp_port) { - Ok(()) => { - // avoid deadlock - drop(socket); - drop(sockets); + match socket.connect(ip, temp_port) { + Ok(()) => { + // avoid deadlock + drop(socket); + drop(sockets); - // wait for connection result - loop { - poll_ifaces(); + // wait for connection result + loop { + poll_ifaces(); - let mut sockets = SOCKETS.lock(); - let socket = sockets.get::(self.handle.0); - match socket.state() { - TcpState::SynSent => { - // still connecting - drop(socket); - drop(sockets); - debug!("poll for connection wait"); - SOCKET_ACTIVITY._wait(); - } - TcpState::Established => { - break Ok(0); - } - _ => { - break Err(SysError::ECONNREFUSED); + let mut sockets = SOCKETS.lock(); + let socket = sockets.get::(self.handle.0); + match socket.state() { + TcpState::SynSent => { + // still connecting + drop(socket); + drop(sockets); + debug!("poll for connection wait"); + SOCKET_ACTIVITY._wait(); + } + TcpState::Established => { + break Ok(0); + } + _ => { + break Err(SysError::ECONNREFUSED); + } } } } + Err(_) => Err(SysError::ENOBUFS), } - Err(_) => Err(SysError::ENOBUFS), + } else { + Err(SysError::EINVAL) } } - fn bind(&mut self, mut endpoint: IpEndpoint) -> SysResult { - if endpoint.port == 0 { - endpoint.port = get_ephemeral_port(); + fn bind(&mut self, mut endpoint: Endpoint) -> SysResult { + if let Endpoint::Ip(mut ip) = endpoint { + if ip.port == 0 { + ip.port = get_ephemeral_port(); + } + self.local_endpoint = Some(ip); + self.is_listening = false; + Ok(0) + } else { + Err(SysError::EINVAL) } - self.local_endpoint = Some(endpoint); - self.is_listening = false; - Ok(0) } fn listen(&mut self) -> SysResult { @@ -260,7 +286,7 @@ impl Socket for TcpSocketState { Ok(0) } - fn accept(&mut self) -> Result<(Box, IpEndpoint), SysError> { + fn accept(&mut self) -> Result<(Box, Endpoint), SysError> { let endpoint = self.local_endpoint.ok_or(SysError::EINVAL)?; loop { let mut sockets = SOCKETS.lock(); @@ -287,7 +313,7 @@ impl Socket for TcpSocketState { drop(sockets); poll_ifaces(); - return Ok((new_socket, remote_endpoint)); + return Ok((new_socket, Endpoint::Ip(remote_endpoint))); } // avoid deadlock @@ -297,24 +323,27 @@ impl Socket for TcpSocketState { } } - fn endpoint(&self) -> Option { - self.local_endpoint.clone().or_else(|| { - let mut sockets = SOCKETS.lock(); - let socket = sockets.get::(self.handle.0); - let endpoint = socket.local_endpoint(); - if endpoint.port != 0 { - Some(endpoint) - } else { - None - } - }) + fn endpoint(&self) -> Option { + self.local_endpoint + .clone() + .map(|e| Endpoint::Ip(e)) + .or_else(|| { + let mut sockets = SOCKETS.lock(); + let socket = sockets.get::(self.handle.0); + let endpoint = socket.local_endpoint(); + if endpoint.port != 0 { + Some(Endpoint::Ip(endpoint)) + } else { + None + } + }) } - fn remote_endpoint(&self) -> Option { + fn remote_endpoint(&self) -> Option { let mut sockets = SOCKETS.lock(); let socket = sockets.get::(self.handle.0); if socket.is_open() { - Some(socket.remote_endpoint()) + Some(Endpoint::Ip(socket.remote_endpoint())) } else { None } @@ -346,7 +375,7 @@ impl UdpSocketState { } impl Socket for UdpSocketState { - fn read(&self, data: &mut [u8]) -> (SysResult, IpEndpoint) { + fn read(&self, data: &mut [u8]) -> (SysResult, Endpoint) { loop { let mut sockets = SOCKETS.lock(); let mut socket = sockets.get::(self.handle.0); @@ -359,10 +388,13 @@ impl Socket for UdpSocketState { drop(sockets); poll_ifaces(); - return (Ok(size), endpoint); + return (Ok(size), Endpoint::Ip(endpoint)); } } else { - return (Err(SysError::ENOTCONN), IpEndpoint::UNSPECIFIED); + return ( + Err(SysError::ENOTCONN), + Endpoint::Ip(IpEndpoint::UNSPECIFIED), + ); } // avoid deadlock @@ -371,9 +403,9 @@ impl Socket for UdpSocketState { } } - fn write(&self, data: &[u8], sendto_endpoint: Option) -> SysResult { + fn write(&self, data: &[u8], sendto_endpoint: Option) -> SysResult { let remote_endpoint = { - if let Some(ref endpoint) = sendto_endpoint { + if let Some(Endpoint::Ip(ref endpoint)) = sendto_endpoint { endpoint } else if let Some(ref endpoint) = self.remote_endpoint { endpoint @@ -422,33 +454,41 @@ impl Socket for UdpSocketState { (input, output, err) } - fn connect(&mut self, endpoint: IpEndpoint) -> SysResult { - self.remote_endpoint = Some(endpoint); - Ok(0) + fn connect(&mut self, endpoint: Endpoint) -> SysResult { + if let Endpoint::Ip(ip) = endpoint { + self.remote_endpoint = Some(ip); + Ok(0) + } else { + Err(SysError::EINVAL) + } } - fn bind(&mut self, endpoint: IpEndpoint) -> SysResult { + fn bind(&mut self, endpoint: Endpoint) -> SysResult { let mut sockets = SOCKETS.lock(); let mut socket = sockets.get::(self.handle.0); - match socket.bind(endpoint) { - Ok(()) => Ok(0), - Err(_) => Err(SysError::EINVAL), + if let Endpoint::Ip(ip) = endpoint { + match socket.bind(ip) { + Ok(()) => Ok(0), + Err(_) => Err(SysError::EINVAL), + } + } else { + Err(SysError::EINVAL) } } - fn endpoint(&self) -> Option { + fn endpoint(&self) -> Option { let mut sockets = SOCKETS.lock(); let socket = sockets.get::(self.handle.0); let endpoint = socket.endpoint(); if endpoint.port != 0 { - Some(endpoint) + Some(Endpoint::Ip(endpoint)) } else { None } } - fn remote_endpoint(&self) -> Option { - self.remote_endpoint.clone() + fn remote_endpoint(&self) -> Option { + self.remote_endpoint.clone().map(|e| Endpoint::Ip(e)) } fn box_clone(&self) -> Box { @@ -482,7 +522,7 @@ impl RawSocketState { } impl Socket for RawSocketState { - fn read(&self, data: &mut [u8]) -> (SysResult, IpEndpoint) { + fn read(&self, data: &mut [u8]) -> (SysResult, Endpoint) { loop { let mut sockets = SOCKETS.lock(); let mut socket = sockets.get::(self.handle.0); @@ -492,10 +532,10 @@ impl Socket for RawSocketState { return ( Ok(size), - IpEndpoint { + Endpoint::Ip(IpEndpoint { addr: IpAddress::Ipv4(packet.src_addr()), port: 0, - }, + }), ); } @@ -506,7 +546,7 @@ impl Socket for RawSocketState { } } - fn write(&self, data: &[u8], sendto_endpoint: Option) -> SysResult { + fn write(&self, data: &[u8], sendto_endpoint: Option) -> SysResult { if self.header_included { let mut sockets = SOCKETS.lock(); let mut socket = sockets.get::(self.handle.0); @@ -516,7 +556,7 @@ impl Socket for RawSocketState { Err(_) => Err(SysError::ENOBUFS), } } else { - if let Some(endpoint) = sendto_endpoint { + if let Some(Endpoint::Ip(endpoint)) = sendto_endpoint { // temporary solution let iface = &*(NET_DRIVERS.read()[0]); let v4_src = iface.ipv4_address().unwrap(); @@ -559,7 +599,7 @@ impl Socket for RawSocketState { unimplemented!() } - fn connect(&mut self, _endpoint: IpEndpoint) -> SysResult { + fn connect(&mut self, _endpoint: Endpoint) -> SysResult { unimplemented!() } @@ -581,6 +621,38 @@ impl Socket for RawSocketState { } } +impl PacketSocketState { + pub fn new() -> Self { + PacketSocketState {} + } +} + +impl Socket for PacketSocketState { + fn read(&self, data: &mut [u8]) -> (SysResult, Endpoint) { + unimplemented!() + } + + fn write(&self, data: &[u8], sendto_endpoint: Option) -> SysResult { + if let Some(endpoint) = sendto_endpoint { + unimplemented!() + } else { + Err(SysError::ENOTCONN) + } + } + + fn poll(&self) -> (bool, bool, bool) { + unimplemented!() + } + + fn connect(&mut self, _endpoint: Endpoint) -> SysResult { + unimplemented!() + } + + fn box_clone(&self) -> Box { + Box::new(self.clone()) + } +} + fn get_ephemeral_port() -> u16 { // TODO selects non-conflict high port static mut EPHEMERAL_PORT: u16 = 0; diff --git a/kernel/src/syscall/net.rs b/kernel/src/syscall/net.rs index fd303f0..71aca45 100644 --- a/kernel/src/syscall/net.rs +++ b/kernel/src/syscall/net.rs @@ -3,7 +3,9 @@ use super::*; use crate::drivers::SOCKET_ACTIVITY; use crate::fs::FileLike; -use crate::net::{RawSocketState, Socket, TcpSocketState, UdpSocketState, SOCKETS}; +use crate::net::{ + Endpoint, PacketSocketState, RawSocketState, Socket, TcpSocketState, UdpSocketState, SOCKETS, +}; use crate::sync::{MutexGuard, SpinNoIrq, SpinNoIrqLock as Mutex}; use alloc::boxed::Box; use core::cmp::min; @@ -11,16 +13,23 @@ use core::mem::size_of; use smoltcp::wire::*; pub fn sys_socket(domain: usize, socket_type: usize, protocol: usize) -> SysResult { + let domain = AddressFamily::from(domain as u16); info!( - "socket: domain: {}, socket_type: {}, protocol: {}", + "socket: domain: {:?}, socket_type: {}, protocol: {}", domain, socket_type, protocol ); let mut proc = process(); let socket: Box = match domain { - AF_INET | AF_UNIX => match socket_type & SOCK_TYPE_MASK { - SOCK_STREAM => Box::new(TcpSocketState::new()), - SOCK_DGRAM => Box::new(UdpSocketState::new()), - SOCK_RAW => Box::new(RawSocketState::new(protocol as u8)), + AddressFamily::Internet | AddressFamily::Unix => { + match SocketType::from(socket_type as u8 & SOCK_TYPE_MASK) { + SocketType::Stream => Box::new(TcpSocketState::new()), + SocketType::Datagram => Box::new(UdpSocketState::new()), + SocketType::Raw => Box::new(RawSocketState::new(protocol as u8)), + _ => return Err(SysError::EINVAL), + } + } + AddressFamily::Packet => match SocketType::from(socket_type as u8 & SOCK_TYPE_MASK) { + SocketType::Raw => Box::new(PacketSocketState::new()), _ => return Err(SysError::EINVAL), }, _ => return Err(SysError::EAFNOSUPPORT), @@ -165,7 +174,7 @@ pub fn sys_bind(fd: usize, addr: *const SockAddr, addr_len: usize) -> SysResult let mut proc = process(); let mut endpoint = sockaddr_to_endpoint(&mut proc, addr, addr_len)?; - info!("sys_bind: fd: {} bind to {}", fd, endpoint); + info!("sys_bind: fd: {} bind to {:?}", fd, endpoint); let socket = proc.get_socket(fd)?; socket.bind(endpoint) @@ -279,10 +288,21 @@ pub struct SockAddrUn { sun_path: [u8; 108], } +#[repr(C)] +pub struct SockAddrLl { + sll_protocol: u16, + sll_ifindex: u32, + sll_hatype: u16, + sll_pkttype: u8, + sll_halen: u8, + sll_addr: u8, +} + #[repr(C)] pub union SockAddrPayload { addr_in: SockAddrIn, addr_un: SockAddrUn, + addr_ll: SockAddrLl, } #[repr(C)] @@ -291,20 +311,24 @@ pub struct SockAddr { payload: SockAddrPayload, } -impl From for SockAddr { - fn from(endpoint: IpEndpoint) -> Self { - match endpoint.addr { - IpAddress::Ipv4(ipv4) => SockAddr { - family: AF_INET as u16, - payload: SockAddrPayload { - addr_in: SockAddrIn { - sin_port: u16::to_be(endpoint.port), - sin_addr: u32::to_be(u32::from_be_bytes(ipv4.0)), - sin_zero: [0; 8], +impl From for SockAddr { + fn from(endpoint: Endpoint) -> Self { + if let Endpoint::Ip(ip) = endpoint { + match ip.addr { + IpAddress::Ipv4(ipv4) => SockAddr { + family: AddressFamily::Internet.into(), + payload: SockAddrPayload { + addr_in: SockAddrIn { + sin_port: u16::to_be(ip.port), + sin_addr: u32::to_be(u32::from_be_bytes(ipv4.0)), + sin_zero: [0; 8], + }, }, }, - }, - _ => unimplemented!("ipv6"), + _ => unimplemented!("only ipv4"), + } + } else { + unimplemented!("only ip"); } } } @@ -315,14 +339,14 @@ fn sockaddr_to_endpoint( proc: &mut Process, addr: *const SockAddr, len: usize, -) -> Result { +) -> Result { if len < size_of::() { return Err(SysError::EINVAL); } proc.vm.check_read_array(addr as *const u8, len)?; unsafe { - match (*addr).family as usize { - AF_INET => { + match AddressFamily::from((*addr).family) { + AddressFamily::Internet => { if len < size_of::() + size_of::() { return Err(SysError::EINVAL); } @@ -330,9 +354,15 @@ fn sockaddr_to_endpoint( let addr = IpAddress::from(Ipv4Address::from_bytes( &u32::from_be((*addr).payload.addr_in.sin_addr).to_be_bytes()[..], )); - Ok((addr, port).into()) + Ok(Endpoint::Ip((addr, port).into())) + } + AddressFamily::Unix => Err(SysError::EINVAL), + AddressFamily::Packet => { + if len < size_of::() + size_of::() { + return Err(SysError::EINVAL); + } + unimplemented!() } - AF_UNIX => Err(SysError::EINVAL), _ => Err(SysError::EINVAL), } } @@ -354,9 +384,9 @@ impl SockAddr { proc.vm.check_write_ptr(addr_len)?; let max_addr_len = *addr_len as usize; - let full_len = match self.family as usize { - AF_INET => size_of::() + size_of::(), - AF_UNIX => return Err(SysError::EINVAL), + let full_len = match AddressFamily::from(self.family) { + AddressFamily::Internet => size_of::() + size_of::(), + AddressFamily::Unix => return Err(SysError::EINVAL), _ => return Err(SysError::EINVAL), }; @@ -372,13 +402,33 @@ impl SockAddr { } } -const AF_UNIX: usize = 1; -const AF_INET: usize = 2; +enum_with_unknown! { + /// Address families + pub doc enum AddressFamily(u16) { + /// Unspecified + Unspecified = 0, + /// Unix domain sockets + Unix = 1, + /// Internet IP Protocol + Internet = 2, + /// Packet family + Packet = 17, + } +} -const SOCK_STREAM: usize = 1; -const SOCK_DGRAM: usize = 2; -const SOCK_RAW: usize = 3; -const SOCK_TYPE_MASK: usize = 0xf; +const SOCK_TYPE_MASK: u8 = 0xf; + +enum_with_unknown! { + /// Socket types + pub doc enum SocketType(u8) { + /// Stream + Stream = 1, + /// Datagram + Datagram = 2, + /// Raw + Raw = 3, + } +} const IPPROTO_IP: usize = 0; const IPPROTO_ICMP: usize = 1; diff --git a/kernel/src/util/mod.rs b/kernel/src/util/mod.rs index 0c6df60..582f101 100644 --- a/kernel/src/util/mod.rs +++ b/kernel/src/util/mod.rs @@ -13,3 +13,58 @@ pub unsafe fn write_cstr(ptr: *mut u8, s: &str) { ptr.copy_from(s.as_ptr(), s.len()); ptr.add(s.len()).write(0); } + +// Taken from m-labs/smoltcp src/macros.rs, thanks for their contribution +// https://github.com/m-labs/smoltcp/blob/master/src/macros.rs +macro_rules! enum_with_unknown { + ( + $( #[$enum_attr:meta] )* + pub enum $name:ident($ty:ty) { + $( $variant:ident = $value:expr ),+ $(,)* + } + ) => { + enum_with_unknown! { + $( #[$enum_attr] )* + pub doc enum $name($ty) { + $( #[doc(shown)] $variant = $value ),+ + } + } + }; + ( + $( #[$enum_attr:meta] )* + pub doc enum $name:ident($ty:ty) { + $( + $( #[$variant_attr:meta] )+ + $variant:ident = $value:expr $(,)* + ),+ + } + ) => { + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] + $( #[$enum_attr] )* + pub enum $name { + $( + $( #[$variant_attr] )* + $variant + ),*, + Unknown($ty) + } + + impl ::core::convert::From<$ty> for $name { + fn from(value: $ty) -> Self { + match value { + $( $value => $name::$variant ),*, + other => $name::Unknown(other) + } + } + } + + impl ::core::convert::From<$name> for $ty { + fn from(value: $name) -> Self { + match value { + $( $name::$variant => $value ),*, + $name::Unknown(other) => other + } + } + } + } +} From c944d2269db71f14b8ee2fc59b859bec0e032bdf Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Thu, 4 Apr 2019 20:31:46 +0800 Subject: [PATCH 08/28] Enable user to send to iface directly via packet socket --- kernel/src/drivers/mod.rs | 5 +++++ kernel/src/drivers/net/e1000.rs | 17 +++++++++++++++++ kernel/src/net/structs.rs | 20 +++++++++++++++++--- kernel/src/syscall/net.rs | 12 ++++++++---- 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/kernel/src/drivers/mod.rs b/kernel/src/drivers/mod.rs index 61e64bb..c9c0cd5 100644 --- a/kernel/src/drivers/mod.rs +++ b/kernel/src/drivers/mod.rs @@ -66,6 +66,11 @@ pub trait Driver: Send + Sync { unimplemented!("not a net driver") } + // send an ethernet frame, only use it when necessary + fn send(&self, data: &[u8]) -> Option { + unimplemented!("not a net driver") + } + // block related drivers should implement these fn read_block(&self, block_id: usize, buf: &mut [u8]) -> bool { unimplemented!("not a block driver") diff --git a/kernel/src/drivers/net/e1000.rs b/kernel/src/drivers/net/e1000.rs index 7461098..39a9133 100644 --- a/kernel/src/drivers/net/e1000.rs +++ b/kernel/src/drivers/net/e1000.rs @@ -149,6 +149,23 @@ impl Driver for E1000Interface { } } } + + // send an ethernet frame, only use it when necessary + fn send(&self, data: &[u8]) -> Option { + use smoltcp::phy::TxToken; + let token = E1000TxToken(self.driver.clone()); + if token + .consume(Instant::from_millis(0), data.len(), |buffer| { + buffer.copy_from_slice(&data); + Ok(()) + }) + .is_ok() + { + Some(data.len()) + } else { + None + } + } } #[repr(C)] diff --git a/kernel/src/net/structs.rs b/kernel/src/net/structs.rs index 6a9e569..064dfaa 100644 --- a/kernel/src/net/structs.rs +++ b/kernel/src/net/structs.rs @@ -8,7 +8,17 @@ use smoltcp::socket::*; use smoltcp::wire::*; #[derive(Clone, Debug)] -pub struct LinkLevelEndpoint {} +pub struct LinkLevelEndpoint { + interface_index: usize, +} + +impl LinkLevelEndpoint { + pub fn new(ifindex: usize) -> Self { + LinkLevelEndpoint { + interface_index: ifindex, + } + } +} #[derive(Clone, Debug)] pub enum Endpoint { @@ -633,8 +643,12 @@ impl Socket for PacketSocketState { } fn write(&self, data: &[u8], sendto_endpoint: Option) -> SysResult { - if let Some(endpoint) = sendto_endpoint { - unimplemented!() + if let Some(Endpoint::LinkLevel(endpoint)) = sendto_endpoint { + let ifaces = NET_DRIVERS.read(); + match ifaces[endpoint.interface_index].send(data) { + Some(len) => Ok(len), + None => Err(SysError::ENOBUFS), + } } else { Err(SysError::ENOTCONN) } diff --git a/kernel/src/syscall/net.rs b/kernel/src/syscall/net.rs index 71aca45..a39c55b 100644 --- a/kernel/src/syscall/net.rs +++ b/kernel/src/syscall/net.rs @@ -4,7 +4,8 @@ use super::*; use crate::drivers::SOCKET_ACTIVITY; use crate::fs::FileLike; use crate::net::{ - Endpoint, PacketSocketState, RawSocketState, Socket, TcpSocketState, UdpSocketState, SOCKETS, + Endpoint, LinkLevelEndpoint, PacketSocketState, RawSocketState, Socket, TcpSocketState, + UdpSocketState, SOCKETS, }; use crate::sync::{MutexGuard, SpinNoIrq, SpinNoIrqLock as Mutex}; use alloc::boxed::Box; @@ -288,14 +289,15 @@ pub struct SockAddrUn { sun_path: [u8; 108], } -#[repr(C)] +// beware of alignment issue +#[repr(C, packed)] pub struct SockAddrLl { sll_protocol: u16, sll_ifindex: u32, sll_hatype: u16, sll_pkttype: u8, sll_halen: u8, - sll_addr: u8, + sll_addr: [u8; 8], } #[repr(C)] @@ -361,7 +363,9 @@ fn sockaddr_to_endpoint( if len < size_of::() + size_of::() { return Err(SysError::EINVAL); } - unimplemented!() + Ok(Endpoint::LinkLevel(LinkLevelEndpoint::new( + (*addr).payload.addr_ll.sll_ifindex as usize, + ))) } _ => Err(SysError::EINVAL), } From 55df9ca8923b8afb6021f584e5e049fcfdda29e5 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Thu, 4 Apr 2019 21:38:32 +0800 Subject: [PATCH 09/28] Initial support for ioctl SIOCGARP --- kernel/Cargo.toml | 2 +- kernel/src/fs/file_like.rs | 9 ++++++++ kernel/src/net/structs.rs | 43 ++++++++++++++++++++++++++++++++++++++ kernel/src/syscall/fs.rs | 10 +++++++++ kernel/src/syscall/mod.rs | 2 +- kernel/src/syscall/net.rs | 36 ++++++++++++++++++------------- 6 files changed, 85 insertions(+), 17 deletions(-) diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 5c06128..3cf9eee 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -49,7 +49,7 @@ pci = { git = "https://github.com/rcore-os/pci-rs" } device_tree = { git = "https://github.com/rcore-os/device_tree-rs" } isomorphic_drivers = { git = "https://github.com/rcore-os/isomorphic_drivers" } lazy_static = { version = "1.3", features = ["spin_no_std"] } -smoltcp = { version = "0.5.0", default-features = false, features = ["alloc", "log", "proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw"] } +smoltcp = { git = "https://github.com/rcore-os/smoltcp", default-features = false, features = ["alloc", "log", "proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw"] } bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator" } rcore-memory = { path = "../crate/memory" } rcore-thread = { git = "https://github.com/rcore-os/rcore-thread" } diff --git a/kernel/src/fs/file_like.rs b/kernel/src/fs/file_like.rs index d765f2c..bd1f660 100644 --- a/kernel/src/fs/file_like.rs +++ b/kernel/src/fs/file_like.rs @@ -28,6 +28,15 @@ impl FileLike { }; Ok(len) } + pub fn ioctl(&mut self, request: usize, arg1: usize, arg2: usize, arg3: usize) -> SysResult { + match self { + FileLike::File(file) => { + warn!("ioctl not implemented for file"); + Ok(0) + } + FileLike::Socket(socket) => socket.ioctl(request, arg1, arg2, arg3), + } + } } impl fmt::Debug for FileLike { diff --git a/kernel/src/net/structs.rs b/kernel/src/net/structs.rs index 064dfaa..0331219 100644 --- a/kernel/src/net/structs.rs +++ b/kernel/src/net/structs.rs @@ -2,6 +2,7 @@ use crate::arch::rand; use crate::drivers::{NET_DRIVERS, SOCKET_ACTIVITY}; use crate::sync::SpinNoIrqLock as Mutex; use crate::syscall::*; +use crate::util; use alloc::boxed::Box; use smoltcp::socket::*; @@ -54,6 +55,10 @@ pub trait Socket: Send + Sync { warn!("setsockopt is unimplemented"); Ok(0) } + fn ioctl(&mut self, request: usize, arg1: usize, arg2: usize, arg3: usize) -> SysResult { + warn!("ioctl is unimplemented for this socket"); + Ok(0) + } fn box_clone(&self) -> Box; } @@ -384,6 +389,15 @@ impl UdpSocketState { } } +#[repr(C)] +struct ArpReq { + arp_pa: SockAddrPlaceholder, + arp_ha: SockAddrPlaceholder, + arp_flags: u32, + arp_netmask: SockAddrPlaceholder, + arp_dev: [u8; 16], +} + impl Socket for UdpSocketState { fn read(&self, data: &mut [u8]) -> (SysResult, Endpoint) { loop { @@ -486,6 +500,35 @@ impl Socket for UdpSocketState { } } + fn ioctl(&mut self, request: usize, arg1: usize, arg2: usize, arg3: usize) -> SysResult { + match request { + // SIOCGARP + 0x8954 => { + // FIXME: check addr + let req = unsafe { &mut *(request as *mut ArpReq) }; + if let AddressFamily::Internet = AddressFamily::from(req.arp_pa.family) { + let name = req.arp_dev.as_ptr(); + let ifname = unsafe { util::from_cstr(name) }; + let addr = &req.arp_pa as *const SockAddrPlaceholder as *const SockAddr; + let addr = unsafe { + IpAddress::from(Ipv4Address::from_bytes( + &u32::from_be((*addr).payload.addr_in.sin_addr).to_be_bytes()[..], + )) + }; + for iface in NET_DRIVERS.read().iter() { + if iface.get_ifname() == ifname { + debug!("get arp matched ifname {}", ifname); + } + } + Err(SysError::ENOENT) + } else { + Err(SysError::EINVAL) + } + } + _ => Ok(0), + } + } + fn endpoint(&self) -> Option { let mut sockets = SOCKETS.lock(); let socket = sockets.get::(self.handle.0); diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index a2636a2..5f7d547 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -472,6 +472,16 @@ pub fn sys_dup2(fd1: usize, fd2: usize) -> SysResult { Ok(fd2) } +pub fn sys_ioctl(fd: usize, request: usize, arg1: usize, arg2: usize, arg3: usize) -> SysResult { + info!( + "ioctl: fd:{}, request:{}, args: {} {} {}", + fd, request, arg1, arg2, arg3 + ); + let mut proc = process(); + let file_like = proc.get_file_like(fd)?; + file_like.ioctl(request, arg1, arg2, arg3) +} + pub fn sys_chdir(path: *const u8) -> SysResult { let mut proc = process(); let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index d8fc481..658992e 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -19,7 +19,7 @@ use self::custom::*; use self::fs::*; use self::mem::*; use self::misc::*; -use self::net::*; +pub use self::net::*; use self::proc::*; use self::time::*; diff --git a/kernel/src/syscall/net.rs b/kernel/src/syscall/net.rs index a39c55b..ad62598 100644 --- a/kernel/src/syscall/net.rs +++ b/kernel/src/syscall/net.rs @@ -279,38 +279,44 @@ impl Process { // cancel alignment #[repr(packed)] pub struct SockAddrIn { - sin_port: u16, - sin_addr: u32, - sin_zero: [u8; 8], + pub sin_port: u16, + pub sin_addr: u32, + pub sin_zero: [u8; 8], } #[repr(C)] pub struct SockAddrUn { - sun_path: [u8; 108], + pub sun_path: [u8; 108], } // beware of alignment issue #[repr(C, packed)] pub struct SockAddrLl { - sll_protocol: u16, - sll_ifindex: u32, - sll_hatype: u16, - sll_pkttype: u8, - sll_halen: u8, - sll_addr: [u8; 8], + pub sll_protocol: u16, + pub sll_ifindex: u32, + pub sll_hatype: u16, + pub sll_pkttype: u8, + pub sll_halen: u8, + pub sll_addr: [u8; 8], } #[repr(C)] pub union SockAddrPayload { - addr_in: SockAddrIn, - addr_un: SockAddrUn, - addr_ll: SockAddrLl, + pub addr_in: SockAddrIn, + pub addr_un: SockAddrUn, + pub addr_ll: SockAddrLl, } #[repr(C)] pub struct SockAddr { - family: u16, - payload: SockAddrPayload, + pub family: u16, + pub payload: SockAddrPayload, +} + +#[repr(C)] +pub struct SockAddrPlaceholder { + pub family: u16, + pub data: [u8; 14], } impl From for SockAddr { From b0c9087f0fc40685d1510799d87725091426a065 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Fri, 5 Apr 2019 01:16:26 +0800 Subject: [PATCH 10/28] Implement ioctl arp translation --- kernel/Cargo.lock | 6 +++--- kernel/Makefile | 6 ++++-- kernel/src/drivers/bus/pci.rs | 8 +++++--- kernel/src/drivers/mod.rs | 7 ++++++- kernel/src/drivers/net/e1000.rs | 9 +++++++-- kernel/src/drivers/net/ixgbe.rs | 16 ++++++++++------ kernel/src/net/structs.rs | 10 +++++++++- kernel/src/syscall/fs.rs | 2 +- kernel/src/syscall/mod.rs | 5 +---- 9 files changed, 46 insertions(+), 23 deletions(-) diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index bb74065..0c0b6e9 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -333,7 +333,7 @@ dependencies = [ "rcore-memory 0.1.0", "rcore-thread 0.1.0 (git+https://github.com/rcore-os/rcore-thread)", "riscv 0.5.0 (git+https://github.com/rcore-os/riscv)", - "smoltcp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smoltcp 0.5.0 (git+https://github.com/rcore-os/smoltcp)", "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -443,7 +443,7 @@ dependencies = [ [[package]] name = "smoltcp" version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/rcore-os/smoltcp#107d299b41a8f8cc370e3105dda38acc33609483" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -647,7 +647,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "061203a849117b0f7090baf8157aa91dac30545208fbb85166ac58b4ca33d89c" -"checksum smoltcp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fef582369edb298c6c41319a544ca9c4e83622f226055ccfcb35974fbb55ed34" +"checksum smoltcp 0.5.0 (git+https://github.com/rcore-os/smoltcp)" = "" "checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" "checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" "checksum static_assertions 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "389ce475f424f267dbed6479cbd8f126c5e1afb053b0acdaa019c74305fc65d1" diff --git a/kernel/Makefile b/kernel/Makefile index e4bec12..c47efc1 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -62,8 +62,7 @@ endif ### qemu options ### qemu_opts := \ -smp cores=$(smp) -qemu_net_opts := \ - -netdev type=tap,id=net0,script=no,downscript=no +qemu_net_opts := ifeq ($(arch), x86_64) qemu_opts += \ @@ -76,6 +75,7 @@ qemu_opts += \ -device isa-debug-exit ifeq ($(pci_passthru), ) qemu_net_opts += \ + -netdev type=tap,id=net0,script=no,downscript=no \ -device e1000e,netdev=net0 else qemu_opts += \ @@ -96,6 +96,7 @@ qemu_opts += \ -drive file=$(SFSIMG),format=qcow2,id=sfs \ -device virtio-blk-device,drive=sfs qemu_net_opts += \ + -netdev type=tap,id=net0,script=no,downscript=no \ -device virtio-net-device,netdev=net0 else ifeq ($(arch), riscv64) @@ -105,6 +106,7 @@ qemu_opts += \ -drive file=$(SFSIMG),format=qcow2,id=sfs \ -device virtio-blk-device,drive=sfs qemu_net_opts += \ + -netdev type=tap,id=net0,script=no,downscript=no \ -device virtio-net-device,netdev=net0 else ifeq ($(arch), aarch64) diff --git a/kernel/src/drivers/bus/pci.rs b/kernel/src/drivers/bus/pci.rs index 1f76b3e..4da0626 100644 --- a/kernel/src/drivers/bus/pci.rs +++ b/kernel/src/drivers/bus/pci.rs @@ -132,9 +132,11 @@ pub fn init_driver(dev: &PCIDevice) { active_table().map_if_not_exists(KERNEL_OFFSET + current_addr, current_addr); current_addr = current_addr + PAGE_SIZE; } - PCI_DRIVERS - .lock() - .insert(dev.loc, ixgbe::ixgbe_init(name, irq, vaddr, len as usize)); + let index = NET_DRIVERS.read().len(); + PCI_DRIVERS.lock().insert( + dev.loc, + ixgbe::ixgbe_init(name, irq, vaddr, len as usize, index), + ); } } (0x8086, 0x2922) => { diff --git a/kernel/src/drivers/mod.rs b/kernel/src/drivers/mod.rs index c9c0cd5..661cfb6 100644 --- a/kernel/src/drivers/mod.rs +++ b/kernel/src/drivers/mod.rs @@ -3,7 +3,7 @@ use alloc::sync::Arc; use alloc::vec::Vec; use lazy_static::lazy_static; -use smoltcp::wire::{EthernetAddress, Ipv4Address}; +use smoltcp::wire::{EthernetAddress, IpAddress, Ipv4Address}; use spin::RwLock; use crate::sync::Condvar; @@ -71,6 +71,11 @@ pub trait Driver: Send + Sync { unimplemented!("not a net driver") } + // get mac address from ip address in arp table + fn get_arp(&self, ip: IpAddress) -> Option { + unimplemented!("not a net driver") + } + // block related drivers should implement these fn read_block(&self, block_id: usize, buf: &mut [u8]) -> bool { unimplemented!("not a block driver") diff --git a/kernel/src/drivers/net/e1000.rs b/kernel/src/drivers/net/e1000.rs index 39a9133..9bd3625 100644 --- a/kernel/src/drivers/net/e1000.rs +++ b/kernel/src/drivers/net/e1000.rs @@ -150,7 +150,6 @@ impl Driver for E1000Interface { } } - // send an ethernet frame, only use it when necessary fn send(&self, data: &[u8]) -> Option { use smoltcp::phy::TxToken; let token = E1000TxToken(self.driver.clone()); @@ -166,6 +165,12 @@ impl Driver for E1000Interface { None } } + + fn get_arp(&self, ip: IpAddress) -> Option { + let iface = self.iface.lock(); + let cache = iface.neighbor_cache(); + cache.lookup_pure(&ip, Instant::from_millis(0)) + } } #[repr(C)] @@ -493,7 +498,7 @@ pub fn e1000_init(name: String, irq: Option, header: usize, size: usize, in .neighbor_cache(neighbor_cache) .finalize(); - info!("e1000 interface {} has addr 10.0.{}.2/24", name, index); + info!("e1000 interface {} up with addr 10.0.{}.2/24", name, index); let e1000_iface = E1000Interface { iface: Mutex::new(iface), driver: net_driver.clone(), diff --git a/kernel/src/drivers/net/ixgbe.rs b/kernel/src/drivers/net/ixgbe.rs index 7e289f7..98eab21 100644 --- a/kernel/src/drivers/net/ixgbe.rs +++ b/kernel/src/drivers/net/ixgbe.rs @@ -100,6 +100,12 @@ impl Driver for IXGBEInterface { } } } + + fn get_arp(&self, ip: IpAddress) -> Option { + let iface = self.iface.lock(); + let cache = iface.neighbor_cache(); + cache.lookup_pure(&ip, Instant::from_millis(0)) + } } pub struct IXGBERxToken(Vec); pub struct IXGBETxToken(IXGBEDriver); @@ -171,6 +177,7 @@ pub fn ixgbe_init( irq: Option, header: usize, size: usize, + index: usize, ) -> Arc { let _ = FlagsGuard::no_irq_region(); let ixgbe = ixgbe::IXGBEDriver::init(Provider::new(), header, size); @@ -185,12 +192,9 @@ pub fn ixgbe_init( mtu: 1500, }; - let ip_addrs = [IpCidr::new(IpAddress::v4(10, 0, 0, 2), 24)]; + let ip_addrs = [IpCidr::new(IpAddress::v4(10, 0, index as u8, 2), 24)]; let neighbor_cache = NeighborCache::new(BTreeMap::new()); - let mut routes = Routes::new(BTreeMap::new()); - routes - .add_default_ipv4_route(Ipv4Address::new(10, 0, 0, 1)) - .unwrap(); + let routes = Routes::new(BTreeMap::new()); let mut iface = EthernetInterfaceBuilder::new(net_driver.clone()) .ethernet_addr(ethernet_addr) .ip_addrs(ip_addrs) @@ -198,7 +202,7 @@ pub fn ixgbe_init( .routes(routes) .finalize(); - info!("ixgbe: interface {} up", &name); + info!("ixgbe interface {} up with addr 10.0.{}.2/24", name, index); let ixgbe_iface = IXGBEInterface { iface: Mutex::new(iface), diff --git a/kernel/src/net/structs.rs b/kernel/src/net/structs.rs index 0331219..28f4970 100644 --- a/kernel/src/net/structs.rs +++ b/kernel/src/net/structs.rs @@ -505,7 +505,7 @@ impl Socket for UdpSocketState { // SIOCGARP 0x8954 => { // FIXME: check addr - let req = unsafe { &mut *(request as *mut ArpReq) }; + let req = unsafe { &mut *(arg1 as *mut ArpReq) }; if let AddressFamily::Internet = AddressFamily::from(req.arp_pa.family) { let name = req.arp_dev.as_ptr(); let ifname = unsafe { util::from_cstr(name) }; @@ -518,6 +518,14 @@ impl Socket for UdpSocketState { for iface in NET_DRIVERS.read().iter() { if iface.get_ifname() == ifname { debug!("get arp matched ifname {}", ifname); + return match iface.get_arp(addr) { + Some(mac) => { + // TODO: update flags + req.arp_ha.data[0..6].copy_from_slice(mac.as_bytes()); + Ok(0) + } + None => Err(SysError::ENOENT), + }; } } Err(SysError::ENOENT) diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index 5f7d547..73e9d53 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -474,7 +474,7 @@ pub fn sys_dup2(fd1: usize, fd2: usize) -> SysResult { pub fn sys_ioctl(fd: usize, request: usize, arg1: usize, arg2: usize, arg3: usize) -> SysResult { info!( - "ioctl: fd:{}, request:{}, args: {} {} {}", + "ioctl: fd: {}, request: {}, args: {} {} {}", fd, request, arg1, arg2, arg3 ); let mut proc = process(); diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 658992e..70ba552 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -70,10 +70,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { warn!("sys_sigprocmask is unimplemented"); Ok(0) } - SYS_IOCTL => { - warn!("sys_ioctl is unimplemented"); - Ok(0) - } + SYS_IOCTL => sys_ioctl(args[0], args[1], args[2], args[3], args[4]), SYS_PREAD64 => sys_pread(args[0], args[1] as *mut u8, args[2], args[3]), SYS_PWRITE64 => sys_pwrite(args[0], args[1] as *const u8, args[2], args[3]), SYS_READV => sys_readv(args[0], args[1] as *const IoVec, args[2]), From a1ae2af269831ef6a9c8082d53d5c53300fbb994 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Fri, 5 Apr 2019 13:49:53 +0800 Subject: [PATCH 11/28] Implement send for ixgbe --- kernel/src/drivers/bus/pci.rs | 5 +++-- kernel/src/drivers/net/ixgbe.rs | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/kernel/src/drivers/bus/pci.rs b/kernel/src/drivers/bus/pci.rs index 4da0626..2c14ea1 100644 --- a/kernel/src/drivers/bus/pci.rs +++ b/kernel/src/drivers/bus/pci.rs @@ -80,8 +80,9 @@ unsafe fn enable(loc: Location) -> Option { let orig_ctrl = am.read32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP); am.write32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP, orig_ctrl | 0x10000); debug!( - "MSI control {:#b}, enabling MSI interrupts", - orig_ctrl >> 16 + "MSI control {:#b}, enabling MSI interrupt {}", + orig_ctrl >> 16, + irq ); msi_found = true; break; diff --git a/kernel/src/drivers/net/ixgbe.rs b/kernel/src/drivers/net/ixgbe.rs index 98eab21..4ee4475 100644 --- a/kernel/src/drivers/net/ixgbe.rs +++ b/kernel/src/drivers/net/ixgbe.rs @@ -101,6 +101,11 @@ impl Driver for IXGBEInterface { } } + fn send(&self, data: &[u8]) -> Option { + self.driver.inner.send(&data); + Some(data.len()) + } + fn get_arp(&self, ip: IpAddress) -> Option { let iface = self.iface.lock(); let cache = iface.neighbor_cache(); From 847664fda1a2d5504b422f44281adcbaa26413f8 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 5 Apr 2019 20:24:45 +0800 Subject: [PATCH 12/28] move AHCI driver to isomorphic_drivers crate --- kernel/Cargo.lock | 3 +- kernel/src/drivers/block/ahci.rs | 464 +------------------------------ kernel/src/drivers/bus/pci.rs | 2 +- kernel/src/drivers/net/ixgbe.rs | 20 +- kernel/src/drivers/provider.rs | 37 +-- 5 files changed, 36 insertions(+), 490 deletions(-) diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 0c0b6e9..901f2c7 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -192,8 +192,9 @@ dependencies = [ [[package]] name = "isomorphic_drivers" version = "0.1.0" -source = "git+https://github.com/rcore-os/isomorphic_drivers#836e91fca59e4f4eb86a1f10c246d9c8cb5d1fad" +source = "git+https://github.com/rcore-os/isomorphic_drivers#35c14cb75145c6f5d9050d664df3922bf5f275c7" dependencies = [ + "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/kernel/src/drivers/block/ahci.rs b/kernel/src/drivers/block/ahci.rs index 842259c..189c6e4 100644 --- a/kernel/src/drivers/block/ahci.rs +++ b/kernel/src/drivers/block/ahci.rs @@ -2,335 +2,18 @@ //! //! Spec: https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/serial-ata-ahci-spec-rev1-3-1.pdf -use alloc::alloc::{alloc_zeroed, Layout}; -use alloc::boxed::Box; use alloc::string::String; use alloc::sync::Arc; -use alloc::vec::Vec; -use core::mem::size_of; -use core::slice; -use core::sync::atomic::spin_loop_hint; -use bit_field::*; -use bitflags::*; -use log::*; -use rcore_fs::dev::BlockDevice; -use volatile::Volatile; - -use rcore_memory::paging::PageTable; -use rcore_memory::{PhysAddr, VirtAddr, PAGE_SIZE}; +use isomorphic_drivers::block::ahci::{AHCI, BLOCK_SIZE}; +use crate::drivers::provider::Provider; use crate::drivers::BlockDriver; -use crate::memory::active_table; use crate::sync::SpinNoIrqLock as Mutex; use super::super::{DeviceType, Driver, BLK_DRIVERS, DRIVERS}; -pub struct AHCI { - header: usize, - size: usize, - received_fis: &'static mut AHCIReceivedFIS, - cmd_list: &'static mut [AHCICommandHeader], - cmd_table: &'static mut AHCICommandTable, - data: &'static mut [u8], - port: &'static mut AHCIPort, -} - -pub struct AHCIDriver(Mutex); - -/// AHCI Generic Host Control (3.1) -#[repr(C)] -pub struct AHCIGHC { - /// Host capability - capability: Volatile, - /// Global host control - global_host_control: Volatile, - /// Interrupt status - interrupt_status: Volatile, - /// Port implemented - port_implemented: Volatile, - /// Version - version: Volatile, - /// Command completion coalescing control - ccc_control: Volatile, - /// Command completion coalescing ports - ccc_ports: Volatile, - /// Enclosure management location - em_location: Volatile, - /// Enclosure management control - em_control: Volatile, - /// Host capabilities extended - capabilities2: Volatile, - /// BIOS/OS handoff control and status - bios_os_handoff_control: Volatile, -} - -bitflags! { - struct AHCICap : u32 { - const S64A = 1 << 31; - const SNCQ = 1 << 30; - const SSNTF = 1 << 29; - const SMPS = 1 << 28; - const SSS = 1 << 27; - const SALP = 1 << 26; - const SAL = 1 << 25; - const SCLO = 1 << 24; - const ISS_GEN_1 = 1 << 20; - const ISS_GEN_2 = 2 << 20; - const ISS_GEN_3 = 3 << 20; - const SAM = 1 << 18; - const SPM = 1 << 17; - const FBSS = 1 << 16; - const PMD = 1 << 15; - const SSC = 1 << 14; - const PSC = 1 << 13; - const CCCS = 1 << 7; - const EMS = 1 << 6; - const SXS = 1 << 5; - // number of ports - 1 - const NUM_MASK = 0b11111; - } -} - -impl AHCIGHC { - fn enable(&mut self) { - self.global_host_control.update(|v| { - v.set_bit(13, true); - }); - } - fn num_ports(&self) -> usize { - (self.capability.read() & AHCICap::NUM_MASK).bits() as usize + 1 - } - fn has_port(&self, port_num: usize) -> bool { - self.port_implemented.read().get_bit(port_num) - } -} - -/// AHCI Port Registers (3.3) (one set per port) -#[repr(C)] -pub struct AHCIPort { - command_list_base_address: Volatile, - fis_base_address: Volatile, - interrupt_status: Volatile, - interrupt_enable: Volatile, - command: Volatile, - reserved: Volatile, - task_file_data: Volatile, - signature: Volatile, - sata_status: Volatile, - sata_control: Volatile, - sata_error: Volatile, - sata_active: Volatile, - command_issue: Volatile, - sata_notification: Volatile, - fis_based_switch_control: Volatile, -} - -impl AHCIPort { - fn spin_on_slot(&mut self, slot: usize) { - loop { - let ci = self.command_issue.read(); - if !ci.get_bit(slot) { - break; - } - spin_loop_hint(); - } - } - fn issue_command(&mut self, slot: usize) { - assert!(slot < 32); - self.command_issue.write(1 << (slot as u32)); - } -} - -/// AHCI Received FIS Structure (4.2.1) -#[repr(C)] -pub struct AHCIReceivedFIS { - dma: [u8; 0x20], - pio: [u8; 0x20], - d2h: [u8; 0x18], - sdbfis: [u8; 0x8], - ufis: [u8; 0x40], - reserved: [u8; 0x60], -} - -/// # AHCI Command List Structure (4.2.2) -/// -/// Host sends commands to the device through Command List. -/// -/// Command List consists of 1 to 32 command headers, each one is called a slot. -/// -/// Each command header describes an ATA or ATAPI command, including a -/// Command FIS, an ATAPI command buffer and a bunch of Physical Region -/// Descriptor Tables specifying the data payload address and size. -/// -/// https://wiki.osdev.org/images/e/e8/Command_list.jpg -#[repr(C)] -pub struct AHCICommandHeader { - /// - flags: CommandHeaderFlags, - /// Physical region descriptor table length in entries - prdt_length: u16, - /// Physical region descriptor byte count transferred - prd_byte_count: u32, - /// Command table descriptor base address - command_table_base_address: u64, - /// Reserved - reserved: [u32; 4], -} - -bitflags! { - pub struct CommandHeaderFlags: u16 { - /// Command FIS length in DWORDS, 2 ~ 16 - const CFL_MASK = 0b11111; - /// ATAPI - const ATAPI = 1 << 5; - /// Write, 1: H2D, 0: D2H - const WRITE = 1 << 6; - /// Prefetchable - const PREFETCHABLE = 1 << 7; - /// Reset - const RESET = 1 << 8; - /// BIST - const BIST = 1 << 9; - /// Clear busy upon R_OK - const CLEAR = 1 << 10; - /// Port multiplier port - const PORT_MULTIPLIER_PORT_MASK = 0b1111 << 12; - } -} - -/// AHCI Command Table (4.2.3) -#[repr(C)] -pub struct AHCICommandTable { - /// Command FIS - cfis: SATAFISRegH2D, - /// ATAPI command, 12 or 16 bytes - acmd: [u8; 16], - /// Reserved - reserved: [u8; 48], - /// Physical region descriptor table entries, 0 ~ 65535 - prdt: [AHCIPrdtEntry; 1], -} - -/// Physical region descriptor table entry -#[repr(C)] -pub struct AHCIPrdtEntry { - /// Data base address - data_base_address: u64, - /// Reserved - reserved: u32, - /// Bit 21-0: Byte count, 4M max - /// Bit 31: Interrupt on completion - dbc_i: u32, -} - -const FIS_REG_H2D: u8 = 0x27; - -const CMD_READ_DMA_EXT: u8 = 0x25; -const CMD_WRITE_DMA_EXT: u8 = 0x35; -const CMD_IDENTIFY_DEVICE: u8 = 0xec; - -/// SATA Register FIS - Host to Device -/// -/// https://wiki.osdev.org/AHCI Figure 5-2 -#[repr(C)] -pub struct SATAFISRegH2D { - fis_type: u8, - cflags: u8, - command: u8, - feature_lo: u8, - - lba_0: u8, // LBA 7:0 - lba_1: u8, // LBA 15:8 - lba_2: u8, // LBA 23:16 - dev_head: u8, - - lba_3: u8, // LBA 31:24 - lba_4: u8, // LBA 39:32 - lba_5: u8, // LBA 47:40 - feature_hi: u8, - - sector_count: u16, - reserved: u8, - control: u8, - - _padding: [u8; 48], -} - -impl SATAFISRegH2D { - fn set_lba(&mut self, lba: u64) { - self.lba_0 = (lba >> 0) as u8; - self.lba_1 = (lba >> 8) as u8; - self.lba_2 = (lba >> 16) as u8; - self.lba_3 = (lba >> 24) as u8; - self.lba_4 = (lba >> 32) as u8; - self.lba_5 = (lba >> 40) as u8; - } -} - -/// IDENTIFY DEVICE data -/// -/// ATA8-ACS Table 29 -#[repr(C)] -pub struct ATAIdentifyPacket { - _1: [u16; 10], - serial: [u8; 20], // words 10-19 - _2: [u16; 3], - firmware: [u8; 8], // words 23-26 - model: [u8; 40], // words 27-46 - _3: [u16; 13], - lba_sectors: u32, // words 60-61 - _4: [u16; 38], - lba48_sectors: u64, // words 100-103 -} - -impl AHCI { - fn read_block(&mut self, block_id: usize, buf: &mut [u8]) -> usize { - self.cmd_list[0].flags = CommandHeaderFlags::empty(); - - let fis = &mut self.cmd_table.cfis; - // Register FIS from HBA to device - fis.fis_type = FIS_REG_H2D; - fis.cflags = 1 << 7; - // 7.25 READ DMA EXT - 25h, DMA - fis.command = CMD_READ_DMA_EXT; - fis.sector_count = 1; - fis.dev_head = 0x40; // LBA - fis.control = 0x80; // LBA48 - fis.set_lba(block_id as u64); - - self.port.issue_command(0); - self.port.spin_on_slot(0); - - let len = buf.len().min(BLOCK_SIZE); - buf[..len].clone_from_slice(&self.data[0..len]); - len - } - - fn write_block(&mut self, block_id: usize, buf: &[u8]) -> usize { - self.cmd_list[0].flags = CommandHeaderFlags::WRITE; // device write - - let len = buf.len().min(BLOCK_SIZE); - self.data[0..len].clone_from_slice(&buf[..len]); - - let fis = &mut self.cmd_table.cfis; - // Register FIS from HBA to device - fis.fis_type = FIS_REG_H2D; - fis.cflags = 1 << 7; - // ATA8-ACS - // 7.63 WRITE DMA EXT - 35h, DMA - fis.command = CMD_WRITE_DMA_EXT; - fis.sector_count = 1; - fis.dev_head = 0x40; // LBA - fis.control = 0x80; // LBA48 - fis.set_lba(block_id as u64); - - self.port.issue_command(0); - self.port.spin_on_slot(0); - - len - } -} +pub struct AHCIDriver(Mutex>); impl Driver for AHCIDriver { fn try_handle_interrupt(&self, _irq: Option) -> bool { @@ -361,137 +44,12 @@ impl Driver for AHCIDriver { } } -const BLOCK_SIZE: usize = 512; - -fn from_ata_string(data: &[u8]) -> String { - let mut swapped_data = Vec::new(); - assert_eq!(data.len() % 2, 0); - for i in (0..data.len()).step_by(2) { - swapped_data.push(data[i + 1]); - swapped_data.push(data[i]); - } - return String::from_utf8(swapped_data).unwrap(); -} - -/// Allocate consequent physical frames for DMA -fn alloc_dma(page_num: usize) -> (VirtAddr, PhysAddr) { - let layout = Layout::from_size_align(PAGE_SIZE * page_num, PAGE_SIZE).unwrap(); - let vaddr = unsafe { alloc_zeroed(layout) } as usize; - let paddr = active_table().get_entry(vaddr).unwrap().target(); - (vaddr, paddr) -} - -pub fn ahci_init(irq: Option, header: usize, size: usize) -> Arc { - let ghc = unsafe { &mut *(header as *mut AHCIGHC) }; - - ghc.enable(); - - for port_num in 0..ghc.num_ports() { - if ghc.has_port(port_num) { - let addr = header + 0x100 + 0x80 * port_num; - let port = unsafe { &mut *(addr as *mut AHCIPort) }; - - // SSTS IPM Active - if port.sata_status.read().get_bits(8..12) != 1 { - continue; - } - - // SSTS DET Present - if port.sata_status.read().get_bits(0..4) != 3 { - continue; - } - - debug!("probing port {}", port_num); - // Disable Port First - port.command.update(|c| { - c.set_bit(4, false); - c.set_bit(0, false); - }); - - let (rfis_va, rfis_pa) = alloc_dma(1); - let (cmd_list_va, cmd_list_pa) = alloc_dma(1); - let (cmd_table_va, cmd_table_pa) = alloc_dma(1); - let (data_va, data_pa) = alloc_dma(1); - - let received_fis = unsafe { &mut *(rfis_va as *mut AHCIReceivedFIS) }; - let cmd_list = unsafe { - slice::from_raw_parts_mut( - cmd_list_va as *mut AHCICommandHeader, - PAGE_SIZE / size_of::(), - ) - }; - let cmd_table = unsafe { &mut *(cmd_table_va as *mut AHCICommandTable) }; - let identify_data = unsafe { &*(data_va as *mut ATAIdentifyPacket) }; - - cmd_table.prdt[0].data_base_address = data_pa as u64; - cmd_table.prdt[0].dbc_i = (BLOCK_SIZE - 1) as u32; - - cmd_list[0].command_table_base_address = cmd_table_pa as u64; - cmd_list[0].prdt_length = 1; - cmd_list[0].prd_byte_count = 0; - - port.command_list_base_address.write(cmd_list_pa as u64); - port.fis_base_address.write(rfis_pa as u64); - - // clear status and errors - port.command_issue.write(0); - port.sata_active.write(0); - port.sata_error.write(0); - - // enable port - port.command.update(|c| { - *c |= 1 << 0 | 1 << 1 | 1 << 2 | 1 << 4 | 1 << 28; - }); - - let stat = port.sata_status.read(); - if stat == 0 { - warn!("port is not connected to external drive?"); - } - - let fis = &mut cmd_table.cfis; - // Register FIS from HBA to device - fis.fis_type = FIS_REG_H2D; - fis.cflags = 1 << 7; - - // 7.15 IDENTIFY DEVICE - ECh, PIO Data-In - fis.command = CMD_IDENTIFY_DEVICE; - fis.sector_count = 1; - - port.issue_command(0); - port.spin_on_slot(0); - - unsafe { - debug!( - "Found ATA Device serial {} firmware {} model {} sectors 24bit={} 48bit={}", - from_ata_string(&identify_data.serial).trim_end(), - from_ata_string(&identify_data.firmware).trim_end(), - from_ata_string(&identify_data.model).trim_end(), - identify_data.lba_sectors, - identify_data.lba48_sectors, - ); - } - - let data = unsafe { slice::from_raw_parts_mut(data_va as *mut u8, BLOCK_SIZE) }; - - let driver = AHCIDriver(Mutex::new(AHCI { - header, - size, - received_fis, - cmd_list, - cmd_table, - data, - port, - })); - - let driver = Arc::new(driver); - DRIVERS.write().push(driver.clone()); - BLK_DRIVERS - .write() - .push(Arc::new(BlockDriver(driver.clone()))); - - return driver; - } - } - - unimplemented!(); +pub fn init(_irq: Option, header: usize, size: usize) -> Arc { + let ahci = AHCI::new(header, size); + let driver = Arc::new(AHCIDriver(Mutex::new(ahci))); + DRIVERS.write().push(driver.clone()); + BLK_DRIVERS + .write() + .push(Arc::new(BlockDriver(driver.clone()))); + driver } diff --git a/kernel/src/drivers/bus/pci.rs b/kernel/src/drivers/bus/pci.rs index 2c14ea1..325c37b 100644 --- a/kernel/src/drivers/bus/pci.rs +++ b/kernel/src/drivers/bus/pci.rs @@ -149,7 +149,7 @@ pub fn init_driver(dev: &PCIDevice) { active_table().map(vaddr, addr as usize); PCI_DRIVERS .lock() - .insert(dev.loc, ahci::ahci_init(irq, vaddr, len as usize)); + .insert(dev.loc, ahci::init(irq, vaddr, len as usize)); } } _ => {} diff --git a/kernel/src/drivers/net/ixgbe.rs b/kernel/src/drivers/net/ixgbe.rs index 4ee4475..72fd7c9 100644 --- a/kernel/src/drivers/net/ixgbe.rs +++ b/kernel/src/drivers/net/ixgbe.rs @@ -26,7 +26,7 @@ use super::super::{provider::Provider, DeviceType, Driver, DRIVERS, NET_DRIVERS, #[derive(Clone)] struct IXGBEDriver { - inner: ixgbe::IXGBEDriver, + inner: Arc>>, header: usize, size: usize, mtu: usize, @@ -49,7 +49,7 @@ impl Driver for IXGBEInterface { let handled = { let _ = FlagsGuard::no_irq_region(); - self.driver.inner.try_handle_interrupt() + self.driver.inner.lock().try_handle_interrupt() }; if handled { @@ -102,7 +102,7 @@ impl Driver for IXGBEInterface { } fn send(&self, data: &[u8]) -> Option { - self.driver.inner.send(&data); + self.driver.inner.lock().send(&data); Some(data.len()) } @@ -121,8 +121,8 @@ impl<'a> phy::Device<'a> for IXGBEDriver { fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { let _ = FlagsGuard::no_irq_region(); - if self.inner.can_send() { - if let Some(data) = self.inner.recv() { + if self.inner.lock().can_send() { + if let Some(data) = self.inner.lock().recv() { Some((IXGBERxToken(data), IXGBETxToken(self.clone()))) } else { None @@ -134,7 +134,7 @@ impl<'a> phy::Device<'a> for IXGBEDriver { fn transmit(&'a mut self) -> Option { let _ = FlagsGuard::no_irq_region(); - if self.inner.can_send() { + if self.inner.lock().can_send() { Some(IXGBETxToken(self.clone())) } else { None @@ -168,10 +168,10 @@ impl phy::TxToken for IXGBETxToken { F: FnOnce(&mut [u8]) -> Result, { let _ = FlagsGuard::no_irq_region(); - let mut buffer = [0u8; ixgbe::IXGBEDriver::get_mtu()]; + let mut buffer = [0u8; ixgbe::IXGBE::::get_mtu()]; let result = f(&mut buffer[..len]); if result.is_ok() { - (self.0).inner.send(&buffer[..len]); + self.0.inner.lock().send(&buffer[..len]); } result } @@ -185,13 +185,13 @@ pub fn ixgbe_init( index: usize, ) -> Arc { let _ = FlagsGuard::no_irq_region(); - let ixgbe = ixgbe::IXGBEDriver::init(Provider::new(), header, size); + let mut ixgbe = ixgbe::IXGBE::new(header, size); ixgbe.enable_irq(); let ethernet_addr = EthernetAddress::from_bytes(&ixgbe.get_mac().as_bytes()); let net_driver = IXGBEDriver { - inner: ixgbe, + inner: Arc::new(Mutex::new(ixgbe)), header, size, mtu: 1500, diff --git a/kernel/src/drivers/provider.rs b/kernel/src/drivers/provider.rs index 6857ae5..1a75efb 100644 --- a/kernel/src/drivers/provider.rs +++ b/kernel/src/drivers/provider.rs @@ -1,36 +1,23 @@ -use crate::memory::active_table; -use alloc::boxed::Box; -use alloc::vec::Vec; +use alloc::alloc::{alloc_zeroed, dealloc, Layout}; + use isomorphic_drivers::provider; use rcore_memory::paging::PageTable; use rcore_memory::PAGE_SIZE; -#[derive(Copy, Clone)] -pub struct Provider; +use crate::memory::active_table; -impl Provider { - pub fn new() -> Box { - Box::new(Provider {}) - } -} +pub struct Provider; impl provider::Provider for Provider { - /// Get page size - fn get_page_size(&self) -> usize { - PAGE_SIZE - } - - // Translate virtual address to physical address - fn translate_va(&self, va: usize) -> usize { - active_table().get_entry(va).unwrap().target() + fn alloc_dma(size: usize) -> (usize, usize) { + let layout = Layout::from_size_align(size, PAGE_SIZE).unwrap(); + let vaddr = unsafe { alloc_zeroed(layout) } as usize; + let paddr = active_table().get_entry(vaddr).unwrap().target(); + (vaddr, paddr) } - // Bulk translate virtual addresses to physical addresses for performance - fn translate_vas(&self, vas: &[usize]) -> Vec { - let mut result = Vec::new(); - for va in vas.iter() { - result.push(active_table().get_entry(*va).unwrap().target()); - } - result + fn dealloc_dma(vaddr: usize, size: usize) { + let layout = Layout::from_size_align(size, PAGE_SIZE).unwrap(); + unsafe { dealloc(vaddr as *mut u8, layout) } } } From ceff1ad60936347f87c944a3ad1e138a884fedb4 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Fri, 5 Apr 2019 20:54:38 +0800 Subject: [PATCH 13/28] Fix aarch64 backtrace --- kernel/src/backtrace.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/src/backtrace.rs b/kernel/src/backtrace.rs index a4b4ecf..32f6919 100644 --- a/kernel/src/backtrace.rs +++ b/kernel/src/backtrace.rs @@ -71,6 +71,9 @@ pub fn backtrace() { #[cfg(target_arch = "aarch64")] { current_fp = *(current_fp as *const usize); + if current_fp < crate::arch::consts::KERNEL_OFFSET { + break; + } if current_fp != 0 { current_pc = *(current_fp as *const usize).offset(1); } From 56cb8654ae2ea7539ce6c48b229fcd290c762236 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 5 Apr 2019 22:15:56 +0800 Subject: [PATCH 14/28] move E1000 driver to isomorphic_drivers crate --- kernel/Cargo.lock | 2 +- kernel/src/drivers/bus/pci.rs | 2 +- kernel/src/drivers/net/e1000.rs | 354 ++------------------------------ kernel/src/drivers/provider.rs | 2 + 4 files changed, 26 insertions(+), 334 deletions(-) diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 901f2c7..36ede46 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "isomorphic_drivers" version = "0.1.0" -source = "git+https://github.com/rcore-os/isomorphic_drivers#35c14cb75145c6f5d9050d664df3922bf5f275c7" +source = "git+https://github.com/rcore-os/isomorphic_drivers#fe4af36d5f7bf3ac32be77597ccc61fc8cf8bd98" dependencies = [ "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/kernel/src/drivers/bus/pci.rs b/kernel/src/drivers/bus/pci.rs index 325c37b..b5fb798 100644 --- a/kernel/src/drivers/bus/pci.rs +++ b/kernel/src/drivers/bus/pci.rs @@ -120,7 +120,7 @@ pub fn init_driver(dev: &PCIDevice) { current_addr = current_addr + PAGE_SIZE; } let index = NET_DRIVERS.read().len(); - e1000::e1000_init(name, irq, vaddr, len as usize, index); + e1000::init(name, irq, vaddr, len as usize, index); } } (0x8086, 0x10fb) => { diff --git a/kernel/src/drivers/net/e1000.rs b/kernel/src/drivers/net/e1000.rs index 9bd3625..f51d90b 100644 --- a/kernel/src/drivers/net/e1000.rs +++ b/kernel/src/drivers/net/e1000.rs @@ -1,74 +1,30 @@ //! Intel PRO/1000 Network Adapter i.e. e1000 network driver //! Datasheet: https://www.intel.ca/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf -use alloc::alloc::{GlobalAlloc, Layout}; -use alloc::format; +use alloc::collections::BTreeMap; use alloc::string::String; use alloc::sync::Arc; use alloc::vec::Vec; -use core::mem::size_of; -use core::slice; -use core::sync::atomic::{fence, Ordering}; -use alloc::collections::BTreeMap; -use bitflags::*; -use log::*; -use rcore_memory::paging::PageTable; -use rcore_memory::PAGE_SIZE; use smoltcp::iface::*; use smoltcp::phy::{self, DeviceCapabilities}; use smoltcp::time::Instant; -use smoltcp::wire::EthernetAddress; use smoltcp::wire::*; use smoltcp::Result; use volatile::Volatile; -use crate::memory::active_table; +use isomorphic_drivers::net::ethernet::intel::e1000::E1000; +use isomorphic_drivers::net::ethernet::structs::EthernetAddress as DriverEthernetAddress; +use rcore_memory::PAGE_SIZE; + +use crate::drivers::provider::Provider; use crate::net::SOCKETS; use crate::sync::SpinNoIrqLock as Mutex; -use crate::HEAP_ALLOCATOR; use super::super::{DeviceType, Driver, DRIVERS, NET_DRIVERS, SOCKET_ACTIVITY}; -// At the beginning, all transmit descriptors have there status non-zero, -// so we need to track whether we are using the descriptor for the first time. -// When the descriptors wrap around, we set first_trans to false, -// and lookup status instead for checking whether it is empty. - -pub struct E1000 { - header: usize, - size: usize, - mac: EthernetAddress, - send_page: usize, - send_buffers: Vec, - recv_page: usize, - recv_buffers: Vec, - first_trans: bool, -} - #[derive(Clone)] -pub struct E1000Driver(Arc>); - -const E1000_STATUS: usize = 0x0008 / 4; -const E1000_ICR: usize = 0x00C0 / 4; -const E1000_IMS: usize = 0x00D0 / 4; -const E1000_IMC: usize = 0x00D8 / 4; -const E1000_RCTL: usize = 0x0100 / 4; -const E1000_TCTL: usize = 0x0400 / 4; -const E1000_TIPG: usize = 0x0410 / 4; -const E1000_RDBAL: usize = 0x2800 / 4; -const E1000_RDBAH: usize = 0x2804 / 4; -const E1000_RDLEN: usize = 0x2808 / 4; -const E1000_RDH: usize = 0x2810 / 4; -const E1000_RDT: usize = 0x2818 / 4; -const E1000_TDBAL: usize = 0x3800 / 4; -const E1000_TDBAH: usize = 0x3804 / 4; -const E1000_TDLEN: usize = 0x3808 / 4; -const E1000_TDH: usize = 0x3810 / 4; -const E1000_TDT: usize = 0x3818 / 4; -const E1000_MTA: usize = 0x5200 / 4; -const E1000_RAL: usize = 0x5400 / 4; -const E1000_RAH: usize = 0x5404 / 4; +pub struct E1000Driver(Arc>>); pub struct E1000Interface { iface: Mutex>, @@ -84,22 +40,7 @@ impl Driver for E1000Interface { return false; } - let data = { - let driver = self.driver.0.lock(); - - let e1000 = unsafe { - slice::from_raw_parts_mut(driver.header as *mut Volatile, driver.size / 4) - }; - - let icr = e1000[E1000_ICR].read(); - if icr != 0 { - // clear it - e1000[E1000_ICR].write(icr); - true - } else { - false - } - }; + let data = self.driver.0.lock().handle_interrupt(); if data { let timestamp = Instant::from_millis(crate::trap::uptime_msec() as i64); @@ -122,7 +63,7 @@ impl Driver for E1000Interface { } fn get_id(&self) -> String { - format!("e1000") + String::from("e1000") } fn get_mac(&self) -> EthernetAddress { @@ -173,97 +114,22 @@ impl Driver for E1000Interface { } } -#[repr(C)] -#[derive(Copy, Clone, Debug)] -struct E1000SendDesc { - addr: u64, - len: u16, - cso: u8, - cmd: u8, - status: u8, - css: u8, - special: u8, -} - -#[repr(C)] -#[derive(Copy, Clone, Debug)] -struct E1000RecvDesc { - addr: u64, - len: u16, - chksum: u16, - status: u16, - error: u8, - special: u8, -} - pub struct E1000RxToken(Vec); pub struct E1000TxToken(E1000Driver); -impl<'a> phy::Device<'a> for E1000Driver { +impl phy::Device<'_> for E1000Driver { type RxToken = E1000RxToken; type TxToken = E1000TxToken; - fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { - let driver = self.0.lock(); - - let e1000 = unsafe { - slice::from_raw_parts_mut(driver.header as *mut Volatile, driver.size / 4) - }; - - let send_queue_size = PAGE_SIZE / size_of::(); - let send_queue = unsafe { - slice::from_raw_parts_mut(driver.send_page as *mut E1000SendDesc, send_queue_size) - }; - let tdt = e1000[E1000_TDT].read(); - let index = (tdt as usize) % send_queue_size; - let send_desc = &mut send_queue[index]; - - let recv_queue_size = PAGE_SIZE / size_of::(); - let recv_queue = unsafe { - slice::from_raw_parts_mut(driver.recv_page as *mut E1000RecvDesc, recv_queue_size) - }; - let mut rdt = e1000[E1000_RDT].read(); - let index = (rdt as usize + 1) % recv_queue_size; - let recv_desc = &mut recv_queue[index]; - - let transmit_avail = driver.first_trans || (*send_desc).status & 1 != 0; - let receive_avail = (*recv_desc).status & 1 != 0; - - if transmit_avail && receive_avail { - let buffer = unsafe { - slice::from_raw_parts( - driver.recv_buffers[index] as *const u8, - recv_desc.len as usize, - ) - }; - - recv_desc.status = recv_desc.status & !1; - - rdt = (rdt + 1) % recv_queue_size as u32; - e1000[E1000_RDT].write(rdt); - - Some((E1000RxToken(buffer.to_vec()), E1000TxToken(self.clone()))) - } else { - None - } + fn receive(&mut self) -> Option<(Self::RxToken, Self::TxToken)> { + self.0 + .lock() + .receive() + .map(|vec| (E1000RxToken(vec), E1000TxToken(self.clone()))) } - fn transmit(&'a mut self) -> Option { - let driver = self.0.lock(); - - let e1000 = unsafe { - slice::from_raw_parts_mut(driver.header as *mut Volatile, driver.size / 4) - }; - - let send_queue_size = PAGE_SIZE / size_of::(); - let send_queue = unsafe { - slice::from_raw_parts_mut(driver.send_page as *mut E1000SendDesc, send_queue_size) - }; - let tdt = e1000[E1000_TDT].read(); - let index = (tdt as usize) % send_queue_size; - let send_desc = &mut send_queue[index]; - let transmit_avail = driver.first_trans || (*send_desc).status & 1 != 0; - if transmit_avail { + fn transmit(&mut self) -> Option { + if self.0.lock().can_send() { Some(E1000TxToken(self.clone())) } else { None @@ -296,198 +162,22 @@ impl phy::TxToken for E1000TxToken { let result = f(&mut buffer[..len]); let mut driver = (self.0).0.lock(); - - let e1000 = unsafe { - slice::from_raw_parts_mut(driver.header as *mut Volatile, driver.size / 4) - }; - let send_queue_size = PAGE_SIZE / size_of::(); - let send_queue = unsafe { - slice::from_raw_parts_mut(driver.send_page as *mut E1000SendDesc, send_queue_size) - }; - let mut tdt = e1000[E1000_TDT].read(); - - let index = (tdt as usize) % send_queue_size; - let send_desc = &mut send_queue[index]; - assert!(driver.first_trans || send_desc.status & 1 != 0); - - let target = - unsafe { slice::from_raw_parts_mut(driver.send_buffers[index] as *mut u8, len) }; - target.copy_from_slice(&buffer[..len]); - - let buffer_page_pa = active_table() - .get_entry(driver.send_buffers[index]) - .unwrap() - .target(); - assert_eq!(buffer_page_pa, send_desc.addr as usize); - send_desc.len = len as u16 + 4; - // RS | IFCS | EOP - send_desc.cmd = (1 << 3) | (1 << 1) | (1 << 0); - send_desc.status = 0; - - fence(Ordering::SeqCst); - - tdt = (tdt + 1) % send_queue_size as u32; - e1000[E1000_TDT].write(tdt); - - fence(Ordering::SeqCst); - - // round - if tdt == 0 { - driver.first_trans = false; - } + driver.send(&buffer); result } } -bitflags! { - struct E1000Status : u32 { - const FD = 1 << 0; - const LU = 1 << 1; - const TXOFF = 1 << 4; - const TBIMODE = 1 << 5; - const SPEED_100M = 1 << 6; - const SPEED_1000M = 1 << 7; - const ASDV_100M = 1 << 8; - const ASDV_1000M = 1 << 9; - const MTXCKOK = 1 << 10; - const PCI66 = 1 << 11; - const BUS64 = 1 << 12; - const PCIX_MODE = 1 << 13; - const GIO_MASTER_ENABLE = 1 << 19; - } -} - // JudgeDuck-OS/kern/e1000.c -pub fn e1000_init(name: String, irq: Option, header: usize, size: usize, index: usize) { +pub fn init(name: String, irq: Option, header: usize, size: usize, index: usize) { info!("Probing e1000 {}", name); - assert_eq!(size_of::(), 16); - assert_eq!(size_of::(), 16); - - let send_page = unsafe { - HEAP_ALLOCATOR.alloc_zeroed(Layout::from_size_align(PAGE_SIZE, PAGE_SIZE).unwrap()) - } as usize; - let recv_page = unsafe { - HEAP_ALLOCATOR.alloc_zeroed(Layout::from_size_align(PAGE_SIZE, PAGE_SIZE).unwrap()) - } as usize; - let send_page_pa = active_table().get_entry(send_page).unwrap().target(); - let recv_page_pa = active_table().get_entry(recv_page).unwrap().target(); - let send_queue_size = PAGE_SIZE / size_of::(); - let recv_queue_size = PAGE_SIZE / size_of::(); - let mut send_queue = - unsafe { slice::from_raw_parts_mut(send_page as *mut E1000SendDesc, send_queue_size) }; - let mut recv_queue = - unsafe { slice::from_raw_parts_mut(recv_page as *mut E1000RecvDesc, recv_queue_size) }; + // randomly generated let mac: [u8; 6] = [0x54, 0x51, 0x9F, 0x71, 0xC0, index as u8]; - let mut driver = E1000 { - header, - size, - mac: EthernetAddress::from_bytes(&mac), - send_page, - send_buffers: Vec::with_capacity(send_queue_size), - recv_page, - recv_buffers: Vec::with_capacity(recv_queue_size), - first_trans: true, - }; - - let e1000 = unsafe { slice::from_raw_parts_mut(header as *mut Volatile, size / 4) }; - debug!( - "status before setup: {:#?}", - E1000Status::from_bits_truncate(e1000[E1000_STATUS].read()) - ); - - // 4.6 Software Initialization Sequence - - // 4.6.6 Transmit Initialization - - // Program the descriptor base address with the address of the region. - e1000[E1000_TDBAL].write(send_page_pa as u32); // TDBAL - e1000[E1000_TDBAH].write((send_page_pa >> 32) as u32); // TDBAH - - // Set the length register to the size of the descriptor ring. - e1000[E1000_TDLEN].write(PAGE_SIZE as u32); // TDLEN - - // If needed, program the head and tail registers. - e1000[E1000_TDH].write(0); // TDH - e1000[E1000_TDT].write(0); // TDT - - for i in 0..send_queue_size { - let buffer_page = unsafe { - HEAP_ALLOCATOR.alloc_zeroed(Layout::from_size_align(PAGE_SIZE, PAGE_SIZE).unwrap()) - } as usize; - let buffer_page_pa = active_table().get_entry(buffer_page).unwrap().target(); - send_queue[i].addr = buffer_page_pa as u64; - driver.send_buffers.push(buffer_page); - } - - // EN | PSP | CT=0x10 | COLD=0x40 - e1000[E1000_TCTL].write((1 << 1) | (1 << 3) | (0x10 << 4) | (0x40 << 12)); // TCTL - // IPGT=0xa | IPGR1=0x8 | IPGR2=0xc - e1000[E1000_TIPG].write(0xa | (0x8 << 10) | (0xc << 20)); // TIPG - - // 4.6.5 Receive Initialization - let mut ral: u32 = 0; - let mut rah: u32 = 0; - for i in 0..4 { - ral = ral | (mac[i] as u32) << (i * 8); - } - for i in 0..2 { - rah = rah | (mac[i + 4] as u32) << (i * 8); - } - - e1000[E1000_RAL].write(ral); // RAL - // AV | AS=DA - e1000[E1000_RAH].write(rah | (1 << 31)); // RAH - - // MTA - for i in E1000_MTA..E1000_RAL { - e1000[i].write(0); - } - - // Program the descriptor base address with the address of the region. - e1000[E1000_RDBAL].write(recv_page_pa as u32); // RDBAL - e1000[E1000_RDBAH].write((recv_page_pa >> 32) as u32); // RDBAH - - // Set the length register to the size of the descriptor ring. - e1000[E1000_RDLEN].write(PAGE_SIZE as u32); // RDLEN - - // If needed, program the head and tail registers. Note: the head and tail pointers are initialized (by hardware) to zero after a power-on or a software-initiated device reset. - e1000[E1000_RDH].write(0); // RDH - - // The tail pointer should be set to point one descriptor beyond the end. - e1000[E1000_RDT].write((recv_queue_size - 1) as u32); // RDT - - // Receive buffers of appropriate size should be allocated and pointers to these buffers should be stored in the descriptor ring. - for i in 0..recv_queue_size { - let buffer_page = unsafe { - HEAP_ALLOCATOR.alloc_zeroed(Layout::from_size_align(PAGE_SIZE, PAGE_SIZE).unwrap()) - } as usize; - let buffer_page_pa = active_table().get_entry(buffer_page).unwrap().target(); - recv_queue[i].addr = buffer_page_pa as u64; - driver.recv_buffers.push(buffer_page); - } - - // EN | BAM | BSIZE=3 | BSEX | SECRC - // BSIZE=3 | BSEX means buffer size = 4096 - e1000[E1000_RCTL].write((1 << 1) | (1 << 15) | (3 << 16) | (1 << 25) | (1 << 26)); // RCTL - - debug!( - "status after setup: {:#?}", - E1000Status::from_bits_truncate(e1000[E1000_STATUS].read()) - ); - - // enable interrupt - // clear interrupt - e1000[E1000_ICR].write(e1000[E1000_ICR].read()); - // RXT0 - e1000[E1000_IMS].write(1 << 7); // IMS - - // clear interrupt - e1000[E1000_ICR].write(e1000[E1000_ICR].read()); + let e1000 = E1000::new(header, size, DriverEthernetAddress::from_bytes(&mac)); - let net_driver = E1000Driver(Arc::new(Mutex::new(driver))); + let net_driver = E1000Driver(Arc::new(Mutex::new(e1000))); let ethernet_addr = EthernetAddress::from_bytes(&mac); let ip_addrs = [IpCidr::new(IpAddress::v4(10, 0, index as u8, 2), 24)]; diff --git a/kernel/src/drivers/provider.rs b/kernel/src/drivers/provider.rs index 1a75efb..19a269a 100644 --- a/kernel/src/drivers/provider.rs +++ b/kernel/src/drivers/provider.rs @@ -9,6 +9,8 @@ use crate::memory::active_table; pub struct Provider; impl provider::Provider for Provider { + const PAGE_SIZE: usize = PAGE_SIZE; + fn alloc_dma(size: usize) -> (usize, usize) { let layout = Layout::from_size_align(size, PAGE_SIZE).unwrap(); let vaddr = unsafe { alloc_zeroed(layout) } as usize; From a712f37c6597a03ef7e69d1b72e064ae9b6e0677 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 5 Apr 2019 23:20:08 +0800 Subject: [PATCH 15/28] update fs. support poll for INode. --- kernel/Cargo.lock | 4 +- kernel/src/fs/file.rs | 10 ++++- kernel/src/fs/file_like.rs | 21 +++++++--- kernel/src/fs/pipe.rs | 4 +- kernel/src/fs/stdio.rs | 19 ++++++++- kernel/src/syscall/fs.rs | 84 ++++++++++++++------------------------ 6 files changed, 77 insertions(+), 65 deletions(-) diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 36ede46..b17ca55 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -345,12 +345,12 @@ dependencies = [ [[package]] name = "rcore-fs" version = "0.1.0" -source = "git+https://github.com/rcore-os/rcore-fs#c611248f800e946acf44d64b218aeb8fc6751640" +source = "git+https://github.com/rcore-os/rcore-fs#d7a2006cc316c98b7050aec63a2770dd690a4a80" [[package]] name = "rcore-fs-sfs" version = "0.1.0" -source = "git+https://github.com/rcore-os/rcore-fs#c611248f800e946acf44d64b218aeb8fc6751640" +source = "git+https://github.com/rcore-os/rcore-fs#d7a2006cc316c98b7050aec63a2770dd690a4a80" dependencies = [ "bitvec 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/kernel/src/fs/file.rs b/kernel/src/fs/file.rs index ecddfff..dfb291f 100644 --- a/kernel/src/fs/file.rs +++ b/kernel/src/fs/file.rs @@ -2,7 +2,7 @@ use alloc::{string::String, sync::Arc}; -use rcore_fs::vfs::{FsError, INode, Metadata, Result}; +use rcore_fs::vfs::{FsError, INode, Metadata, PollStatus, Result}; #[derive(Clone)] pub struct FileHandle { @@ -108,4 +108,12 @@ impl FileHandle { self.offset += 1; Ok(name) } + + pub fn poll(&self) -> Result { + self.inode.poll() + } + + pub fn io_control(&self, cmd: u32, arg: u32) -> Result<()> { + self.inode.io_control(cmd, arg) + } } diff --git a/kernel/src/fs/file_like.rs b/kernel/src/fs/file_like.rs index bd1f660..47a3cc6 100644 --- a/kernel/src/fs/file_like.rs +++ b/kernel/src/fs/file_like.rs @@ -2,8 +2,9 @@ use core::fmt; use super::FileHandle; use crate::net::Socket; -use crate::syscall::SysResult; +use crate::syscall::{SysError, SysResult}; use alloc::boxed::Box; +use rcore_fs::vfs::PollStatus; // TODO: merge FileLike to FileHandle ? // TODO: fix dup and remove Clone @@ -30,12 +31,22 @@ impl FileLike { } pub fn ioctl(&mut self, request: usize, arg1: usize, arg2: usize, arg3: usize) -> SysResult { match self { - FileLike::File(file) => { - warn!("ioctl not implemented for file"); - Ok(0) + FileLike::File(file) => file.io_control(request as u32, arg1 as u32)?, + FileLike::Socket(socket) => { + socket.ioctl(request, arg1, arg2, arg3)?; } - FileLike::Socket(socket) => socket.ioctl(request, arg1, arg2, arg3), } + Ok(0) + } + pub fn poll(&self) -> Result { + let status = match self { + FileLike::File(file) => file.poll()?, + FileLike::Socket(socket) => { + let (read, write, error) = socket.poll(); + PollStatus { read, write, error } + } + }; + Ok(status) } } diff --git a/kernel/src/fs/pipe.rs b/kernel/src/fs/pipe.rs index 4f35fc3..c0c50ea 100644 --- a/kernel/src/fs/pipe.rs +++ b/kernel/src/fs/pipe.rs @@ -57,7 +57,9 @@ impl Pipe { // TODO: better way to provide default impl? macro_rules! impl_inode { () => { + fn poll(&self) -> Result { Err(FsError::NotSupported) } fn metadata(&self) -> Result { Err(FsError::NotSupported) } + fn set_metadata(&self, _metadata: &Metadata) -> Result<()> { Ok(()) } fn sync_all(&self) -> Result<()> { Ok(()) } fn sync_data(&self) -> Result<()> { Ok(()) } fn resize(&self, _len: usize) -> Result<()> { Err(FsError::NotSupported) } @@ -67,9 +69,9 @@ macro_rules! impl_inode { fn move_(&self, _old_name: &str, _target: &Arc, _new_name: &str) -> Result<()> { Err(FsError::NotDir) } fn find(&self, _name: &str) -> Result> { Err(FsError::NotDir) } fn get_entry(&self, _id: usize) -> Result { Err(FsError::NotDir) } + fn io_control(&self, _cmd: u32, _data: u32) -> Result<()> { Err(FsError::NotSupported) } fn fs(&self) -> Arc { unimplemented!() } fn as_any_ref(&self) -> &Any { self } - fn chmod(&self, _mode: u16) -> Result<()> { Ok(()) } }; } diff --git a/kernel/src/fs/stdio.rs b/kernel/src/fs/stdio.rs index 37da693..d2ceda2 100644 --- a/kernel/src/fs/stdio.rs +++ b/kernel/src/fs/stdio.rs @@ -47,6 +47,7 @@ lazy_static! { macro_rules! impl_inode { () => { fn metadata(&self) -> Result { Err(FsError::NotSupported) } + fn set_metadata(&self, _metadata: &Metadata) -> Result<()> { Ok(()) } fn sync_all(&self) -> Result<()> { Ok(()) } fn sync_data(&self) -> Result<()> { Ok(()) } fn resize(&self, _len: usize) -> Result<()> { Err(FsError::NotSupported) } @@ -56,20 +57,27 @@ macro_rules! impl_inode { fn move_(&self, _old_name: &str, _target: &Arc, _new_name: &str) -> Result<()> { Err(FsError::NotDir) } fn find(&self, _name: &str) -> Result> { Err(FsError::NotDir) } fn get_entry(&self, _id: usize) -> Result { Err(FsError::NotDir) } + fn io_control(&self, _cmd: u32, _data: u32) -> Result<()> { Err(FsError::NotSupported) } fn fs(&self) -> Arc { unimplemented!() } fn as_any_ref(&self) -> &Any { self } - fn chmod(&self, _mode: u16) -> Result<()> { Ok(()) } }; } impl INode for Stdin { - fn read_at(&self, _offset: usize, buf: &mut [u8]) -> Result { + fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { buf[0] = self.pop() as u8; Ok(1) } fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result { unimplemented!() } + fn poll(&self) -> Result { + Ok(PollStatus { + read: self.can_read(), + write: false, + error: false, + }) + } impl_inode!(); } @@ -84,5 +92,12 @@ impl INode for Stdout { print!("{}", s); Ok(buf.len()) } + fn poll(&self) -> Result { + Ok(PollStatus { + read: false, + write: true, + error: false, + }) + } impl_inode!(); } diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index 73e9d53..9628242 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -88,34 +88,24 @@ pub fn sys_poll(ufds: *mut PollFd, nfds: usize, timeout_msecs: usize) -> SysResu let proc = process(); let mut events = 0; for poll in polls.iter_mut() { - poll.revents = PE::NONE; - match proc.files.get(&(poll.fd as usize)) { - Some(FileLike::File(_)) => { - // FIXME: assume it is stdin for now - if poll.events.contains(PE::IN) && STDIN.can_read() { - poll.revents = poll.revents | PE::IN; - events = events + 1; - } + poll.revents = PE::empty(); + if let Some(file_like) = proc.files.get(&(poll.fd as usize)) { + let status = file_like.poll()?; + if status.error { + poll.revents |= PE::HUP; + events += 1; } - Some(FileLike::Socket(socket)) => { - let (input, output, err) = socket.poll(); - if err { - poll.revents = poll.revents | PE::HUP; - events = events + 1; - } - if input && poll.events.contains(PE::IN) { - poll.revents = poll.revents | PE::IN; - events = events + 1; - } - if output && poll.events.contains(PE::OUT) { - poll.revents = poll.revents | PE::OUT; - events = events + 1; - } + if status.read && poll.events.contains(PE::IN) { + poll.revents |= PE::IN; + events += 1; } - None => { - poll.revents = poll.revents | PE::ERR; - events = events + 1; + if status.write && poll.events.contains(PE::OUT) { + poll.revents |= PE::OUT; + events += 1; } + } else { + poll.revents |= PE::ERR; + events += 1; } } drop(proc); @@ -163,33 +153,21 @@ pub fn sys_select( let proc = process(); let mut events = 0; for (&fd, file_like) in proc.files.iter() { - if fd < nfds { - match file_like { - FileLike::File(_) => { - // FIXME: assume it is stdin for now - if STDIN.can_read() { - if read_fds.contains(fd) { - read_fds.set(fd); - events = events + 1; - } - } - } - FileLike::Socket(socket) => { - let (input, output, err) = socket.poll(); - if err && err_fds.contains(fd) { - err_fds.set(fd); - events = events + 1; - } - if input && read_fds.contains(fd) { - read_fds.set(fd); - events = events + 1; - } - if output && write_fds.contains(fd) { - write_fds.set(fd); - events = events + 1; - } - } - } + if fd >= nfds { + continue; + } + let status = file_like.poll()?; + if status.error && err_fds.contains(fd) { + err_fds.set(fd); + events += 1; + } + if status.read && read_fds.contains(fd) { + read_fds.set(fd); + events += 1; + } + if status.write && write_fds.contains(fd) { + write_fds.set(fd); + events += 1; } } drop(proc); @@ -1165,8 +1143,6 @@ pub struct PollFd { bitflags! { pub struct PollEvents: u16 { - /// Nothing Happens - const NONE = 0x0000; /// There is data to read. const IN = 0x0001; /// Writing is now possible. From 58932e0bee2b1a9dfe270831d666f587dc741b24 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Fri, 5 Apr 2019 23:31:02 +0800 Subject: [PATCH 16/28] Add uboot instructions --- docs/uboot_raspi3.md | 18 ++++++++++++++++++ kernel/Makefile | 27 ++++++++++++++++++--------- 2 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 docs/uboot_raspi3.md diff --git a/docs/uboot_raspi3.md b/docs/uboot_raspi3.md new file mode 100644 index 0000000..aa792bd --- /dev/null +++ b/docs/uboot_raspi3.md @@ -0,0 +1,18 @@ +How to use u-boot to boot rCore in Raspberry Pi +=============== + +Tested under QEMU. + +Instructions: + +1. Build u-boot + 1. Download aarch64 toolchain and u-boot source + 2. `make rpi_3_defconfig ARCH=arm CROSS_COMPILE=aarch64-elf-` + 3. `make all ARCH=arm CROSS_COMILE=aarch64-elf-` + 4. A file named `u-boot.bin` should be generated +2. Use u-boot to run rCore + 1. `make run arch=aarch64 u_boot=/path/to/u-boot.bin` + 2. In u-boot, enter following commands: + 1. `mmc read 0x1000000 0 ${nblocks}`, where ${nblocks} can be probed if you enter a large enought number + 2. `bootelf -p 0x1000000` + 3. rCore should boot now \ No newline at end of file diff --git a/kernel/Makefile b/kernel/Makefile index c47efc1..3543c70 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -16,18 +16,19 @@ # # Options: # arch = x86_64 | riscv32 | riscv64 | aarch64 -# d = int | in_asm | ... QEMU debug info +# d = int | in_asm | ... QEMU debug info # mode = debug | release # LOG = off | error | warn | info | debug | trace -# SFSIMG = SFS image path of user programs -# smp = 1 | 2 | ... SMP core number -# graphic = on | off enable/disable qemu graphical output -# board = none Running on QEMU -# | u540 Only available on riscv64, run on HiFive U540, use Sv39 -# | raspi3 Only available on aarch64, run on Raspberry Pi 3 Model B/B+ -# pci_passthru = 0000:00:00.1 Only available on x86_64, passthrough the specified PCI device -# init = /bin/ls Only available on riscv64, run specified program instead of user shell +# SFSIMG = SFS image path of user programs +# smp = 1 | 2 | ... SMP core number +# graphic = on | off Enable/disable qemu graphical output +# board = none Running on QEMU +# | u540 Only available on riscv64, run on HiFive U540, use Sv39 +# | raspi3 Only available on aarch64, run on Raspberry Pi 3 Model B/B+ +# pci_passthru = 0000:00:00.1 Only available on x86_64, passthrough the specified PCI device +# init = /bin/ls Only available on riscv64, run specified program instead of user shell # extra_nic = on | off Only available on x86_64, add an additional e1000 nic +# u_boot = /path/to/u-boot.bin Only available on aarch64, use u-boot to boot rcore arch ?= riscv64 board ?= none @@ -114,6 +115,10 @@ qemu_opts += \ -machine $(board) \ -serial null -serial mon:stdio \ -kernel $(kernel_img) +ifneq ($(u_boot), ) +qemu_opts += \ + -sd $(bootloader) +endif endif ifdef d @@ -262,8 +267,12 @@ else ifeq ($(arch), riscv64) make -j && \ cp bbl $(abspath $@) else ifeq ($(arch), aarch64) +ifneq ($(u_boot), ) + @cp $(u_boot) $@ +else @$(objcopy) $(bootloader) --strip-all -O binary $@ endif +endif kernel: @echo Building $(arch) kernel From 6335597897764f8571df75b22efa775d0276fa2a Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Sat, 6 Apr 2019 13:33:17 +0800 Subject: [PATCH 17/28] Add netlink socket skeleton --- kernel/src/drivers/block/virtio_blk.rs | 1 - kernel/src/drivers/bus/pci.rs | 1 - kernel/src/drivers/input/virtio_input.rs | 1 - kernel/src/drivers/net/e1000.rs | 1 - kernel/src/drivers/net/ixgbe.rs | 1 - kernel/src/net/structs.rs | 55 +++++++++++++++++++++++- kernel/src/syscall/net.rs | 47 ++++++++++++++------ 7 files changed, 89 insertions(+), 18 deletions(-) diff --git a/kernel/src/drivers/block/virtio_blk.rs b/kernel/src/drivers/block/virtio_blk.rs index b6cc9cb..c992aaf 100644 --- a/kernel/src/drivers/block/virtio_blk.rs +++ b/kernel/src/drivers/block/virtio_blk.rs @@ -1,4 +1,3 @@ -use alloc::boxed::Box; use alloc::string::String; use alloc::sync::Arc; use core::cmp::min; diff --git a/kernel/src/drivers/bus/pci.rs b/kernel/src/drivers/bus/pci.rs index b5fb798..c0de3bc 100644 --- a/kernel/src/drivers/bus/pci.rs +++ b/kernel/src/drivers/bus/pci.rs @@ -4,7 +4,6 @@ use crate::drivers::net::*; use crate::drivers::{Driver, DRIVERS, NET_DRIVERS}; use crate::memory::active_table; use alloc::collections::BTreeMap; -use alloc::string::String; use alloc::sync::Arc; use core::cmp::Ordering; use pci::*; diff --git a/kernel/src/drivers/input/virtio_input.rs b/kernel/src/drivers/input/virtio_input.rs index 9ff1587..fe16d45 100644 --- a/kernel/src/drivers/input/virtio_input.rs +++ b/kernel/src/drivers/input/virtio_input.rs @@ -2,7 +2,6 @@ use alloc::boxed::Box; use alloc::string::String; use alloc::sync::Arc; use alloc::vec; -use alloc::vec::Vec; use core::fmt; use core::mem::size_of; use core::mem::transmute_copy; diff --git a/kernel/src/drivers/net/e1000.rs b/kernel/src/drivers/net/e1000.rs index f51d90b..0dbcb0b 100644 --- a/kernel/src/drivers/net/e1000.rs +++ b/kernel/src/drivers/net/e1000.rs @@ -11,7 +11,6 @@ use smoltcp::phy::{self, DeviceCapabilities}; use smoltcp::time::Instant; use smoltcp::wire::*; use smoltcp::Result; -use volatile::Volatile; use isomorphic_drivers::net::ethernet::intel::e1000::E1000; use isomorphic_drivers::net::ethernet::structs::EthernetAddress as DriverEthernetAddress; diff --git a/kernel/src/drivers/net/ixgbe.rs b/kernel/src/drivers/net/ixgbe.rs index 72fd7c9..9cf4444 100644 --- a/kernel/src/drivers/net/ixgbe.rs +++ b/kernel/src/drivers/net/ixgbe.rs @@ -9,7 +9,6 @@ use alloc::collections::BTreeMap; use isomorphic_drivers::net::ethernet::intel::ixgbe; use log::*; use rcore_memory::paging::PageTable; -use rcore_memory::PAGE_SIZE; use smoltcp::iface::*; use smoltcp::phy::{self, Checksum, DeviceCapabilities}; use smoltcp::time::Instant; diff --git a/kernel/src/net/structs.rs b/kernel/src/net/structs.rs index 28f4970..4b45f65 100644 --- a/kernel/src/net/structs.rs +++ b/kernel/src/net/structs.rs @@ -21,10 +21,26 @@ impl LinkLevelEndpoint { } } +#[derive(Clone, Debug)] +pub struct NetlinkEndpoint { + port_id: u32, + multicast_groups_mask: u32, +} + +impl NetlinkEndpoint { + pub fn new(port_id: u32, multicast_groups_mask: u32) -> Self { + NetlinkEndpoint { + port_id, + multicast_groups_mask, + } + } +} + #[derive(Clone, Debug)] pub enum Endpoint { Ip(IpEndpoint), LinkLevel(LinkLevelEndpoint), + Netlink(NetlinkEndpoint), } /// Common methods that a socket must have @@ -98,8 +114,12 @@ pub struct RawSocketState { #[derive(Debug, Clone)] pub struct PacketSocketState { + // no state, only ethernet egress +} + +#[derive(Debug, Clone)] +pub struct NetlinkSocketState { // no state -// only ethernet egress } /// A wrapper for `SocketHandle`. @@ -718,6 +738,39 @@ impl Socket for PacketSocketState { } } +impl NetlinkSocketState { + pub fn new() -> Self { + NetlinkSocketState {} + } +} + +impl Socket for NetlinkSocketState { + fn read(&self, data: &mut [u8]) -> (SysResult, Endpoint) { + unimplemented!() + } + + fn write(&self, data: &[u8], _sendto_endpoint: Option) -> SysResult { + debug!("data: {:x?}", &data); + unimplemented!() + } + + fn poll(&self) -> (bool, bool, bool) { + unimplemented!() + } + + fn connect(&mut self, _endpoint: Endpoint) -> SysResult { + unimplemented!() + } + + fn bind(&mut self, _endpoint: Endpoint) -> SysResult { + Ok(0) + } + + fn box_clone(&self) -> Box { + Box::new(self.clone()) + } +} + fn get_ephemeral_port() -> u16 { // TODO selects non-conflict high port static mut EPHEMERAL_PORT: u16 = 0; diff --git a/kernel/src/syscall/net.rs b/kernel/src/syscall/net.rs index ad62598..cda2062 100644 --- a/kernel/src/syscall/net.rs +++ b/kernel/src/syscall/net.rs @@ -4,8 +4,8 @@ use super::*; use crate::drivers::SOCKET_ACTIVITY; use crate::fs::FileLike; use crate::net::{ - Endpoint, LinkLevelEndpoint, PacketSocketState, RawSocketState, Socket, TcpSocketState, - UdpSocketState, SOCKETS, + Endpoint, LinkLevelEndpoint, NetlinkEndpoint, NetlinkSocketState, PacketSocketState, + RawSocketState, Socket, TcpSocketState, UdpSocketState, SOCKETS, }; use crate::sync::{MutexGuard, SpinNoIrq, SpinNoIrqLock as Mutex}; use alloc::boxed::Box; @@ -15,24 +15,27 @@ use smoltcp::wire::*; pub fn sys_socket(domain: usize, socket_type: usize, protocol: usize) -> SysResult { let domain = AddressFamily::from(domain as u16); + let socket_type = SocketType::from(socket_type as u8 & SOCK_TYPE_MASK); info!( - "socket: domain: {:?}, socket_type: {}, protocol: {}", + "socket: domain: {:?}, socket_type: {:?}, protocol: {}", domain, socket_type, protocol ); let mut proc = process(); let socket: Box = match domain { - AddressFamily::Internet | AddressFamily::Unix => { - match SocketType::from(socket_type as u8 & SOCK_TYPE_MASK) { - SocketType::Stream => Box::new(TcpSocketState::new()), - SocketType::Datagram => Box::new(UdpSocketState::new()), - SocketType::Raw => Box::new(RawSocketState::new(protocol as u8)), - _ => return Err(SysError::EINVAL), - } - } - AddressFamily::Packet => match SocketType::from(socket_type as u8 & SOCK_TYPE_MASK) { + AddressFamily::Internet | AddressFamily::Unix => match socket_type { + SocketType::Stream => Box::new(TcpSocketState::new()), + SocketType::Datagram => Box::new(UdpSocketState::new()), + SocketType::Raw => Box::new(RawSocketState::new(protocol as u8)), + _ => return Err(SysError::EINVAL), + }, + AddressFamily::Packet => match socket_type { SocketType::Raw => Box::new(PacketSocketState::new()), _ => return Err(SysError::EINVAL), }, + AddressFamily::Netlink => match socket_type { + SocketType::Raw => Box::new(NetlinkSocketState::new()), + _ => return Err(SysError::EINVAL), + }, _ => return Err(SysError::EAFNOSUPPORT), }; let fd = proc.get_free_fd(); @@ -300,11 +303,20 @@ pub struct SockAddrLl { pub sll_addr: [u8; 8], } +// cancel alignment +#[repr(packed)] +pub struct SockAddrNl { + nl_pad: u16, + nl_pid: u32, + nl_groups: u32, +} + #[repr(C)] pub union SockAddrPayload { pub addr_in: SockAddrIn, pub addr_un: SockAddrUn, pub addr_ll: SockAddrLl, + pub addr_nl: SockAddrNl, } #[repr(C)] @@ -373,6 +385,15 @@ fn sockaddr_to_endpoint( (*addr).payload.addr_ll.sll_ifindex as usize, ))) } + AddressFamily::Netlink => { + if len < size_of::() + size_of::() { + return Err(SysError::EINVAL); + } + Ok(Endpoint::Netlink(NetlinkEndpoint::new( + (*addr).payload.addr_nl.nl_pid, + (*addr).payload.addr_nl.nl_groups, + ))) + } _ => Err(SysError::EINVAL), } } @@ -421,6 +442,8 @@ enum_with_unknown! { Unix = 1, /// Internet IP Protocol Internet = 2, + /// Netlink + Netlink = 16, /// Packet family Packet = 17, } From 1f99f1270aaf49b92b483fcce87717065c572caf Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Sat, 6 Apr 2019 14:21:35 +0800 Subject: [PATCH 18/28] Implement recvmsg syscall for netlink --- kernel/src/drivers/net/ixgbe.rs | 1 - kernel/src/net/structs.rs | 70 ++++++++++++++++++++++++++++++++- kernel/src/process/structs.rs | 2 +- kernel/src/syscall/fs.rs | 10 ++--- kernel/src/syscall/mod.rs | 2 +- kernel/src/syscall/net.rs | 35 +++++++++++++++++ 6 files changed, 111 insertions(+), 9 deletions(-) diff --git a/kernel/src/drivers/net/ixgbe.rs b/kernel/src/drivers/net/ixgbe.rs index 9cf4444..2d3816e 100644 --- a/kernel/src/drivers/net/ixgbe.rs +++ b/kernel/src/drivers/net/ixgbe.rs @@ -8,7 +8,6 @@ use alloc::vec::Vec; use alloc::collections::BTreeMap; use isomorphic_drivers::net::ethernet::intel::ixgbe; use log::*; -use rcore_memory::paging::PageTable; use smoltcp::iface::*; use smoltcp::phy::{self, Checksum, DeviceCapabilities}; use smoltcp::time::Instant; diff --git a/kernel/src/net/structs.rs b/kernel/src/net/structs.rs index 4b45f65..9ff1ded 100644 --- a/kernel/src/net/structs.rs +++ b/kernel/src/net/structs.rs @@ -4,6 +4,8 @@ use crate::sync::SpinNoIrqLock as Mutex; use crate::syscall::*; use crate::util; use alloc::boxed::Box; +use bitflags::*; +use core::mem::size_of; use smoltcp::socket::*; use smoltcp::wire::*; @@ -738,6 +740,62 @@ impl Socket for PacketSocketState { } } +#[repr(C)] +#[derive(Debug)] +struct NetlinkMessageHeader { + nlmsg_len: u32, // length of message including header + nlmsg_type: u16, // message content + nlmsg_flags: NetlinkMessageFlags, // additional flags + nlmsg_seq: u32, // sequence number + nlmsg_pid: u32, // sending process port id +} + +bitflags! { + struct NetlinkMessageFlags : u16 { + const REQUEST = 0x01; + const MULTI = 0x02; + const ACK = 0x04; + const ECHO = 0x08; + const DUMP_INTR = 0x10; + const DUMP_FILTERED = 0x20; + // GET request + const ROOT = 0x100; + const MATCH = 0x200; + const ATOMIC = 0x400; + const DUMP = 0x100 | 0x200; + // NEW request + const REPLACE = 0x100; + const EXCL = 0x200; + const CREATE = 0x400; + const APPEND = 0x800; + // DELETE request + const NONREC = 0x100; + // ACK message + const CAPPED = 0x100; + const ACK_TLVS = 0x200; + } +} + +enum_with_unknown! { + /// Netlink message types + pub doc enum NetlinkMessageType(u16) { + /// New link + NewLink = 16, + /// Delete link + DelLink = 17, + /// Get link + GetLink = 18, + /// Set link + SetLink = 19, + /// New addr + NewAddr = 20, + /// Delete addr + DelAddr = 21, + /// Get addr + GetAddr = 22, + } +} + impl NetlinkSocketState { pub fn new() -> Self { NetlinkSocketState {} @@ -751,7 +809,17 @@ impl Socket for NetlinkSocketState { fn write(&self, data: &[u8], _sendto_endpoint: Option) -> SysResult { debug!("data: {:x?}", &data); - unimplemented!() + if data.len() < size_of::() { + return Err(SysError::EINVAL); + } + let header = unsafe { &*(data.as_ptr() as *const NetlinkMessageHeader) }; + if header.nlmsg_len as usize > data.len() { + return Err(SysError::EINVAL); + } + let message_type = NetlinkMessageType::from(header.nlmsg_type); + debug!("header: {:?}", header); + debug!("type: {:?}", message_type); + Ok(data.len()) } fn poll(&self) -> (bool, bool, bool) { diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index 93820af..057af1c 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -15,7 +15,7 @@ use xmas_elf::{ use crate::arch::interrupt::{Context, TrapFrame}; use crate::fs::{FileHandle, FileLike, INodeExt, OpenOptions, FOLLOW_MAX_DEPTH}; use crate::memory::{ByFrame, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet}; -use crate::net::{Socket, SOCKETS}; +use crate::net::SOCKETS; use crate::sync::{Condvar, SpinNoIrqLock as Mutex}; use super::abi::{self, ProcInitInfo}; diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index 9628242..f59c203 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -1069,10 +1069,10 @@ pub struct IoVec { /// A valid IoVecs request from user #[derive(Debug)] -struct IoVecs(Vec<&'static mut [u8]>); +pub struct IoVecs(Vec<&'static mut [u8]>); impl IoVecs { - fn check_and_new( + pub fn check_and_new( iov_ptr: *const IoVec, iov_count: usize, vm: &MemorySet, @@ -1098,7 +1098,7 @@ impl IoVecs { Ok(IoVecs(slices)) } - fn read_all_to_vec(&self) -> Vec { + pub fn read_all_to_vec(&self) -> Vec { let mut buf = self.new_buf(false); for slice in self.0.iter() { buf.extend(slice.iter()); @@ -1106,7 +1106,7 @@ impl IoVecs { buf } - fn write_all_from_slice(&mut self, buf: &[u8]) { + pub fn write_all_from_slice(&mut self, buf: &[u8]) { let mut copied_len = 0; for slice in self.0.iter_mut() { let copy_len = min(slice.len(), buf.len() - copied_len); @@ -1122,7 +1122,7 @@ impl IoVecs { /// Create a new Vec buffer from IoVecs /// For readv: `set_len` is true, Vec.len = total_len. /// For writev: `set_len` is false, Vec.cap = total_len. - fn new_buf(&self, set_len: bool) -> Vec { + pub fn new_buf(&self, set_len: bool) -> Vec { let total_len = self.0.iter().map(|slice| slice.len()).sum::(); let mut buf = Vec::with_capacity(total_len); if set_len { diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 70ba552..dc2ef48 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -109,7 +109,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { args[5] as *mut u32, ), // SYS_SENDMSG => sys_sendmsg(), - // SYS_RECVMSG => sys_recvmsg(), + SYS_RECVMSG => sys_recvmsg(args[0], args[1] as *mut MsgHdr, args[2]), SYS_SHUTDOWN => sys_shutdown(args[0], args[1]), SYS_BIND => sys_bind(args[0], args[1] as *const SockAddr, args[2]), // 50 diff --git a/kernel/src/syscall/net.rs b/kernel/src/syscall/net.rs index cda2062..b771422 100644 --- a/kernel/src/syscall/net.rs +++ b/kernel/src/syscall/net.rs @@ -1,5 +1,6 @@ //! Syscalls for networking +use super::fs::IoVecs; use super::*; use crate::drivers::SOCKET_ACTIVITY; use crate::fs::FileLike; @@ -173,6 +174,28 @@ pub fn sys_recvfrom( result } +pub fn sys_recvmsg(fd: usize, msg: *mut MsgHdr, flags: usize) -> SysResult { + info!("recvmsg: fd: {}, msg: {:?}, flags: {}", fd, msg, flags); + let mut proc = process(); + proc.vm.check_read_ptr(msg)?; + let hdr = unsafe { &mut *msg }; + let mut iovs = IoVecs::check_and_new(hdr.msg_iov, hdr.msg_iovlen, &proc.vm, true)?; + + let mut buf = iovs.new_buf(true); + let socket = proc.get_socket(fd)?; + let (result, endpoint) = socket.read(&mut buf); + + if let Ok(len) = result { + // copy data to user + iovs.write_all_from_slice(&buf[..len]); + let sockaddr_in = SockAddr::from(endpoint); + unsafe { + sockaddr_in.write_to(&mut proc, hdr.msg_name, &mut hdr.msg_namelen as *mut u32)?; + } + } + unimplemented!() +} + pub fn sys_bind(fd: usize, addr: *const SockAddr, addr_len: usize) -> SysResult { info!("sys_bind: fd: {} addr: {:?} len: {}", fd, addr, addr_len); let mut proc = process(); @@ -433,6 +456,18 @@ impl SockAddr { } } +#[repr(C)] +#[derive(Debug)] +pub struct MsgHdr { + msg_name: *mut SockAddr, + msg_namelen: u32, + msg_iov: *mut IoVec, + msg_iovlen: usize, + msg_control: usize, + msg_controllen: usize, + msg_flags: usize, +} + enum_with_unknown! { /// Address families pub doc enum AddressFamily(u16) { From a7a8c3aa9275416c9cc0f94880e4fd77d7e6d75f Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Sun, 7 Apr 2019 01:59:23 +0800 Subject: [PATCH 19/28] implement getlink for netlink --- kernel/src/net/structs.rs | 199 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 189 insertions(+), 10 deletions(-) diff --git a/kernel/src/net/structs.rs b/kernel/src/net/structs.rs index 9ff1ded..6da97f7 100644 --- a/kernel/src/net/structs.rs +++ b/kernel/src/net/structs.rs @@ -4,15 +4,19 @@ use crate::sync::SpinNoIrqLock as Mutex; use crate::syscall::*; use crate::util; use alloc::boxed::Box; +use alloc::sync::Arc; +use alloc::vec::Vec; use bitflags::*; +use core::cmp::min; use core::mem::size_of; +use core::slice; use smoltcp::socket::*; use smoltcp::wire::*; #[derive(Clone, Debug)] pub struct LinkLevelEndpoint { - interface_index: usize, + pub interface_index: usize, } impl LinkLevelEndpoint { @@ -25,8 +29,8 @@ impl LinkLevelEndpoint { #[derive(Clone, Debug)] pub struct NetlinkEndpoint { - port_id: u32, - multicast_groups_mask: u32, + pub port_id: u32, + pub multicast_groups_mask: u32, } impl NetlinkEndpoint { @@ -121,7 +125,7 @@ pub struct PacketSocketState { #[derive(Debug, Clone)] pub struct NetlinkSocketState { - // no state + data: Arc>>>, } /// A wrapper for `SocketHandle`. @@ -534,7 +538,7 @@ impl Socket for UdpSocketState { let addr = &req.arp_pa as *const SockAddrPlaceholder as *const SockAddr; let addr = unsafe { IpAddress::from(Ipv4Address::from_bytes( - &u32::from_be((*addr).payload.addr_in.sin_addr).to_be_bytes()[..], + &u32::from_be((*addr).addr_in.sin_addr).to_be_bytes()[..], )) }; for iface in NET_DRIVERS.read().iter() { @@ -740,8 +744,12 @@ impl Socket for PacketSocketState { } } +/// Common structure: +/// | nlmsghdr | ifinfomsg | rtattr | rtattr | rtattr | ... | rtattr +/// All aligned to 4 bytes boundary + #[repr(C)] -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] struct NetlinkMessageHeader { nlmsg_len: u32, // length of message including header nlmsg_type: u16, // message content @@ -750,6 +758,23 @@ struct NetlinkMessageHeader { nlmsg_pid: u32, // sending process port id } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +struct IfaceInfoMsg { + ifi_family: u16, + ifi_type: u16, + ifi_index: u32, + ifi_flags: u32, + ifi_change: u32, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +struct RouteAttr { + rta_len: u16, + rta_type: u16, +} + bitflags! { struct NetlinkMessageFlags : u16 { const REQUEST = 0x01; @@ -779,6 +804,14 @@ bitflags! { enum_with_unknown! { /// Netlink message types pub doc enum NetlinkMessageType(u16) { + /// Nothing + Noop = 1, + /// Error + Error = 2, + /// End of a dump + Done = 3, + /// Data lost + Overrun = 4, /// New link NewLink = 16, /// Delete link @@ -796,19 +829,92 @@ enum_with_unknown! { } } +enum_with_unknown! { + /// Route Attr Types + pub doc enum RouteAttrTypes(u16) { + /// Unspecified + Unspecified = 0, + /// MAC Address + Address = 1, + /// Broadcast + Broadcast = 2, + /// Interface name + Ifname = 3, + /// MTU + MTU = 4, + /// Link + Link = 5, + } +} + impl NetlinkSocketState { pub fn new() -> Self { - NetlinkSocketState {} + NetlinkSocketState { + data: Arc::new(Mutex::new(Vec::new())), + } + } +} + +trait VecExt { + fn align4(&mut self); + fn push_ext(&mut self, data: T); + fn set_ext(&mut self, offset: usize, data: T); +} + +impl VecExt for Vec { + fn align4(&mut self) { + let len = (self.len() + 3) & !3; + if len > self.len() { + self.resize(len, 0); + } + } + + fn push_ext(&mut self, data: T) { + let bytes = + unsafe { slice::from_raw_parts(&data as *const T as *const u8, size_of::()) }; + for byte in bytes { + self.push(*byte); + } + } + + fn set_ext(&mut self, offset: usize, data: T) { + if self.len() < offset + size_of::() { + self.resize(offset + size_of::(), 0); + } + let bytes = + unsafe { slice::from_raw_parts(&data as *const T as *const u8, size_of::()) }; + for i in 0..bytes.len() { + self[offset + i] = bytes[i]; + } } } impl Socket for NetlinkSocketState { fn read(&self, data: &mut [u8]) -> (SysResult, Endpoint) { - unimplemented!() + let mut buffer = self.data.lock(); + if buffer.len() > 0 { + let msg = buffer.remove(0); + let len = min(msg.len(), data.len()); + data[..len].copy_from_slice(&msg[..len]); + ( + Ok(len), + Endpoint::Netlink(NetlinkEndpoint { + port_id: 0, + multicast_groups_mask: 0, + }), + ) + } else { + ( + Ok(0), + Endpoint::Netlink(NetlinkEndpoint { + port_id: 0, + multicast_groups_mask: 0, + }), + ) + } } fn write(&self, data: &[u8], _sendto_endpoint: Option) -> SysResult { - debug!("data: {:x?}", &data); if data.len() < size_of::() { return Err(SysError::EINVAL); } @@ -817,8 +923,81 @@ impl Socket for NetlinkSocketState { return Err(SysError::EINVAL); } let message_type = NetlinkMessageType::from(header.nlmsg_type); - debug!("header: {:?}", header); debug!("type: {:?}", message_type); + let mut buffer = self.data.lock(); + buffer.clear(); + match message_type { + NetlinkMessageType::GetLink => { + let ifaces = NET_DRIVERS.read(); + for i in 0..ifaces.len() { + let mut msg = Vec::new(); + let mut new_header = NetlinkMessageHeader { + nlmsg_len: 0, // to be determined later + nlmsg_type: NetlinkMessageType::NewLink.into(), + nlmsg_flags: NetlinkMessageFlags::MULTI, + nlmsg_seq: header.nlmsg_seq, + nlmsg_pid: header.nlmsg_pid, + }; + msg.push_ext(new_header); + + let if_info = IfaceInfoMsg { + ifi_family: AddressFamily::Unspecified.into(), + ifi_type: 0, + ifi_index: i as u32, + ifi_flags: 0, + ifi_change: 0, + }; + msg.align4(); + msg.push_ext(if_info); + + let mut attrs = Vec::new(); + + let mac_addr = ifaces[i].get_mac(); + let attr = RouteAttr { + rta_len: (mac_addr.as_bytes().len() + size_of::()) as u16, + rta_type: RouteAttrTypes::Address.into(), + }; + attrs.align4(); + attrs.push_ext(attr); + for byte in mac_addr.as_bytes() { + attrs.push(*byte); + } + + let ifname = ifaces[i].get_ifname(); + let attr = RouteAttr { + rta_len: (ifname.as_bytes().len() + size_of::()) as u16, + rta_type: RouteAttrTypes::Ifname.into(), + }; + attrs.align4(); + attrs.push_ext(attr); + for byte in ifname.as_bytes() { + attrs.push(*byte); + } + + msg.align4(); + msg.append(&mut attrs); + + msg.align4(); + msg.set_ext(0, msg.len() as u32); + + buffer.push(msg); + } + + let mut msg = Vec::new(); + let mut new_header = NetlinkMessageHeader { + nlmsg_len: 0, // to be determined later + nlmsg_type: NetlinkMessageType::Done.into(), + nlmsg_flags: NetlinkMessageFlags::MULTI, + nlmsg_seq: header.nlmsg_seq, + nlmsg_pid: header.nlmsg_pid, + }; + msg.push_ext(new_header); + msg.align4(); + msg.set_ext(0, msg.len() as u32); + buffer.push(msg); + } + _ => {} + } Ok(data.len()) } From 2c3a4d75dd04adfc32755c9c6c3857020c6ea1c0 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Sun, 7 Apr 2019 02:19:07 +0800 Subject: [PATCH 20/28] implement getaddr for netlink, ip l/ip a is working now --- kernel/src/drivers/mod.rs | 7 ++- kernel/src/drivers/net/e1000.rs | 5 ++ kernel/src/drivers/net/ixgbe.rs | 5 ++ kernel/src/net/structs.rs | 84 ++++++++++++++++++++++++++++----- kernel/src/syscall/net.rs | 84 +++++++++++++++++++++------------ 5 files changed, 141 insertions(+), 44 deletions(-) diff --git a/kernel/src/drivers/mod.rs b/kernel/src/drivers/mod.rs index 661cfb6..05735c1 100644 --- a/kernel/src/drivers/mod.rs +++ b/kernel/src/drivers/mod.rs @@ -3,7 +3,7 @@ use alloc::sync::Arc; use alloc::vec::Vec; use lazy_static::lazy_static; -use smoltcp::wire::{EthernetAddress, IpAddress, Ipv4Address}; +use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address}; use spin::RwLock; use crate::sync::Condvar; @@ -56,6 +56,11 @@ pub trait Driver: Send + Sync { unimplemented!("not a net driver") } + // get ip addresses + fn get_ip_addresses(&self) -> Vec { + unimplemented!("not a net driver") + } + // get ipv4 address fn ipv4_address(&self) -> Option { unimplemented!("not a net driver") diff --git a/kernel/src/drivers/net/e1000.rs b/kernel/src/drivers/net/e1000.rs index 0dbcb0b..24e34aa 100644 --- a/kernel/src/drivers/net/e1000.rs +++ b/kernel/src/drivers/net/e1000.rs @@ -73,6 +73,11 @@ impl Driver for E1000Interface { self.name.clone() } + // get ip addresses + fn get_ip_addresses(&self) -> Vec { + Vec::from(self.iface.lock().ip_addrs()) + } + fn ipv4_address(&self) -> Option { self.iface.lock().ipv4_address() } diff --git a/kernel/src/drivers/net/ixgbe.rs b/kernel/src/drivers/net/ixgbe.rs index 2d3816e..115a0bd 100644 --- a/kernel/src/drivers/net/ixgbe.rs +++ b/kernel/src/drivers/net/ixgbe.rs @@ -82,6 +82,11 @@ impl Driver for IXGBEInterface { self.ifname.clone() } + // get ip addresses + fn get_ip_addresses(&self) -> Vec { + Vec::from(self.iface.lock().ip_addrs()) + } + fn ipv4_address(&self) -> Option { self.iface.lock().ipv4_address() } diff --git a/kernel/src/net/structs.rs b/kernel/src/net/structs.rs index 6da97f7..7dcb754 100644 --- a/kernel/src/net/structs.rs +++ b/kernel/src/net/structs.rs @@ -745,7 +745,7 @@ impl Socket for PacketSocketState { } /// Common structure: -/// | nlmsghdr | ifinfomsg | rtattr | rtattr | rtattr | ... | rtattr +/// | nlmsghdr | ifinfomsg/ifaddrmsg | rtattr | rtattr | rtattr | ... | rtattr /// All aligned to 4 bytes boundary #[repr(C)] @@ -768,6 +768,16 @@ struct IfaceInfoMsg { ifi_change: u32, } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +struct IfaceAddrMsg { + ifa_family: u8, + ifa_prefixlen: u8, + ifa_flags: u8, + ifa_scope: u8, + ifa_index: u32, +} + #[repr(C)] #[derive(Debug, Copy, Clone)] struct RouteAttr { @@ -982,22 +992,70 @@ impl Socket for NetlinkSocketState { buffer.push(msg); } + } + NetlinkMessageType::GetAddr => { + let ifaces = NET_DRIVERS.read(); + for i in 0..ifaces.len() { + let ip_addrs = ifaces[i].get_ip_addresses(); + for j in 0..ip_addrs.len() { + let mut msg = Vec::new(); + let mut new_header = NetlinkMessageHeader { + nlmsg_len: 0, // to be determined later + nlmsg_type: NetlinkMessageType::NewAddr.into(), + nlmsg_flags: NetlinkMessageFlags::MULTI, + nlmsg_seq: header.nlmsg_seq, + nlmsg_pid: header.nlmsg_pid, + }; + msg.push_ext(new_header); + + let family: u16 = AddressFamily::Internet.into(); + let if_addr = IfaceAddrMsg { + ifa_family: family as u8, + ifa_prefixlen: ip_addrs[j].prefix_len(), + ifa_flags: 0, + ifa_scope: 0, + ifa_index: i as u32, + }; + msg.align4(); + msg.push_ext(if_addr); + + let mut attrs = Vec::new(); + + let ip_addr = ip_addrs[j].address(); + let attr = RouteAttr { + rta_len: (ip_addr.as_bytes().len() + size_of::()) as u16, + rta_type: RouteAttrTypes::Address.into(), + }; + attrs.align4(); + attrs.push_ext(attr); + for byte in ip_addr.as_bytes() { + attrs.push(*byte); + } - let mut msg = Vec::new(); - let mut new_header = NetlinkMessageHeader { - nlmsg_len: 0, // to be determined later - nlmsg_type: NetlinkMessageType::Done.into(), - nlmsg_flags: NetlinkMessageFlags::MULTI, - nlmsg_seq: header.nlmsg_seq, - nlmsg_pid: header.nlmsg_pid, - }; - msg.push_ext(new_header); - msg.align4(); - msg.set_ext(0, msg.len() as u32); - buffer.push(msg); + msg.align4(); + msg.append(&mut attrs); + + msg.align4(); + msg.set_ext(0, msg.len() as u32); + + buffer.push(msg); + } + } } _ => {} } + let mut msg = Vec::new(); + let mut new_header = NetlinkMessageHeader { + nlmsg_len: 0, // to be determined later + nlmsg_type: NetlinkMessageType::Done.into(), + nlmsg_flags: NetlinkMessageFlags::MULTI, + nlmsg_seq: header.nlmsg_seq, + nlmsg_pid: header.nlmsg_pid, + }; + msg.push_ext(new_header); + msg.align4(); + msg.set_ext(0, msg.len() as u32); + buffer.push(msg); Ok(data.len()) } diff --git a/kernel/src/syscall/net.rs b/kernel/src/syscall/net.rs index b771422..1372340 100644 --- a/kernel/src/syscall/net.rs +++ b/kernel/src/syscall/net.rs @@ -193,7 +193,7 @@ pub fn sys_recvmsg(fd: usize, msg: *mut MsgHdr, flags: usize) -> SysResult { sockaddr_in.write_to(&mut proc, hdr.msg_name, &mut hdr.msg_namelen as *mut u32)?; } } - unimplemented!() + result } pub fn sys_bind(fd: usize, addr: *const SockAddr, addr_len: usize) -> SysResult { @@ -302,9 +302,9 @@ impl Process { } } -// cancel alignment -#[repr(packed)] +#[repr(C)] pub struct SockAddrIn { + pub sin_family: u16, pub sin_port: u16, pub sin_addr: u32, pub sin_zero: [u8; 8], @@ -312,12 +312,13 @@ pub struct SockAddrIn { #[repr(C)] pub struct SockAddrUn { + pub sun_family: u16, pub sun_path: [u8; 108], } -// beware of alignment issue -#[repr(C, packed)] +#[repr(C)] pub struct SockAddrLl { + pub sll_family: u16, pub sll_protocol: u16, pub sll_ifindex: u32, pub sll_hatype: u16, @@ -326,26 +327,22 @@ pub struct SockAddrLl { pub sll_addr: [u8; 8], } -// cancel alignment -#[repr(packed)] +#[repr(C)] pub struct SockAddrNl { + nl_family: u16, nl_pad: u16, nl_pid: u32, nl_groups: u32, } #[repr(C)] -pub union SockAddrPayload { +pub union SockAddr { + pub family: u16, pub addr_in: SockAddrIn, pub addr_un: SockAddrUn, pub addr_ll: SockAddrLl, pub addr_nl: SockAddrNl, -} - -#[repr(C)] -pub struct SockAddr { - pub family: u16, - pub payload: SockAddrPayload, + pub addr_ph: SockAddrPlaceholder, } #[repr(C)] @@ -359,17 +356,42 @@ impl From for SockAddr { if let Endpoint::Ip(ip) = endpoint { match ip.addr { IpAddress::Ipv4(ipv4) => SockAddr { - family: AddressFamily::Internet.into(), - payload: SockAddrPayload { - addr_in: SockAddrIn { - sin_port: u16::to_be(ip.port), - sin_addr: u32::to_be(u32::from_be_bytes(ipv4.0)), - sin_zero: [0; 8], - }, + addr_in: SockAddrIn { + sin_family: AddressFamily::Internet.into(), + sin_port: u16::to_be(ip.port), + sin_addr: u32::to_be(u32::from_be_bytes(ipv4.0)), + sin_zero: [0; 8], + }, + }, + IpAddress::Unspecified => SockAddr { + addr_ph: SockAddrPlaceholder { + family: AddressFamily::Unspecified.into(), + data: [0; 14], }, }, _ => unimplemented!("only ipv4"), } + } else if let Endpoint::LinkLevel(link_level) = endpoint { + SockAddr { + addr_ll: SockAddrLl { + sll_family: AddressFamily::Packet.into(), + sll_protocol: 0, + sll_ifindex: link_level.interface_index as u32, + sll_hatype: 0, + sll_pkttype: 0, + sll_halen: 0, + sll_addr: [0; 8], + }, + } + } else if let Endpoint::Netlink(netlink) = endpoint { + SockAddr { + addr_nl: SockAddrNl { + nl_family: AddressFamily::Netlink.into(), + nl_pad: 0, + nl_pid: netlink.port_id, + nl_groups: netlink.multicast_groups_mask, + }, + } } else { unimplemented!("only ip"); } @@ -390,31 +412,31 @@ fn sockaddr_to_endpoint( unsafe { match AddressFamily::from((*addr).family) { AddressFamily::Internet => { - if len < size_of::() + size_of::() { + if len < size_of::() { return Err(SysError::EINVAL); } - let port = u16::from_be((*addr).payload.addr_in.sin_port); + let port = u16::from_be((*addr).addr_in.sin_port); let addr = IpAddress::from(Ipv4Address::from_bytes( - &u32::from_be((*addr).payload.addr_in.sin_addr).to_be_bytes()[..], + &u32::from_be((*addr).addr_in.sin_addr).to_be_bytes()[..], )); Ok(Endpoint::Ip((addr, port).into())) } AddressFamily::Unix => Err(SysError::EINVAL), AddressFamily::Packet => { - if len < size_of::() + size_of::() { + if len < size_of::() { return Err(SysError::EINVAL); } Ok(Endpoint::LinkLevel(LinkLevelEndpoint::new( - (*addr).payload.addr_ll.sll_ifindex as usize, + (*addr).addr_ll.sll_ifindex as usize, ))) } AddressFamily::Netlink => { - if len < size_of::() + size_of::() { + if len < size_of::() { return Err(SysError::EINVAL); } Ok(Endpoint::Netlink(NetlinkEndpoint::new( - (*addr).payload.addr_nl.nl_pid, - (*addr).payload.addr_nl.nl_groups, + (*addr).addr_nl.nl_pid, + (*addr).addr_nl.nl_groups, ))) } _ => Err(SysError::EINVAL), @@ -439,7 +461,9 @@ impl SockAddr { proc.vm.check_write_ptr(addr_len)?; let max_addr_len = *addr_len as usize; let full_len = match AddressFamily::from(self.family) { - AddressFamily::Internet => size_of::() + size_of::(), + AddressFamily::Internet => size_of::(), + AddressFamily::Packet => size_of::(), + AddressFamily::Netlink => size_of::(), AddressFamily::Unix => return Err(SysError::EINVAL), _ => return Err(SysError::EINVAL), }; From 358fa09f6da85532c52e0173c48a262e89322af5 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Wed, 10 Apr 2019 13:12:26 +0800 Subject: [PATCH 21/28] Update README about bootimage version --- README.md | 3 ++- user | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 184ecb4..9907e44 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,8 @@ See [Travis script](./.travis.yml) for details. ```bash $ rustup component add rust-src -$ cargo install cargo-xbuild bootimage +$ cargo install cargo-xbuild --force +$ cargo install bootimage --version 0.5.7 --force ``` ```bash diff --git a/user b/user index aeea2b5..fdaa1be 160000 --- a/user +++ b/user @@ -1 +1 @@ -Subproject commit aeea2b569efe90e38b39d3c72edb4bc015837d14 +Subproject commit fdaa1be8635944d88ff128da13bf0464f7ce2eb6 From e12074c936aa83efe7934941f7f5bd261b72a208 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 12 Apr 2019 00:23:34 +0800 Subject: [PATCH 22/28] replace gnu binutils with cargo-binutils --- .travis.yml | 7 ++++--- README.md | 11 ++++++----- kernel/Makefile | 11 +++-------- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9e99092..1b3e81a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,8 +36,8 @@ matrix: install: - if [ $ARCH = riscv32 ] || [ $ARCH = riscv64 ]; then - [ $TRAVIS_OS_NAME = linux ] && export FILE="riscv64-unknown-elf-gcc-8.1.0-2019.01.0-x86_64-linux-ubuntu14"; - [ $TRAVIS_OS_NAME = osx ] && export FILE="riscv64-unknown-elf-gcc-8.1.0-2019.01.0-x86_64-apple-darwin"; + [ $TRAVIS_OS_NAME = linux ] && export FILE="riscv64-unknown-elf-gcc-8.2.0-2019.02.0-x86_64-linux-ubuntu14"; + [ $TRAVIS_OS_NAME = osx ] && export FILE="riscv64-unknown-elf-gcc-8.2.0-2019.02.0-x86_64-apple-darwin"; wget https://static.dev.sifive.com/dev-tools/$FILE.tar.gz; tar xf $FILE.tar.gz; export PATH=$PATH:$PWD/$FILE/bin; @@ -103,7 +103,8 @@ install: before_script: - - rustup component add rust-src + - rustup component add rust-src llvm-tools-preview + - (test -x $HOME/.cargo/bin/cargo-objdump || cargo install cargo-binutils) - (test -x $HOME/.cargo/bin/cargo-xbuild || cargo install cargo-xbuild) - if [ $ARCH = x86_64 ]; then (test -x $HOME/.cargo/bin/bootimage || cargo install bootimage); diff --git a/README.md b/README.md index 9907e44..7bc1057 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Rust version of THU [uCore OS Plus](https://github.com/chyyuu/ucore_os_plus). Going to be the next generation teaching operating system. -Supported architectures: x86_64, RISCV32/64, AArch64, MIPS (planned) +Supported architectures: x86_64, RISCV32/64, AArch64, MIPS32 Tested boards: QEMU, HiFive Unleashed, x86_64 PC (i5/i7), Raspberry Pi 3B+ @@ -18,7 +18,7 @@ Tested boards: QEMU, HiFive Unleashed, x86_64 PC (i5/i7), Raspberry Pi 3B+ ### Environment -* [Rust](https://www.rust-lang.org) toolchain at nightly-2019-02-16 +* [Rust](https://www.rust-lang.org) toolchain at nightly-2019-03-05 * Cargo tools: [cargo-xbuild](https://github.com/rust-osdev/cargo-xbuild) * [QEMU](https://www.qemu.org) >= 3.1.0 * [bootimage](https://github.com/rust-osdev/bootimage) (for x86_64) @@ -32,7 +32,8 @@ See [Travis script](./.travis.yml) for details. ### How to run ```bash -$ rustup component add rust-src +$ rustup component add rust-src llvm-tools-preview +$ cargo install cargo-binutils $ cargo install cargo-xbuild --force $ cargo install bootimage --version 0.5.7 --force ``` @@ -40,9 +41,9 @@ $ cargo install bootimage --version 0.5.7 --force ```bash $ git clone https://github.com/rcore-os/rCore.git --recursive $ cd rCore/user -$ make sfsimg arch={riscv32,riscv64,x86_64,aarch64} # requires x86_64-linux-musl-gcc or musl-gcc +$ make sfsimg arch={riscv32,riscv64,x86_64,aarch64,mipsel} # requires $(arch)-linux-musl-gcc $ cd ../kernel -$ make run arch={riscv32,riscv64,x86_64,aarch64} mode=release +$ make run arch={riscv32,riscv64,x86_64,aarch64,mipsel} mode=release $ make run arch=x86_64 mode=release pci_passthru=0000:00:00.1 # for ixgbe real nic, find its pci (bus, dev, func) first ``` diff --git a/kernel/Makefile b/kernel/Makefile index e6592a5..b8edfb8 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -216,16 +216,11 @@ ifeq (,$(shell which $(prefix)ld)) endif endif -ld := $(prefix)ld -objdump := $(prefix)objdump -objcopy := $(prefix)objcopy -cc := $(prefix)gcc -as := $(prefix)as gdb := $(prefix)gdb -strip := $(prefix)strip +objdump := cargo objdump -- -arch-name=$(subst _,-,$(arch)) +objcopy := cargo objcopy -- --binary-architecture=$(subst _,-,$(arch)) +strip := cargo strip -- dtc := dtc -export CC = $(cc) - hostcc := gcc .PHONY: all clean build asm doc debug kernel sfsimg install run justrun runnet justrunnet runui justrunui runtest justruntest From a4221a559c9120a4526662bb3a5071016243b086 Mon Sep 17 00:00:00 2001 From: NagiNikaido Date: Fri, 12 Apr 2019 13:10:34 +0800 Subject: [PATCH 23/28] .gitignore updated. --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 4b4a5a8..021a507 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,8 @@ Cargo.lock # for eclipse .project +# for vscode .vscode + +# for vim +*.swp From fe0045c0c9ed576d31fa0359775b6fecd534f4aa Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 12 Apr 2019 19:23:45 +0800 Subject: [PATCH 24/28] remove legacy 'is32' code --- kernel/src/arch/aarch64/consts.rs | 1 - kernel/src/arch/aarch64/interrupt/context.rs | 1 - kernel/src/arch/mipsel/consts.rs | 1 - kernel/src/arch/mipsel/context.rs | 1 - kernel/src/arch/riscv32/consts.rs | 1 - kernel/src/arch/riscv32/context.rs | 1 - kernel/src/arch/x86_64/consts.rs | 1 - kernel/src/arch/x86_64/interrupt/trapframe.rs | 14 +++----------- kernel/src/process/structs.rs | 14 ++++---------- 9 files changed, 7 insertions(+), 28 deletions(-) diff --git a/kernel/src/arch/aarch64/consts.rs b/kernel/src/arch/aarch64/consts.rs index ea71e7a..3a7c500 100644 --- a/kernel/src/arch/aarch64/consts.rs +++ b/kernel/src/arch/aarch64/consts.rs @@ -5,4 +5,3 @@ pub const KERNEL_HEAP_SIZE: usize = 8 * 1024 * 1024; pub const MEMORY_OFFSET: usize = 0; pub const USER_STACK_OFFSET: usize = 0x0000_8000_0000_0000 - USER_STACK_SIZE; pub const USER_STACK_SIZE: usize = 1 * 1024 * 1024; -pub const USER32_STACK_OFFSET: usize = USER_STACK_OFFSET; diff --git a/kernel/src/arch/aarch64/interrupt/context.rs b/kernel/src/arch/aarch64/interrupt/context.rs index 6639ab8..87f3a4e 100644 --- a/kernel/src/arch/aarch64/interrupt/context.rs +++ b/kernel/src/arch/aarch64/interrupt/context.rs @@ -163,7 +163,6 @@ impl Context { entry_addr: usize, ustack_top: usize, kstack_top: usize, - _is32: bool, ttbr: usize, ) -> Self { InitStack { diff --git a/kernel/src/arch/mipsel/consts.rs b/kernel/src/arch/mipsel/consts.rs index ff2ef0c..48b1b82 100644 --- a/kernel/src/arch/mipsel/consts.rs +++ b/kernel/src/arch/mipsel/consts.rs @@ -8,6 +8,5 @@ pub const MEMORY_OFFSET: usize = 0x8000_0000; pub const USER_STACK_OFFSET: usize = 0x80000000 - USER_STACK_SIZE; pub const USER_STACK_SIZE: usize = 0x10000; -pub const USER32_STACK_OFFSET: usize = 0x80000000 - USER_STACK_SIZE; pub const MAX_DTB_SIZE: usize = 0x2000; diff --git a/kernel/src/arch/mipsel/context.rs b/kernel/src/arch/mipsel/context.rs index 85bc56b..69f9016 100644 --- a/kernel/src/arch/mipsel/context.rs +++ b/kernel/src/arch/mipsel/context.rs @@ -206,7 +206,6 @@ impl Context { entry_addr: usize, ustack_top: usize, kstack_top: usize, - _is32: bool, satp: usize, ) -> Self { info!( diff --git a/kernel/src/arch/riscv32/consts.rs b/kernel/src/arch/riscv32/consts.rs index a3004b0..45fa998 100644 --- a/kernel/src/arch/riscv32/consts.rs +++ b/kernel/src/arch/riscv32/consts.rs @@ -37,6 +37,5 @@ pub const MEMORY_END: usize = 0x8100_0000; // FIXME: rv64 `sh` and `ls` will crash if stack top > 0x80000000 ??? pub const USER_STACK_OFFSET: usize = 0x80000000 - USER_STACK_SIZE; pub const USER_STACK_SIZE: usize = 0x10000; -pub const USER32_STACK_OFFSET: usize = 0xC0000000 - USER_STACK_SIZE; pub const MAX_DTB_SIZE: usize = 0x2000; diff --git a/kernel/src/arch/riscv32/context.rs b/kernel/src/arch/riscv32/context.rs index e05dafe..51df0c1 100644 --- a/kernel/src/arch/riscv32/context.rs +++ b/kernel/src/arch/riscv32/context.rs @@ -236,7 +236,6 @@ impl Context { entry_addr: usize, ustack_top: usize, kstack_top: usize, - _is32: bool, satp: usize, ) -> Self { InitStack { diff --git a/kernel/src/arch/x86_64/consts.rs b/kernel/src/arch/x86_64/consts.rs index 7543779..2095e39 100644 --- a/kernel/src/arch/x86_64/consts.rs +++ b/kernel/src/arch/x86_64/consts.rs @@ -53,7 +53,6 @@ pub const USER_GRANT_PML4: usize = (USER_GRANT_OFFSET & PML4_MASK) / PML4_SIZE; /// Offset to user stack pub const USER_STACK_OFFSET: usize = USER_GRANT_OFFSET + PML4_SIZE; -pub const USER32_STACK_OFFSET: usize = 0xB000_0000; pub const USER_STACK_PML4: usize = (USER_STACK_OFFSET & PML4_MASK) / PML4_SIZE; /// Size of user stack pub const USER_STACK_SIZE: usize = 1024 * 1024; // 1 MB diff --git a/kernel/src/arch/x86_64/interrupt/trapframe.rs b/kernel/src/arch/x86_64/interrupt/trapframe.rs index 03f4c32..d9ab7f7 100644 --- a/kernel/src/arch/x86_64/interrupt/trapframe.rs +++ b/kernel/src/arch/x86_64/interrupt/trapframe.rs @@ -73,14 +73,10 @@ impl TrapFrame { tf.fpstate_offset = 16; // skip restoring for first time tf } - fn new_user_thread(entry_addr: usize, rsp: usize, is32: bool) -> Self { + fn new_user_thread(entry_addr: usize, rsp: usize) -> Self { use crate::arch::gdt; let mut tf = TrapFrame::default(); - tf.cs = if is32 { - gdt::UCODE32_SELECTOR.0 - } else { - gdt::UCODE_SELECTOR.0 - } as usize; + tf.cs = gdt::UCODE_SELECTOR.0 as usize; tf.rip = entry_addr; tf.ss = gdt::UDATA32_SELECTOR.0 as usize; tf.rsp = rsp; @@ -88,9 +84,6 @@ impl TrapFrame { tf.fpstate_offset = 16; // skip restoring for first time tf } - pub fn is_user(&self) -> bool { - self.cs & 0x3 == 0x3 - } } #[derive(Debug, Default)] @@ -203,12 +196,11 @@ impl Context { entry_addr: usize, ustack_top: usize, kstack_top: usize, - is32: bool, cr3: usize, ) -> Self { InitStack { context: ContextData::new(cr3), - tf: TrapFrame::new_user_thread(entry_addr, ustack_top, is32), + tf: TrapFrame::new_user_thread(entry_addr, ustack_top), } .push_at(kstack_top) } diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index 057af1c..084469f 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -175,10 +175,6 @@ impl Thread { { // Parse ELF let elf = ElfFile::new(data).expect("failed to read elf"); - let is32 = match elf.header.pt2 { - header::HeaderPt2::Header32(_) => true, - header::HeaderPt2::Header64(_) => false, - }; // Check ELF type match elf.header.pt2.type_().as_type() { @@ -210,12 +206,10 @@ impl Thread { let mut vm = elf.make_memory_set(); // User stack - use crate::consts::{USER32_STACK_OFFSET, USER_STACK_OFFSET, USER_STACK_SIZE}; + use crate::consts::{USER_STACK_OFFSET, USER_STACK_SIZE}; let mut ustack_top = { - let (ustack_buttom, ustack_top) = match is32 { - true => (USER32_STACK_OFFSET, USER32_STACK_OFFSET + USER_STACK_SIZE), - false => (USER_STACK_OFFSET, USER_STACK_OFFSET + USER_STACK_SIZE), - }; + let ustack_buttom = USER_STACK_OFFSET; + let ustack_top = USER_STACK_OFFSET + USER_STACK_SIZE; vm.push( ustack_buttom, ustack_top, @@ -288,7 +282,7 @@ impl Thread { Box::new(Thread { context: unsafe { - Context::new_user_thread(entry_addr, ustack_top, kstack.top(), is32, vm.token()) + Context::new_user_thread(entry_addr, ustack_top, kstack.top(), vm.token()) }, kstack, clear_child_tid: 0, From 3556c758db105bf22ed7fc87beb3e6f0106c8fec Mon Sep 17 00:00:00 2001 From: WangRunji Date: Sun, 14 Apr 2019 15:47:42 +0800 Subject: [PATCH 25/28] impl more file system *at syscalls --- kernel/src/process/structs.rs | 15 +-- kernel/src/syscall/fs.rs | 197 +++++++++++++++++++++------------- kernel/src/syscall/mod.rs | 15 +-- 3 files changed, 135 insertions(+), 92 deletions(-) diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index 084469f..700d4c2 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -123,24 +123,13 @@ impl rcore_thread::Context for Thread { impl Thread { /// Make a struct for the init thread - /// TODO: remove this, we only need `Context::null()` pub unsafe fn new_init() -> Box { Box::new(Thread { context: Context::null(), kstack: KernelStack::new(), clear_child_tid: 0, - proc: Arc::new(Mutex::new(Process { - vm: MemorySet::new(), - files: BTreeMap::default(), - cwd: String::from("/"), - futexes: BTreeMap::default(), - pid: Pid::uninitialized(), - parent: None, - children: Vec::new(), - threads: Vec::new(), - child_exit: Arc::new(Condvar::new()), - child_exit_code: BTreeMap::new(), - })), + // safety: this field will never be used + proc: core::mem::uninitialized(), }) } diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index f59c203..274154c 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -237,49 +237,24 @@ pub fn sys_openat(dir_fd: usize, path: *const u8, flags: usize, mode: usize) -> dir_fd as isize, path, flags, mode ); - let inode = if dir_fd == AT_FDCWD { - // from process cwd - if flags.contains(OpenFlags::CREATE) { - let (dir_path, file_name) = split_path(&path); - // relative to cwd - let dir_inode = proc.lookup_inode(dir_path)?; - match dir_inode.find(file_name) { - Ok(file_inode) => { - if flags.contains(OpenFlags::EXCLUSIVE) { - return Err(SysError::EEXIST); - } - file_inode + let inode = if flags.contains(OpenFlags::CREATE) { + let (dir_path, file_name) = split_path(&path); + // relative to cwd + let dir_inode = proc.lookup_inode_at(dir_fd, dir_path)?; + match dir_inode.find(file_name) { + Ok(file_inode) => { + if flags.contains(OpenFlags::EXCLUSIVE) { + return Err(SysError::EEXIST); } - Err(FsError::EntryNotFound) => { - dir_inode.create(file_name, FileType::File, mode as u32)? - } - Err(e) => return Err(SysError::from(e)), + file_inode } - } else { - proc.lookup_inode(&path)? - } - } else { - // relative to dir_fd - let dir_file = proc.get_file(dir_fd)?; - if flags.contains(OpenFlags::CREATE) { - let (dir_path, file_name) = split_path(&path); - // relative to cwd - let dir_inode = dir_file.lookup_follow(dir_path, FOLLOW_MAX_DEPTH)?; - match dir_inode.find(file_name) { - Ok(file_inode) => { - if flags.contains(OpenFlags::EXCLUSIVE) { - return Err(SysError::EEXIST); - } - file_inode - } - Err(FsError::EntryNotFound) => { - dir_inode.create(file_name, FileType::File, mode as u32)? - } - Err(e) => return Err(SysError::from(e)), + Err(FsError::EntryNotFound) => { + dir_inode.create(file_name, FileType::File, mode as u32)? } - } else { - dir_file.lookup_follow(&path, FOLLOW_MAX_DEPTH)? + Err(e) => return Err(SysError::from(e)), } + } else { + proc.lookup_inode_at(dir_fd, &path)? }; let fd = proc.get_free_fd(); @@ -297,14 +272,22 @@ pub fn sys_close(fd: usize) -> SysResult { } pub fn sys_access(path: *const u8, mode: usize) -> SysResult { + sys_faccessat(AT_FDCWD, path, mode, 0) +} + +pub fn sys_faccessat(dirfd: usize, path: *const u8, mode: usize, flags: usize) -> SysResult { // TODO: check permissions based on uid/gid let proc = process(); let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; + let flags = AtFlags::from_bits_truncate(flags); if !proc.pid.is_init() { // we trust pid 0 process - info!("access: path: {:?}, mode: {:#o}", path, mode); + info!( + "faccessat: dirfd: {}, path: {:?}, mode: {:#o}, flags: {:?}", + dirfd, path, mode, flags + ); } - let inode = proc.lookup_inode(&path)?; + let inode = proc.lookup_inode_at(dirfd, &path)?; Ok(0) } @@ -322,9 +305,9 @@ pub fn sys_getcwd(buf: *mut u8, len: usize) -> SysResult { Ok(buf as usize) } -pub fn sys_stat(path: *const u8, stat_ptr: *mut Stat) -> SysResult { - warn!("stat is partial implemented as lstat"); - sys_lstat(path, stat_ptr) +pub fn sys_lstat(path: *const u8, stat_ptr: *mut Stat) -> SysResult { + warn!("lstat is partial implemented as stat"); + sys_stat(path, stat_ptr) } pub fn sys_fstat(fd: usize, stat_ptr: *mut Stat) -> SysResult { @@ -333,20 +316,23 @@ pub fn sys_fstat(fd: usize, stat_ptr: *mut Stat) -> SysResult { proc.vm.check_write_ptr(stat_ptr)?; let file = proc.get_file(fd)?; let stat = Stat::from(file.metadata()?); - // TODO: handle symlink unsafe { stat_ptr.write(stat); } Ok(0) } -pub fn sys_lstat(path: *const u8, stat_ptr: *mut Stat) -> SysResult { +pub fn sys_fstatat(dirfd: usize, path: *const u8, stat_ptr: *mut Stat, flags: usize) -> SysResult { let proc = process(); let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; proc.vm.check_write_ptr(stat_ptr)?; - info!("lstat: path: {:?}, stat_ptr: {:?}", path, stat_ptr); + let flags = AtFlags::from_bits_truncate(flags); + info!( + "fstatat: dirfd: {}, path: {:?}, stat_ptr: {:?}, flags: {:?}", + dirfd, path, stat_ptr, flags + ); - let inode = proc.lookup_inode(&path)?; + let inode = proc.lookup_inode_at(dirfd, &path)?; let stat = Stat::from(inode.metadata()?); unsafe { stat_ptr.write(stat); @@ -354,13 +340,21 @@ pub fn sys_lstat(path: *const u8, stat_ptr: *mut Stat) -> SysResult { Ok(0) } +pub fn sys_stat(path: *const u8, stat_ptr: *mut Stat) -> SysResult { + sys_fstatat(AT_FDCWD, path, stat_ptr, 0) +} + pub fn sys_readlink(path: *const u8, base: *mut u8, len: usize) -> SysResult { + sys_readlinkat(AT_FDCWD, path, base, len) +} + +pub fn sys_readlinkat(dirfd: usize, path: *const u8, base: *mut u8, len: usize) -> SysResult { let proc = process(); let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; proc.vm.check_write_array(base, len)?; info!("readlink: path: {:?}, base: {:?}, len: {}", path, base, len); - let inode = proc.lookup_inode(&path)?; + let inode = proc.lookup_inode_at(dirfd, &path)?; if inode.metadata()?.type_ == FileType::SymLink { // TODO: recursive link resolution and loop detection let mut slice = unsafe { slice::from_raw_parts_mut(base, len) }; @@ -504,30 +498,27 @@ pub fn sys_renameat( let (old_dir_path, old_file_name) = split_path(&oldpath); let (new_dir_path, new_file_name) = split_path(&newpath); - let old_dir_inode = if olddirfd == AT_FDCWD { - proc.lookup_inode(old_dir_path)? - } else { - proc.get_file(olddirfd)? - .lookup_follow(old_dir_path, FOLLOW_MAX_DEPTH)? - }; - let new_dir_inode = if newdirfd == AT_FDCWD { - proc.lookup_inode(new_dir_path)? - } else { - proc.get_file(newdirfd)? - .lookup_follow(new_dir_path, FOLLOW_MAX_DEPTH)? - }; + let old_dir_inode = proc.lookup_inode_at(olddirfd, old_dir_path)?; + let new_dir_inode = proc.lookup_inode_at(newdirfd, new_dir_path)?; old_dir_inode.move_(old_file_name, &new_dir_inode, new_file_name)?; Ok(0) } pub fn sys_mkdir(path: *const u8, mode: usize) -> SysResult { + sys_mkdirat(AT_FDCWD, path, mode) +} + +pub fn sys_mkdirat(dirfd: usize, path: *const u8, mode: usize) -> SysResult { let proc = process(); let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; // TODO: check pathname - info!("mkdir: path: {:?}, mode: {:#o}", path, mode); + info!( + "mkdirat: dirfd: {}, path: {:?}, mode: {:#o}", + dirfd, path, mode + ); let (dir_path, file_name) = split_path(&path); - let inode = proc.lookup_inode(dir_path)?; + let inode = proc.lookup_inode_at(dirfd, dir_path)?; if inode.find(file_name).is_ok() { return Err(SysError::EEXIST); } @@ -551,25 +542,47 @@ pub fn sys_rmdir(path: *const u8) -> SysResult { } pub fn sys_link(oldpath: *const u8, newpath: *const u8) -> SysResult { + sys_linkat(AT_FDCWD, oldpath, AT_FDCWD, newpath, 0) +} + +pub fn sys_linkat( + olddirfd: usize, + oldpath: *const u8, + newdirfd: usize, + newpath: *const u8, + flags: usize, +) -> SysResult { let proc = process(); let oldpath = unsafe { proc.vm.check_and_clone_cstr(oldpath)? }; let newpath = unsafe { proc.vm.check_and_clone_cstr(newpath)? }; - info!("link: oldpath: {:?}, newpath: {:?}", oldpath, newpath); + let flags = AtFlags::from_bits_truncate(flags); + info!( + "linkat: olddirfd: {}, oldpath: {:?}, newdirfd: {}, newpath: {:?}, flags: {:?}", + olddirfd, oldpath, newdirfd, newpath, flags + ); let (new_dir_path, new_file_name) = split_path(&newpath); - let inode = proc.lookup_inode(&oldpath)?; - let new_dir_inode = proc.lookup_inode(new_dir_path)?; + let inode = proc.lookup_inode_at(olddirfd, &oldpath)?; + let new_dir_inode = proc.lookup_inode_at(newdirfd, new_dir_path)?; new_dir_inode.link(new_file_name, &inode)?; Ok(0) } pub fn sys_unlink(path: *const u8) -> SysResult { + sys_unlinkat(AT_FDCWD, path, 0) +} + +pub fn sys_unlinkat(dirfd: usize, path: *const u8, flags: usize) -> SysResult { let proc = process(); let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; - info!("unlink: path: {:?}", path); + let flags = AtFlags::from_bits_truncate(flags); + info!( + "unlinkat: dirfd: {}, path: {:?}, flags: {:?}", + dirfd, path, flags + ); let (dir_path, file_name) = split_path(&path); - let dir_inode = proc.lookup_inode(dir_path)?; + let dir_inode = proc.lookup_inode_at(dirfd, dir_path)?; let file_inode = dir_inode.find(file_name)?; if file_inode.metadata()?.type_ == FileType::Dir { return Err(SysError::EISDIR); @@ -701,11 +714,44 @@ impl Process { _ => Err(SysError::EBADF), } } + /// Lookup INode from the process. + /// + /// - If `path` is relative, then it is interpreted relative to the directory + /// referred to by the file descriptor `dirfd`. + /// + /// - If the `dirfd` is the special value `AT_FDCWD`, then the directory is + /// current working directory of the process. + /// + /// - If `path` is absolute, then `dirfd` is ignored. + /// + /// - If `follow` is true, then dereference `path` if it is a symbolic link. + pub fn lookup_inode_at( + &self, + dirfd: usize, + path: &str, + // follow: bool, + ) -> Result, SysError> { + let follow = true; + debug!( + "lookup_inode_at: fd: {:?}, cwd: {:?}, path: {:?}, follow: {:?}", + dirfd, self.cwd, path, follow + ); + let follow_max_depth = if follow { FOLLOW_MAX_DEPTH } else { 0 }; + if dirfd == AT_FDCWD { + Ok(ROOT_INODE + .lookup(&self.cwd)? + .lookup_follow(path, follow_max_depth)?) + } else { + let file = match self.files.get(&dirfd).ok_or(SysError::EBADF)? { + FileLike::File(file) => file, + _ => return Err(SysError::EBADF), + }; + Ok(file.lookup_follow(path, follow_max_depth)?) + } + } + pub fn lookup_inode(&self, path: &str) -> Result, SysError> { - debug!("lookup_inode: cwd {} path {}", self.cwd, path); - Ok(ROOT_INODE - .lookup(&self.cwd)? - .lookup_follow(path, FOLLOW_MAX_DEPTH)?) + self.lookup_inode_at(AT_FDCWD, path) } } @@ -740,6 +786,13 @@ impl From for SysError { } } +bitflags! { + struct AtFlags: usize { + const EMPTY_PATH = 0x1000; + const SYMLINK_NOFOLLOW = 0x100; + } +} + bitflags! { struct OpenFlags: usize { /// read only diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index d74e125..ef12052 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -244,20 +244,21 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { } SYS_CLOCK_GETTIME => sys_clock_gettime(args[0], args[1] as *mut TimeSpec), SYS_EXIT_GROUP => sys_exit_group(args[0]), - SYS_OPENAT => sys_openat(args[0], args[1] as *const u8, args[2], args[3]), // TODO: handle `dfd` - SYS_MKDIRAT => sys_mkdir(args[1] as *const u8, args[2]), // TODO: handle `dfd` + SYS_OPENAT => sys_openat(args[0], args[1] as *const u8, args[2], args[3]), + SYS_MKDIRAT => sys_mkdirat(args[0], args[1] as *const u8, args[2]), // SYS_MKNODAT => sys_mknod(), // 260 SYS_FCHOWNAT => { warn!("sys_fchownat is unimplemented"); Ok(0) } - SYS_NEWFSTATAT => sys_stat(args[1] as *const u8, args[2] as *mut Stat), // TODO: handle `dfd`, `flag` - SYS_UNLINKAT => sys_unlink(args[1] as *const u8), // TODO: handle `dfd`, `flag` - SYS_RENAMEAT => sys_renameat(args[0], args[1] as *const u8, args[2], args[3] as *const u8), // TODO: handle `olddfd`, `newdfd` - SYS_LINKAT => sys_link(args[1] as *const u8, args[3] as *const u8), // TODO: handle `olddfd`, `newdfd`, `flags` + SYS_NEWFSTATAT => sys_fstatat(args[0], args[1] as *const u8, args[2] as *mut Stat, args[3]), + SYS_UNLINKAT => sys_unlinkat(args[0], args[1] as *const u8, args[2]), + SYS_READLINKAT => sys_readlinkat(args[0], args[1] as *const u8, args[2] as *mut u8, args[3]), + SYS_RENAMEAT => sys_renameat(args[0], args[1] as *const u8, args[2], args[3] as *const u8), + SYS_LINKAT => sys_linkat(args[0], args[1] as *const u8, args[2], args[3] as *const u8, args[4]), SYS_SYMLINKAT => Err(SysError::EACCES), - SYS_FACCESSAT => sys_access(args[1] as *const u8, args[2]), // TODO: handle `dfd` + SYS_FACCESSAT => sys_faccessat(args[0], args[1] as *const u8, args[2], args[3]), // 280 SYS_UTIMENSAT => { warn!("sys_utimensat is unimplemented"); From c3813c4b38a6e9a5f7c67add07482eae87ca76a1 Mon Sep 17 00:00:00 2001 From: NagiNikaido Date: Mon, 15 Apr 2019 00:41:28 +0800 Subject: [PATCH 26/28] BUGFIX: rewrited sys_chdir(). --- kernel/src/syscall/fs.rs | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index f59c203..97138b7 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -474,12 +474,34 @@ pub fn sys_chdir(path: *const u8) -> SysResult { return Err(SysError::ENOTDIR); } - if path.len() > 0 && path.as_bytes()[0] == b'/' { - // absolute - proc.cwd = path; - } else { - // relative - proc.cwd += &path; + // BUGFIX: '..' and '.' + if path.len() > 0 { + let cwd = match path.as_bytes()[0] { + b'/' => String::from("/"), + _ => proc.cwd.clone() + }; + let mut cwd_vec:Vec<_> = + cwd.split("/") + .filter(|&x| x != "") + .collect(); + let path_split = path.split("/").filter(|&x| x != ""); + for seg in path_split { + if seg == ".." { + cwd_vec.pop(); + } else if seg == "." { + // nothing to do here. + } else { + cwd_vec.push(seg); + } + } + proc.cwd = String::from(""); + for seg in cwd_vec { + proc.cwd.push_str("/"); + proc.cwd.push_str(seg); + } + if proc.cwd == "" { + proc.cwd = String::from("/"); + } } Ok(0) } From f88cffb8ab9e1a81f4999a6db61b328f27fe93a9 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Mon, 15 Apr 2019 21:10:49 +0800 Subject: [PATCH 27/28] fix bitvec version --- kernel/Cargo.lock | 2 +- kernel/src/syscall/fs.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 28447a3..a4eacbc 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -85,7 +85,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitvec" version = "0.11.0" -source = "git+https://github.com/myrrlyn/bitvec.git#f6e1fbed95061955d96617dfed6c112ffba45a7e" +source = "git+https://github.com/myrrlyn/bitvec.git#ed2aec38bfb5b1116e3585b1574c50655b9c85ec" [[package]] name = "bootloader" diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index 7e52e7b..1ef806e 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -10,7 +10,7 @@ use crate::fs::*; use crate::memory::MemorySet; use crate::sync::Condvar; -use bitvec::{BitSlice, BitVec, LittleEndian}; +use bitvec::prelude::{BitSlice, BitVec, LittleEndian}; use super::*; From 81152561622df06ee996aadfb7705688525ed5d2 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Tue, 16 Apr 2019 10:05:42 +0800 Subject: [PATCH 28/28] Check exec args --- kernel/src/syscall/proc.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/src/syscall/proc.rs b/kernel/src/syscall/proc.rs index 2c4b909..c6cc4ec 100644 --- a/kernel/src/syscall/proc.rs +++ b/kernel/src/syscall/proc.rs @@ -146,6 +146,9 @@ pub fn sys_exec( } } info!("exec: args {:?}", args); + if args.is_empty() { + return Err(SysError::EINVAL); + } // Read program file let path = args[0].as_str();