From ca8eb86d48eba38f7da445f0aed7882f2ddbefe9 Mon Sep 17 00:00:00 2001 From: Harry Chen Date: Thu, 9 May 2019 11:01:48 +0800 Subject: [PATCH 01/12] Update README Signed-off-by: Harry Chen --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 35f5a35..38be12e 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Going to be the next generation teaching operating system. Supported architectures: x86_64, RISCV32/64, AArch64, MIPS32 -Tested boards: QEMU, HiFive Unleashed, x86_64 PC (i5/i7), Raspberry Pi 3B+, Kendryte K210 and FPGA running Rocket Chip +Tested boards: QEMU, HiFive Unleashed, x86_64 PC (i5/i7), Raspberry Pi 3B+, Kendryte K210 and FPGA running Rocket Chip / [TrivialMIPS](https://github.com/Harry-Chen/TrivialMIPS) ![demo](./docs/2_OSLab/os2atc/demo.png) @@ -50,9 +50,9 @@ $ make run arch=x86_64 mode=release pci_passthru=0000:00:00.1 # for ixgbe real n | Module | Maintainer | |--------|-----------------------| | x86_64 | @wangrunji0408 | -| RISCV | @jiegec | +| RISC-V | @jiegec | | ARM (Raspi3) | @equation314 | -| MIPS | @HarryChen @miskcoo | +| MIPS | @Harry_Chen @miskcoo | | Memory, Process, File System | @wangrunji0408 | | Network with drivers | @jiegec | | GUI | @equation314 | From a7b9ec3736b62b153ebc0031d57e7d518b00ed73 Mon Sep 17 00:00:00 2001 From: Harry Chen Date: Thu, 9 May 2019 11:02:05 +0800 Subject: [PATCH 02/12] Bump to latest user, try to fix CI errors Signed-off-by: Harry Chen --- user | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user b/user index 9fb1d45..dca77ec 160000 --- a/user +++ b/user @@ -1 +1 @@ -Subproject commit 9fb1d459b50bc14c7ac56d9fd94b4b8485620730 +Subproject commit dca77ec5ec8bc43306f0d3b9ae3783d67d99fe7e From ef9a038ef59ce6e816061eb57bb6a0efd5861590 Mon Sep 17 00:00:00 2001 From: Harry Chen Date: Thu, 9 May 2019 11:12:10 +0800 Subject: [PATCH 03/12] Update user Signed-off-by: Harry Chen --- user | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user b/user index dca77ec..ad822e6 160000 --- a/user +++ b/user @@ -1 +1 @@ -Subproject commit dca77ec5ec8bc43306f0d3b9ae3783d67d99fe7e +Subproject commit ad822e6d3b626b598874bb52a407e90f549c5ab9 From 59323727501012f2b37bbc86affe5a3cbbf4bebc Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Thu, 9 May 2019 17:08:28 +0800 Subject: [PATCH 04/12] Initial rcore router device support --- .../arch/riscv32/board/rocket_chip/device.dts | 7 + .../src/arch/riscv32/board/rocket_chip/mod.rs | 13 +- kernel/src/arch/riscv32/memory.rs | 15 +- kernel/src/drivers/device_tree.rs | 4 + kernel/src/drivers/net/mod.rs | 1 + kernel/src/drivers/net/router.rs | 198 ++++++++++++++++++ 6 files changed, 230 insertions(+), 8 deletions(-) create mode 100644 kernel/src/drivers/net/router.rs diff --git a/kernel/src/arch/riscv32/board/rocket_chip/device.dts b/kernel/src/arch/riscv32/board/rocket_chip/device.dts index 42cf330..048a047 100644 --- a/kernel/src/arch/riscv32/board/rocket_chip/device.dts +++ b/kernel/src/arch/riscv32/board/rocket_chip/device.dts @@ -100,6 +100,13 @@ compatible = "xlnx,xps-intc-1.00.a"; reg = <0x61200000 0x1000>; interrupt-parent = <&L10>; + interrupts = <0>; + }; + + router: router@64A00000 { + compatible = "rcore,router"; + reg = <0x64A00000 0x1000>; + interrupt-parent = <&L10>; interrupts = <1>; }; }; diff --git a/kernel/src/arch/riscv32/board/rocket_chip/mod.rs b/kernel/src/arch/riscv32/board/rocket_chip/mod.rs index cb14a51..40fcaf9 100644 --- a/kernel/src/arch/riscv32/board/rocket_chip/mod.rs +++ b/kernel/src/arch/riscv32/board/rocket_chip/mod.rs @@ -1,19 +1,22 @@ use super::consts::KERNEL_OFFSET; +use crate::memory::active_table; +use rcore_memory::paging::PageTable; /// Mask all external interrupt except serial. pub unsafe fn init_external_interrupt() { const HART0_S_MODE_INTERRUPT_ENABLES: *mut u64 = (KERNEL_OFFSET + 0x0C00_2080) as *mut u64; + // enable all external interrupts HART0_S_MODE_INTERRUPT_ENABLES.write_volatile(0xf); // mask interrupts first - const AXI_INTC_IER: *mut u32 = (KERNEL_OFFSET + 0x1900_0008) as *mut u32; + const AXI_INTC_IER: *mut u32 = (KERNEL_OFFSET + 0x1810_0008) as *mut u32; AXI_INTC_IER.write_volatile(0x0); // acknowledge all interrupts - const AXI_INTC_IAR: *mut u32 = (KERNEL_OFFSET + 0x1900_000C) as *mut u32; + const AXI_INTC_IAR: *mut u32 = (KERNEL_OFFSET + 0x1810_000C) as *mut u32; AXI_INTC_IAR.write_volatile(0xffffffff); - const AXI_INTC_MER: *mut u32 = (KERNEL_OFFSET + 0x1900_001C) as *mut u32; + const AXI_INTC_MER: *mut u32 = (KERNEL_OFFSET + 0x1810_001C) as *mut u32; // Hardware Interrupt enable | Enable irq output AXI_INTC_MER.write_volatile(0b11); @@ -32,7 +35,7 @@ pub unsafe fn handle_external_interrupt() { HART0_S_MODE_INTERRUPT_CLAIM_COMPLETE.write_volatile(source); // acknowledge all interrupts - const AXI_INTC_IAR: *mut u32 = (KERNEL_OFFSET + 0x1900_000C) as *mut u32; + const AXI_INTC_IAR: *mut u32 = (KERNEL_OFFSET + 0x1810_000C) as *mut u32; AXI_INTC_IAR.write_volatile(0xffffffff); } @@ -42,4 +45,4 @@ pub unsafe fn enable_serial_interrupt() { // Intr enable | rx reset | tx reset const UART_IE: u32 = 0x13; SERIAL_BASE.add(UART_CTRL_REG).write_volatile(UART_IE); -} +} \ No newline at end of file diff --git a/kernel/src/arch/riscv32/memory.rs b/kernel/src/arch/riscv32/memory.rs index 304e9f6..b5f3161 100644 --- a/kernel/src/arch/riscv32/memory.rs +++ b/kernel/src/arch/riscv32/memory.rs @@ -154,12 +154,21 @@ fn remap_the_kernel(dtb: usize) { // map AXI INTC for Rocket Chip #[cfg(feature = "board_rocket_chip")] ms.push( - KERNEL_OFFSET + 0x19000000, - KERNEL_OFFSET + 0x19000000 + PAGE_SIZE, + KERNEL_OFFSET + 0x18100000, + KERNEL_OFFSET + 0x18100000 + PAGE_SIZE, MemoryAttr::default(), - Linear::new(-(KERNEL_OFFSET as isize + 0x19000000 - 0x61200000)), + Linear::new(-(KERNEL_OFFSET as isize + 0x18100000 - 0x61200000)), "axi_intc", ); + // map AXI4-Stream Data FIFO for Rocket Chip + #[cfg(feature = "board_rocket_chip")] + ms.push( + KERNEL_OFFSET + 0x18200000, + KERNEL_OFFSET + 0x18200000 + PAGE_SIZE, + MemoryAttr::default(), + Linear::new(-(KERNEL_OFFSET as isize + 0x18200000 - 0x64A00000)), + "router", + ); unsafe { ms.activate(); } diff --git a/kernel/src/drivers/device_tree.rs b/kernel/src/drivers/device_tree.rs index 656b7e2..8b74fc1 100644 --- a/kernel/src/drivers/device_tree.rs +++ b/kernel/src/drivers/device_tree.rs @@ -4,6 +4,7 @@ use core::slice; use device_tree::{DeviceTree, Node}; use super::bus::virtio_mmio::virtio_probe; +use super::net::router::router_init; use super::CMDLINE; const DEVICE_TREE_MAGIC: u32 = 0xd00dfeed; @@ -14,6 +15,9 @@ fn walk_dt_node(dt: &Node) { if compatible == "virtio,mmio" { virtio_probe(dt); } + if compatible == "rcore,router" { + router_init(); + } // TODO: initial other devices (16650, etc.) } if let Ok(bootargs) = dt.prop_str("bootargs") { diff --git a/kernel/src/drivers/net/mod.rs b/kernel/src/drivers/net/mod.rs index 0019043..875cbab 100644 --- a/kernel/src/drivers/net/mod.rs +++ b/kernel/src/drivers/net/mod.rs @@ -1,3 +1,4 @@ pub mod e1000; pub mod ixgbe; pub mod virtio_net; +pub mod router; \ No newline at end of file diff --git a/kernel/src/drivers/net/router.rs b/kernel/src/drivers/net/router.rs new file mode 100644 index 0000000..4a6a877 --- /dev/null +++ b/kernel/src/drivers/net/router.rs @@ -0,0 +1,198 @@ +//! rCore Router Driver + +use alloc::collections::BTreeMap; +use alloc::string::String; +use alloc::sync::Arc; +use alloc::vec::Vec; + +use smoltcp::iface::*; +use smoltcp::phy::{self, DeviceCapabilities}; +use smoltcp::time::Instant; +use smoltcp::wire::*; +use smoltcp::Result; + +use rcore_memory::PAGE_SIZE; + +use crate::drivers::provider::Provider; +use crate::net::SOCKETS; +use crate::sync::SpinNoIrqLock as Mutex; + +use super::super::{DeviceType, Driver, DRIVERS, NET_DRIVERS, SOCKET_ACTIVITY}; +use crate::consts::{KERNEL_OFFSET, MEMORY_END, MEMORY_OFFSET}; + +const AXI_STREAM_FIFO_ISR: *mut u32 = (KERNEL_OFFSET + 0x1820_0000) as *mut u32; +const AXI_STREAM_FIFO_IER: *mut u32 = (KERNEL_OFFSET + 0x1820_0004) as *mut u32; +const AXI_STREAM_FIFO_RDFR: *mut u32 = (KERNEL_OFFSET + 0x1820_0018) as *mut u32; +const AXI_STREAM_FIFO_RDFO: *mut u32 = (KERNEL_OFFSET + 0x1820_001C) as *mut u32; +const AXI_STREAM_FIFO_RDFD: *mut u32 = (KERNEL_OFFSET + 0x1820_0020) as *mut u32; +const AXI_STREAM_FIFO_RLR: *mut u32 = (KERNEL_OFFSET + 0x1820_0024) as *mut u32; +const AXI_STREAM_FIFO_RDR: *mut u32 = (KERNEL_OFFSET + 0x1820_0030) as *mut u32; + +pub struct Router { + buffer: Vec> +} + +impl Router { + fn transmit_available(&self) -> bool { + false + } + + fn receive_available(&self) -> bool { + false + } +} + +#[derive(Clone)] +pub struct RouterDriver(Arc>); + +pub struct RouterRxToken(RouterDriver); +pub struct RouterTxToken(RouterDriver); + +impl<'a> phy::Device<'a> for RouterDriver { + type RxToken = RouterRxToken; + type TxToken = RouterTxToken; + + fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { + let driver = self.0.lock(); + if driver.transmit_available() && driver.receive_available() { + // potential racing + Some(( + RouterRxToken(self.clone()), + RouterTxToken(self.clone()), + )) + } else { + None + } + } + + fn transmit(&'a mut self) -> Option { + let driver = self.0.lock(); + if driver.transmit_available() { + Some(RouterTxToken(self.clone())) + } else { + None + } + } + + fn capabilities(&self) -> DeviceCapabilities { + let mut caps = DeviceCapabilities::default(); + caps.max_transmission_unit = 1536; + caps.max_burst_size = Some(1); + caps + } +} + +impl phy::RxToken for RouterRxToken { + fn consume(self, _timestamp: Instant, f: F) -> Result + where + F: FnOnce(&[u8]) -> Result, + { + unimplemented!() + } +} + +impl phy::TxToken for RouterTxToken { + fn consume(self, _timestamp: Instant, len: usize, f: F) -> Result + where + F: FnOnce(&mut [u8]) -> Result, + { + unimplemented!() + } +} + +pub struct RouterInterface { + iface: Mutex>, + driver: RouterDriver, +} + +impl Driver for RouterInterface { + fn try_handle_interrupt(&self, _irq: Option) -> bool { + let mut driver = self.driver.0.lock(); + + let isr = unsafe { + AXI_STREAM_FIFO_ISR.read_volatile() + }; + + if isr > 0 { + info!("handle router interrupt {:b}", isr); + unsafe { + AXI_STREAM_FIFO_ISR.write(isr); + let rdfo = AXI_STREAM_FIFO_RDFO.read_volatile(); + if rdfo > 0 { + let mut buffer = Vec::new(); + let rlr = AXI_STREAM_FIFO_RLR.read_volatile(); + let rdr = AXI_STREAM_FIFO_RDR.read_volatile(); + for i in 0..rdfo { + buffer.push(AXI_STREAM_FIFO_RDFD.read_volatile() as u8); + } + info!("got packet of length {}", rdfo); + driver.buffer.push(buffer); + } + } + return true; + } + return false; + } + + fn device_type(&self) -> DeviceType { + DeviceType::Net + } + + fn get_id(&self) -> String { + format!("router") + } + + fn get_mac(&self) -> EthernetAddress { + unimplemented!() + } + + fn get_ifname(&self) -> String { + format!("router") + } + + fn ipv4_address(&self) -> Option { + unimplemented!() + } + + fn poll(&self) { + unimplemented!() + } +} + +pub fn router_init( +) -> Arc { + let ethernet_addr = EthernetAddress::from_bytes(&[2, 2, 3, 3, 0, 0]); + + let net_driver = RouterDriver(Arc::new(Mutex::new(Router { + buffer: Vec::new() + }))); + + let ip_addrs = [IpCidr::new(IpAddress::v4(10, 0, 0, 1), 24), IpCidr::new(IpAddress::v4(10, 0, 1, 1), 24)]; + let neighbor_cache = NeighborCache::new(BTreeMap::new()); + let routes = Routes::new(BTreeMap::new()); + let iface = EthernetInterfaceBuilder::new(net_driver.clone()) + .ethernet_addr(ethernet_addr) + .ip_addrs(ip_addrs) + .neighbor_cache(neighbor_cache) + .routes(routes) + .finalize(); + + info!("router interface up"); + + let router_iface = RouterInterface { + iface: Mutex::new(iface), + driver: net_driver + }; + + let driver = Arc::new(router_iface); + DRIVERS.write().push(driver.clone()); + NET_DRIVERS.write().push(driver.clone()); + + const AXI_STREAM_FIFO_IER: *mut u32 = (KERNEL_OFFSET + 0x1820_0004) as *mut u32; + // Enable Receive Complete Interrupt + unsafe { + AXI_STREAM_FIFO_IER.write_volatile(1 << 26); + } + + driver +} From 2653069a43ec80b6f07e1326f12d2fb031a29da1 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Thu, 9 May 2019 17:54:10 +0800 Subject: [PATCH 05/12] Implement tx for router driver --- .../src/arch/riscv32/board/rocket_chip/mod.rs | 2 +- kernel/src/drivers/net/mod.rs | 2 +- kernel/src/drivers/net/router.rs | 66 +++++++++++++------ 3 files changed, 47 insertions(+), 23 deletions(-) diff --git a/kernel/src/arch/riscv32/board/rocket_chip/mod.rs b/kernel/src/arch/riscv32/board/rocket_chip/mod.rs index 40fcaf9..8a96256 100644 --- a/kernel/src/arch/riscv32/board/rocket_chip/mod.rs +++ b/kernel/src/arch/riscv32/board/rocket_chip/mod.rs @@ -45,4 +45,4 @@ pub unsafe fn enable_serial_interrupt() { // Intr enable | rx reset | tx reset const UART_IE: u32 = 0x13; SERIAL_BASE.add(UART_CTRL_REG).write_volatile(UART_IE); -} \ No newline at end of file +} diff --git a/kernel/src/drivers/net/mod.rs b/kernel/src/drivers/net/mod.rs index 875cbab..87d321b 100644 --- a/kernel/src/drivers/net/mod.rs +++ b/kernel/src/drivers/net/mod.rs @@ -1,4 +1,4 @@ pub mod e1000; pub mod ixgbe; +pub mod router; pub mod virtio_net; -pub mod router; \ No newline at end of file diff --git a/kernel/src/drivers/net/router.rs b/kernel/src/drivers/net/router.rs index 4a6a877..3824522 100644 --- a/kernel/src/drivers/net/router.rs +++ b/kernel/src/drivers/net/router.rs @@ -28,17 +28,21 @@ const AXI_STREAM_FIFO_RDFD: *mut u32 = (KERNEL_OFFSET + 0x1820_0020) as *mut u32 const AXI_STREAM_FIFO_RLR: *mut u32 = (KERNEL_OFFSET + 0x1820_0024) as *mut u32; const AXI_STREAM_FIFO_RDR: *mut u32 = (KERNEL_OFFSET + 0x1820_0030) as *mut u32; +const AXI_STREAM_FIFO_TDR: *mut u32 = (KERNEL_OFFSET + 0x1820_002C) as *mut u32; +const AXI_STREAM_FIFO_TDFD: *mut u32 = (KERNEL_OFFSET + 0x1820_0010) as *mut u32; +const AXI_STREAM_FIFO_TLR: *mut u32 = (KERNEL_OFFSET + 0x1820_0014) as *mut u32; + pub struct Router { - buffer: Vec> + buffer: Vec>, } impl Router { fn transmit_available(&self) -> bool { - false + true } fn receive_available(&self) -> bool { - false + self.buffer.len() > 0 } } @@ -56,10 +60,7 @@ impl<'a> phy::Device<'a> for RouterDriver { let driver = self.0.lock(); if driver.transmit_available() && driver.receive_available() { // potential racing - Some(( - RouterRxToken(self.clone()), - RouterTxToken(self.clone()), - )) + Some((RouterRxToken(self.clone()), RouterTxToken(self.clone()))) } else { None } @@ -87,7 +88,9 @@ impl phy::RxToken for RouterRxToken { where F: FnOnce(&[u8]) -> Result, { - unimplemented!() + let mut router = (self.0).0.lock(); + let buffer = router.buffer.pop().unwrap(); + f(&buffer) } } @@ -96,7 +99,18 @@ impl phy::TxToken for RouterTxToken { where F: FnOnce(&mut [u8]) -> Result, { - unimplemented!() + let mut buffer = vec![0; len]; + let res = f(&mut buffer); + debug!("out buf {}", len); + + unsafe { + AXI_STREAM_FIFO_TDR.write_volatile(2); + for byte in buffer { + AXI_STREAM_FIFO_TDFD.write_volatile(byte as u32); + } + AXI_STREAM_FIFO_TLR.write(len as u32); + } + res } } @@ -109,12 +123,10 @@ impl Driver for RouterInterface { fn try_handle_interrupt(&self, _irq: Option) -> bool { let mut driver = self.driver.0.lock(); - let isr = unsafe { - AXI_STREAM_FIFO_ISR.read_volatile() - }; + let isr = unsafe { AXI_STREAM_FIFO_ISR.read_volatile() }; if isr > 0 { - info!("handle router interrupt {:b}", isr); + debug!("handle router interrupt {:b}", isr); unsafe { AXI_STREAM_FIFO_ISR.write(isr); let rdfo = AXI_STREAM_FIFO_RDFO.read_volatile(); @@ -125,9 +137,21 @@ impl Driver for RouterInterface { for i in 0..rdfo { buffer.push(AXI_STREAM_FIFO_RDFD.read_volatile() as u8); } - info!("got packet of length {}", rdfo); + debug!("got packet of length {}", rdfo); driver.buffer.push(buffer); } + drop(driver); + + let timestamp = Instant::from_millis(crate::trap::uptime_msec() as i64); + let mut sockets = SOCKETS.lock(); + match self.iface.lock().poll(&mut sockets, timestamp) { + Ok(_) => { + SOCKET_ACTIVITY.notify_all(); + } + Err(err) => { + debug!("poll got err {}", err); + } + } } return true; } @@ -159,15 +183,15 @@ impl Driver for RouterInterface { } } -pub fn router_init( -) -> Arc { +pub fn router_init() -> Arc { let ethernet_addr = EthernetAddress::from_bytes(&[2, 2, 3, 3, 0, 0]); - let net_driver = RouterDriver(Arc::new(Mutex::new(Router { - buffer: Vec::new() - }))); + let net_driver = RouterDriver(Arc::new(Mutex::new(Router { buffer: Vec::new() }))); - let ip_addrs = [IpCidr::new(IpAddress::v4(10, 0, 0, 1), 24), IpCidr::new(IpAddress::v4(10, 0, 1, 1), 24)]; + let ip_addrs = [ + IpCidr::new(IpAddress::v4(10, 0, 0, 1), 24), + IpCidr::new(IpAddress::v4(10, 0, 1, 1), 24), + ]; let neighbor_cache = NeighborCache::new(BTreeMap::new()); let routes = Routes::new(BTreeMap::new()); let iface = EthernetInterfaceBuilder::new(net_driver.clone()) @@ -181,7 +205,7 @@ pub fn router_init( let router_iface = RouterInterface { iface: Mutex::new(iface), - driver: net_driver + driver: net_driver, }; let driver = Arc::new(router_iface); From d28f54ce32c0341840f0cbd79866b805e7fba22d Mon Sep 17 00:00:00 2001 From: WangRunji Date: Thu, 9 May 2019 21:32:31 +0800 Subject: [PATCH 06/12] show tid on log --- kernel/Cargo.lock | 2 +- kernel/src/logging.rs | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 15dc395..a674b88 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -411,7 +411,7 @@ dependencies = [ [[package]] name = "rcore-thread" version = "0.1.0" -source = "git+https://github.com/rcore-os/rcore-thread#fd972c7e3aa2b7618f625f143655c16adfd2ca78" +source = "git+https://github.com/rcore-os/rcore-thread#77e8e0778154734ee59525e043caab6339e14d75" dependencies = [ "deque 0.3.2 (git+https://github.com/rcore-os/deque.git?branch=no_std)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/kernel/src/logging.rs b/kernel/src/logging.rs index 838abe5..5cf1ba2 100644 --- a/kernel/src/logging.rs +++ b/kernel/src/logging.rs @@ -3,6 +3,7 @@ use core::fmt; use lazy_static::lazy_static; use log::{self, Level, LevelFilter, Log, Metadata, Record}; +use crate::processor; use crate::sync::SpinNoIrqLock as Mutex; use crate::util::color::ConsoleColor; @@ -63,12 +64,17 @@ impl Log for SimpleLogger { true } fn log(&self, record: &Record) { - static DISABLED_TARGET: &[&str] = &[]; - if self.enabled(record.metadata()) && !DISABLED_TARGET.contains(&record.target()) { - // let target = record.target(); - // let begin = target.as_bytes().iter().rposition(|&c| c == b':').map(|i| i + 1).unwrap_or(0); + if !self.enabled(record.metadata()) { + return; + } + if let Some(tid) = processor().tid_option() { + print_in_color( + format_args!("[{:>5}][{}] {}\n", record.level(), tid, record.args()), + ConsoleColor::from(record.level()), + ); + } else { print_in_color( - format_args!("[{:>5}] {}\n", record.level(), record.args()), + format_args!("[{:>5}][-] {}\n", record.level(), record.args()), ConsoleColor::from(record.level()), ); } From 9df9d01e686bd366a3f4f163f95d6709e3a430f3 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Thu, 9 May 2019 22:27:44 +0800 Subject: [PATCH 07/12] impl deadlock detection --- kernel/src/drivers/net/router.rs | 2 +- kernel/src/sync/mutex.rs | 17 ++++++++++++++++- kernel/src/sync/test.rs | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/kernel/src/drivers/net/router.rs b/kernel/src/drivers/net/router.rs index 3824522..9621644 100644 --- a/kernel/src/drivers/net/router.rs +++ b/kernel/src/drivers/net/router.rs @@ -18,7 +18,7 @@ use crate::net::SOCKETS; use crate::sync::SpinNoIrqLock as Mutex; use super::super::{DeviceType, Driver, DRIVERS, NET_DRIVERS, SOCKET_ACTIVITY}; -use crate::consts::{KERNEL_OFFSET, MEMORY_END, MEMORY_OFFSET}; +use crate::consts::{KERNEL_OFFSET, MEMORY_OFFSET}; const AXI_STREAM_FIFO_ISR: *mut u32 = (KERNEL_OFFSET + 0x1820_0000) as *mut u32; const AXI_STREAM_FIFO_IER: *mut u32 = (KERNEL_OFFSET + 0x1820_0004) as *mut u32; diff --git a/kernel/src/sync/mutex.rs b/kernel/src/sync/mutex.rs index 8af1460..623bac5 100644 --- a/kernel/src/sync/mutex.rs +++ b/kernel/src/sync/mutex.rs @@ -28,6 +28,7 @@ use super::Condvar; use crate::arch::interrupt; +use crate::processor; use core::cell::UnsafeCell; use core::fmt; use core::ops::{Deref, DerefMut}; @@ -35,11 +36,12 @@ use core::sync::atomic::{AtomicBool, Ordering}; pub type SpinLock = Mutex; pub type SpinNoIrqLock = Mutex; -pub type ThreadLock = Mutex; +pub type SleepLock = Mutex; pub struct Mutex { lock: AtomicBool, support: S, + user: UnsafeCell<(usize, usize)>, // (cid, tid) data: UnsafeCell, } @@ -78,6 +80,7 @@ impl Mutex { lock: AtomicBool::new(false), data: UnsafeCell::new(user_data), support: S::new(), + user: UnsafeCell::new((0, 0)), } } @@ -93,11 +96,23 @@ impl Mutex { impl Mutex { fn obtain_lock(&self) { while self.lock.compare_and_swap(false, true, Ordering::Acquire) != false { + let mut try_count = 0; // Wait until the lock looks unlocked before retrying while self.lock.load(Ordering::Relaxed) { self.support.cpu_relax(); + try_count += 1; + if try_count == 0x100000 { + let (cid, tid) = unsafe { *self.user.get() }; + error!( + "Mutex: deadlock detected! locked by cpu {} thread {} @ {:?}", + cid, tid, self as *const Self + ); + } } } + let cid = crate::arch::cpu::id(); + let tid = processor().tid_option().unwrap_or(0); + unsafe { self.user.get().write((cid, tid)) }; } /// Locks the spinlock and returns a guard. diff --git a/kernel/src/sync/test.rs b/kernel/src/sync/test.rs index 3b7e1c7..76196e8 100644 --- a/kernel/src/sync/test.rs +++ b/kernel/src/sync/test.rs @@ -3,7 +3,7 @@ //! The code is borrowed from [RustDoc - Dining Philosophers](https://doc.rust-lang.org/1.6.0/book/dining-philosophers.html) use crate::sync::Condvar; -use crate::sync::ThreadLock as Mutex; +use crate::sync::SleepLock as Mutex; use crate::thread; use alloc::vec; use alloc::{sync::Arc, vec::Vec}; From ba8d08d7337edd4a56e20f89b72f5ea6b8b8d364 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Thu, 9 May 2019 23:56:27 +0800 Subject: [PATCH 08/12] fix Process dropping by making `proc.parent` a weak reference --- kernel/src/process/structs.rs | 23 +++++++-- kernel/src/syscall/fs.rs | 2 +- kernel/src/syscall/proc.rs | 87 +++++++++++------------------------ 3 files changed, 46 insertions(+), 66 deletions(-) diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index 3f7c272..f19e145 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -22,6 +22,7 @@ use crate::sync::{Condvar, SpinNoIrqLock as Mutex}; use super::abi::{self, ProcInitInfo}; use core::mem::uninitialized; use rcore_fs::vfs::INode; +use crate::processor; pub struct Thread { context: Context, @@ -66,7 +67,7 @@ pub struct Process { // relationship pub pid: Pid, // i.e. tgid, usually the tid of first thread - pub parent: Option>>, + pub parent: Weak>, pub children: Vec>>, pub threads: Vec, // threads in the same process @@ -125,7 +126,7 @@ impl Thread { exec_path: String::new(), futexes: BTreeMap::default(), pid: Pid(0), - parent: None, + parent: Weak::new(), children: Vec::new(), threads: Vec::new(), child_exit: Arc::new(Condvar::new()), @@ -303,7 +304,7 @@ impl Thread { exec_path: String::from(exec_path), futexes: BTreeMap::default(), pid: Pid(0), - parent: None, + parent: Weak::new(), children: Vec::new(), threads: Vec::new(), child_exit: Arc::new(Condvar::new()), @@ -329,7 +330,7 @@ impl Thread { exec_path: proc.exec_path.clone(), futexes: BTreeMap::default(), pid: Pid(0), - parent: Some(self.proc.clone()), + parent: Arc::downgrade(&self.proc), children: Vec::new(), threads: Vec::new(), child_exit: Arc::new(Condvar::new()), @@ -403,6 +404,20 @@ impl Process { } self.futexes.get(&uaddr).unwrap().clone() } + /// Exit the process. + /// Kill all threads and notify parent with the exit code. + pub fn exit(&mut self, exit_code: usize) { + // quit all threads + for tid in self.threads.iter() { + processor().manager().exit(*tid, 1); + } + // notify parent and fill exit code + if let Some(parent) = self.parent.upgrade() { + let mut parent = parent.lock(); + parent.child_exit_code.insert(self.pid.get(), exit_code); + parent.child_exit.notify_one(); + } + } } trait ToMemoryAttr { diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index 401a950..5cbe1e2 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -524,7 +524,7 @@ impl Syscall<'_> { arg3: usize, ) -> SysResult { info!( - "ioctl: fd: {}, request: {:x}, args: {} {} {}", + "ioctl: fd: {}, request: {:#x}, args: {:#x} {:#x} {:#x}", fd, request, arg1, arg2, arg3 ); let mut proc = self.process(); diff --git a/kernel/src/syscall/proc.rs b/kernel/src/syscall/proc.rs index e5269db..89cb0f4 100644 --- a/kernel/src/syscall/proc.rs +++ b/kernel/src/syscall/proc.rs @@ -54,7 +54,6 @@ impl Syscall<'_> { let new_thread = self .thread .clone(self.tf, newsp, newtls, child_tid as usize); - // FIXME: parent pid let tid = processor().manager().add(new_thread); processor().manager().detach(tid); info!("clone: {} -> {}", thread::current().id(), tid); @@ -66,7 +65,7 @@ impl Syscall<'_> { /// Wait for the process exit. /// Return the PID. Store exit code to `wstatus` if it's not null. pub fn sys_wait4(&mut self, pid: isize, wstatus: *mut i32) -> SysResult { - //info!("wait4: pid: {}, code: {:?}", pid, wstatus); + info!("wait4: pid: {}, code: {:?}", pid, wstatus); let wstatus = if !wstatus.is_null() { Some(unsafe { self.vm().check_write_ptr(wstatus)? }) } else { @@ -75,10 +74,12 @@ impl Syscall<'_> { #[derive(Debug)] enum WaitFor { AnyChild, + AnyChildInGroup, Pid(usize), } let target = match pid { - -1 | 0 => WaitFor::AnyChild, + -1 => WaitFor::AnyChild, + 0 => WaitFor::AnyChildInGroup, p if p > 0 => WaitFor::Pid(p as usize), _ => unimplemented!(), }; @@ -86,7 +87,7 @@ impl Syscall<'_> { let mut proc = self.process(); // check child_exit_code let find = match target { - WaitFor::AnyChild => proc + WaitFor::AnyChild | WaitFor::AnyChildInGroup => proc .child_exit_code .iter() .next() @@ -102,17 +103,19 @@ impl Syscall<'_> { return Ok(pid); } // if not, check pid - let children: Vec<_> = proc - .children - .iter() - .filter_map(|weak| weak.upgrade()) - .collect(); - let invalid = match target { - WaitFor::AnyChild => children.len() == 0, - WaitFor::Pid(pid) => children + let invalid = { + let children: Vec<_> = proc + .children .iter() - .find(|p| p.lock().pid.get() == pid) - .is_none(), + .filter_map(|weak| weak.upgrade()) + .collect(); + match target { + WaitFor::AnyChild | WaitFor::AnyChildInGroup => children.len() == 0, + WaitFor::Pid(pid) => children + .iter() + .find(|p| p.lock().pid.get() == pid) + .is_none(), + } }; if invalid { return Err(SysError::ECHILD); @@ -204,7 +207,7 @@ impl Syscall<'_> { /// Kill the process pub fn sys_kill(&mut self, pid: usize, sig: usize) -> SysResult { info!( - "kill: {} killed: {} with sig {}", + "kill: thread {} kill process {} with signal {}", thread::current().id(), pid, sig @@ -215,21 +218,8 @@ impl Syscall<'_> { self.sys_exit_group(sig); } else { if let Some(proc_arc) = PROCESSES.read().get(&pid).and_then(|weak| weak.upgrade()) { - let proc = proc_arc.lock(); - // quit all threads - for tid in proc.threads.iter() { - processor().manager().exit(*tid, sig); - } - // notify parent and fill exit code - // avoid deadlock - let proc_parent = proc.parent.clone(); - let pid = proc.pid.get(); - drop(proc); - if let Some(parent) = proc_parent { - let mut parent = parent.lock(); - parent.child_exit_code.insert(pid, sig); - parent.child_exit.notify_one(); - } + let mut proc = proc_arc.lock(); + proc.exit(sig); Ok(0) } else { Err(SysError::EINVAL) @@ -252,7 +242,7 @@ impl Syscall<'_> { /// Get the parent process id pub fn sys_getppid(&mut self) -> SysResult { - if let Some(parent) = self.process().parent.as_ref() { + if let Some(parent) = self.process().parent.upgrade() { Ok(parent.lock().pid.get()) } else { Ok(0) @@ -266,26 +256,15 @@ impl Syscall<'_> { let mut proc = self.process(); proc.threads.retain(|&id| id != tid); - // for last thread, - // notify parent and fill exit code - // avoid deadlock - let exit = proc.threads.len() == 0; - let proc_parent = proc.parent.clone(); - let pid = proc.pid.get(); - drop(proc); - if exit { - if let Some(parent) = proc_parent { - let mut parent = parent.lock(); - parent.child_exit_code.insert(pid, exit_code); - parent.child_exit.notify_one(); - } + // for last thread, exit the process + if proc.threads.len() == 0 { + proc.exit(exit_code); } // perform futex wake 1 // ref: http://man7.org/linux/man-pages/man2/set_tid_address.2.html // FIXME: do it in all possible ways a thread can exit // it has memory access so we can't move it to Thread::drop? - let mut proc = self.process(); let clear_child_tid = self.thread.clear_child_tid as *mut u32; if !clear_child_tid.is_null() { info!("exit: futex {:#?} wake 1", clear_child_tid); @@ -304,24 +283,10 @@ impl Syscall<'_> { /// Exit the current thread group (i.e. process) pub fn sys_exit_group(&mut self, exit_code: usize) -> ! { - let proc = self.process(); + let mut proc = self.process(); info!("exit_group: {}, code: {}", proc.pid, exit_code); - // quit all threads - for tid in proc.threads.iter() { - processor().manager().exit(*tid, exit_code); - } - - // notify parent and fill exit code - // avoid deadlock - let proc_parent = proc.parent.clone(); - let pid = proc.pid.get(); - drop(proc); - if let Some(parent) = proc_parent { - let mut parent = parent.lock(); - parent.child_exit_code.insert(pid, exit_code); - parent.child_exit.notify_one(); - } + proc.exit(exit_code); processor().yield_now(); unreachable!(); From fbd2aef916672b9ae6608d22d34331db22a9f1ca Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 10 May 2019 00:11:09 +0800 Subject: [PATCH 09/12] fix page table racing by adding a global mutex --- kernel/src/memory.rs | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/kernel/src/memory.rs b/kernel/src/memory.rs index d4bff95..a27f236 100644 --- a/kernel/src/memory.rs +++ b/kernel/src/memory.rs @@ -16,7 +16,7 @@ use super::HEAP_ALLOCATOR; pub use crate::arch::paging::*; use crate::consts::{KERNEL_OFFSET, MEMORY_OFFSET}; use crate::process::current_thread; -use crate::sync::SpinNoIrqLock; +use crate::sync::{SpinNoIrqLock, MutexGuard, SpinNoIrq}; use alloc::boxed::Box; use bitmap_allocator::BitAlloc; use buddy_system_allocator::Heap; @@ -52,24 +52,19 @@ pub type FrameAlloc = bitmap_allocator::BitAlloc4K; lazy_static! { pub static ref FRAME_ALLOCATOR: SpinNoIrqLock = SpinNoIrqLock::new(FrameAlloc::default()); + pub static ref ACTIVE_TABLE: SpinNoIrqLock = + SpinNoIrqLock::new(unsafe { ActivePageTable::new() }); } -/// The only way to get active page table +/// The only way to get current active page table safely /// -/// ## CHANGE LOG -/// -/// In the past, this function returns a `MutexGuard` of a global -/// `Mutex` object, which means only one CPU core -/// can access its active table at a time. -/// -/// But given that a page table is ** process local **, and being active -/// when and only when a thread of the process is running. -/// The ownership of this page table is in the `MemorySet` object. -/// So it's safe to access the active table inside `MemorySet`. -/// But the shared parts is readonly, e.g. all pages mapped in -/// `InactivePageTable::map_kernel()`. -pub fn active_table() -> ActivePageTable { - unsafe { ActivePageTable::new() } +/// NOTE: +/// Current implementation of recursive page table has a problem that +/// will cause race condition to the initial page table. +/// So we have to add a global mutex to avoid the racing. +/// This will be removed after replacing recursive mapping by linear mapping. +pub fn active_table() -> MutexGuard<'static, ActivePageTable, SpinNoIrq> { + ACTIVE_TABLE.lock() } #[derive(Debug, Clone, Copy)] From 6bb11a54331a33cb77eb3dc78ca83f987534d6a5 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Fri, 10 May 2019 08:10:03 +0800 Subject: [PATCH 10/12] Reset router tx/rx fifo and fix tx length --- kernel/src/drivers/net/router.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/kernel/src/drivers/net/router.rs b/kernel/src/drivers/net/router.rs index 9621644..8c1e929 100644 --- a/kernel/src/drivers/net/router.rs +++ b/kernel/src/drivers/net/router.rs @@ -22,15 +22,15 @@ use crate::consts::{KERNEL_OFFSET, MEMORY_OFFSET}; const AXI_STREAM_FIFO_ISR: *mut u32 = (KERNEL_OFFSET + 0x1820_0000) as *mut u32; const AXI_STREAM_FIFO_IER: *mut u32 = (KERNEL_OFFSET + 0x1820_0004) as *mut u32; +const AXI_STREAM_FIFO_TDFR: *mut u32 = (KERNEL_OFFSET + 0x1820_0008) as *mut u32; +const AXI_STREAM_FIFO_TDFD: *mut u32 = (KERNEL_OFFSET + 0x1820_0010) as *mut u32; +const AXI_STREAM_FIFO_TLR: *mut u32 = (KERNEL_OFFSET + 0x1820_0014) as *mut u32; const AXI_STREAM_FIFO_RDFR: *mut u32 = (KERNEL_OFFSET + 0x1820_0018) as *mut u32; const AXI_STREAM_FIFO_RDFO: *mut u32 = (KERNEL_OFFSET + 0x1820_001C) as *mut u32; const AXI_STREAM_FIFO_RDFD: *mut u32 = (KERNEL_OFFSET + 0x1820_0020) as *mut u32; const AXI_STREAM_FIFO_RLR: *mut u32 = (KERNEL_OFFSET + 0x1820_0024) as *mut u32; -const AXI_STREAM_FIFO_RDR: *mut u32 = (KERNEL_OFFSET + 0x1820_0030) as *mut u32; - const AXI_STREAM_FIFO_TDR: *mut u32 = (KERNEL_OFFSET + 0x1820_002C) as *mut u32; -const AXI_STREAM_FIFO_TDFD: *mut u32 = (KERNEL_OFFSET + 0x1820_0010) as *mut u32; -const AXI_STREAM_FIFO_TLR: *mut u32 = (KERNEL_OFFSET + 0x1820_0014) as *mut u32; +const AXI_STREAM_FIFO_RDR: *mut u32 = (KERNEL_OFFSET + 0x1820_0030) as *mut u32; pub struct Router { buffer: Vec>, @@ -108,7 +108,7 @@ impl phy::TxToken for RouterTxToken { for byte in buffer { AXI_STREAM_FIFO_TDFD.write_volatile(byte as u32); } - AXI_STREAM_FIFO_TLR.write(len as u32); + AXI_STREAM_FIFO_TLR.write((len * 4) as u32); } res } @@ -184,6 +184,13 @@ impl Driver for RouterInterface { } pub fn router_init() -> Arc { + unsafe { + // reset tx fifo + AXI_STREAM_FIFO_TDFR.write_volatile(0xA5); + // reset rx fifo + AXI_STREAM_FIFO_RDFR.write_volatile(0xA5); + } + let ethernet_addr = EthernetAddress::from_bytes(&[2, 2, 3, 3, 0, 0]); let net_driver = RouterDriver(Arc::new(Mutex::new(Router { buffer: Vec::new() }))); From 6e5b3e2515a2238e4fbb98bda4442a584db78dd6 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 10 May 2019 12:28:37 +0800 Subject: [PATCH 11/12] fix broken pipe status. rustc works now! --- kernel/src/fs/pipe.rs | 54 ++++++++++++++------------------------ kernel/src/syscall/fs.rs | 4 +++ kernel/src/syscall/misc.rs | 9 +++---- 3 files changed, 27 insertions(+), 40 deletions(-) diff --git a/kernel/src/fs/pipe.rs b/kernel/src/fs/pipe.rs index 6059e1a..59fa2fa 100644 --- a/kernel/src/fs/pipe.rs +++ b/kernel/src/fs/pipe.rs @@ -45,13 +45,25 @@ impl Pipe { ) } - pub fn can_read(&self) -> bool { + fn can_read(&self) -> bool { if let PipeEnd::Read = self.direction { - self.data.lock().buf.len() > 0 + self.data.lock().buf.len() > 0 || self.is_broken() } else { false } } + + fn can_write(&self) -> bool { + if let PipeEnd::Write = self.direction { + !self.is_broken() + } else { + false + } + } + + fn is_broken(&self) -> bool { + Arc::strong_count(&self.data) < 2 + } } // TODO: better way to provide default impl? @@ -105,39 +117,11 @@ impl INode for Pipe { } fn poll(&self) -> Result { - let data = self.data.lock(); - match self.direction { - PipeEnd::Read => { - if data.buf.len() > 0 { - Ok(PollStatus { - read: true, - write: false, - error: false, - }) - } else { - Ok(PollStatus { - read: false, - write: false, - error: false, - }) - } - } - PipeEnd::Write => { - if data.buf.len() > 0 { - Ok(PollStatus { - read: false, - write: true, - error: false, - }) - } else { - Ok(PollStatus { - read: false, - write: false, - error: false, - }) - } - } - } + Ok(PollStatus { + read: self.can_read(), + write: self.can_write(), + error: false, + }) } impl_inode!(); } diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index 5cbe1e2..35f0a4f 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -141,6 +141,9 @@ impl Syscall<'_> { return Ok(0); } + // NOTE: To run rustc, uncomment yield_now and comment Condvar. + // Waking up from pipe is unimplemented now. + // thread::yield_now(); Condvar::wait_any(&[&STDIN.pushed, &(*SOCKET_ACTIVITY)]); } } @@ -1416,6 +1419,7 @@ impl IoVecs { } #[repr(C)] +#[derive(Debug)] pub struct PollFd { fd: u32, events: PollEvents, diff --git a/kernel/src/syscall/misc.rs b/kernel/src/syscall/misc.rs index 119cf8b..df0dec0 100644 --- a/kernel/src/syscall/misc.rs +++ b/kernel/src/syscall/misc.rs @@ -69,10 +69,9 @@ impl Syscall<'_> { val, timeout ); - // if op & OP_PRIVATE == 0 { - // unimplemented!("futex only support process-private"); - // return Err(SysError::ENOSYS); - // } + if op & OP_PRIVATE == 0 { + warn!("process-shared futex is unimplemented"); + } if uaddr % size_of::() != 0 { return Err(SysError::EINVAL); } @@ -80,7 +79,7 @@ impl Syscall<'_> { const OP_WAIT: u32 = 0; const OP_WAKE: u32 = 1; - const OP_PRIVATE: u32 = 128; + const OP_PRIVATE: u32 = 0x80; let mut proc = self.process(); let queue = proc.get_futex(uaddr); From 8149793b9a62a96e298dbc5f82c0bdabda69dc29 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Fri, 10 May 2019 17:34:18 +0800 Subject: [PATCH 12/12] Fix typo in mips paging --- kernel/src/arch/mipsel/paging.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/src/arch/mipsel/paging.rs b/kernel/src/arch/mipsel/paging.rs index af0a782..b949dbc 100644 --- a/kernel/src/arch/mipsel/paging.rs +++ b/kernel/src/arch/mipsel/paging.rs @@ -23,7 +23,7 @@ impl PageTable for ActivePageTable { let frame = Frame::of_addr(PhysAddr::new(target)); // we may need frame allocator to alloc frame for new page table(first/second) self.get_table() - .map_to(page, frame, flags, &mut FrameAllocatorForRiscv) + .map_to(page, frame, flags, &mut FrameAllocatorForMips) .unwrap() .flush(); self.get_entry(addr).expect("fail to get entry") @@ -254,15 +254,15 @@ impl Drop for InactivePageTable0 { } } -struct FrameAllocatorForRiscv; +struct FrameAllocatorForMips; -impl FrameAllocator for FrameAllocatorForRiscv { +impl FrameAllocator for FrameAllocatorForMips { fn alloc(&mut self) -> Option { alloc_frame().map(|addr| Frame::of_addr(PhysAddr::new(addr))) } } -impl FrameDeallocator for FrameAllocatorForRiscv { +impl FrameDeallocator for FrameAllocatorForMips { fn dealloc(&mut self, frame: Frame) { dealloc_frame(frame.start_address().as_usize()); }