Merge branch 'dev'

master
Jiajie Chen 6 years ago
commit 9aa24ccacb

4
.gitignore vendored

@ -14,4 +14,8 @@ Cargo.lock
# for eclipse # for eclipse
.project .project
# for vscode
.vscode .vscode
# for vim
*.swp

@ -36,8 +36,8 @@ matrix:
install: install:
- if [ $ARCH = riscv32 ] || [ $ARCH = riscv64 ]; then - 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 = 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.1.0-2019.01.0-x86_64-apple-darwin"; [ $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; wget https://static.dev.sifive.com/dev-tools/$FILE.tar.gz;
tar xf $FILE.tar.gz; tar xf $FILE.tar.gz;
export PATH=$PATH:$PWD/$FILE/bin; export PATH=$PATH:$PWD/$FILE/bin;
@ -103,7 +103,8 @@ install:
before_script: 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) - (test -x $HOME/.cargo/bin/cargo-xbuild || cargo install cargo-xbuild)
- if [ $ARCH = x86_64 ]; then - if [ $ARCH = x86_64 ]; then
(test -x $HOME/.cargo/bin/bootimage || cargo install bootimage); (test -x $HOME/.cargo/bin/bootimage || cargo install bootimage);

@ -1,8 +1,6 @@
[workspace] [workspace]
members = [ members = [
"crate/bit-allocator",
"crate/memory", "crate/memory",
"crate/sync", "crate/sync",
"crate/thread",
] ]
exclude = ["kernel", "bootloader", "user/rust"] exclude = ["kernel", "bootloader", "user/rust"]

@ -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. 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+ 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 ### 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) * Cargo tools: [cargo-xbuild](https://github.com/rust-osdev/cargo-xbuild)
* [QEMU](https://www.qemu.org) >= 3.1.0 * [QEMU](https://www.qemu.org) >= 3.1.0
* [bootimage](https://github.com/rust-osdev/bootimage) (for x86_64) * [bootimage](https://github.com/rust-osdev/bootimage) (for x86_64)
@ -32,16 +32,18 @@ See [Travis script](./.travis.yml) for details.
### How to run ### How to run
```bash ```bash
$ rustup component add rust-src $ rustup component add rust-src llvm-tools-preview
$ cargo install cargo-xbuild bootimage $ cargo install cargo-binutils
$ cargo install cargo-xbuild --force
$ cargo install bootimage --version 0.5.7 --force
``` ```
```bash ```bash
$ git clone https://github.com/rcore-os/rCore.git --recursive $ git clone https://github.com/rcore-os/rCore.git --recursive
$ cd rCore/user $ 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 $ 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 $ make run arch=x86_64 mode=release pci_passthru=0000:00:00.1 # for ixgbe real nic, find its pci (bus, dev, func) first
``` ```

@ -1,7 +0,0 @@
[package]
name = "bit-allocator"
version = "0.1.0"
authors = ["WangRunji <wangrunji0408@163.com>"]
[dependencies]
bit_field = "0.9"

@ -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<usize>;
fn dealloc(&mut self, key: usize);
fn insert(&mut self, range: Range<usize>);
fn remove(&mut self, range: Range<usize>);
fn any(&self) -> bool;
fn test(&self, key: usize) -> bool;
}
pub type BitAlloc256 = BitAllocCascade16<BitAlloc16>;
pub type BitAlloc4K = BitAllocCascade16<BitAlloc256>;
pub type BitAlloc64K = BitAllocCascade16<BitAlloc4K>;
pub type BitAlloc1M = BitAllocCascade16<BitAlloc64K>;
pub type BitAlloc16M = BitAllocCascade16<BitAlloc1M>;
pub type BitAlloc256M = BitAllocCascade16<BitAlloc16M>;
/// Implement the bit allocator by segment tree algorithm.
#[derive(Default)]
pub struct BitAllocCascade16<T: BitAlloc> {
bitset: u16, // for each bit, 1 indicates available, 0 indicates inavailable
sub: [T; 16],
}
impl<T: BitAlloc> BitAlloc for BitAllocCascade16<T> {
const CAP: usize = T::CAP * 16;
fn alloc(&mut self) -> Option<usize> {
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<usize>) {
self.for_range(range, |sub: &mut T, range| sub.insert(range));
}
fn remove(&mut self, range: Range<usize>) {
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<T: BitAlloc> BitAllocCascade16<T> {
fn for_range(&mut self, range: Range<usize>, f: impl Fn(&mut T, Range<usize>)) {
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<usize> {
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<usize>) {
self.0.set_bits(range.clone(), 0xffff.get_bits(range));
}
fn remove(&mut self, range: Range<usize>) {
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());
}
}

@ -1,11 +0,0 @@
[package]
name = "rcore-thread"
version = "0.1.0"
authors = ["WangRunji <wangrunji0408@163.com>"]
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" }

@ -1 +0,0 @@
fn main() {}

@ -1,19 +0,0 @@
[package]
name = "example"
version = "0.1.0"
authors = ["WangRunji <wangrunji0408@163.com>"]
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"
]

@ -1,5 +0,0 @@
# Example of `rcore-thread` crate
```bash
bootimage run --release
```

@ -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<Self> {
Box::new(core::mem::uninitialized())
}
fn new(entry: extern fn(usize) -> !, arg0: usize) -> Box<Self> {
let mut thread = unsafe { Thread::init() };
let rsp = thread.stack.as_ptr() as usize + STACK_SIZE - core::mem::size_of::<ContextData>();
// 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<Context> {
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");
}

@ -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"
}

@ -1,92 +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");
}
#[inline(always)]
#[cfg(target_arch = "mips")]
pub unsafe fn disable_and_store() -> usize {
let cp0_status: usize;
asm!("mfc0 $0, $$12;" : "=r"(cp0_status) ::: "volatile");
let cp0_status_new = cp0_status & !1;
asm!("mtc0 $0, $$12;" : : "r"(cp0_status_new) :: "volatile");
cp0_status & 1
}
#[inline(always)]
#[cfg(target_arch = "mips")]
pub unsafe fn restore(flags: usize) {
let cp0_status: usize;
asm!("mfc0 $0, $$12;" : "=r"(cp0_status) ::: "volatile");
let cp0_status_new = cp0_status | flags;
asm!("mtc0 $0, $$12;" : : "r"(cp0_status_new) :: "volatile");
}
#[inline(always)]
#[cfg(target_arch = "mips")]
pub unsafe fn enable_and_wfi() {
let cp0_status: usize;
asm!("mfc0 $0, $$12;" : "=r"(cp0_status) ::: "volatile");
let cp0_status_new = cp0_status | 1;
asm!("mtc0 $0, $$12; wait;" : : "r"(cp0_status_new) :: "volatile");
}

@ -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::*;

@ -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<Option<ProcessorInner>>,
}
unsafe impl Sync for Processor {}
struct ProcessorInner {
id: usize,
proc: Option<(Tid, Box<Context>)>,
loop_context: Box<Context>,
manager: Arc<ThreadPool>,
}
impl Processor {
pub const fn new() -> Self {
Processor {
inner: UnsafeCell::new(None),
}
}
pub unsafe fn init(&self, id: usize, context: Box<Context>, manager: Arc<ThreadPool>) {
*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();
}
}
}

@ -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<Tid>;
/// 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<T: Default + Clone>(vec: &mut Vec<T>, id: usize) {
let len = vec.len();
vec.resize(len.max(id + 1), T::default());
}

@ -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<O1SchedulerInner>,
}
struct O1SchedulerInner {
active_queue: usize,
queues: [Vec<Tid>; 2],
}
impl Scheduler for O1Scheduler {
fn push(&self, tid: usize) {
self.inner.lock().push(tid);
}
fn pop(&self, _cpu_id: usize) -> Option<usize> {
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<Tid> {
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
}
}

@ -1,109 +0,0 @@
use super::*;
pub struct RRScheduler {
inner: Mutex<RRSchedulerInner>,
}
struct RRSchedulerInner {
max_time_slice: usize,
infos: Vec<RRProcInfo>,
}
#[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<usize> {
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<Tid> {
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;
}
}

@ -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<StrideSchedulerInner>,
}
pub struct StrideSchedulerInner {
max_time_slice: usize,
infos: Vec<StrideProcInfo>,
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<usize> {
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<Tid> {
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);
}
}

@ -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<Worker<Tid>>,
/// Stealers to all processors' queue
stealers: Vec<Stealer<Tid>>,
}
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<usize> {
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) {}
}

@ -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<Context> {
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, T>(f: F) -> JoinHandle<T>
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, T>(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, T>, 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<T> {
thread: Thread,
mark: PhantomData<T>,
}
impl<T> JoinHandle<T> {
/// 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<T, ()> {
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();
}
}
}

@ -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<Tid>,
context: Option<Box<Context>>,
}
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<Mutex<Option<Thread>>>,
scheduler: Box<Scheduler>,
timer: Mutex<Timer<Event>>,
}
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<Option<Thread>>) {
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<Context>) -> 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<Tid>) -> 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<Context>)> {
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<Context>) {
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<ExitCode> {
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<T: Default>(size: usize) -> Vec<T> {
let mut vec = Vec::new();
vec.resize_with(size, Default::default);
vec
}

@ -1,65 +0,0 @@
//! A simple timer
use alloc::collections::VecDeque;
type Time = usize;
struct Event<T> {
time: Time,
data: T,
}
/// A simple timer using ordered dequeue
pub struct Timer<T> {
tick: Time,
timers: VecDeque<Event<T>>,
}
impl<T: PartialEq> Timer<T> {
/// 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<T> {
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);
}
}
}

@ -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

42
kernel/Cargo.lock generated

@ -59,13 +59,6 @@ dependencies = [
"volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "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]] [[package]]
name = "bit_field" name = "bit_field"
version = "0.9.0" version = "0.9.0"
@ -76,11 +69,24 @@ name = "bitflags"
version = "1.0.4" version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "bitvec" name = "bitvec"
version = "0.9.0" version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" 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#ed2aec38bfb5b1116e3585b1574c50655b9c85ec"
[[package]] [[package]]
name = "bootloader" name = "bootloader"
version = "0.4.0" version = "0.4.0"
@ -186,8 +192,9 @@ dependencies = [
[[package]] [[package]]
name = "isomorphic_drivers" name = "isomorphic_drivers"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/rcore-os/isomorphic_drivers#a564ac855887a823dac80529ec4138194583905d" source = "git+https://github.com/rcore-os/isomorphic_drivers#fe4af36d5f7bf3ac32be77597ccc61fc8cf8bd98"
dependencies = [ 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)", "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)", "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)", "volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -360,9 +367,10 @@ dependencies = [
"aarch64 2.2.2 (git+https://github.com/rcore-os/aarch64)", "aarch64 2.2.2 (git+https://github.com/rcore-os/aarch64)",
"apic 0.1.0 (git+https://github.com/rcore-os/apic-rs)", "apic 0.1.0 (git+https://github.com/rcore-os/apic-rs)",
"bcm2837 0.1.0 (git+https://github.com/rcore-os/bcm2837)", "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)", "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)", "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)", "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)", "buddy_system_allocator 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)",
@ -381,9 +389,9 @@ dependencies = [
"rcore-fs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)", "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-fs-sfs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)",
"rcore-memory 0.1.0", "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)", "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)", "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)", "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)", "volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -394,12 +402,12 @@ dependencies = [
[[package]] [[package]]
name = "rcore-fs" name = "rcore-fs"
version = "0.1.0" 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]] [[package]]
name = "rcore-fs-sfs" name = "rcore-fs-sfs"
version = "0.1.0" 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 = [ dependencies = [
"bitvec 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -418,6 +426,7 @@ dependencies = [
[[package]] [[package]]
name = "rcore-thread" name = "rcore-thread"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/rcore-os/rcore-thread#7236bfd2e2bde673773214739695bb2925a77ae5"
dependencies = [ dependencies = [
"deque 0.3.2 (git+https://github.com/rcore-os/deque.git?branch=no_std)", "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)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -492,7 +501,7 @@ dependencies = [
[[package]] [[package]]
name = "smoltcp" name = "smoltcp"
version = "0.5.0" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/rcore-os/smoltcp#107d299b41a8f8cc370e3105dda38acc33609483"
dependencies = [ dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -666,6 +675,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum bcm2837 0.1.0 (git+https://github.com/rcore-os/bcm2837)" = "<none>" "checksum bcm2837 0.1.0 (git+https://github.com/rcore-os/bcm2837)" = "<none>"
"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" "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 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)" = "<none>"
"checksum bitvec 0.11.0 (git+https://github.com/myrrlyn/bitvec.git)" = "<none>"
"checksum bitvec 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cfadef5c4e2c2e64067b9ecc061179f12ac7ec65ba613b1f60f3972bbada1f5b" "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)" = "<none>" "checksum bootloader 0.4.0 (git+https://github.com/rcore-os/bootloader)" = "<none>"
"checksum buddy_system_allocator 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2ed828f1e227d6e32b998d6375b67fd63ac5389d50b23f258ce151d22b6cc595" "checksum buddy_system_allocator 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2ed828f1e227d6e32b998d6375b67fd63ac5389d50b23f258ce151d22b6cc595"
@ -706,6 +717,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 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)" = "<none>" "checksum rcore-fs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)" = "<none>"
"checksum rcore-fs-sfs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)" = "<none>" "checksum rcore-fs-sfs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)" = "<none>"
"checksum rcore-thread 0.1.0 (git+https://github.com/rcore-os/rcore-thread)" = "<none>"
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "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 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" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
@ -714,7 +726,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 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 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 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)" = "<none>"
"checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" "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 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" "checksum static_assertions 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "389ce475f424f267dbed6479cbd8f126c5e1afb053b0acdaa019c74305fc65d1"

@ -49,16 +49,17 @@ bitflags = "1.0"
bit_field = "0.9" bit_field = "0.9"
volatile = "0.2" volatile = "0.2"
heapless = "0.4" heapless = "0.4"
bitvec = { git = "https://github.com/myrrlyn/bitvec.git", default-features = false, features = ["alloc"] }
console-traits = "0.3" console-traits = "0.3"
buddy_system_allocator = "0.1" buddy_system_allocator = "0.1"
pci = { git = "https://github.com/rcore-os/pci-rs" } pci = { git = "https://github.com/rcore-os/pci-rs" }
device_tree = { git = "https://github.com/rcore-os/device_tree-rs" } device_tree = { git = "https://github.com/rcore-os/device_tree-rs" }
isomorphic_drivers = { git = "https://github.com/rcore-os/isomorphic_drivers" } isomorphic_drivers = { git = "https://github.com/rcore-os/isomorphic_drivers" }
lazy_static = { version = "1.3", features = ["spin_no_std"] } 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"] }
bit-allocator = { path = "../crate/bit-allocator" } bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator" }
rcore-memory = { path = "../crate/memory" } 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 = { git = "https://github.com/rcore-os/rcore-fs" }
rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs" } rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs" }

@ -19,16 +19,17 @@
# d = int | in_asm | ... QEMU debug info # d = int | in_asm | ... QEMU debug info
# mode = debug | release # mode = debug | release
# LOG = off | error | warn | info | debug | trace # LOG = off | error | warn | info | debug | trace
# SFSIMG = <sfsimg> SFS image path of user programs # SFSIMG = <sfsimg> SFS image path of user programs
# smp = 1 | 2 | ... SMP core number # smp = 1 | 2 | ... SMP core number
# graphic = on | off enable/disable qemu graphical output # graphic = on | off Enable/disable qemu graphical output
# board = none Running on QEMU # board = none Running on QEMU
# | pc Only available on x86_64, run on real pc # | pc Only available on x86_64, run on real pc
# | u540 Only available on riscv64, run on HiFive U540, use Sv39 # | u540 Only available on riscv64, run on HiFive U540, use Sv39
# | raspi3 Only available on aarch64, run on Raspberry Pi 3 Model B/B+ # | 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 # 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 # 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 # 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 arch ?= riscv64
board ?= none board ?= none
@ -93,8 +94,7 @@ export DTB = $(dtb)
### qemu options ### ### qemu options ###
qemu_opts := \ qemu_opts := \
-smp cores=$(smp) -smp cores=$(smp)
qemu_net_opts := \ qemu_net_opts :=
-netdev type=tap,id=net0,script=no,downscript=no
ifeq ($(arch), x86_64) ifeq ($(arch), x86_64)
qemu_opts += \ qemu_opts += \
@ -111,6 +111,7 @@ qemu_opts += \
-device isa-debug-exit -device isa-debug-exit
ifeq ($(pci_passthru), ) ifeq ($(pci_passthru), )
qemu_net_opts += \ qemu_net_opts += \
-netdev type=tap,id=net0,script=no,downscript=no \
-device e1000e,netdev=net0 -device e1000e,netdev=net0
else else
qemu_opts += \ qemu_opts += \
@ -131,6 +132,7 @@ qemu_opts += \
-drive file=$(SFSIMG),format=qcow2,id=sfs \ -drive file=$(SFSIMG),format=qcow2,id=sfs \
-device virtio-blk-device,drive=sfs -device virtio-blk-device,drive=sfs
qemu_net_opts += \ qemu_net_opts += \
-netdev type=tap,id=net0,script=no,downscript=no \
-device virtio-net-device,netdev=net0 -device virtio-net-device,netdev=net0
else ifeq ($(arch), riscv64) else ifeq ($(arch), riscv64)
@ -140,6 +142,7 @@ qemu_opts += \
-drive file=$(SFSIMG),format=qcow2,id=sfs \ -drive file=$(SFSIMG),format=qcow2,id=sfs \
-device virtio-blk-device,drive=sfs -device virtio-blk-device,drive=sfs
qemu_net_opts += \ qemu_net_opts += \
-netdev type=tap,id=net0,script=no,downscript=no \
-device virtio-net-device,netdev=net0 -device virtio-net-device,netdev=net0
else ifeq ($(arch), aarch64) else ifeq ($(arch), aarch64)
@ -147,6 +150,10 @@ qemu_opts += \
-machine $(board) \ -machine $(board) \
-serial null -serial mon:stdio \ -serial null -serial mon:stdio \
-kernel $(kernel_img) -kernel $(kernel_img)
ifneq ($(u_boot), )
qemu_opts += \
-sd $(bootloader)
endif
else ifeq ($(arch), mipsel) else ifeq ($(arch), mipsel)
ifeq ($(board), malta) ifeq ($(board), malta)
@ -224,16 +231,11 @@ ifeq (,$(shell which $(prefix)ld))
endif endif
endif endif
ld := $(prefix)ld
objdump := $(prefix)objdump
objcopy := $(prefix)objcopy
cc := $(prefix)gcc
as := $(prefix)as
gdb := $(prefix)gdb 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 dtc := dtc
export CC = $(cc)
hostcc := gcc hostcc := gcc
.PHONY: all clean build asm doc debug kernel sfsimg install run justrun runnet justrunnet runui justrunui runtest justruntest .PHONY: all clean build asm doc debug kernel sfsimg install run justrun runnet justrunnet runui justrunui runtest justruntest
@ -324,7 +326,11 @@ else ifeq ($(arch), riscv64)
make -j && \ make -j && \
cp bbl $(abspath $@) cp bbl $(abspath $@)
else ifeq ($(arch), aarch64) else ifeq ($(arch), aarch64)
ifneq ($(u_boot), )
@cp $(u_boot) $@
else
@$(objcopy) $(bootloader) --strip-all -O binary $@ @$(objcopy) $(bootloader) --strip-all -O binary $@
endif
else ifeq ($(arch), mipsel) else ifeq ($(arch), mipsel)
# qemu-system-mipsel accepts ELF file only, so objcopy is not needed # qemu-system-mipsel accepts ELF file only, so objcopy is not needed
@$(strip) $(kernel) -o $@ @$(strip) $(kernel) -o $@

@ -0,0 +1,62 @@
virtqueue_pop
virtio_blk_req_complete
virtio_blk_rw_complete
virtio_blk_submit_multireq
virtio_blk_handle_write
virtio_blk_handle_read
e1000e_link_status
e1000e_mac_set_sw
e1000e_irq_itr_set
e1000e_irq_eitr_set
e1000e_tx_disabled
e1000e_tx_descr
e1000e_rx_descr
#e1000e_rx_has_buffers
e1000e_rx_start_recv
#e1000e_rx_can_recv
e1000e_rx_can_recv_rings_full
e1000_receiver_overrun
#e1000e_rx_receive_iov
e1000e_core_ctrl_sw_reset
e1000e_core_ctrl_phy_reset
e1000e_rx_desc_buff_sizes
e1000e_rx_set_rctl
e1000e_rx_desc_len
e1000e_core_ctrl_write
e1000e_link_status_changed
e1000e_rx_rss_dispatched_to_queue
e1000e_rx_desc_buff_write
e1000e_rx_null_descriptor
e1000e_rx_set_rdt
e1000e_msix_use_vector_fail
e1000e_msix_init_fail
e1000e_msi_init_fail
e1000e_cb_pci_uninit
e1000e_cfg_support_virtio
e1000e_irq_msi_notify_postponed
e1000e_irq_msix_notify_postponed_vec
e1000e_irq_throttling_no_pending_vec
e1000e_irq_msix_notify_vec
e1000e_wrn_msix_vec_wrong
e1000e_wrn_msix_invalid
e1000e_irq_iam_clear_eiame
e1000e_irq_icr_clear_eiac
e1000e_irq_msi_notify
pci_update_mappings_del
pci_update_mappings_add
e1000e_irq_icr_write
e1000e_irq_icr_read_entry
e1000e_irq_legacy_notify
e1000e_irq_add_msi_other
e1000e_irq_pending_interrupts
e1000e_irq_icr_write
e1000e_irq_msix_notify_vec
e1000e_wrn_msix_vec_wrong
e1000e_wrn_msix_invalid
e1000e_irq_iam_clear_eiame
e1000e_irq_icr_clear_eiac
e1000e_irq_postponed_by_xitr
e1000e_intrmgr_rearm_timer
msix_*
#ahci_*
ide_*

@ -5,4 +5,3 @@ pub const KERNEL_HEAP_SIZE: usize = 8 * 1024 * 1024;
pub const MEMORY_OFFSET: usize = 0; pub const MEMORY_OFFSET: usize = 0;
pub const USER_STACK_OFFSET: usize = 0x0000_8000_0000_0000 - USER_STACK_SIZE; pub const USER_STACK_OFFSET: usize = 0x0000_8000_0000_0000 - USER_STACK_SIZE;
pub const USER_STACK_SIZE: usize = 1 * 1024 * 1024; pub const USER_STACK_SIZE: usize = 1 * 1024 * 1024;
pub const USER32_STACK_OFFSET: usize = USER_STACK_OFFSET;

@ -163,7 +163,6 @@ impl Context {
entry_addr: usize, entry_addr: usize,
ustack_top: usize, ustack_top: usize,
kstack_top: usize, kstack_top: usize,
_is32: bool,
ttbr: usize, ttbr: usize,
) -> Self { ) -> Self {
InitStack { InitStack {

@ -16,7 +16,7 @@ pub fn init() {
} }
fn init_frame_allocator() { fn init_frame_allocator() {
use bit_allocator::BitAlloc; use bitmap_allocator::BitAlloc;
use core::ops::Range; use core::ops::Range;
let end = super::board::probe_memory() let end = super::board::probe_memory()

@ -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_OFFSET: usize = 0x80000000 - USER_STACK_SIZE;
pub const USER_STACK_SIZE: usize = 0x10000; pub const USER_STACK_SIZE: usize = 0x10000;
pub const USER32_STACK_OFFSET: usize = 0x80000000 - USER_STACK_SIZE;
pub const MAX_DTB_SIZE: usize = 0x2000; pub const MAX_DTB_SIZE: usize = 0x2000;

@ -206,7 +206,6 @@ impl Context {
entry_addr: usize, entry_addr: usize,
ustack_top: usize, ustack_top: usize,
kstack_top: usize, kstack_top: usize,
_is32: bool,
satp: usize, satp: usize,
) -> Self { ) -> Self {
info!( info!(

@ -25,7 +25,7 @@ pub fn init_other() {
} }
fn init_frame_allocator() { fn init_frame_allocator() {
use bit_allocator::BitAlloc; use bitmap_allocator::BitAlloc;
use core::ops::Range; use core::ops::Range;
let mut ba = FRAME_ALLOCATOR.lock(); let mut ba = FRAME_ALLOCATOR.lock();

@ -37,6 +37,5 @@ pub const MEMORY_END: usize = 0x8100_0000;
// FIXME: rv64 `sh` and `ls` will crash if stack top > 0x80000000 ??? // 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_OFFSET: usize = 0x80000000 - USER_STACK_SIZE;
pub const USER_STACK_SIZE: usize = 0x10000; pub const USER_STACK_SIZE: usize = 0x10000;
pub const USER32_STACK_OFFSET: usize = 0xC0000000 - USER_STACK_SIZE;
pub const MAX_DTB_SIZE: usize = 0x2000; pub const MAX_DTB_SIZE: usize = 0x2000;

@ -236,7 +236,6 @@ impl Context {
entry_addr: usize, entry_addr: usize,
ustack_top: usize, ustack_top: usize,
kstack_top: usize, kstack_top: usize,
_is32: bool,
satp: usize, satp: usize,
) -> Self { ) -> Self {
InitStack { InitStack {

@ -26,7 +26,7 @@ pub fn init_other() {
} }
fn init_frame_allocator() { fn init_frame_allocator() {
use bit_allocator::BitAlloc; use bitmap_allocator::BitAlloc;
use core::ops::Range; use core::ops::Range;
let mut ba = FRAME_ALLOCATOR.lock(); let mut ba = FRAME_ALLOCATOR.lock();

@ -53,7 +53,6 @@ pub const USER_GRANT_PML4: usize = (USER_GRANT_OFFSET & PML4_MASK) / PML4_SIZE;
/// Offset to user stack /// Offset to user stack
pub const USER_STACK_OFFSET: usize = USER_GRANT_OFFSET + PML4_SIZE; 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; pub const USER_STACK_PML4: usize = (USER_STACK_OFFSET & PML4_MASK) / PML4_SIZE;
/// Size of user stack /// Size of user stack
pub const USER_STACK_SIZE: usize = 1024 * 1024; // 1 MB pub const USER_STACK_SIZE: usize = 1024 * 1024; // 1 MB

@ -73,14 +73,10 @@ impl TrapFrame {
tf.fpstate_offset = 16; // skip restoring for first time tf.fpstate_offset = 16; // skip restoring for first time
tf 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; use crate::arch::gdt;
let mut tf = TrapFrame::default(); let mut tf = TrapFrame::default();
tf.cs = if is32 { tf.cs = gdt::UCODE_SELECTOR.0 as usize;
gdt::UCODE32_SELECTOR.0
} else {
gdt::UCODE_SELECTOR.0
} as usize;
tf.rip = entry_addr; tf.rip = entry_addr;
tf.ss = gdt::UDATA32_SELECTOR.0 as usize; tf.ss = gdt::UDATA32_SELECTOR.0 as usize;
tf.rsp = rsp; tf.rsp = rsp;
@ -88,9 +84,6 @@ impl TrapFrame {
tf.fpstate_offset = 16; // skip restoring for first time tf.fpstate_offset = 16; // skip restoring for first time
tf tf
} }
pub fn is_user(&self) -> bool {
self.cs & 0x3 == 0x3
}
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
@ -203,12 +196,11 @@ impl Context {
entry_addr: usize, entry_addr: usize,
ustack_top: usize, ustack_top: usize,
kstack_top: usize, kstack_top: usize,
is32: bool,
cr3: usize, cr3: usize,
) -> Self { ) -> Self {
InitStack { InitStack {
context: ContextData::new(cr3), 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) .push_at(kstack_top)
} }

@ -1,5 +1,5 @@
use crate::consts::KERNEL_OFFSET; use crate::consts::KERNEL_OFFSET;
use bit_allocator::BitAlloc; use bitmap_allocator::BitAlloc;
// Depends on kernel // Depends on kernel
use super::{BootInfo, MemoryRegionType}; use super::{BootInfo, MemoryRegionType};
use crate::memory::{active_table, alloc_frame, init_heap, FRAME_ALLOCATOR}; use crate::memory::{active_table, alloc_frame, init_heap, FRAME_ALLOCATOR};

@ -106,6 +106,9 @@ pub fn backtrace() {
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
{ {
current_fp = *(current_fp as *const usize); current_fp = *(current_fp as *const usize);
if current_fp < crate::arch::consts::KERNEL_OFFSET {
break;
}
if current_fp != 0 { if current_fp != 0 {
current_pc = *(current_fp as *const usize).offset(1); current_pc = *(current_fp as *const usize).offset(1);
} }

@ -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 //! 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::string::String;
use alloc::sync::Arc; 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 isomorphic_drivers::block::ahci::{AHCI, BLOCK_SIZE};
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 crate::drivers::provider::Provider;
use crate::drivers::BlockDriver; use crate::drivers::BlockDriver;
use crate::memory::active_table;
use crate::sync::SpinNoIrqLock as Mutex; use crate::sync::SpinNoIrqLock as Mutex;
use super::super::{DeviceType, Driver, BLK_DRIVERS, DRIVERS}; use super::super::{DeviceType, Driver, BLK_DRIVERS, DRIVERS};
pub struct AHCI { pub struct AHCIDriver(Mutex<AHCI<Provider>>);
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>);
/// AHCI Generic Host Control (3.1)
#[repr(C)]
pub struct AHCIGHC {
/// Host capability
capability: Volatile<AHCICap>,
/// Global host control
global_host_control: Volatile<u32>,
/// Interrupt status
interrupt_status: Volatile<u32>,
/// Port implemented
port_implemented: Volatile<u32>,
/// Version
version: Volatile<u32>,
/// Command completion coalescing control
ccc_control: Volatile<u32>,
/// Command completion coalescing ports
ccc_ports: Volatile<u32>,
/// Enclosure management location
em_location: Volatile<u32>,
/// Enclosure management control
em_control: Volatile<u32>,
/// Host capabilities extended
capabilities2: Volatile<u32>,
/// BIOS/OS handoff control and status
bios_os_handoff_control: Volatile<u32>,
}
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<u64>,
fis_base_address: Volatile<u64>,
interrupt_status: Volatile<u32>,
interrupt_enable: Volatile<u32>,
command: Volatile<u32>,
reserved: Volatile<u32>,
task_file_data: Volatile<u32>,
signature: Volatile<u32>,
sata_status: Volatile<u32>,
sata_control: Volatile<u32>,
sata_error: Volatile<u32>,
sata_active: Volatile<u32>,
command_issue: Volatile<u32>,
sata_notification: Volatile<u32>,
fis_based_switch_control: Volatile<u32>,
}
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
}
}
impl Driver for AHCIDriver { impl Driver for AHCIDriver {
fn try_handle_interrupt(&self, _irq: Option<u32>) -> bool { fn try_handle_interrupt(&self, _irq: Option<u32>) -> bool {
@ -361,137 +44,12 @@ impl Driver for AHCIDriver {
} }
} }
const BLOCK_SIZE: usize = 512; pub fn init(_irq: Option<u32>, header: usize, size: usize) -> Arc<AHCIDriver> {
let ahci = AHCI::new(header, size);
fn from_ata_string(data: &[u8]) -> String { let driver = Arc::new(AHCIDriver(Mutex::new(ahci)));
let mut swapped_data = Vec::new(); DRIVERS.write().push(driver.clone());
assert_eq!(data.len() % 2, 0); BLK_DRIVERS
for i in (0..data.len()).step_by(2) { .write()
swapped_data.push(data[i + 1]); .push(Arc::new(BlockDriver(driver.clone())));
swapped_data.push(data[i]); driver
}
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<u32>, header: usize, size: usize) -> Arc<AHCIDriver> {
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::<AHCICommandHeader>(),
)
};
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!();
} }

@ -1,4 +1,3 @@
use alloc::boxed::Box;
use alloc::string::String; use alloc::string::String;
use alloc::sync::Arc; use alloc::sync::Arc;
use core::cmp::min; use core::cmp::min;

@ -4,7 +4,6 @@ use crate::drivers::net::*;
use crate::drivers::{Driver, DRIVERS, NET_DRIVERS}; use crate::drivers::{Driver, DRIVERS, NET_DRIVERS};
use crate::memory::active_table; use crate::memory::active_table;
use alloc::collections::BTreeMap; use alloc::collections::BTreeMap;
use alloc::string::String;
use alloc::sync::Arc; use alloc::sync::Arc;
use core::cmp::Ordering; use core::cmp::Ordering;
use pci::*; use pci::*;
@ -110,8 +109,9 @@ unsafe fn enable(loc: Location) -> Option<u32> {
let orig_ctrl = am.read32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP); 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); am.write32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP, orig_ctrl | 0x10000);
debug!( debug!(
"MSI control {:#b}, enabling MSI interrupts", "MSI control {:#b}, enabling MSI interrupt {}",
orig_ctrl >> 16 orig_ctrl >> 16,
irq
); );
msi_found = true; msi_found = true;
break; break;
@ -148,7 +148,8 @@ pub fn init_driver(dev: &PCIDevice) {
active_table().map_if_not_exists(KERNEL_OFFSET + current_addr, current_addr); active_table().map_if_not_exists(KERNEL_OFFSET + current_addr, current_addr);
current_addr = current_addr + PAGE_SIZE; current_addr = current_addr + PAGE_SIZE;
} }
e1000::e1000_init(name, irq, vaddr, len as usize); let index = NET_DRIVERS.read().len();
e1000::init(name, irq, vaddr, len as usize, index);
} }
} }
(0x8086, 0x10fb) => { (0x8086, 0x10fb) => {
@ -161,9 +162,11 @@ pub fn init_driver(dev: &PCIDevice) {
active_table().map_if_not_exists(KERNEL_OFFSET + current_addr, current_addr); active_table().map_if_not_exists(KERNEL_OFFSET + current_addr, current_addr);
current_addr = current_addr + PAGE_SIZE; current_addr = current_addr + PAGE_SIZE;
} }
PCI_DRIVERS let index = NET_DRIVERS.read().len();
.lock() PCI_DRIVERS.lock().insert(
.insert(dev.loc, ixgbe::ixgbe_init(name, irq, vaddr, len as usize)); dev.loc,
ixgbe::ixgbe_init(name, irq, vaddr, len as usize, index),
);
} }
} }
(0x8086, 0x2922) => { (0x8086, 0x2922) => {
@ -175,7 +178,7 @@ pub fn init_driver(dev: &PCIDevice) {
active_table().map(vaddr, addr as usize); active_table().map(vaddr, addr as usize);
PCI_DRIVERS PCI_DRIVERS
.lock() .lock()
.insert(dev.loc, ahci::ahci_init(irq, vaddr, len as usize)); .insert(dev.loc, ahci::init(irq, vaddr, len as usize));
} }
} }
_ => {} _ => {}

@ -2,7 +2,6 @@ use alloc::boxed::Box;
use alloc::string::String; use alloc::string::String;
use alloc::sync::Arc; use alloc::sync::Arc;
use alloc::vec; use alloc::vec;
use alloc::vec::Vec;
use core::fmt; use core::fmt;
use core::mem::size_of; use core::mem::size_of;
use core::mem::transmute_copy; use core::mem::transmute_copy;

@ -3,7 +3,7 @@ use alloc::sync::Arc;
use alloc::vec::Vec; use alloc::vec::Vec;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use smoltcp::wire::{EthernetAddress, Ipv4Address}; use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address};
use spin::RwLock; use spin::RwLock;
use crate::sync::Condvar; use crate::sync::Condvar;
@ -56,6 +56,11 @@ pub trait Driver: Send + Sync {
unimplemented!("not a net driver") unimplemented!("not a net driver")
} }
// get ip addresses
fn get_ip_addresses(&self) -> Vec<IpCidr> {
unimplemented!("not a net driver")
}
// get ipv4 address // get ipv4 address
fn ipv4_address(&self) -> Option<Ipv4Address> { fn ipv4_address(&self) -> Option<Ipv4Address> {
unimplemented!("not a net driver") unimplemented!("not a net driver")
@ -66,6 +71,16 @@ pub trait Driver: Send + Sync {
unimplemented!("not a net driver") unimplemented!("not a net driver")
} }
// send an ethernet frame, only use it when necessary
fn send(&self, data: &[u8]) -> Option<usize> {
unimplemented!("not a net driver")
}
// get mac address from ip address in arp table
fn get_arp(&self, ip: IpAddress) -> Option<EthernetAddress> {
unimplemented!("not a net driver")
}
// block related drivers should implement these // block related drivers should implement these
fn read_block(&self, block_id: usize, buf: &mut [u8]) -> bool { fn read_block(&self, block_id: usize, buf: &mut [u8]) -> bool {
unimplemented!("not a block driver") unimplemented!("not a block driver")

@ -1,74 +1,29 @@
//! Intel PRO/1000 Network Adapter i.e. e1000 network driver //! Intel PRO/1000 Network Adapter i.e. e1000 network driver
//! Datasheet: https://www.intel.ca/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf //! Datasheet: https://www.intel.ca/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf
use alloc::alloc::{GlobalAlloc, Layout}; use alloc::collections::BTreeMap;
use alloc::format;
use alloc::string::String; use alloc::string::String;
use alloc::sync::Arc; use alloc::sync::Arc;
use alloc::vec::Vec; 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::iface::*;
use smoltcp::phy::{self, DeviceCapabilities}; use smoltcp::phy::{self, DeviceCapabilities};
use smoltcp::time::Instant; use smoltcp::time::Instant;
use smoltcp::wire::EthernetAddress;
use smoltcp::wire::*; use smoltcp::wire::*;
use smoltcp::Result; 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::net::SOCKETS;
use crate::sync::SpinNoIrqLock as Mutex; use crate::sync::SpinNoIrqLock as Mutex;
use crate::HEAP_ALLOCATOR;
use super::super::{DeviceType, Driver, DRIVERS, NET_DRIVERS, SOCKET_ACTIVITY}; 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<usize>,
recv_page: usize,
recv_buffers: Vec<usize>,
first_trans: bool,
}
#[derive(Clone)] #[derive(Clone)]
pub struct E1000Driver(Arc<Mutex<E1000>>); pub struct E1000Driver(Arc<Mutex<E1000<Provider>>>);
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 E1000Interface { pub struct E1000Interface {
iface: Mutex<EthernetInterface<'static, 'static, 'static, E1000Driver>>, iface: Mutex<EthernetInterface<'static, 'static, 'static, E1000Driver>>,
@ -84,22 +39,7 @@ impl Driver for E1000Interface {
return false; return false;
} }
let data = { let data = self.driver.0.lock().handle_interrupt();
let driver = self.driver.0.lock();
let e1000 = unsafe {
slice::from_raw_parts_mut(driver.header as *mut Volatile<u32>, driver.size / 4)
};
let icr = e1000[E1000_ICR].read();
if icr != 0 {
// clear it
e1000[E1000_ICR].write(icr);
true
} else {
false
}
};
if data { if data {
let timestamp = Instant::from_millis(crate::trap::uptime_msec() as i64); let timestamp = Instant::from_millis(crate::trap::uptime_msec() as i64);
@ -122,7 +62,7 @@ impl Driver for E1000Interface {
} }
fn get_id(&self) -> String { fn get_id(&self) -> String {
format!("e1000") String::from("e1000")
} }
fn get_mac(&self) -> EthernetAddress { fn get_mac(&self) -> EthernetAddress {
@ -133,6 +73,11 @@ impl Driver for E1000Interface {
self.name.clone() self.name.clone()
} }
// get ip addresses
fn get_ip_addresses(&self) -> Vec<IpCidr> {
Vec::from(self.iface.lock().ip_addrs())
}
fn ipv4_address(&self) -> Option<Ipv4Address> { fn ipv4_address(&self) -> Option<Ipv4Address> {
self.iface.lock().ipv4_address() self.iface.lock().ipv4_address()
} }
@ -149,99 +94,46 @@ impl Driver for E1000Interface {
} }
} }
} }
}
#[repr(C)] fn send(&self, data: &[u8]) -> Option<usize> {
#[derive(Copy, Clone, Debug)] use smoltcp::phy::TxToken;
struct E1000SendDesc { let token = E1000TxToken(self.driver.clone());
addr: u64, if token
len: u16, .consume(Instant::from_millis(0), data.len(), |buffer| {
cso: u8, buffer.copy_from_slice(&data);
cmd: u8, Ok(())
status: u8, })
css: u8, .is_ok()
special: u8, {
} Some(data.len())
} else {
None
}
}
#[repr(C)] fn get_arp(&self, ip: IpAddress) -> Option<EthernetAddress> {
#[derive(Copy, Clone, Debug)] let iface = self.iface.lock();
struct E1000RecvDesc { let cache = iface.neighbor_cache();
addr: u64, cache.lookup_pure(&ip, Instant::from_millis(0))
len: u16, }
chksum: u16,
status: u16,
error: u8,
special: u8,
} }
pub struct E1000RxToken(Vec<u8>); pub struct E1000RxToken(Vec<u8>);
pub struct E1000TxToken(E1000Driver); pub struct E1000TxToken(E1000Driver);
impl<'a> phy::Device<'a> for E1000Driver { impl phy::Device<'_> for E1000Driver {
type RxToken = E1000RxToken; type RxToken = E1000RxToken;
type TxToken = E1000TxToken; type TxToken = E1000TxToken;
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { fn receive(&mut self) -> Option<(Self::RxToken, Self::TxToken)> {
let driver = self.0.lock(); self.0
.lock()
let e1000 = unsafe { .receive()
slice::from_raw_parts_mut(driver.header as *mut Volatile<u32>, driver.size / 4) .map(|vec| (E1000RxToken(vec), E1000TxToken(self.clone())))
};
let send_queue_size = PAGE_SIZE / size_of::<E1000SendDesc>();
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::<E1000RecvDesc>();
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 transmit(&'a mut self) -> Option<Self::TxToken> { fn transmit(&mut self) -> Option<Self::TxToken> {
let driver = self.0.lock(); if self.0.lock().can_send() {
let e1000 = unsafe {
slice::from_raw_parts_mut(driver.header as *mut Volatile<u32>, driver.size / 4)
};
let send_queue_size = PAGE_SIZE / size_of::<E1000SendDesc>();
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 {
Some(E1000TxToken(self.clone())) Some(E1000TxToken(self.clone()))
} else { } else {
None None
@ -274,201 +166,25 @@ impl phy::TxToken for E1000TxToken {
let result = f(&mut buffer[..len]); let result = f(&mut buffer[..len]);
let mut driver = (self.0).0.lock(); let mut driver = (self.0).0.lock();
driver.send(&buffer);
let e1000 = unsafe {
slice::from_raw_parts_mut(driver.header as *mut Volatile<u32>, driver.size / 4)
};
let send_queue_size = PAGE_SIZE / size_of::<E1000SendDesc>();
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;
}
result 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 // JudgeDuck-OS/kern/e1000.c
pub fn e1000_init(name: String, irq: Option<u32>, header: usize, size: usize) { pub fn init(name: String, irq: Option<u32>, header: usize, size: usize, index: usize) {
info!("Probing e1000 {}", name); info!("Probing e1000 {}", name);
assert_eq!(size_of::<E1000SendDesc>(), 16);
assert_eq!(size_of::<E1000RecvDesc>(), 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() as u64;
let recv_page_pa = active_table().get_entry(recv_page).unwrap().target() as u64;
let send_queue_size = PAGE_SIZE / size_of::<E1000SendDesc>();
let recv_queue_size = PAGE_SIZE / size_of::<E1000RecvDesc>();
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, 0x3C];
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<u32>, 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. // randomly generated
e1000[E1000_RDT].write((recv_queue_size - 1) as u32); // RDT let mac: [u8; 6] = [0x54, 0x51, 0x9F, 0x71, 0xC0, index as u8];
// 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 let e1000 = E1000::new(header, size, DriverEthernetAddress::from_bytes(&mac));
e1000[E1000_ICR].write(e1000[E1000_ICR].read());
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 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 neighbor_cache = NeighborCache::new(BTreeMap::new());
let iface = EthernetInterfaceBuilder::new(net_driver.clone()) let iface = EthernetInterfaceBuilder::new(net_driver.clone())
.ethernet_addr(ethernet_addr) .ethernet_addr(ethernet_addr)
@ -476,6 +192,7 @@ pub fn e1000_init(name: String, irq: Option<u32>, header: usize, size: usize) {
.neighbor_cache(neighbor_cache) .neighbor_cache(neighbor_cache)
.finalize(); .finalize();
info!("e1000 interface {} up with addr 10.0.{}.2/24", name, index);
let e1000_iface = E1000Interface { let e1000_iface = E1000Interface {
iface: Mutex::new(iface), iface: Mutex::new(iface),
driver: net_driver.clone(), driver: net_driver.clone(),

@ -8,8 +8,6 @@ use alloc::vec::Vec;
use alloc::collections::BTreeMap; use alloc::collections::BTreeMap;
use isomorphic_drivers::net::ethernet::intel::ixgbe; use isomorphic_drivers::net::ethernet::intel::ixgbe;
use log::*; use log::*;
use rcore_memory::paging::PageTable;
use rcore_memory::PAGE_SIZE;
use smoltcp::iface::*; use smoltcp::iface::*;
use smoltcp::phy::{self, Checksum, DeviceCapabilities}; use smoltcp::phy::{self, Checksum, DeviceCapabilities};
use smoltcp::time::Instant; use smoltcp::time::Instant;
@ -26,7 +24,7 @@ use super::super::{provider::Provider, DeviceType, Driver, DRIVERS, NET_DRIVERS,
#[derive(Clone)] #[derive(Clone)]
struct IXGBEDriver { struct IXGBEDriver {
inner: ixgbe::IXGBEDriver, inner: Arc<Mutex<ixgbe::IXGBE<Provider>>>,
header: usize, header: usize,
size: usize, size: usize,
mtu: usize, mtu: usize,
@ -49,7 +47,7 @@ impl Driver for IXGBEInterface {
let handled = { let handled = {
let _ = FlagsGuard::no_irq_region(); let _ = FlagsGuard::no_irq_region();
self.driver.inner.try_handle_interrupt() self.driver.inner.lock().try_handle_interrupt()
}; };
if handled { if handled {
@ -84,6 +82,11 @@ impl Driver for IXGBEInterface {
self.ifname.clone() self.ifname.clone()
} }
// get ip addresses
fn get_ip_addresses(&self) -> Vec<IpCidr> {
Vec::from(self.iface.lock().ip_addrs())
}
fn ipv4_address(&self) -> Option<Ipv4Address> { fn ipv4_address(&self) -> Option<Ipv4Address> {
self.iface.lock().ipv4_address() self.iface.lock().ipv4_address()
} }
@ -100,6 +103,17 @@ impl Driver for IXGBEInterface {
} }
} }
} }
fn send(&self, data: &[u8]) -> Option<usize> {
self.driver.inner.lock().send(&data);
Some(data.len())
}
fn get_arp(&self, ip: IpAddress) -> Option<EthernetAddress> {
let iface = self.iface.lock();
let cache = iface.neighbor_cache();
cache.lookup_pure(&ip, Instant::from_millis(0))
}
} }
pub struct IXGBERxToken(Vec<u8>); pub struct IXGBERxToken(Vec<u8>);
pub struct IXGBETxToken(IXGBEDriver); pub struct IXGBETxToken(IXGBEDriver);
@ -110,8 +124,8 @@ impl<'a> phy::Device<'a> for IXGBEDriver {
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
let _ = FlagsGuard::no_irq_region(); let _ = FlagsGuard::no_irq_region();
if self.inner.can_send() { if self.inner.lock().can_send() {
if let Some(data) = self.inner.recv() { if let Some(data) = self.inner.lock().recv() {
Some((IXGBERxToken(data), IXGBETxToken(self.clone()))) Some((IXGBERxToken(data), IXGBETxToken(self.clone())))
} else { } else {
None None
@ -123,7 +137,7 @@ impl<'a> phy::Device<'a> for IXGBEDriver {
fn transmit(&'a mut self) -> Option<Self::TxToken> { fn transmit(&'a mut self) -> Option<Self::TxToken> {
let _ = FlagsGuard::no_irq_region(); let _ = FlagsGuard::no_irq_region();
if self.inner.can_send() { if self.inner.lock().can_send() {
Some(IXGBETxToken(self.clone())) Some(IXGBETxToken(self.clone()))
} else { } else {
None None
@ -157,10 +171,10 @@ impl phy::TxToken for IXGBETxToken {
F: FnOnce(&mut [u8]) -> Result<R>, F: FnOnce(&mut [u8]) -> Result<R>,
{ {
let _ = FlagsGuard::no_irq_region(); let _ = FlagsGuard::no_irq_region();
let mut buffer = [0u8; ixgbe::IXGBEDriver::get_mtu()]; let mut buffer = [0u8; ixgbe::IXGBE::<Provider>::get_mtu()];
let result = f(&mut buffer[..len]); let result = f(&mut buffer[..len]);
if result.is_ok() { if result.is_ok() {
(self.0).inner.send(&buffer[..len]); self.0.inner.lock().send(&buffer[..len]);
} }
result result
} }
@ -171,26 +185,24 @@ pub fn ixgbe_init(
irq: Option<u32>, irq: Option<u32>,
header: usize, header: usize,
size: usize, size: usize,
index: usize,
) -> Arc<IXGBEInterface> { ) -> Arc<IXGBEInterface> {
let _ = FlagsGuard::no_irq_region(); 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(); ixgbe.enable_irq();
let ethernet_addr = EthernetAddress::from_bytes(&ixgbe.get_mac().as_bytes()); let ethernet_addr = EthernetAddress::from_bytes(&ixgbe.get_mac().as_bytes());
let net_driver = IXGBEDriver { let net_driver = IXGBEDriver {
inner: ixgbe, inner: Arc::new(Mutex::new(ixgbe)),
header, header,
size, size,
mtu: 1500, 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 neighbor_cache = NeighborCache::new(BTreeMap::new());
let mut routes = Routes::new(BTreeMap::new()); let routes = Routes::new(BTreeMap::new());
routes
.add_default_ipv4_route(Ipv4Address::new(10, 0, 0, 1))
.unwrap();
let mut iface = EthernetInterfaceBuilder::new(net_driver.clone()) let mut iface = EthernetInterfaceBuilder::new(net_driver.clone())
.ethernet_addr(ethernet_addr) .ethernet_addr(ethernet_addr)
.ip_addrs(ip_addrs) .ip_addrs(ip_addrs)
@ -198,7 +210,7 @@ pub fn ixgbe_init(
.routes(routes) .routes(routes)
.finalize(); .finalize();
info!("ixgbe: interface {} up", &name); info!("ixgbe interface {} up with addr 10.0.{}.2/24", name, index);
let ixgbe_iface = IXGBEInterface { let ixgbe_iface = IXGBEInterface {
iface: Mutex::new(iface), iface: Mutex::new(iface),

@ -1,36 +1,25 @@
use crate::memory::active_table; use alloc::alloc::{alloc_zeroed, dealloc, Layout};
use alloc::boxed::Box;
use alloc::vec::Vec;
use isomorphic_drivers::provider; use isomorphic_drivers::provider;
use rcore_memory::paging::PageTable; use rcore_memory::paging::PageTable;
use rcore_memory::PAGE_SIZE; use rcore_memory::PAGE_SIZE;
#[derive(Copy, Clone)] use crate::memory::active_table;
pub struct Provider;
impl Provider { pub struct Provider;
pub fn new() -> Box<Provider> {
Box::new(Provider {})
}
}
impl provider::Provider for Provider { impl provider::Provider for Provider {
/// Get page size const PAGE_SIZE: usize = PAGE_SIZE;
fn get_page_size(&self) -> usize {
PAGE_SIZE
}
// Translate virtual address to physical address fn alloc_dma(size: usize) -> (usize, usize) {
fn translate_va(&self, va: usize) -> usize { let layout = Layout::from_size_align(size, PAGE_SIZE).unwrap();
active_table().get_entry(va).unwrap().target() 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 dealloc_dma(vaddr: usize, size: usize) {
fn translate_vas(&self, vas: &[usize]) -> Vec<usize> { let layout = Layout::from_size_align(size, PAGE_SIZE).unwrap();
let mut result = Vec::new(); unsafe { dealloc(vaddr as *mut u8, layout) }
for va in vas.iter() {
result.push(active_table().get_entry(*va).unwrap().target());
}
result
} }
} }

@ -2,7 +2,7 @@
use alloc::{string::String, sync::Arc}; 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)] #[derive(Clone)]
pub struct FileHandle { pub struct FileHandle {
@ -108,4 +108,12 @@ impl FileHandle {
self.offset += 1; self.offset += 1;
Ok(name) Ok(name)
} }
pub fn poll(&self) -> Result<PollStatus> {
self.inode.poll()
}
pub fn io_control(&self, cmd: u32, arg: u32) -> Result<()> {
self.inode.io_control(cmd, arg)
}
} }

@ -2,8 +2,9 @@ use core::fmt;
use super::FileHandle; use super::FileHandle;
use crate::net::Socket; use crate::net::Socket;
use crate::syscall::SysResult; use crate::syscall::{SysError, SysResult};
use alloc::boxed::Box; use alloc::boxed::Box;
use rcore_fs::vfs::PollStatus;
// TODO: merge FileLike to FileHandle ? // TODO: merge FileLike to FileHandle ?
// TODO: fix dup and remove Clone // TODO: fix dup and remove Clone
@ -28,6 +29,25 @@ impl FileLike {
}; };
Ok(len) Ok(len)
} }
pub fn ioctl(&mut self, request: usize, arg1: usize, arg2: usize, arg3: usize) -> SysResult {
match self {
FileLike::File(file) => file.io_control(request as u32, arg1 as u32)?,
FileLike::Socket(socket) => {
socket.ioctl(request, arg1, arg2, arg3)?;
}
}
Ok(0)
}
pub fn poll(&self) -> Result<PollStatus, SysError> {
let status = match self {
FileLike::File(file) => file.poll()?,
FileLike::Socket(socket) => {
let (read, write, error) = socket.poll();
PollStatus { read, write, error }
}
};
Ok(status)
}
} }
impl fmt::Debug for FileLike { impl fmt::Debug for FileLike {

@ -57,7 +57,9 @@ impl Pipe {
// TODO: better way to provide default impl? // TODO: better way to provide default impl?
macro_rules! impl_inode { macro_rules! impl_inode {
() => { () => {
fn poll(&self) -> Result<PollStatus> { Err(FsError::NotSupported) }
fn metadata(&self) -> Result<Metadata> { Err(FsError::NotSupported) } fn metadata(&self) -> Result<Metadata> { Err(FsError::NotSupported) }
fn set_metadata(&self, _metadata: &Metadata) -> Result<()> { Ok(()) }
fn sync_all(&self) -> Result<()> { Ok(()) } fn sync_all(&self) -> Result<()> { Ok(()) }
fn sync_data(&self) -> Result<()> { Ok(()) } fn sync_data(&self) -> Result<()> { Ok(()) }
fn resize(&self, _len: usize) -> Result<()> { Err(FsError::NotSupported) } 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<INode>, _new_name: &str) -> Result<()> { Err(FsError::NotDir) } fn move_(&self, _old_name: &str, _target: &Arc<INode>, _new_name: &str) -> Result<()> { Err(FsError::NotDir) }
fn find(&self, _name: &str) -> Result<Arc<INode>> { Err(FsError::NotDir) } fn find(&self, _name: &str) -> Result<Arc<INode>> { Err(FsError::NotDir) }
fn get_entry(&self, _id: usize) -> Result<String> { Err(FsError::NotDir) } fn get_entry(&self, _id: usize) -> Result<String> { Err(FsError::NotDir) }
fn io_control(&self, _cmd: u32, _data: u32) -> Result<()> { Err(FsError::NotSupported) }
fn fs(&self) -> Arc<FileSystem> { unimplemented!() } fn fs(&self) -> Arc<FileSystem> { unimplemented!() }
fn as_any_ref(&self) -> &Any { self } fn as_any_ref(&self) -> &Any { self }
fn chmod(&self, _mode: u16) -> Result<()> { Ok(()) }
}; };
} }

@ -47,6 +47,7 @@ lazy_static! {
macro_rules! impl_inode { macro_rules! impl_inode {
() => { () => {
fn metadata(&self) -> Result<Metadata> { Err(FsError::NotSupported) } fn metadata(&self) -> Result<Metadata> { Err(FsError::NotSupported) }
fn set_metadata(&self, _metadata: &Metadata) -> Result<()> { Ok(()) }
fn sync_all(&self) -> Result<()> { Ok(()) } fn sync_all(&self) -> Result<()> { Ok(()) }
fn sync_data(&self) -> Result<()> { Ok(()) } fn sync_data(&self) -> Result<()> { Ok(()) }
fn resize(&self, _len: usize) -> Result<()> { Err(FsError::NotSupported) } 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<INode>, _new_name: &str) -> Result<()> { Err(FsError::NotDir) } fn move_(&self, _old_name: &str, _target: &Arc<INode>, _new_name: &str) -> Result<()> { Err(FsError::NotDir) }
fn find(&self, _name: &str) -> Result<Arc<INode>> { Err(FsError::NotDir) } fn find(&self, _name: &str) -> Result<Arc<INode>> { Err(FsError::NotDir) }
fn get_entry(&self, _id: usize) -> Result<String> { Err(FsError::NotDir) } fn get_entry(&self, _id: usize) -> Result<String> { Err(FsError::NotDir) }
fn io_control(&self, _cmd: u32, _data: u32) -> Result<()> { Err(FsError::NotSupported) }
fn fs(&self) -> Arc<FileSystem> { unimplemented!() } fn fs(&self) -> Arc<FileSystem> { unimplemented!() }
fn as_any_ref(&self) -> &Any { self } fn as_any_ref(&self) -> &Any { self }
fn chmod(&self, _mode: u16) -> Result<()> { Ok(()) }
}; };
} }
impl INode for Stdin { impl INode for Stdin {
fn read_at(&self, _offset: usize, buf: &mut [u8]) -> Result<usize> { fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
buf[0] = self.pop() as u8; buf[0] = self.pop() as u8;
Ok(1) Ok(1)
} }
fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize> { fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize> {
unimplemented!() unimplemented!()
} }
fn poll(&self) -> Result<PollStatus> {
Ok(PollStatus {
read: self.can_read(),
write: false,
error: false,
})
}
impl_inode!(); impl_inode!();
} }
@ -84,5 +92,12 @@ impl INode for Stdout {
print!("{}", s); print!("{}", s);
Ok(buf.len()) Ok(buf.len())
} }
fn poll(&self) -> Result<PollStatus> {
Ok(PollStatus {
read: false,
write: true,
error: false,
})
}
impl_inode!(); impl_inode!();
} }

@ -22,6 +22,8 @@ use rcore_thread::std_thread as thread;
#[macro_use] // print! #[macro_use] // print!
mod logging; mod logging;
#[macro_use]
mod util;
mod backtrace; mod backtrace;
mod consts; mod consts;
mod drivers; mod drivers;
@ -34,7 +36,6 @@ mod shell;
mod sync; mod sync;
mod syscall; mod syscall;
mod trap; mod trap;
mod util;
#[allow(dead_code)] #[allow(dead_code)]
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]

@ -3,7 +3,7 @@ pub use crate::arch::paging::*;
use crate::consts::MEMORY_OFFSET; use crate::consts::MEMORY_OFFSET;
use crate::process::process_unsafe; use crate::process::process_unsafe;
use crate::sync::SpinNoIrqLock; use crate::sync::SpinNoIrqLock;
use bit_allocator::BitAlloc; use bitmap_allocator::BitAlloc;
use buddy_system_allocator::LockedHeap; use buddy_system_allocator::LockedHeap;
use lazy_static::*; use lazy_static::*;
use log::*; use log::*;
@ -14,15 +14,15 @@ pub type MemorySet = rcore_memory::memory_set::MemorySet<InactivePageTable0>;
// x86_64 support up to 64G memory // x86_64 support up to 64G memory
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
pub type FrameAlloc = bit_allocator::BitAlloc16M; pub type FrameAlloc = bitmap_allocator::BitAlloc16M;
// RISCV has 8M memory // RISCV has 8M memory
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] #[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 // Raspberry Pi 3 has 1G memory
#[cfg(any(target_arch = "aarch64", target_arch = "mips"))] #[cfg(any(target_arch = "aarch64", target_arch = "mips"))]
pub type FrameAlloc = bit_allocator::BitAlloc1M; pub type FrameAlloc = bitmap_allocator::BitAlloc1M;
lazy_static! { lazy_static! {
pub static ref FRAME_ALLOCATOR: SpinNoIrqLock<FrameAlloc> = pub static ref FRAME_ALLOCATOR: SpinNoIrqLock<FrameAlloc> =

@ -2,18 +2,60 @@ use crate::arch::rand;
use crate::drivers::{NET_DRIVERS, SOCKET_ACTIVITY}; use crate::drivers::{NET_DRIVERS, SOCKET_ACTIVITY};
use crate::sync::SpinNoIrqLock as Mutex; use crate::sync::SpinNoIrqLock as Mutex;
use crate::syscall::*; use crate::syscall::*;
use crate::util;
use alloc::boxed::Box; 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::socket::*;
use smoltcp::wire::*; use smoltcp::wire::*;
/// #[derive(Clone, Debug)]
pub struct LinkLevelEndpoint {
pub interface_index: usize,
}
impl LinkLevelEndpoint {
pub fn new(ifindex: usize) -> Self {
LinkLevelEndpoint {
interface_index: ifindex,
}
}
}
#[derive(Clone, Debug)]
pub struct NetlinkEndpoint {
pub port_id: u32,
pub 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
pub trait Socket: Send + Sync { pub trait Socket: Send + Sync {
fn read(&self, data: &mut [u8]) -> (SysResult, IpEndpoint); fn read(&self, data: &mut [u8]) -> (SysResult, Endpoint);
fn write(&self, data: &[u8], sendto_endpoint: Option<IpEndpoint>) -> SysResult; fn write(&self, data: &[u8], sendto_endpoint: Option<Endpoint>) -> SysResult;
fn poll(&self) -> (bool, bool, bool); // (in, out, err) fn poll(&self) -> (bool, bool, bool); // (in, out, err)
fn connect(&mut self, endpoint: IpEndpoint) -> SysResult; fn connect(&mut self, endpoint: Endpoint) -> SysResult;
fn bind(&mut self, endpoint: IpEndpoint) -> SysResult { fn bind(&mut self, endpoint: Endpoint) -> SysResult {
Err(SysError::EINVAL) Err(SysError::EINVAL)
} }
fn listen(&mut self) -> SysResult { fn listen(&mut self) -> SysResult {
@ -22,15 +64,23 @@ pub trait Socket: Send + Sync {
fn shutdown(&self) -> SysResult { fn shutdown(&self) -> SysResult {
Err(SysError::EINVAL) Err(SysError::EINVAL)
} }
fn accept(&mut self) -> Result<(Box<dyn Socket>, IpEndpoint), SysError> { fn accept(&mut self) -> Result<(Box<dyn Socket>, Endpoint), SysError> {
Err(SysError::EINVAL) Err(SysError::EINVAL)
} }
fn endpoint(&self) -> Option<IpEndpoint> { fn endpoint(&self) -> Option<Endpoint> {
None None
} }
fn remote_endpoint(&self) -> Option<IpEndpoint> { fn remote_endpoint(&self) -> Option<Endpoint> {
None None
} }
fn setsockopt(&mut self, level: usize, opt: usize, data: &[u8]) -> SysResult {
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<dyn Socket>; fn box_clone(&self) -> Box<dyn Socket>;
} }
@ -65,6 +115,17 @@ pub struct UdpSocketState {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct RawSocketState { pub struct RawSocketState {
handle: GlobalSocketHandle, handle: GlobalSocketHandle,
header_included: bool,
}
#[derive(Debug, Clone)]
pub struct PacketSocketState {
// no state, only ethernet egress
}
#[derive(Debug, Clone)]
pub struct NetlinkSocketState {
data: Arc<Mutex<Vec<Vec<u8>>>>,
} }
/// A wrapper for `SocketHandle`. /// A wrapper for `SocketHandle`.
@ -107,7 +168,7 @@ impl TcpSocketState {
} }
impl Socket for 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 || { spin_and_wait(&[&SOCKET_ACTIVITY], move || {
poll_ifaces(); poll_ifaces();
let mut sockets = SOCKETS.lock(); let mut sockets = SOCKETS.lock();
@ -122,17 +183,20 @@ impl Socket for TcpSocketState {
drop(sockets); drop(sockets);
poll_ifaces(); poll_ifaces();
return Some((Ok(size), endpoint)); return Some((Ok(size), Endpoint::Ip(endpoint)));
} }
} }
} else { } else {
return Some((Err(SysError::ENOTCONN), IpEndpoint::UNSPECIFIED)); return Some((
Err(SysError::ENOTCONN),
Endpoint::Ip(IpEndpoint::UNSPECIFIED),
));
} }
None None
}) })
} }
fn write(&self, data: &[u8], sendto_endpoint: Option<IpEndpoint>) -> SysResult { fn write(&self, data: &[u8], sendto_endpoint: Option<Endpoint>) -> SysResult {
let mut sockets = SOCKETS.lock(); let mut sockets = SOCKETS.lock();
let mut socket = sockets.get::<TcpSocket>(self.handle.0); let mut socket = sockets.get::<TcpSocket>(self.handle.0);
@ -178,52 +242,60 @@ impl Socket for TcpSocketState {
(input, output, err) (input, output, err)
} }
fn connect(&mut self, endpoint: IpEndpoint) -> SysResult { fn connect(&mut self, endpoint: Endpoint) -> SysResult {
let mut sockets = SOCKETS.lock(); let mut sockets = SOCKETS.lock();
let mut socket = sockets.get::<TcpSocket>(self.handle.0); let mut socket = sockets.get::<TcpSocket>(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) { match socket.connect(ip, temp_port) {
Ok(()) => { Ok(()) => {
// avoid deadlock // avoid deadlock
drop(socket); drop(socket);
drop(sockets); drop(sockets);
// wait for connection result // wait for connection result
loop { loop {
poll_ifaces(); poll_ifaces();
let mut sockets = SOCKETS.lock(); let mut sockets = SOCKETS.lock();
let socket = sockets.get::<TcpSocket>(self.handle.0); let socket = sockets.get::<TcpSocket>(self.handle.0);
match socket.state() { match socket.state() {
TcpState::SynSent => { TcpState::SynSent => {
// still connecting // still connecting
drop(socket); drop(socket);
drop(sockets); drop(sockets);
debug!("poll for connection wait"); debug!("poll for connection wait");
SOCKET_ACTIVITY._wait(); SOCKET_ACTIVITY._wait();
} }
TcpState::Established => { TcpState::Established => {
break Ok(0); break Ok(0);
} }
_ => { _ => {
break Err(SysError::ECONNREFUSED); break Err(SysError::ECONNREFUSED);
}
} }
} }
} }
Err(_) => Err(SysError::ENOBUFS),
} }
Err(_) => Err(SysError::ENOBUFS), } else {
Err(SysError::EINVAL)
} }
} }
fn bind(&mut self, mut endpoint: IpEndpoint) -> SysResult { fn bind(&mut self, mut endpoint: Endpoint) -> SysResult {
if endpoint.port == 0 { if let Endpoint::Ip(mut ip) = endpoint {
endpoint.port = get_ephemeral_port(); 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 { fn listen(&mut self) -> SysResult {
@ -255,7 +327,7 @@ impl Socket for TcpSocketState {
Ok(0) Ok(0)
} }
fn accept(&mut self) -> Result<(Box<dyn Socket>, IpEndpoint), SysError> { fn accept(&mut self) -> Result<(Box<dyn Socket>, Endpoint), SysError> {
let endpoint = self.local_endpoint.ok_or(SysError::EINVAL)?; let endpoint = self.local_endpoint.ok_or(SysError::EINVAL)?;
loop { loop {
let mut sockets = SOCKETS.lock(); let mut sockets = SOCKETS.lock();
@ -282,7 +354,7 @@ impl Socket for TcpSocketState {
drop(sockets); drop(sockets);
poll_ifaces(); poll_ifaces();
return Ok((new_socket, remote_endpoint)); return Ok((new_socket, Endpoint::Ip(remote_endpoint)));
} }
// avoid deadlock // avoid deadlock
@ -292,24 +364,27 @@ impl Socket for TcpSocketState {
} }
} }
fn endpoint(&self) -> Option<IpEndpoint> { fn endpoint(&self) -> Option<Endpoint> {
self.local_endpoint.clone().or_else(|| { self.local_endpoint
let mut sockets = SOCKETS.lock(); .clone()
let socket = sockets.get::<TcpSocket>(self.handle.0); .map(|e| Endpoint::Ip(e))
let endpoint = socket.local_endpoint(); .or_else(|| {
if endpoint.port != 0 { let mut sockets = SOCKETS.lock();
Some(endpoint) let socket = sockets.get::<TcpSocket>(self.handle.0);
} else { let endpoint = socket.local_endpoint();
None if endpoint.port != 0 {
} Some(Endpoint::Ip(endpoint))
}) } else {
None
}
})
} }
fn remote_endpoint(&self) -> Option<IpEndpoint> { fn remote_endpoint(&self) -> Option<Endpoint> {
let mut sockets = SOCKETS.lock(); let mut sockets = SOCKETS.lock();
let socket = sockets.get::<TcpSocket>(self.handle.0); let socket = sockets.get::<TcpSocket>(self.handle.0);
if socket.is_open() { if socket.is_open() {
Some(socket.remote_endpoint()) Some(Endpoint::Ip(socket.remote_endpoint()))
} else { } else {
None None
} }
@ -340,8 +415,17 @@ 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 { impl Socket for UdpSocketState {
fn read(&self, data: &mut [u8]) -> (SysResult, IpEndpoint) { fn read(&self, data: &mut [u8]) -> (SysResult, Endpoint) {
loop { loop {
let mut sockets = SOCKETS.lock(); let mut sockets = SOCKETS.lock();
let mut socket = sockets.get::<UdpSocket>(self.handle.0); let mut socket = sockets.get::<UdpSocket>(self.handle.0);
@ -354,10 +438,13 @@ impl Socket for UdpSocketState {
drop(sockets); drop(sockets);
poll_ifaces(); poll_ifaces();
return (Ok(size), endpoint); return (Ok(size), Endpoint::Ip(endpoint));
} }
} else { } else {
return (Err(SysError::ENOTCONN), IpEndpoint::UNSPECIFIED); return (
Err(SysError::ENOTCONN),
Endpoint::Ip(IpEndpoint::UNSPECIFIED),
);
} }
// avoid deadlock // avoid deadlock
@ -366,9 +453,9 @@ impl Socket for UdpSocketState {
} }
} }
fn write(&self, data: &[u8], sendto_endpoint: Option<IpEndpoint>) -> SysResult { fn write(&self, data: &[u8], sendto_endpoint: Option<Endpoint>) -> SysResult {
let remote_endpoint = { let remote_endpoint = {
if let Some(ref endpoint) = sendto_endpoint { if let Some(Endpoint::Ip(ref endpoint)) = sendto_endpoint {
endpoint endpoint
} else if let Some(ref endpoint) = self.remote_endpoint { } else if let Some(ref endpoint) = self.remote_endpoint {
endpoint endpoint
@ -417,33 +504,78 @@ impl Socket for UdpSocketState {
(input, output, err) (input, output, err)
} }
fn connect(&mut self, endpoint: IpEndpoint) -> SysResult { fn connect(&mut self, endpoint: Endpoint) -> SysResult {
self.remote_endpoint = Some(endpoint); if let Endpoint::Ip(ip) = endpoint {
Ok(0) 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 sockets = SOCKETS.lock();
let mut socket = sockets.get::<UdpSocket>(self.handle.0); let mut socket = sockets.get::<UdpSocket>(self.handle.0);
match socket.bind(endpoint) { if let Endpoint::Ip(ip) = endpoint {
Ok(()) => Ok(0), match socket.bind(ip) {
Err(_) => Err(SysError::EINVAL), Ok(()) => Ok(0),
Err(_) => Err(SysError::EINVAL),
}
} else {
Err(SysError::EINVAL)
} }
} }
fn endpoint(&self) -> Option<IpEndpoint> { fn ioctl(&mut self, request: usize, arg1: usize, arg2: usize, arg3: usize) -> SysResult {
match request {
// SIOCGARP
0x8954 => {
// FIXME: check addr
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) };
let addr = &req.arp_pa as *const SockAddrPlaceholder as *const SockAddr;
let addr = unsafe {
IpAddress::from(Ipv4Address::from_bytes(
&u32::from_be((*addr).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);
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)
} else {
Err(SysError::EINVAL)
}
}
_ => Ok(0),
}
}
fn endpoint(&self) -> Option<Endpoint> {
let mut sockets = SOCKETS.lock(); let mut sockets = SOCKETS.lock();
let socket = sockets.get::<UdpSocket>(self.handle.0); let socket = sockets.get::<UdpSocket>(self.handle.0);
let endpoint = socket.endpoint(); let endpoint = socket.endpoint();
if endpoint.port != 0 { if endpoint.port != 0 {
Some(endpoint) Some(Endpoint::Ip(endpoint))
} else { } else {
None None
} }
} }
fn remote_endpoint(&self) -> Option<IpEndpoint> { fn remote_endpoint(&self) -> Option<Endpoint> {
self.remote_endpoint.clone() self.remote_endpoint.clone().map(|e| Endpoint::Ip(e))
} }
fn box_clone(&self) -> Box<dyn Socket> { fn box_clone(&self) -> Box<dyn Socket> {
@ -469,12 +601,15 @@ impl RawSocketState {
); );
let handle = GlobalSocketHandle(SOCKETS.lock().add(socket)); let handle = GlobalSocketHandle(SOCKETS.lock().add(socket));
RawSocketState { handle } RawSocketState {
handle,
header_included: false,
}
} }
} }
impl Socket for RawSocketState { impl Socket for RawSocketState {
fn read(&self, data: &mut [u8]) -> (SysResult, IpEndpoint) { fn read(&self, data: &mut [u8]) -> (SysResult, Endpoint) {
loop { loop {
let mut sockets = SOCKETS.lock(); let mut sockets = SOCKETS.lock();
let mut socket = sockets.get::<RawSocket>(self.handle.0); let mut socket = sockets.get::<RawSocket>(self.handle.0);
@ -484,10 +619,10 @@ impl Socket for RawSocketState {
return ( return (
Ok(size), Ok(size),
IpEndpoint { Endpoint::Ip(IpEndpoint {
addr: IpAddress::Ipv4(packet.src_addr()), addr: IpAddress::Ipv4(packet.src_addr()),
port: 0, port: 0,
}, }),
); );
} }
@ -498,39 +633,98 @@ impl Socket for RawSocketState {
} }
} }
fn write(&self, data: &[u8], sendto_endpoint: Option<IpEndpoint>) -> SysResult { fn write(&self, data: &[u8], sendto_endpoint: Option<Endpoint>) -> SysResult {
if let Some(endpoint) = sendto_endpoint { if self.header_included {
// temporary solution
let iface = &*(NET_DRIVERS.read()[0]);
let v4_src = iface.ipv4_address().unwrap();
let mut sockets = SOCKETS.lock(); let mut sockets = SOCKETS.lock();
let mut socket = sockets.get::<RawSocket>(self.handle.0); let mut socket = sockets.get::<RawSocket>(self.handle.0);
if let IpAddress::Ipv4(v4_dst) = endpoint.addr { match socket.send_slice(&data) {
let len = data.len(); Ok(()) => Ok(data.len()),
// using 20-byte IPv4 header Err(_) => Err(SysError::ENOBUFS),
let mut buffer = vec![0u8; len + 20]; }
let mut packet = Ipv4Packet::new_unchecked(&mut buffer); } else {
packet.set_version(4); if let Some(Endpoint::Ip(endpoint)) = sendto_endpoint {
packet.set_header_len(20); // temporary solution
packet.set_total_len((20 + len) as u16); let iface = &*(NET_DRIVERS.read()[0]);
packet.set_protocol(socket.ip_protocol().into()); let v4_src = iface.ipv4_address().unwrap();
packet.set_src_addr(v4_src); let mut sockets = SOCKETS.lock();
packet.set_dst_addr(v4_dst); let mut socket = sockets.get::<RawSocket>(self.handle.0);
let payload = packet.payload_mut();
payload.copy_from_slice(data); if let IpAddress::Ipv4(v4_dst) = endpoint.addr {
packet.fill_checksum(); let len = data.len();
// using 20-byte IPv4 header
socket.send_slice(&buffer).unwrap(); let mut buffer = vec![0u8; len + 20];
let mut packet = Ipv4Packet::new_unchecked(&mut buffer);
// avoid deadlock packet.set_version(4);
drop(socket); packet.set_header_len(20);
drop(sockets); packet.set_total_len((20 + len) as u16);
iface.poll(); 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();
Ok(len) Ok(len)
} else {
unimplemented!("ip type")
}
} else { } else {
unimplemented!("ip type") Err(SysError::ENOTCONN)
}
}
}
fn poll(&self) -> (bool, bool, bool) {
unimplemented!()
}
fn connect(&mut self, _endpoint: Endpoint) -> SysResult {
unimplemented!()
}
fn box_clone(&self) -> Box<dyn Socket> {
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)
}
}
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<Endpoint>) -> SysResult {
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 { } else {
Err(SysError::ENOTCONN) Err(SysError::ENOTCONN)
@ -541,7 +735,7 @@ impl Socket for RawSocketState {
unimplemented!() unimplemented!()
} }
fn connect(&mut self, _endpoint: IpEndpoint) -> SysResult { fn connect(&mut self, _endpoint: Endpoint) -> SysResult {
unimplemented!() unimplemented!()
} }
@ -550,6 +744,338 @@ impl Socket for RawSocketState {
} }
} }
/// Common structure:
/// | nlmsghdr | ifinfomsg/ifaddrmsg | rtattr | rtattr | rtattr | ... | rtattr
/// All aligned to 4 bytes boundary
#[repr(C)]
#[derive(Debug, Copy, Clone)]
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
}
#[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 IfaceAddrMsg {
ifa_family: u8,
ifa_prefixlen: u8,
ifa_flags: u8,
ifa_scope: u8,
ifa_index: u32,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct RouteAttr {
rta_len: u16,
rta_type: u16,
}
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) {
/// Nothing
Noop = 1,
/// Error
Error = 2,
/// End of a dump
Done = 3,
/// Data lost
Overrun = 4,
/// 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,
}
}
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 {
data: Arc::new(Mutex::new(Vec::new())),
}
}
}
trait VecExt {
fn align4(&mut self);
fn push_ext<T: Sized>(&mut self, data: T);
fn set_ext<T: Sized>(&mut self, offset: usize, data: T);
}
impl VecExt for Vec<u8> {
fn align4(&mut self) {
let len = (self.len() + 3) & !3;
if len > self.len() {
self.resize(len, 0);
}
}
fn push_ext<T: Sized>(&mut self, data: T) {
let bytes =
unsafe { slice::from_raw_parts(&data as *const T as *const u8, size_of::<T>()) };
for byte in bytes {
self.push(*byte);
}
}
fn set_ext<T: Sized>(&mut self, offset: usize, data: T) {
if self.len() < offset + size_of::<T>() {
self.resize(offset + size_of::<T>(), 0);
}
let bytes =
unsafe { slice::from_raw_parts(&data as *const T as *const u8, size_of::<T>()) };
for i in 0..bytes.len() {
self[offset + i] = bytes[i];
}
}
}
impl Socket for NetlinkSocketState {
fn read(&self, data: &mut [u8]) -> (SysResult, Endpoint) {
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<Endpoint>) -> SysResult {
if data.len() < size_of::<NetlinkMessageHeader>() {
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!("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::<RouteAttr>()) 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::<RouteAttr>()) 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);
}
}
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::<RouteAttr>()) as u16,
rta_type: RouteAttrTypes::Address.into(),
};
attrs.align4();
attrs.push_ext(attr);
for byte in ip_addr.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())
}
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<dyn Socket> {
Box::new(self.clone())
}
}
fn get_ephemeral_port() -> u16 { fn get_ephemeral_port() -> u16 {
// TODO selects non-conflict high port // TODO selects non-conflict high port
static mut EPHEMERAL_PORT: u16 = 0; static mut EPHEMERAL_PORT: u16 = 0;
@ -580,6 +1106,6 @@ const UDP_METADATA_BUF: usize = 1024;
const UDP_SENDBUF: usize = 64 * 1024; // 64K const UDP_SENDBUF: usize = 64 * 1024; // 64K
const UDP_RECVBUF: usize = 64 * 1024; // 64K const UDP_RECVBUF: usize = 64 * 1024; // 64K
const RAW_METADATA_BUF: usize = 2; const RAW_METADATA_BUF: usize = 1024;
const RAW_SENDBUF: usize = 2 * 1024; // 2K const RAW_SENDBUF: usize = 64 * 1024; // 64K
const RAW_RECVBUF: usize = 2 * 1024; // 2K const RAW_RECVBUF: usize = 64 * 1024; // 64K

@ -15,7 +15,7 @@ use xmas_elf::{
use crate::arch::interrupt::{Context, TrapFrame}; use crate::arch::interrupt::{Context, TrapFrame};
use crate::fs::{FileHandle, FileLike, INodeExt, OpenOptions, FOLLOW_MAX_DEPTH}; use crate::fs::{FileHandle, FileLike, INodeExt, OpenOptions, FOLLOW_MAX_DEPTH};
use crate::memory::{ByFrame, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet}; 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 crate::sync::{Condvar, SpinNoIrqLock as Mutex};
use super::abi::{self, ProcInitInfo}; use super::abi::{self, ProcInitInfo};
@ -123,24 +123,13 @@ impl rcore_thread::Context for Thread {
impl Thread { impl Thread {
/// Make a struct for the init thread /// Make a struct for the init thread
/// TODO: remove this, we only need `Context::null()`
pub unsafe fn new_init() -> Box<Thread> { pub unsafe fn new_init() -> Box<Thread> {
Box::new(Thread { Box::new(Thread {
context: Context::null(), context: Context::null(),
kstack: KernelStack::new(), kstack: KernelStack::new(),
clear_child_tid: 0, clear_child_tid: 0,
proc: Arc::new(Mutex::new(Process { // safety: this field will never be used
vm: MemorySet::new(), proc: core::mem::uninitialized(),
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(),
})),
}) })
} }
@ -175,10 +164,6 @@ impl Thread {
{ {
// Parse ELF // Parse ELF
let elf = ElfFile::new(data).expect("failed to read 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 // Check ELF type
match elf.header.pt2.type_().as_type() { match elf.header.pt2.type_().as_type() {
@ -210,12 +195,10 @@ impl Thread {
let mut vm = elf.make_memory_set(); let mut vm = elf.make_memory_set();
// User stack // 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 mut ustack_top = {
let (ustack_buttom, ustack_top) = match is32 { let ustack_buttom = USER_STACK_OFFSET;
true => (USER32_STACK_OFFSET, USER32_STACK_OFFSET + USER_STACK_SIZE), let ustack_top = USER_STACK_OFFSET + USER_STACK_SIZE;
false => (USER_STACK_OFFSET, USER_STACK_OFFSET + USER_STACK_SIZE),
};
vm.push( vm.push(
ustack_buttom, ustack_buttom,
ustack_top, ustack_top,
@ -288,7 +271,7 @@ impl Thread {
Box::new(Thread { Box::new(Thread {
context: unsafe { 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, kstack,
clear_child_tid: 0, clear_child_tid: 0,

@ -10,6 +10,8 @@ use crate::fs::*;
use crate::memory::MemorySet; use crate::memory::MemorySet;
use crate::sync::Condvar; use crate::sync::Condvar;
use bitvec::prelude::{BitSlice, BitVec, LittleEndian};
use super::*; use super::*;
pub fn sys_read(fd: usize, base: *mut u8, len: usize) -> SysResult { pub fn sys_read(fd: usize, base: *mut u8, len: usize) -> SysResult {
@ -86,34 +88,24 @@ pub fn sys_poll(ufds: *mut PollFd, nfds: usize, timeout_msecs: usize) -> SysResu
let proc = process(); let proc = process();
let mut events = 0; let mut events = 0;
for poll in polls.iter_mut() { for poll in polls.iter_mut() {
poll.revents = PE::NONE; poll.revents = PE::empty();
match proc.files.get(&(poll.fd as usize)) { if let Some(file_like) = proc.files.get(&(poll.fd as usize)) {
Some(FileLike::File(_)) => { let status = file_like.poll()?;
// FIXME: assume it is stdin for now if status.error {
if poll.events.contains(PE::IN) && STDIN.can_read() { poll.revents |= PE::HUP;
poll.revents = poll.revents | PE::IN; events += 1;
events = events + 1;
}
} }
Some(FileLike::Socket(socket)) => { if status.read && poll.events.contains(PE::IN) {
let (input, output, err) = socket.poll(); poll.revents |= PE::IN;
if err { events += 1;
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;
}
} }
None => { if status.write && poll.events.contains(PE::OUT) {
poll.revents = poll.revents | PE::ERR; poll.revents |= PE::OUT;
events = events + 1; events += 1;
} }
} else {
poll.revents |= PE::ERR;
events += 1;
} }
} }
drop(proc); drop(proc);
@ -160,34 +152,22 @@ pub fn sys_select(
loop { loop {
let proc = process(); let proc = process();
let mut events = 0; let mut events = 0;
for (fd, file_like) in proc.files.iter() { for (&fd, file_like) in proc.files.iter() {
if *fd < nfds { if fd >= nfds {
match file_like { continue;
FileLike::File(_) => { }
// FIXME: assume it is stdin for now let status = file_like.poll()?;
if STDIN.can_read() { if status.error && err_fds.contains(fd) {
if read_fds.is_set(*fd) { err_fds.set(fd);
read_fds.set(*fd); events += 1;
events = events + 1; }
} if status.read && read_fds.contains(fd) {
} read_fds.set(fd);
} events += 1;
FileLike::Socket(socket) => { }
let (input, output, err) = socket.poll(); if status.write && write_fds.contains(fd) {
if err && err_fds.is_set(*fd) { write_fds.set(fd);
err_fds.set(*fd); events += 1;
events = events + 1;
}
if input && read_fds.is_set(*fd) {
read_fds.set(*fd);
events = events + 1;
}
if output && write_fds.is_set(*fd) {
write_fds.set(*fd);
events = events + 1;
}
}
}
} }
} }
drop(proc); drop(proc);
@ -257,49 +237,24 @@ pub fn sys_openat(dir_fd: usize, path: *const u8, flags: usize, mode: usize) ->
dir_fd as isize, path, flags, mode dir_fd as isize, path, flags, mode
); );
let inode = if dir_fd == AT_FDCWD { let inode = if flags.contains(OpenFlags::CREATE) {
// from process cwd let (dir_path, file_name) = split_path(&path);
if flags.contains(OpenFlags::CREATE) { // relative to cwd
let (dir_path, file_name) = split_path(&path); let dir_inode = proc.lookup_inode_at(dir_fd, dir_path)?;
// relative to cwd match dir_inode.find(file_name) {
let dir_inode = proc.lookup_inode(dir_path)?; Ok(file_inode) => {
match dir_inode.find(file_name) { if flags.contains(OpenFlags::EXCLUSIVE) {
Ok(file_inode) => { return Err(SysError::EEXIST);
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)), file_inode
} }
} else { Err(FsError::EntryNotFound) => {
proc.lookup_inode(&path)? dir_inode.create(file_name, FileType::File, mode as u32)?
}
} 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)),
} }
} else { Err(e) => return Err(SysError::from(e)),
dir_file.lookup_follow(&path, FOLLOW_MAX_DEPTH)?
} }
} else {
proc.lookup_inode_at(dir_fd, &path)?
}; };
let fd = proc.get_free_fd(); let fd = proc.get_free_fd();
@ -317,14 +272,22 @@ pub fn sys_close(fd: usize) -> SysResult {
} }
pub fn sys_access(path: *const u8, mode: 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 // TODO: check permissions based on uid/gid
let proc = process(); let proc = process();
let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; let path = unsafe { proc.vm.check_and_clone_cstr(path)? };
let flags = AtFlags::from_bits_truncate(flags);
if !proc.pid.is_init() { if !proc.pid.is_init() {
// we trust pid 0 process // 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) Ok(0)
} }
@ -342,9 +305,9 @@ pub fn sys_getcwd(buf: *mut u8, len: usize) -> SysResult {
Ok(buf as usize) Ok(buf as usize)
} }
pub fn sys_stat(path: *const u8, stat_ptr: *mut Stat) -> SysResult { pub fn sys_lstat(path: *const u8, stat_ptr: *mut Stat) -> SysResult {
warn!("stat is partial implemented as lstat"); warn!("lstat is partial implemented as stat");
sys_lstat(path, stat_ptr) sys_stat(path, stat_ptr)
} }
pub fn sys_fstat(fd: usize, stat_ptr: *mut Stat) -> SysResult { pub fn sys_fstat(fd: usize, stat_ptr: *mut Stat) -> SysResult {
@ -353,20 +316,23 @@ pub fn sys_fstat(fd: usize, stat_ptr: *mut Stat) -> SysResult {
proc.vm.check_write_ptr(stat_ptr)?; proc.vm.check_write_ptr(stat_ptr)?;
let file = proc.get_file(fd)?; let file = proc.get_file(fd)?;
let stat = Stat::from(file.metadata()?); let stat = Stat::from(file.metadata()?);
// TODO: handle symlink
unsafe { unsafe {
stat_ptr.write(stat); stat_ptr.write(stat);
} }
Ok(0) 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 proc = process();
let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; let path = unsafe { proc.vm.check_and_clone_cstr(path)? };
proc.vm.check_write_ptr(stat_ptr)?; 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()?); let stat = Stat::from(inode.metadata()?);
unsafe { unsafe {
stat_ptr.write(stat); stat_ptr.write(stat);
@ -374,13 +340,21 @@ pub fn sys_lstat(path: *const u8, stat_ptr: *mut Stat) -> SysResult {
Ok(0) 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 { 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 proc = process();
let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; let path = unsafe { proc.vm.check_and_clone_cstr(path)? };
proc.vm.check_write_array(base, len)?; proc.vm.check_write_array(base, len)?;
info!("readlink: path: {:?}, base: {:?}, len: {}", path, 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 { if inode.metadata()?.type_ == FileType::SymLink {
// TODO: recursive link resolution and loop detection // TODO: recursive link resolution and loop detection
let mut slice = unsafe { slice::from_raw_parts_mut(base, len) }; let mut slice = unsafe { slice::from_raw_parts_mut(base, len) };
@ -470,6 +444,16 @@ pub fn sys_dup2(fd1: usize, fd2: usize) -> SysResult {
Ok(fd2) 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 { pub fn sys_chdir(path: *const u8) -> SysResult {
let mut proc = process(); let mut proc = process();
let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; let path = unsafe { proc.vm.check_and_clone_cstr(path)? };
@ -484,12 +468,34 @@ pub fn sys_chdir(path: *const u8) -> SysResult {
return Err(SysError::ENOTDIR); return Err(SysError::ENOTDIR);
} }
if path.len() > 0 && path.as_bytes()[0] == b'/' { // BUGFIX: '..' and '.'
// absolute if path.len() > 0 {
proc.cwd = path; let cwd = match path.as_bytes()[0] {
} else { b'/' => String::from("/"),
// relative _ => proc.cwd.clone()
proc.cwd += &path; };
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) Ok(0)
} }
@ -514,30 +520,27 @@ pub fn sys_renameat(
let (old_dir_path, old_file_name) = split_path(&oldpath); let (old_dir_path, old_file_name) = split_path(&oldpath);
let (new_dir_path, new_file_name) = split_path(&newpath); let (new_dir_path, new_file_name) = split_path(&newpath);
let old_dir_inode = if olddirfd == AT_FDCWD { let old_dir_inode = proc.lookup_inode_at(olddirfd, old_dir_path)?;
proc.lookup_inode(old_dir_path)? let new_dir_inode = proc.lookup_inode_at(newdirfd, new_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)?
};
old_dir_inode.move_(old_file_name, &new_dir_inode, new_file_name)?; old_dir_inode.move_(old_file_name, &new_dir_inode, new_file_name)?;
Ok(0) Ok(0)
} }
pub fn sys_mkdir(path: *const u8, mode: usize) -> SysResult { 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 proc = process();
let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; let path = unsafe { proc.vm.check_and_clone_cstr(path)? };
// TODO: check pathname // 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 (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() { if inode.find(file_name).is_ok() {
return Err(SysError::EEXIST); return Err(SysError::EEXIST);
} }
@ -561,25 +564,47 @@ pub fn sys_rmdir(path: *const u8) -> SysResult {
} }
pub fn sys_link(oldpath: *const u8, newpath: *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 proc = process();
let oldpath = unsafe { proc.vm.check_and_clone_cstr(oldpath)? }; let oldpath = unsafe { proc.vm.check_and_clone_cstr(oldpath)? };
let newpath = unsafe { proc.vm.check_and_clone_cstr(newpath)? }; 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 (new_dir_path, new_file_name) = split_path(&newpath);
let inode = proc.lookup_inode(&oldpath)?; let inode = proc.lookup_inode_at(olddirfd, &oldpath)?;
let new_dir_inode = proc.lookup_inode(new_dir_path)?; let new_dir_inode = proc.lookup_inode_at(newdirfd, new_dir_path)?;
new_dir_inode.link(new_file_name, &inode)?; new_dir_inode.link(new_file_name, &inode)?;
Ok(0) Ok(0)
} }
pub fn sys_unlink(path: *const u8) -> SysResult { 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 proc = process();
let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; 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_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)?; let file_inode = dir_inode.find(file_name)?;
if file_inode.metadata()?.type_ == FileType::Dir { if file_inode.metadata()?.type_ == FileType::Dir {
return Err(SysError::EISDIR); return Err(SysError::EISDIR);
@ -711,11 +736,44 @@ impl Process {
_ => Err(SysError::EBADF), _ => 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<Arc<INode>, 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<Arc<INode>, SysError> { pub fn lookup_inode(&self, path: &str) -> Result<Arc<INode>, SysError> {
debug!("lookup_inode: cwd {} path {}", self.cwd, path); self.lookup_inode_at(AT_FDCWD, path)
Ok(ROOT_INODE
.lookup(&self.cwd)?
.lookup_follow(path, FOLLOW_MAX_DEPTH)?)
} }
} }
@ -750,6 +808,13 @@ impl From<FsError> for SysError {
} }
} }
bitflags! {
struct AtFlags: usize {
const EMPTY_PATH = 0x1000;
const SYMLINK_NOFOLLOW = 0x100;
}
}
bitflags! { bitflags! {
struct OpenFlags: usize { struct OpenFlags: usize {
/// read only /// read only
@ -1079,10 +1144,10 @@ pub struct IoVec {
/// A valid IoVecs request from user /// A valid IoVecs request from user
#[derive(Debug)] #[derive(Debug)]
struct IoVecs(Vec<&'static mut [u8]>); pub struct IoVecs(Vec<&'static mut [u8]>);
impl IoVecs { impl IoVecs {
fn check_and_new( pub fn check_and_new(
iov_ptr: *const IoVec, iov_ptr: *const IoVec,
iov_count: usize, iov_count: usize,
vm: &MemorySet, vm: &MemorySet,
@ -1108,7 +1173,7 @@ impl IoVecs {
Ok(IoVecs(slices)) Ok(IoVecs(slices))
} }
fn read_all_to_vec(&self) -> Vec<u8> { pub fn read_all_to_vec(&self) -> Vec<u8> {
let mut buf = self.new_buf(false); let mut buf = self.new_buf(false);
for slice in self.0.iter() { for slice in self.0.iter() {
buf.extend(slice.iter()); buf.extend(slice.iter());
@ -1116,7 +1181,7 @@ impl IoVecs {
buf 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; let mut copied_len = 0;
for slice in self.0.iter_mut() { for slice in self.0.iter_mut() {
let copy_len = min(slice.len(), buf.len() - copied_len); let copy_len = min(slice.len(), buf.len() - copied_len);
@ -1132,7 +1197,7 @@ impl IoVecs {
/// Create a new Vec buffer from IoVecs /// Create a new Vec buffer from IoVecs
/// For readv: `set_len` is true, Vec.len = total_len. /// For readv: `set_len` is true, Vec.len = total_len.
/// For writev: `set_len` is false, Vec.cap = total_len. /// For writev: `set_len` is false, Vec.cap = total_len.
fn new_buf(&self, set_len: bool) -> Vec<u8> { pub fn new_buf(&self, set_len: bool) -> Vec<u8> {
let total_len = self.0.iter().map(|slice| slice.len()).sum::<usize>(); let total_len = self.0.iter().map(|slice| slice.len()).sum::<usize>();
let mut buf = Vec::with_capacity(total_len); let mut buf = Vec::with_capacity(total_len);
if set_len { if set_len {
@ -1153,8 +1218,6 @@ pub struct PollFd {
bitflags! { bitflags! {
pub struct PollEvents: u16 { pub struct PollEvents: u16 {
/// Nothing Happens
const NONE = 0x0000;
/// There is data to read. /// There is data to read.
const IN = 0x0001; const IN = 0x0001;
/// Writing is now possible. /// Writing is now possible.
@ -1172,54 +1235,51 @@ const FD_PER_ITEM: usize = 8 * size_of::<u32>();
const MAX_FDSET_SIZE: usize = 1024 / FD_PER_ITEM; const MAX_FDSET_SIZE: usize = 1024 / FD_PER_ITEM;
struct FdSet { struct FdSet {
addr: *mut u32, bitset: &'static mut BitSlice<LittleEndian, u32>,
nfds: usize, origin: BitVec<LittleEndian, u32>,
saved: [u32; MAX_FDSET_SIZE],
} }
impl FdSet { impl FdSet {
/// Initialize a `FdSet` from pointer and number of fds /// Initialize a `FdSet` from pointer and number of fds
/// Check if the array is large enough /// Check if the array is large enough
fn new(vm: &MemorySet, addr: *mut u32, nfds: usize) -> Result<FdSet, SysError> { fn new(vm: &MemorySet, addr: *mut u32, nfds: usize) -> Result<FdSet, SysError> {
let mut saved = [0u32; MAX_FDSET_SIZE]; if addr.is_null() {
if addr as usize != 0 { Ok(FdSet {
bitset: BitSlice::empty_mut(),
origin: BitVec::new(),
})
} else {
let len = (nfds + FD_PER_ITEM - 1) / FD_PER_ITEM; let len = (nfds + FD_PER_ITEM - 1) / FD_PER_ITEM;
vm.check_write_array(addr, len)?; vm.check_write_array(addr, len)?;
if len > MAX_FDSET_SIZE { if len > MAX_FDSET_SIZE {
return Err(SysError::EINVAL); return Err(SysError::EINVAL);
} }
let slice = unsafe { slice::from_raw_parts_mut(addr, len) }; let slice = unsafe { slice::from_raw_parts_mut(addr, len) };
let bitset: &'static mut BitSlice<LittleEndian, u32> = slice.into();
// save the fdset, and clear it // save the fdset, and clear it
for i in 0..len { use alloc::prelude::ToOwned;
saved[i] = slice[i]; let origin = bitset.to_owned();
slice[i] = 0; bitset.set_all(false);
} Ok(FdSet { bitset, origin })
} }
Ok(FdSet { addr, nfds, saved })
} }
/// Try to set fd in `FdSet` /// Try to set fd in `FdSet`
/// Return true when `FdSet` is valid, and false when `FdSet` is bad (i.e. null pointer) /// Return true when `FdSet` is valid, and false when `FdSet` is bad (i.e. null pointer)
/// Fd should be less than nfds /// Fd should be less than nfds
fn set(&mut self, fd: usize) -> bool { fn set(&mut self, fd: usize) -> bool {
if self.addr as usize != 0 { if self.bitset.is_empty() {
assert!(fd < self.nfds); return false;
unsafe {
*self.addr.add(fd / 8 / size_of::<u32>()) |= 1 << (fd % (8 * size_of::<u32>()));
}
true
} else {
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 /// Fd should be less than nfds
fn is_set(&mut self, fd: usize) -> bool { fn contains(&self, fd: usize) -> bool {
assert!(fd < self.nfds); self.origin[fd]
self.saved[fd / 8 / size_of::<u32>()] & (1 << (fd % (8 * size_of::<u32>()))) != 0
} }
} }

@ -19,7 +19,7 @@ use self::custom::*;
use self::fs::*; use self::fs::*;
use self::mem::*; use self::mem::*;
use self::misc::*; use self::misc::*;
use self::net::*; pub use self::net::*;
use self::proc::*; use self::proc::*;
use self::time::*; use self::time::*;
@ -70,10 +70,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
warn!("sys_sigprocmask is unimplemented"); warn!("sys_sigprocmask is unimplemented");
Ok(0) Ok(0)
} }
SYS_IOCTL => { SYS_IOCTL => sys_ioctl(args[0], args[1], args[2], args[3], args[4]),
warn!("sys_ioctl is unimplemented");
Ok(0)
}
SYS_PREAD64 => sys_pread(args[0], args[1] as *mut u8, args[2], args[3]), 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_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]), SYS_READV => sys_readv(args[0], args[1] as *const IoVec, args[2]),
@ -112,7 +109,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
args[5] as *mut u32, args[5] as *mut u32,
), ),
// SYS_SENDMSG => sys_sendmsg(), // 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_SHUTDOWN => sys_shutdown(args[0], args[1]),
SYS_BIND => sys_bind(args[0], args[1] as *const SockAddr, args[2]), SYS_BIND => sys_bind(args[0], args[1] as *const SockAddr, args[2]),
// 50 // 50
@ -247,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_CLOCK_GETTIME => sys_clock_gettime(args[0], args[1] as *mut TimeSpec),
SYS_EXIT_GROUP => sys_exit_group(args[0]), 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_OPENAT => sys_openat(args[0], args[1] as *const u8, args[2], args[3]),
SYS_MKDIRAT => sys_mkdir(args[1] as *const u8, args[2]), // TODO: handle `dfd` SYS_MKDIRAT => sys_mkdirat(args[0], args[1] as *const u8, args[2]),
// SYS_MKNODAT => sys_mknod(), // SYS_MKNODAT => sys_mknod(),
// 260 // 260
SYS_FCHOWNAT => { SYS_FCHOWNAT => {
warn!("sys_fchownat is unimplemented"); warn!("sys_fchownat is unimplemented");
Ok(0) Ok(0)
} }
SYS_NEWFSTATAT => sys_stat(args[1] as *const u8, args[2] as *mut Stat), // TODO: handle `dfd`, `flag` SYS_NEWFSTATAT => sys_fstatat(args[0], args[1] as *const u8, args[2] as *mut Stat, args[3]),
SYS_UNLINKAT => sys_unlink(args[1] as *const u8), // TODO: handle `dfd`, `flag` SYS_UNLINKAT => sys_unlinkat(args[0], args[1] as *const u8, args[2]),
SYS_RENAMEAT => sys_renameat(args[0], args[1] as *const u8, args[2], args[3] as *const u8), // TODO: handle `olddfd`, `newdfd` SYS_READLINKAT => sys_readlinkat(args[0], args[1] as *const u8, args[2] as *mut u8, args[3]),
SYS_LINKAT => sys_link(args[1] as *const u8, args[3] as *const u8), // TODO: handle `olddfd`, `newdfd`, `flags` 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_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 // 280
SYS_UTIMENSAT => { SYS_UTIMENSAT => {
warn!("sys_utimensat is unimplemented"); warn!("sys_utimensat is unimplemented");

@ -1,9 +1,13 @@
//! Syscalls for networking //! Syscalls for networking
use super::fs::IoVecs;
use super::*; use super::*;
use crate::drivers::SOCKET_ACTIVITY; use crate::drivers::SOCKET_ACTIVITY;
use crate::fs::FileLike; use crate::fs::FileLike;
use crate::net::{RawSocketState, Socket, TcpSocketState, UdpSocketState, SOCKETS}; use crate::net::{
Endpoint, LinkLevelEndpoint, NetlinkEndpoint, NetlinkSocketState, PacketSocketState,
RawSocketState, Socket, TcpSocketState, UdpSocketState, SOCKETS,
};
use crate::sync::{MutexGuard, SpinNoIrq, SpinNoIrqLock as Mutex}; use crate::sync::{MutexGuard, SpinNoIrq, SpinNoIrqLock as Mutex};
use alloc::boxed::Box; use alloc::boxed::Box;
use core::cmp::min; use core::cmp::min;
@ -11,16 +15,26 @@ use core::mem::size_of;
use smoltcp::wire::*; use smoltcp::wire::*;
pub fn sys_socket(domain: usize, socket_type: usize, protocol: usize) -> SysResult { 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!( info!(
"socket: domain: {}, socket_type: {}, protocol: {}", "socket: domain: {:?}, socket_type: {:?}, protocol: {}",
domain, socket_type, protocol domain, socket_type, protocol
); );
let mut proc = process(); let mut proc = process();
let socket: Box<dyn Socket> = match domain { let socket: Box<dyn Socket> = match domain {
AF_INET | AF_UNIX => match socket_type & SOCK_TYPE_MASK { AddressFamily::Internet | AddressFamily::Unix => match socket_type {
SOCK_STREAM => Box::new(TcpSocketState::new()), SocketType::Stream => Box::new(TcpSocketState::new()),
SOCK_DGRAM => Box::new(UdpSocketState::new()), SocketType::Datagram => Box::new(UdpSocketState::new()),
SOCK_RAW => Box::new(RawSocketState::new(protocol as u8)), 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::EINVAL),
}, },
_ => return Err(SysError::EAFNOSUPPORT), _ => return Err(SysError::EAFNOSUPPORT),
@ -34,15 +48,18 @@ pub fn sys_setsockopt(
fd: usize, fd: usize,
level: usize, level: usize,
optname: usize, optname: usize,
_optval: *const u8, optval: *const u8,
_optlen: usize, optlen: usize,
) -> SysResult { ) -> SysResult {
info!( info!(
"setsockopt: fd: {}, level: {}, optname: {}", "setsockopt: fd: {}, level: {}, optname: {}",
fd, level, optname fd, level, optname
); );
warn!("sys_setsockopt is unimplemented"); let mut proc = process();
Ok(0) 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( pub fn sys_getsockopt(
@ -157,12 +174,34 @@ pub fn sys_recvfrom(
result 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)?;
}
}
result
}
pub fn sys_bind(fd: usize, addr: *const SockAddr, addr_len: usize) -> SysResult { pub fn sys_bind(fd: usize, addr: *const SockAddr, addr_len: usize) -> SysResult {
info!("sys_bind: fd: {} addr: {:?} len: {}", fd, addr, addr_len); info!("sys_bind: fd: {} addr: {:?} len: {}", fd, addr, addr_len);
let mut proc = process(); let mut proc = process();
let mut endpoint = sockaddr_to_endpoint(&mut proc, addr, addr_len)?; 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)?; let socket = proc.get_socket(fd)?;
socket.bind(endpoint) socket.bind(endpoint)
@ -263,45 +302,98 @@ impl Process {
} }
} }
// cancel alignment #[repr(C)]
#[repr(packed)]
pub struct SockAddrIn { pub struct SockAddrIn {
sin_port: u16, pub sin_family: u16,
sin_addr: u32, pub sin_port: u16,
sin_zero: [u8; 8], pub sin_addr: u32,
pub sin_zero: [u8; 8],
} }
#[repr(C)] #[repr(C)]
pub struct SockAddrUn { pub struct SockAddrUn {
sun_path: [u8; 108], pub sun_family: u16,
pub sun_path: [u8; 108],
}
#[repr(C)]
pub struct SockAddrLl {
pub sll_family: u16,
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 struct SockAddrNl {
nl_family: u16,
nl_pad: u16,
nl_pid: u32,
nl_groups: u32,
} }
#[repr(C)] #[repr(C)]
pub union SockAddrPayload { pub union SockAddr {
addr_in: SockAddrIn, pub family: u16,
addr_un: SockAddrUn, pub addr_in: SockAddrIn,
pub addr_un: SockAddrUn,
pub addr_ll: SockAddrLl,
pub addr_nl: SockAddrNl,
pub addr_ph: SockAddrPlaceholder,
} }
#[repr(C)] #[repr(C)]
pub struct SockAddr { pub struct SockAddrPlaceholder {
family: u16, pub family: u16,
payload: SockAddrPayload, pub data: [u8; 14],
} }
impl From<IpEndpoint> for SockAddr { impl From<Endpoint> for SockAddr {
fn from(endpoint: IpEndpoint) -> Self { fn from(endpoint: Endpoint) -> Self {
match endpoint.addr { if let Endpoint::Ip(ip) = endpoint {
IpAddress::Ipv4(ipv4) => SockAddr { match ip.addr {
family: AF_INET as u16, IpAddress::Ipv4(ipv4) => SockAddr {
payload: SockAddrPayload {
addr_in: SockAddrIn { addr_in: SockAddrIn {
sin_port: u16::to_be(endpoint.port), sin_family: AddressFamily::Internet.into(),
sin_port: u16::to_be(ip.port),
sin_addr: u32::to_be(u32::from_be_bytes(ipv4.0)), sin_addr: u32::to_be(u32::from_be_bytes(ipv4.0)),
sin_zero: [0; 8], sin_zero: [0; 8],
}, },
}, },
}, IpAddress::Unspecified => SockAddr {
_ => unimplemented!("ipv6"), 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");
} }
} }
} }
@ -312,24 +404,41 @@ fn sockaddr_to_endpoint(
proc: &mut Process, proc: &mut Process,
addr: *const SockAddr, addr: *const SockAddr,
len: usize, len: usize,
) -> Result<IpEndpoint, SysError> { ) -> Result<Endpoint, SysError> {
if len < size_of::<u16>() { if len < size_of::<u16>() {
return Err(SysError::EINVAL); return Err(SysError::EINVAL);
} }
proc.vm.check_read_array(addr as *const u8, len)?; proc.vm.check_read_array(addr as *const u8, len)?;
unsafe { unsafe {
match (*addr).family as usize { match AddressFamily::from((*addr).family) {
AF_INET => { AddressFamily::Internet => {
if len < size_of::<u16>() + size_of::<SockAddrIn>() { if len < size_of::<SockAddrIn>() {
return Err(SysError::EINVAL); 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( 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((addr, port).into()) Ok(Endpoint::Ip((addr, port).into()))
}
AddressFamily::Unix => Err(SysError::EINVAL),
AddressFamily::Packet => {
if len < size_of::<SockAddrLl>() {
return Err(SysError::EINVAL);
}
Ok(Endpoint::LinkLevel(LinkLevelEndpoint::new(
(*addr).addr_ll.sll_ifindex as usize,
)))
}
AddressFamily::Netlink => {
if len < size_of::<SockAddrNl>() {
return Err(SysError::EINVAL);
}
Ok(Endpoint::Netlink(NetlinkEndpoint::new(
(*addr).addr_nl.nl_pid,
(*addr).addr_nl.nl_groups,
)))
} }
AF_UNIX => Err(SysError::EINVAL),
_ => Err(SysError::EINVAL), _ => Err(SysError::EINVAL),
} }
} }
@ -351,9 +460,11 @@ impl SockAddr {
proc.vm.check_write_ptr(addr_len)?; proc.vm.check_write_ptr(addr_len)?;
let max_addr_len = *addr_len as usize; let max_addr_len = *addr_len as usize;
let full_len = match self.family as usize { let full_len = match AddressFamily::from(self.family) {
AF_INET => size_of::<u16>() + size_of::<SockAddrIn>(), AddressFamily::Internet => size_of::<SockAddrIn>(),
AF_UNIX => return Err(SysError::EINVAL), AddressFamily::Packet => size_of::<SockAddrLl>(),
AddressFamily::Netlink => size_of::<SockAddrNl>(),
AddressFamily::Unix => return Err(SysError::EINVAL),
_ => return Err(SysError::EINVAL), _ => return Err(SysError::EINVAL),
}; };
@ -369,13 +480,47 @@ impl SockAddr {
} }
} }
const AF_UNIX: usize = 1; #[repr(C)]
const AF_INET: usize = 2; #[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,
}
const SOCK_STREAM: usize = 1; enum_with_unknown! {
const SOCK_DGRAM: usize = 2; /// Address families
const SOCK_RAW: usize = 3; pub doc enum AddressFamily(u16) {
const SOCK_TYPE_MASK: usize = 0xf; /// Unspecified
Unspecified = 0,
/// Unix domain sockets
Unix = 1,
/// Internet IP Protocol
Internet = 2,
/// Netlink
Netlink = 16,
/// Packet family
Packet = 17,
}
}
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_IP: usize = 0;
const IPPROTO_ICMP: usize = 1; const IPPROTO_ICMP: usize = 1;
@ -387,3 +532,5 @@ const SO_RCVBUF: usize = 8;
const SO_LINGER: usize = 13; const SO_LINGER: usize = 13;
const TCP_CONGESTION: usize = 13; const TCP_CONGESTION: usize = 13;
const IP_HDRINCL: usize = 3;

@ -146,6 +146,9 @@ pub fn sys_exec(
} }
} }
info!("exec: args {:?}", args); info!("exec: args {:?}", args);
if args.is_empty() {
return Err(SysError::EINVAL);
}
// Read program file // Read program file
let path = args[0].as_str(); let path = args[0].as_str();

@ -16,6 +16,61 @@ pub unsafe fn write_cstr(ptr: *mut u8, s: &str) {
ptr.add(s.len()).write(0); 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
}
}
}
}
}
#[inline(always)] #[inline(always)]
pub fn write<T>(addr: usize, content: T) { pub fn write<T>(addr: usize, content: T) {
let cell = (addr) as *mut T; let cell = (addr) as *mut T;
@ -28,4 +83,4 @@ pub fn write<T>(addr: usize, content: T) {
pub fn read<T>(addr: usize) -> T { pub fn read<T>(addr: usize) -> T {
let cell = (addr) as *const T; let cell = (addr) as *const T;
unsafe { read_volatile(cell) } unsafe { read_volatile(cell) }
} }

Binary file not shown.
Loading…
Cancel
Save