diff --git a/Cargo.lock b/Cargo.lock index 33021e148..d083c4aa9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1970,7 +1970,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "virtio-drivers" version = "0.4.0" -source = "git+https://github.com/syswonder/virtio-drivers.git?rev=256ec4c#256ec4ca669a40719090aeaec858f707e8259183" +source = "git+https://github.com/syswonder/virtio-drivers.git?rev=62dbe5a#62dbe5a09aff0cac00037c8fe6528d94665286b8" dependencies = [ "bitflags 1.3.2", "log", diff --git a/api/ruxos_posix_api/src/imp/getrandom.rs b/api/ruxos_posix_api/src/imp/getrandom.rs index 49186e8e3..8187bccc9 100644 --- a/api/ruxos_posix_api/src/imp/getrandom.rs +++ b/api/ruxos_posix_api/src/imp/getrandom.rs @@ -22,6 +22,9 @@ use crate::ctypes::{size_t, ssize_t}; use axerrno::LinuxError; +#[cfg(all(target_arch = "x86_64", feature = "random-hw"))] +use core::arch::x86_64::__cpuid; + static SEED: AtomicU64 = AtomicU64::new(0xae_f3); /// Returns a 32-bit unsigned pseudo random interger using LCG. @@ -54,15 +57,7 @@ fn srand_lcg(seed: u64) { fn has_rdrand() -> bool { #[cfg(target_arch = "x86_64")] { - let mut ecx: u32; - unsafe { - core::arch::asm!( - "mov eax, 1", - "cpuid", - out("ecx") ecx - ) - } - ecx & (1 << 30) != 0 + unsafe { __cpuid(1).ecx & (1 << 30) != 0 } } #[cfg(target_arch = "aarch64")] { diff --git a/crates/driver_pci/Cargo.toml b/crates/driver_pci/Cargo.toml index ba037cc7f..dec497669 100644 --- a/crates/driver_pci/Cargo.toml +++ b/crates/driver_pci/Cargo.toml @@ -10,4 +10,4 @@ repository = "https://github.com/rcore-os/arceos/tree/main/crates/driver_pci" documentation = "https://rcore-os.github.io/arceos/driver_pci/index.html" [dependencies] -virtio-drivers = { git = "https://github.com/syswonder/virtio-drivers.git", rev = "256ec4c"} +virtio-drivers = { git = "https://github.com/syswonder/virtio-drivers.git", rev = "62dbe5a"} diff --git a/crates/driver_virtio/Cargo.toml b/crates/driver_virtio/Cargo.toml index 3e76f764a..2415441ec 100644 --- a/crates/driver_virtio/Cargo.toml +++ b/crates/driver_virtio/Cargo.toml @@ -23,4 +23,4 @@ driver_block = { path = "../driver_block", optional = true } driver_net = { path = "../driver_net", optional = true } driver_display = { path = "../driver_display", optional = true} driver_9p = { path = "../driver_9p", optional = true} -virtio-drivers = { git = "https://github.com/syswonder/virtio-drivers.git", rev = "256ec4c" } +virtio-drivers = { git = "https://github.com/syswonder/virtio-drivers.git", rev = "62dbe5a" } diff --git a/modules/rux9p/src/drv.rs b/modules/rux9p/src/drv.rs index 43df23b54..131aa8cb1 100644 --- a/modules/rux9p/src/drv.rs +++ b/modules/rux9p/src/drv.rs @@ -400,7 +400,7 @@ impl Drv9pOps { /// write perform I/O on the file represented by fid. /// Note that in v9fs, a read(2) or write(2) system call for a chunk of the file that won't fit in a single request is broken up into multiple requests. - pub fn twrite(&mut self, fid: u32, offset: u64, data: &[u8]) -> Result { + pub fn twrite(&mut self, fid: u32, offset: u64, data: &[u8]) -> Result { const MAX_READ_LEN: u32 = _9P_MAX_PSIZE - 32; let mut writing_len = data.len() as u32; if writing_len > MAX_READ_LEN { @@ -416,7 +416,7 @@ impl Drv9pOps { } request.finish(); match self.request(&request.buffer, &mut response_buffer) { - Ok(_) => Ok(lbytes2u64(&response_buffer[7..11]) as u8), // index from 7 to 11 corresponing to total count of writed byte + Ok(_) => Ok(lbytes2u64(&response_buffer[7..11]) as usize), // index from 7 to 11 corresponing to total count of writed byte Err(ecode) => Err(ecode), } } @@ -903,6 +903,10 @@ impl FileAttr { } } + pub fn get_perm(&self) -> u32 { + self.mode + } + pub fn set_size(&mut self, size: u64) { self.vaild |= _9P_SETATTR_SIZE; self.size = size; @@ -1018,6 +1022,10 @@ impl UStatFs { self.name.clone() } + pub fn get_perm(&self) -> u32 { + self.mode + } + pub fn get_ftype(&self) -> u8 { match self.qid.ftype { 0x00 => 0o10, diff --git a/modules/rux9p/src/fs.rs b/modules/rux9p/src/fs.rs index b25c19b6e..72843870e 100644 --- a/modules/rux9p/src/fs.rs +++ b/modules/rux9p/src/fs.rs @@ -11,11 +11,10 @@ //! //! The implementation is based on [`axfs_vfs`]. use crate::drv::{self, Drv9pOps}; -use alloc::{ - collections::BTreeMap, string::String, string::ToString, sync::Arc, sync::Weak, vec::Vec, -}; +use alloc::{string::String, string::ToString, sync::Arc, sync::Weak, vec::Vec}; use axfs_vfs::{ - VfsDirEntry, VfsError, VfsNodeAttr, VfsNodeOps, VfsNodeRef, VfsNodeType, VfsOps, VfsResult, + VfsDirEntry, VfsError, VfsNodeAttr, VfsNodeOps, VfsNodePerm, VfsNodeRef, VfsNodeType, VfsOps, + VfsResult, }; use log::*; use spin::{once::Once, RwLock}; @@ -62,8 +61,7 @@ impl _9pFileSystem { let fid = match dev.write().get_fid() { Some(id) => id, None => { - warn!("9pfs: No enough fids! Check fid_MAX constrant or fid leaky."); - 0xff_ff_ff_ff + panic!("9pfs: No enough fids! Check fid_MAX constrant or fid leaky."); } }; @@ -120,23 +118,35 @@ impl CommonNode { dev: Arc>, protocol: Arc, ) -> Arc { - const OPEN_FLAG: u8 = 0x02; - if *protocol == "9P2000.L" { - match dev.write().l_topen(fid, OPEN_FLAG as u32) { - Ok(_) => {} - Err(errcode) => { - error!("9pfs open failed! error code: {}", errcode); - } - } + const O_RDWR: u8 = 0x02; + const O_RDONLY: u8 = 0x00; + const EISDIR: u8 = 21; + + let result = if *protocol == "9P2000.L" { + dev.write().l_topen(fid, O_RDWR as u32) } else if *protocol == "9P2000.u" { - match dev.write().topen(fid, OPEN_FLAG) { - Ok(_) => {} - Err(errcode) => { - error!("9pfs open failed! error code: {}", errcode); - } - } + dev.write().topen(fid, O_RDWR) } else { error!("9pfs open failed! Unsupported protocol version"); + Ok(()) + }; + + if let Err(EISDIR) = result { + if *protocol == "9P2000.L" { + handle_result!( + dev.write().l_topen(fid, O_RDONLY as u32), + "9pfs l_topen failed! error code: {}" + ); + } else if *protocol == "9P2000.u" { + handle_result!( + dev.write().topen(fid, O_RDONLY), + "9pfs topen failed! error code: {}" + ); + } else { + error!("9pfs open failed! Unsupported protocol version"); + } + } else if let Err(ecode) = result { + error!("9pfs topen failed! error code: {}", ecode); } Arc::new_cyclic(|this| Self { @@ -166,8 +176,7 @@ impl CommonNode { let fid = match self.inner.write().get_fid() { Some(id) => id, None => { - error!("No enough fids! Check fid_MAX constrant or fid leaky."); - 0xff_ff_ff_ff + panic!("9pfs: No enough fids! Check fid_MAX constrant or fid leaky."); } }; match ty { @@ -223,8 +232,7 @@ impl CommonNode { let fid = match self.inner.write().get_fid() { Some(id) => id, None => { - warn!("9pfs: No enough fids! Check fid_MAX constrant or fid leaky."); - 0xff_ff_ff_ff + panic!("9pfs: No enough fids! Check fid_MAX constrant or fid leaky."); } }; @@ -273,8 +281,7 @@ impl CommonNode { let new_fid = match self.inner.write().get_fid() { Some(id) => id, None => { - warn!("9pfs: No enough fids! Check fid_MAX constrant or fid leaky."); - 0xff_ff_ff_ff + panic!("9pfs: No enough fids! Check fid_MAX constrant or fid leaky."); } }; @@ -294,45 +301,6 @@ impl CommonNode { Err(_) => Err(VfsError::BadState), } } - - /// Update nodes from host filesystem - fn all_nodes(&self) -> Result, VfsError> { - let mut node_map: BTreeMap = BTreeMap::new(); - debug!("reading all nodes in 9p, fid={}", *self.fid); - let dirents = match self.protocol.as_str() { - "9P2000.L" => match self.inner.write().treaddir(*self.fid) { - Ok(contents) => contents, - Err(errcode) => { - error!("9pfs treaddir failed! error code: {}", errcode); - return Err(VfsError::BadState); - } - }, - "9P2000.u" => match self.inner.write().u_treaddir(*self.fid) { - Ok(contents) => contents, - Err(errcode) => { - error!("9pfs u_treaddir failed! error code: {}", errcode); - return Err(VfsError::BadState); - } - }, - _ => { - error!("Unsupport 9P protocol version: {}", *self.protocol); - return Err(VfsError::BadState); - } - }; - - for direntry in dirents { - let fname = direntry.get_name(); - if fname.eq("..") || fname.eq(".") { - continue; - } - - trace!("9pfs update node {}, type {}", fname, direntry.get_type()); - - let node: VfsNodeRef = self.try_get(fname).unwrap(); - node_map.insert(fname.into(), node); - } - Ok(node_map) - } } impl Drop for CommonNode { @@ -413,10 +381,16 @@ impl VfsNodeOps for CommonNode { debug!("get_attr {:?}", resp); match resp { Ok(stat) if stat.get_ftype() == 0o4 => { - Ok(VfsNodeAttr::new_dir(stat.get_size(), stat.get_blk_num())) + let mut attr = VfsNodeAttr::new_dir(stat.get_size(), stat.get_blk_num()); + let mode = stat.get_perm() as u16 & 0o777_u16; + attr.set_perm(VfsNodePerm::from_bits(mode).unwrap()); + Ok(attr) } Ok(stat) if stat.get_ftype() == 0o10 => { - Ok(VfsNodeAttr::new_file(stat.get_size(), stat.get_blk_num())) + let mut attr = VfsNodeAttr::new_file(stat.get_size(), stat.get_blk_num()); + let mode = stat.get_perm() as u16 & 0o777_u16; + attr.set_perm(VfsNodePerm::from_bits(mode).unwrap()); + Ok(attr) } _ => Err(VfsError::BadState), } @@ -424,10 +398,16 @@ impl VfsNodeOps for CommonNode { let resp = self.inner.write().tstat(*self.fid); match resp { Ok(stat) if stat.get_ftype() == 0o4 => { - Ok(VfsNodeAttr::new_dir(stat.get_length(), stat.get_blk_num())) + let mut attr = VfsNodeAttr::new_dir(stat.get_length(), stat.get_blk_num()); + let mode = stat.get_perm() as u16 & 0o777_u16; + attr.set_perm(VfsNodePerm::from_bits(mode).unwrap()); + Ok(attr) } Ok(stat) if stat.get_ftype() == 0o10 => { - Ok(VfsNodeAttr::new_file(stat.get_length(), stat.get_blk_num())) + let mut attr = VfsNodeAttr::new_file(stat.get_length(), stat.get_blk_num()); + let mode = stat.get_perm() as u16 & 0o777_u16; + attr.set_perm(VfsNodePerm::from_bits(mode).unwrap()); + Ok(attr) } _ => Err(VfsError::BadState), } @@ -446,39 +426,59 @@ impl VfsNodeOps for CommonNode { self.try_get(path) } - fn read_dir(&self, start_idx: usize, dirents: &mut [VfsDirEntry]) -> VfsResult { - debug!("9pfs reading dirents"); - let _9p_map = match self.all_nodes() { - Ok(contents) => contents, - Err(errcode) => { - error!("9pfs all_nodes failed! error code = {}", errcode); + fn read_dir(&self, start_idx: usize, vfs_dirents: &mut [VfsDirEntry]) -> VfsResult { + debug!("9pfs reading dirents: start_idx = {:x?}", start_idx); + let dirents = match self.protocol.as_str() { + "9P2000.L" => match self.inner.write().treaddir(*self.fid) { + Ok(contents) => contents, + Err(errcode) => { + error!("9pfs treaddir failed! error code: {}", errcode); + return Err(VfsError::BadState); + } + }, + "9P2000.u" => match self.inner.write().u_treaddir(*self.fid) { + Ok(contents) => contents, + Err(errcode) => { + error!("9pfs u_treaddir failed! error code: {}", errcode); + return Err(VfsError::BadState); + } + }, + _ => { + error!("Unsupport 9P protocol version: {}", *self.protocol); return Err(VfsError::BadState); } }; - let mut item_iter = _9p_map.iter().skip(start_idx.max(2) - 2); - for (i, ent) in dirents.iter_mut().enumerate() { + let mut item_iter = dirents + .iter() + .filter(|&e| !(e.get_name().eq(".") || e.get_name().eq(".."))) + .skip(start_idx.max(2) - 2); // read from start_idx + for (i, ent) in vfs_dirents.iter_mut().enumerate() { match i + start_idx { 0 => *ent = VfsDirEntry::new(".", VfsNodeType::Dir), 1 => *ent = VfsDirEntry::new("..", VfsNodeType::Dir), _ => { - if let Some((name, node)) = item_iter.next() { - let attr = node.get_attr(); - let file_type = match attr { - Ok(attr) => attr.file_type(), - Err(ecode) => { - error!("get [{}] attribute failed, error code:{}.", name, ecode); - continue; - } + if let Some(entry) = item_iter.next() { + let file_type = match entry.get_type() { + 0o1_u8 => VfsNodeType::Fifo, + 0o2_u8 => VfsNodeType::CharDevice, + 0o4_u8 => VfsNodeType::Dir, + 0o6_u8 => VfsNodeType::BlockDevice, + 0o10_u8 => VfsNodeType::File, + 0o12_u8 => VfsNodeType::SymLink, + 0o14_u8 => VfsNodeType::Socket, + _ => panic!("9pfs: Unexpected file type found!"), }; - *ent = VfsDirEntry::new(name, file_type); + *ent = VfsDirEntry::new(entry.get_name(), file_type); } else { + debug!("9pfs read dirents finished: start_idx = {:x?}", start_idx); return Ok(i); } } } } - Ok(dirents.len()) + debug!("9pfs read dirents finished: start_idx = {:x?}", start_idx); + Ok(vfs_dirents.len()) } fn create(&self, path: &str, ty: VfsNodeType) -> VfsResult { @@ -533,6 +533,7 @@ impl VfsNodeOps for CommonNode { /// Read data from the file at the given offset. fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult { + debug!("read 9pid:{} length: {}", self.fid, buf.len()); let mut dev = self.inner.write(); let mut read_len = buf.len(); let mut offset_ptr = 0; @@ -552,19 +553,19 @@ impl VfsNodeOps for CommonNode { read_len -= rlen; offset_ptr += rlen; } - debug!("9P Reading {}, length: {}", self.fid, buf.len()); Ok(buf.len()) } /// Write data to the file at the given offset. fn write_at(&self, offset: u64, buf: &[u8]) -> VfsResult { + debug!("write 9pid:{} length: {}", self.fid, buf.len()); let mut dev = self.inner.write(); let mut write_len = buf.len(); let mut offset_ptr = 0; while write_len > 0 { let target_buf = &buf[offset_ptr..]; let wlen = match dev.twrite(*self.fid, offset + offset_ptr as u64, target_buf) { - Ok(writed_length) => writed_length as usize, + Ok(writed_length) => writed_length, Err(_) => return Err(VfsError::BadState), }; if wlen == 0 { @@ -573,6 +574,7 @@ impl VfsNodeOps for CommonNode { write_len -= wlen; offset_ptr += wlen; } + Ok(buf.len()) } diff --git a/modules/ruxhal/src/platform/aarch64_common/pl011.rs b/modules/ruxhal/src/platform/aarch64_common/pl011.rs index 170abcda8..2ce048ac8 100644 --- a/modules/ruxhal/src/platform/aarch64_common/pl011.rs +++ b/modules/ruxhal/src/platform/aarch64_common/pl011.rs @@ -8,21 +8,67 @@ */ //! PL011 UART. - use arm_pl011::pl011::Pl011Uart; +use cfg_if::cfg_if; use memory_addr::PhysAddr; use spinlock::SpinNoIrq; use crate::mem::phys_to_virt; const UART_BASE: PhysAddr = PhysAddr::from(ruxconfig::UART_PADDR); +#[cfg(feature = "irq")] +const BUFFER_SIZE: usize = 128; + +#[cfg(feature = "irq")] +struct RxRingBuffer { + buffer: [u8; BUFFER_SIZE], + head: usize, + tail: usize, +} + +#[cfg(feature = "irq")] +impl RxRingBuffer { + const fn new() -> Self { + RxRingBuffer { + buffer: [0_u8; BUFFER_SIZE], + head: 0_usize, + tail: 0_usize, + } + } + + fn push(&mut self, n: u8) { + if self.tail != self.head { + self.buffer[self.tail] = n; + self.tail = (self.tail + 1) % BUFFER_SIZE; + } + } + + fn pop(&mut self) -> Option { + if self.head == self.tail { + None + } else { + let ret = self.buffer[self.head]; + self.head += (self.head + 1) % BUFFER_SIZE; + Some(ret) + } + } +} + +struct UartDrv { + inner: SpinNoIrq, + #[cfg(feature = "irq")] + buffer: SpinNoIrq, +} -static UART: SpinNoIrq = - SpinNoIrq::new(Pl011Uart::new(phys_to_virt(UART_BASE).as_mut_ptr())); +static UART: UartDrv = UartDrv { + inner: SpinNoIrq::new(Pl011Uart::new(phys_to_virt(UART_BASE).as_mut_ptr())), + #[cfg(feature = "irq")] + buffer: SpinNoIrq::new(RxRingBuffer::new()), +}; /// Writes a byte to the console. pub fn putchar(c: u8) { - let mut uart = UART.lock(); + let mut uart = UART.inner.lock(); match c { b'\n' => { uart.putchar(b'\r'); @@ -34,27 +80,37 @@ pub fn putchar(c: u8) { /// Reads a byte from the console, or returns [`None`] if no input is available. pub fn getchar() -> Option { - UART.lock().getchar() + cfg_if! { + if #[cfg(feature = "irq")] { + UART.buffer.lock().pop() + }else{ + UART.inner.lock().getchar() + } + } } /// Initialize the UART pub fn init_early() { - UART.lock().init(); + UART.inner.lock().init(); } /// Set UART IRQ Enable pub fn init() { #[cfg(feature = "irq")] - crate::irq::set_enable(crate::platform::irq::UART_IRQ_NUM, true); + { + crate::irq::register_handler(crate::platform::irq::UART_IRQ_NUM, handle); + crate::irq::set_enable(crate::platform::irq::UART_IRQ_NUM, true); + } } /// UART IRQ Handler +#[cfg(feature = "irq")] pub fn handle() { - let is_receive_interrupt = UART.lock().is_receive_interrupt(); - UART.lock().ack_interrupts(); + let is_receive_interrupt = UART.inner.lock().is_receive_interrupt(); if is_receive_interrupt { - while let Some(c) = getchar() { - putchar(c); + UART.inner.lock().ack_interrupts(); + while let Some(c) = UART.inner.lock().getchar() { + UART.buffer.lock().push(c); } } }