diff --git a/Makefile b/Makefile index a47365da..25100e61 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,7 @@ ROOTFS_URL := http://dl-cdn.alpinelinux.org/alpine/v3.12/releases/x86_64/$(ROOTF RISCV64_ROOTFS_TAR := prebuild.tar.xz RISCV64_ROOTFS_URL := https://github.com/rcore-os/libc-test-prebuilt/releases/download/0.1/$(RISCV64_ROOTFS_TAR) +LIBC_TEST_URL := https://github.com/rcore-os/libc-test.git ARCH ?= x86_64 rcore_fs_fuse_revision := 7f5eeac @@ -38,9 +39,14 @@ riscv-rootfs:prebuilt/linux/riscv64/$(RISCV64_ROOTFS_TAR) @ln -s busybox riscv_rootfs/bin/ls libc-test: - cd rootfs && git clone git://repo.or.cz/libc-test --depth 1 + cd rootfs && git clone $(LIBC_TEST_URL) --depth 1 cd rootfs/libc-test && cp config.mak.def config.mak && echo 'CC := musl-gcc' >> config.mak && make -j +rt-test: + cd rootfs && git clone https://kernel.googlesource.com/pub/scm/linux/kernel/git/clrkwllms/rt-tests --depth 1 + cd rootfs/rt-tests && make + echo x86 gcc build rt-test,now need manual modificy. + rcore-fs-fuse: ifneq ($(shell rcore-fs-fuse dir image git-version), $(rcore_fs_fuse_revision)) @echo Installing rcore-fs-fuse @@ -89,7 +95,7 @@ baremetal-test-img: prebuilt/linux/$(ROOTFS_TAR) rcore-fs-fuse @tar xf $< -C $(TMP_ROOTFS) @mkdir -p rootfs/lib @cp $(TMP_ROOTFS)/lib/ld-musl-x86_64.so.1 rootfs/lib/ - @cd rootfs && rm -rf libc-test && git clone git://repo.or.cz/libc-test --depth 1 + @cd rootfs && rm -rf libc-test && git clone $(LIBC_TEST_URL) --depth 1 @cd rootfs/libc-test && cp config.mak.def config.mak && echo 'CC := musl-gcc' >> config.mak && make -j @rcore-fs-fuse $(OUT_IMG) rootfs zip # recover rootfs/ld-musl-x86_64.so.1 for zcore usr libos @@ -97,3 +103,16 @@ baremetal-test-img: prebuilt/linux/$(ROOTFS_TAR) rcore-fs-fuse @cp prebuilt/linux/libc-libos.so rootfs/lib/ld-musl-x86_64.so.1 @echo Resizing $(ARCH).img @qemu-img resize $(OUT_IMG) +5M + +baremetal-test: + @make -C zCore baremetal-test MODE=release LINUX=1 | tee stdout-baremetal-test + +baremetal-test-rv64: + @make -C zCore baremetal-test-rv64 ARCH=riscv64 MODE=release LINUX=1 ROOTPROC=$(ROOTPROC) | tee -a stdout-baremetal-test-rv64 | tee stdout-rv64 + + +check: + cargo fmt --all -- --check + cargo clippy --all-features + cd zCore && make clippy ARCH=x86_64 + cd zCore && make clippy ARCH=riscv64 LINUX=1 diff --git a/drivers/Cargo.toml b/drivers/Cargo.toml index f320a9a8..015e2b68 100644 --- a/drivers/Cargo.toml +++ b/drivers/Cargo.toml @@ -21,6 +21,7 @@ lazy_static = "1.4" numeric-enum-macro = "0.2" device_tree = { git = "https://github.com/rcore-os/device_tree-rs", rev = "2f2e55f" } bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev = "b3f9f51" } +pci = { git = "https://github.com/rcore-os/pci-rs", rev = "a4e7cea6" } virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "2aaf7d6", optional = true } rcore-console = { git = "https://github.com/rcore-os/rcore-console", default-features = false, rev = "ca5b1bc", optional = true } lock = { git = "https://github.com/DeathWish5/kernel-sync" } @@ -39,6 +40,7 @@ sdl2 = { version = "0.34", optional = true } [target.'cfg(target_arch = "x86_64")'.dependencies] acpi = "4.1" x2apic = "0.4" +x86_64 = "0.14" [target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies] riscv = { git = "https://github.com/rust-embedded/riscv", rev = "cd31989", features = ["inline-asm"] } diff --git a/drivers/src/bus/mod.rs b/drivers/src/bus/mod.rs new file mode 100644 index 00000000..9e67d9bf --- /dev/null +++ b/drivers/src/bus/mod.rs @@ -0,0 +1,24 @@ +#![allow(unused)] + +#[cfg(target_arch = "x86_64")] +pub mod pci; + +pub fn phys_to_virt(paddr: PhysAddr) -> VirtAddr { + unsafe { drivers_phys_to_virt(paddr) } +} + +pub fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr { + unsafe { drivers_virt_to_phys(vaddr) } +} + +extern "C" { + fn drivers_dma_alloc(pages: usize) -> PhysAddr; + fn drivers_dma_dealloc(paddr: PhysAddr, pages: usize) -> i32; + fn drivers_phys_to_virt(paddr: PhysAddr) -> VirtAddr; + fn drivers_virt_to_phys(vaddr: VirtAddr) -> PhysAddr; +} + +pub const PAGE_SIZE: usize = 4096; + +type VirtAddr = usize; +type PhysAddr = usize; diff --git a/drivers/src/bus/pci.rs b/drivers/src/bus/pci.rs new file mode 100644 index 00000000..eba115c2 --- /dev/null +++ b/drivers/src/bus/pci.rs @@ -0,0 +1,274 @@ +//use crate::drivers::{Driver, DRIVERS, NET_DRIVERS}; +use super::{phys_to_virt, PAGE_SIZE}; +use alloc::{collections::BTreeMap, format, sync::Arc}; +use lazy_static::lazy_static; +use pci::*; +use spin::Mutex; + +const PCI_COMMAND: u16 = 0x04; +const PCI_CAP_PTR: u16 = 0x34; +const PCI_INTERRUPT_LINE: u16 = 0x3c; +const PCI_INTERRUPT_PIN: u16 = 0x3d; + +const PCI_MSI_CTRL_CAP: u16 = 0x00; +const PCI_MSI_ADDR: u16 = 0x04; +const PCI_MSI_UPPER_ADDR: u16 = 0x08; +const PCI_MSI_DATA_32: u16 = 0x08; +const PCI_MSI_DATA_64: u16 = 0x0C; + +const PCI_CAP_ID_MSI: u8 = 0x05; + +struct PortOpsImpl; + +#[cfg(target_arch = "x86_64")] +use x86_64::instructions::port::Port; + +#[cfg(target_arch = "x86_64")] +impl PortOps for PortOpsImpl { + unsafe fn read8(&self, port: u16) -> u8 { + Port::new(port).read() + } + unsafe fn read16(&self, port: u16) -> u16 { + Port::new(port).read() + } + unsafe fn read32(&self, port: u16) -> u32 { + Port::new(port).read() + } + unsafe fn write8(&self, port: u16, val: u8) { + Port::new(port).write(val); + } + unsafe fn write16(&self, port: u16, val: u16) { + Port::new(port).write(val); + } + unsafe fn write32(&self, port: u16, val: u32) { + Port::new(port).write(val); + } +} + +#[cfg(target_arch = "mips")] +use crate::util::{read, write}; +#[cfg(feature = "board_malta")] +const PCI_BASE: usize = 0xbbe00000; + +#[cfg(target_arch = "mips")] +impl PortOps for PortOpsImpl { + unsafe fn read8(&self, port: u16) -> u8 { + read(PCI_BASE + port as usize) + } + unsafe fn read16(&self, port: u16) -> u16 { + read(PCI_BASE + port as usize) + } + unsafe fn read32(&self, port: u16) -> u32 { + read(PCI_BASE + port as usize) + } + unsafe fn write8(&self, port: u16, val: u8) { + write(PCI_BASE + port as usize, val); + } + unsafe fn write16(&self, port: u16, val: u16) { + write(PCI_BASE + port as usize, val); + } + unsafe fn write32(&self, port: u16, val: u32) { + write(PCI_BASE + port as usize, val); + } +} + +/// Enable the pci device and its interrupt +/// Return assigned MSI interrupt number when applicable +unsafe fn enable(loc: Location) -> Option { + let ops = &PortOpsImpl; + let am = CSpaceAccessMethod::IO; + + // 23 and lower are used + static mut MSI_IRQ: u32 = 23; + + let orig = am.read16(ops, loc, PCI_COMMAND); + // IO Space | MEM Space | Bus Mastering | Special Cycles | PCI Interrupt Disable + am.write32(ops, loc, PCI_COMMAND, (orig | 0x40f) as u32); + + // find MSI cap + let mut msi_found = false; + let mut cap_ptr = am.read8(ops, loc, PCI_CAP_PTR) as u16; + let mut assigned_irq = None; + while cap_ptr > 0 { + let cap_id = am.read8(ops, loc, cap_ptr); + if cap_id == PCI_CAP_ID_MSI { + let orig_ctrl = am.read32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP); + // The manual Volume 3 Chapter 10.11 Message Signalled Interrupts + // 0 is (usually) the apic id of the bsp. Write "0xfee00000 | (0 << 12)" + am.write32(ops, loc, cap_ptr + PCI_MSI_ADDR, 0xfee00000); + MSI_IRQ += 1; + let irq = MSI_IRQ; + assigned_irq = Some(irq as usize); + // we offset all our irq numbers by 32 + if (orig_ctrl >> 16) & (1 << 7) != 0 { + // 64bit + am.write32(ops, loc, cap_ptr + PCI_MSI_DATA_64, irq + 32); + } else { + // 32bit + am.write32(ops, loc, cap_ptr + PCI_MSI_DATA_32, irq + 32); + } + + // enable MSI interrupt, assuming 64bit for now + am.write32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP, orig_ctrl | 0x10000); + debug!( + "MSI control {:#b}, enabling MSI interrupt {}", + orig_ctrl >> 16, + irq + ); + msi_found = true; + } + debug!("PCI device has cap id {} at {:#X}", cap_id, cap_ptr); + cap_ptr = am.read8(ops, loc, cap_ptr + 1) as u16; + } + + if !msi_found { + // Use PCI legacy interrupt instead + // IO Space | MEM Space | Bus Mastering | Special Cycles + am.write32(ops, loc, PCI_COMMAND, (orig | 0xf) as u32); + debug!("MSI not found, using PCI interrupt"); + } + + info!("pci device enable done"); + + assigned_irq +} + +pub fn init_driver(dev: &PCIDevice) { + let name = format!("enp{}s{}f{}", dev.loc.bus, dev.loc.device, dev.loc.function); + match (dev.id.vendor_id, dev.id.device_id) { + (0x8086, 0x100e) | (0x8086, 0x100f) | (0x8086, 0x10d3) => { + // 0x100e + // 82540EM Gigabit Ethernet Controller + // 0x100f + // 82545EM Gigabit Ethernet Controller (Copper) + // 0x10d3 + // 82574L Gigabit Network Connection + if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] { + let irq = unsafe { enable(dev.loc) }; + let vaddr = phys_to_virt(addr as usize); + info!("Found E1000 dev {:#x}, irq: {:?}", vaddr, irq); + /* + let index = NET_DRIVERS.read().len(); + e1000::init(name, irq, vaddr, len as usize, index); + */ + return; + } + } + (0x8086, 0x10fb) => { + // 82599ES 10-Gigabit SFI/SFP+ Network Connection + if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] { + let irq = unsafe { enable(dev.loc) }; + let vaddr = phys_to_virt(addr as usize); + info!("Found ixgbe dev {:#x}, irq: {:?}", vaddr, irq); + /* + let index = NET_DRIVERS.read().len(); + PCI_DRIVERS.lock().insert( + dev.loc, + ixgbe::ixgbe_init(name, irq, vaddr, len as usize, index), + ); + */ + return; + } + } + (0x8086, 0x1539) => { + if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] { + info!( + "Found Intel I211 ethernet controller dev {:?}, addr: {:x?}", + dev, addr + ); + /* + let irq = unsafe { enable(dev.loc) }; + let vaddr = phys_to_virt(addr as usize); + info!("Found ixgbe dev {:#x}, irq: {:?}", vaddr, irq); + let index = NET_DRIVERS.read().len(); + PCI_DRIVERS.lock().insert( + dev.loc, + ixgbe::ixgbe_init(name, irq, vaddr, len as usize, index), + ); + */ + return; + } + } + _ => {} + } + if dev.id.class == 0x01 && dev.id.subclass == 0x06 { + // Mass storage class + // SATA subclass + if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[5] { + info!("Found AHCI dev {:?} BAR5 {:x?}", dev, addr); + /* + let irq = unsafe { enable(dev.loc) }; + assert!(len as usize <= PAGE_SIZE); + let vaddr = phys_to_virt(addr as usize); + if let Some(driver) = ahci::init(irq, vaddr, len as usize) { + PCI_DRIVERS.lock().insert(dev.loc, driver); + } + */ + } + } +} + +pub fn detach_driver(loc: &Location) -> bool { + /* + match PCI_DRIVERS.lock().remove(loc) { + Some(driver) => { + DRIVERS + .write() + .retain(|dri| dri.get_id() != driver.get_id()); + NET_DRIVERS + .write() + .retain(|dri| dri.get_id() != driver.get_id()); + true + } + None => false, + } + */ + false +} + +pub fn init() { + let pci_iter = unsafe { scan_bus(&PortOpsImpl, CSpaceAccessMethod::IO) }; + for dev in pci_iter { + info!( + "pci: {:02x}:{:02x}.{} {:#x} {:#x} ({} {}) irq: {}:{:?}", + dev.loc.bus, + dev.loc.device, + dev.loc.function, + dev.id.vendor_id, + dev.id.device_id, + dev.id.class, + dev.id.subclass, + dev.pic_interrupt_line, + dev.interrupt_pin, + ); + init_driver(&dev); + } +} + +pub fn find_device(vendor: u16, product: u16) -> Option { + let pci_iter = unsafe { scan_bus(&PortOpsImpl, CSpaceAccessMethod::IO) }; + for dev in pci_iter { + if dev.id.vendor_id == vendor && dev.id.device_id == product { + return Some(dev.loc); + } + } + None +} + +pub fn get_bar0_mem(loc: Location) -> Option<(usize, usize)> { + unsafe { probe_function(&PortOpsImpl, loc, CSpaceAccessMethod::IO) } + .and_then(|dev| dev.bars[0]) + .map(|bar| match bar { + BAR::Memory(addr, len, _, _) => (addr as usize, len as usize), + _ => unimplemented!(), + }) +} + +/* +lazy_static! { + pub static ref PCI_DRIVERS: Mutex>> = + Mutex::new(BTreeMap::new()); +} +*/ + +// all devices stored in:AllDeviceList diff --git a/drivers/src/display/mod.rs b/drivers/src/display/mod.rs index 1a498699..4728780b 100644 --- a/drivers/src/display/mod.rs +++ b/drivers/src/display/mod.rs @@ -1,3 +1,5 @@ +//! Only UEFI Display currently. + mod uefi; pub use uefi::UefiDisplay; diff --git a/drivers/src/input/mod.rs b/drivers/src/input/mod.rs index 2be83dfd..80237ef2 100644 --- a/drivers/src/input/mod.rs +++ b/drivers/src/input/mod.rs @@ -1,3 +1,5 @@ +//! Only Mouse currently. + mod mouse; pub mod input_event_codes; diff --git a/drivers/src/io/mmio.rs b/drivers/src/io/mmio.rs index 32bc81f5..dde61f0b 100644 --- a/drivers/src/io/mmio.rs +++ b/drivers/src/io/mmio.rs @@ -1,12 +1,10 @@ -use core::mem::MaybeUninit; +use super::Io; use core::ops::{BitAnd, BitOr, Not}; -use super::Io; - +// 主存映射 I/O。 +/// Memory-mapped I/O. #[repr(transparent)] -pub struct Mmio { - value: MaybeUninit, -} +pub struct Mmio(T); impl Mmio { /// # Safety @@ -25,9 +23,7 @@ impl Mmio { } pub fn add<'a>(&self, offset: usize) -> &'a mut Self { - unsafe { - Self::from_base(self.value.as_ptr() as usize + offset * core::mem::size_of::()) - } + unsafe { Self::from_base((&self.0 as *const T).add(offset) as _) } } } @@ -38,10 +34,19 @@ where type Value = T; fn read(&self) -> T { - unsafe { core::ptr::read_volatile(self.value.as_ptr()) } + unsafe { + let val = core::ptr::read_volatile(&self.0 as *const _); + #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] + core::arch::asm!("fence i,r"); + val + } } fn write(&mut self, value: T) { - unsafe { core::ptr::write_volatile(self.value.as_mut_ptr(), value) }; + unsafe { + #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] + core::arch::asm!("fence w,o"); + core::ptr::write_volatile(&mut self.0 as *mut _, value) + }; } } diff --git a/drivers/src/io/mod.rs b/drivers/src/io/mod.rs index 4f73ee04..4afcc0fe 100644 --- a/drivers/src/io/mod.rs +++ b/drivers/src/io/mod.rs @@ -1,55 +1,79 @@ +// 封装对外设地址空间的访问,包括内存映射 IO 和端口映射 IO。 +// +// 要了解这两种访问外设的方式,查看[维基百科](https://en.wikipedia.org/wiki/Memory-mapped_I/O)。 +//! Peripheral address space access, including memory-mapped IO and port-mapped IO. +//! +//! About these two methods of performing I/O, see [wikipedia](https://en.wikipedia.org/wiki/Memory-mapped_I/O). + use core::ops::{BitAnd, BitOr, Not}; mod mmio; #[cfg(target_arch = "x86_64")] -mod pio; +mod pmio; pub use mmio::Mmio; #[cfg(target_arch = "x86_64")] -pub use pio::Pio; +pub use pmio::Pmio; +// 用于处理外设地址空间访问的接口。 +/// An interface for dealing with device address space access. pub trait Io { + // 可访问的对象的类型。 + /// The type of object to access. type Value: Copy + BitAnd + BitOr + Not; + // 从外设读取值。 + /// Reads value from device. fn read(&self) -> Self::Value; + + // 向外设写入值。 + /// Writes `value` to device. fn write(&mut self, value: Self::Value); } +// 外设地址空间的一个只读单元。 +/// A readonly unit in device address space. #[repr(transparent)] -pub struct ReadOnly { - inner: I, -} +pub struct ReadOnly(I); impl ReadOnly { - pub const fn new(inner: I) -> ReadOnly { - ReadOnly { inner } + // 构造外设地址空间的一个只读单元。 + /// Constructs a readonly unit in device address space. + pub const fn new(inner: I) -> Self { + Self(inner) } } impl ReadOnly { + // 从外设读取值。 + /// Reads value from device. #[inline(always)] pub fn read(&self) -> I::Value { - self.inner.read() + self.0.read() } } +// 外设地址空间的一个只写单元。 +/// A write-only unit in device address space. #[repr(transparent)] -pub struct WriteOnly { - inner: I, -} +pub struct WriteOnly(I); impl WriteOnly { - pub const fn new(inner: I) -> WriteOnly { - WriteOnly { inner } + // 构造外设地址空间的一个只写单元。 + /// Constructs a write-only unit in device address space. + pub const fn new(inner: I) -> Self { + Self(inner) } } impl WriteOnly { + // 向外设写入值。 + /// Writes `value` to device. #[inline(always)] pub fn write(&mut self, value: I::Value) { - self.inner.write(value) + self.0.write(value); } } diff --git a/drivers/src/io/pio.rs b/drivers/src/io/pmio.rs similarity index 68% rename from drivers/src/io/pio.rs rename to drivers/src/io/pmio.rs index 47fa8f86..e3e9a0cf 100644 --- a/drivers/src/io/pio.rs +++ b/drivers/src/io/pmio.rs @@ -1,30 +1,35 @@ -use core::arch::asm; -use core::marker::PhantomData; +// 端口映射 I/O。 +//! Port-mapped I/O. use super::Io; +use core::{arch::asm, marker::PhantomData}; -/// Generic PIO +// 端口映射 I/O。 +/// Port-mapped I/O. #[derive(Copy, Clone)] -pub struct Pio { +pub struct Pmio { port: u16, _phantom: PhantomData, } -impl Pio { - /// Create a PIO from a given port +impl Pmio { + // 映射指定端口进行外设访问。 + /// Maps a given port to assess device. pub const fn new(port: u16) -> Self { - Pio:: { + Self { port, _phantom: PhantomData, } } } -/// Read/Write for byte PIO -impl Io for Pio { +// 逐字节端口映射读写。 +/// Read/Write for byte PMIO. +impl Io for Pmio { type Value = u8; - /// Read + // 读。 + /// Read. #[inline(always)] fn read(&self) -> u8 { let value: u8; @@ -34,7 +39,8 @@ impl Io for Pio { value } - /// Write + // 写。 + /// Write. #[inline(always)] fn write(&mut self, value: u8) { unsafe { @@ -43,11 +49,13 @@ impl Io for Pio { } } -/// Read/Write for word PIO -impl Io for Pio { +// 逐字端口映射读写。 +/// Read/Write for word PMIO. +impl Io for Pmio { type Value = u16; - /// Read + // 读。 + /// Read. #[inline(always)] fn read(&self) -> u16 { let value: u16; @@ -57,7 +65,8 @@ impl Io for Pio { value } - /// Write + // 写。 + /// Write. #[inline(always)] fn write(&mut self, value: u16) { unsafe { @@ -66,11 +75,13 @@ impl Io for Pio { } } -/// Read/Write for doubleword PIO -impl Io for Pio { +// 逐双字端口映射读写。 +/// Read/Write for double-word PMIO. +impl Io for Pmio { type Value = u32; - /// Read + // 读。 + /// Read. #[inline(always)] fn read(&self) -> u32 { let value: u32; @@ -80,7 +91,8 @@ impl Io for Pio { value } - /// Write + // 写。 + /// Write. #[inline(always)] fn write(&mut self, value: u32) { unsafe { diff --git a/drivers/src/irq/mod.rs b/drivers/src/irq/mod.rs index d12ddbf6..6e626d3e 100644 --- a/drivers/src/irq/mod.rs +++ b/drivers/src/irq/mod.rs @@ -1,8 +1,11 @@ +//! External interrupt request and handle. + cfg_if::cfg_if! { if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] { mod riscv_intc; mod riscv_plic; + /// Implementation of risc-v interrupt controller. #[doc(cfg(any(target_arch = "riscv32", target_arch = "riscv64")))] pub mod riscv { pub use super::riscv_intc::{Intc, ScauseIntCode}; @@ -11,6 +14,7 @@ cfg_if::cfg_if! { } else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { mod x86_apic; + /// Implementation of x86 Advanced Programmable Interrupt Controller. #[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))] pub mod x86 { pub use super::x86_apic::Apic; diff --git a/drivers/src/irq/riscv_plic.rs b/drivers/src/irq/riscv_plic.rs index 8e70021c..44aec6c1 100644 --- a/drivers/src/irq/riscv_plic.rs +++ b/drivers/src/irq/riscv_plic.rs @@ -40,8 +40,7 @@ impl PlicUnlocked { let hart_id = cpu_id() as usize; let mmio = self .enable_base - .add(PLIC_ENABLE_HART_OFFSET * hart_id) - .add(irq_num / 32); + .add(PLIC_ENABLE_HART_OFFSET * hart_id + irq_num / 32); let mask = 1 << (irq_num % 32); if enable { @@ -56,8 +55,7 @@ impl PlicUnlocked { let hart_id = cpu_id() as usize; let irq_num = self .context_base - .add(PLIC_CONTEXT_CLAIM_HART_OFFSET * hart_id) - .add(PLIC_CONTEXT_CLAIM) + .add(PLIC_CONTEXT_CLAIM_HART_OFFSET * hart_id + PLIC_CONTEXT_CLAIM) .read() as usize; if irq_num == 0 { None @@ -71,8 +69,7 @@ impl PlicUnlocked { debug_assert!(IRQ_RANGE.contains(&irq_num)); let hart_id = cpu_id() as usize; self.context_base - .add(PLIC_CONTEXT_CLAIM) - .add(PLIC_CONTEXT_CLAIM_HART_OFFSET * hart_id) + .add(PLIC_CONTEXT_CLAIM + PLIC_CONTEXT_CLAIM_HART_OFFSET * hart_id) .write(irq_num as _); } @@ -86,8 +83,7 @@ impl PlicUnlocked { fn set_threshold(&mut self, threshold: u8) { let hart_id = cpu_id() as usize; self.context_base - .add(PLIC_PRIORITY_HART_OFFSET * hart_id) - .add(PLIC_CONTEXT_THRESHOLD) + .add(PLIC_PRIORITY_HART_OFFSET * hart_id + PLIC_CONTEXT_THRESHOLD) .write(threshold as _); } diff --git a/drivers/src/irq/x86_apic/ioapic.rs b/drivers/src/irq/x86_apic/ioapic.rs index 2257902b..124106fa 100644 --- a/drivers/src/irq/x86_apic/ioapic.rs +++ b/drivers/src/irq/x86_apic/ioapic.rs @@ -67,9 +67,23 @@ impl IoApic { let mut inner = unsafe { IoApicInner::new(base_vaddr as u64) }; let max_entry = unsafe { inner.max_table_entry() }; unsafe { assert_eq!(id, inner.id()) }; - // disable all interrupts + + unsafe { + inner.init(super::X86_INT_BASE as u8); + } for i in 0..max_entry + 1 { - unsafe { inner.disable_irq(i) } + unsafe { + // disable all interrupts + inner.disable_irq(i); + + // Clean the redirection table + let mut entry = inner.table_entry(i); + entry.set_vector(0); + entry.set_dest(0); + entry.set_mode(IrqMode::Fixed); + entry.set_flags(IrqFlags::MASKED); + inner.set_table_entry(i, entry); + } } Self { id, diff --git a/drivers/src/irq/x86_apic/mod.rs b/drivers/src/irq/x86_apic/mod.rs index dcd1d85e..0109ed5a 100644 --- a/drivers/src/irq/x86_apic/mod.rs +++ b/drivers/src/irq/x86_apic/mod.rs @@ -19,6 +19,7 @@ const LAPIC_IRQ_RANGE: Range = 0..16; type Phys2VirtFn = fn(paddr: PhysAddr) -> VirtAddr; +/// Advanced Programmable Interrupt Controller pub struct Apic { ioapic_list: IoApicList, manager_ioapic: Mutex>, @@ -26,6 +27,7 @@ pub struct Apic { } impl Apic { + /// Construct a new `Apic`. pub fn new(acpi_rsdp: usize, phys_to_virt: Phys2VirtFn) -> Self { Self { ioapic_list: IoApicList::new(acpi_rsdp, phys_to_virt), diff --git a/drivers/src/lib.rs b/drivers/src/lib.rs index 75dede10..3e1a2806 100644 --- a/drivers/src/lib.rs +++ b/drivers/src/lib.rs @@ -1,3 +1,5 @@ +//! Device drivers of zCore. + #![cfg_attr(not(feature = "mock"), no_std)] #![feature(doc_cfg)] @@ -18,6 +20,7 @@ pub mod mock; pub mod virtio; pub mod builder; +pub mod bus; pub mod display; pub mod input; pub mod io; @@ -28,6 +31,7 @@ pub mod scheme; pub mod uart; pub mod utils; +/// The error type for external device. #[derive(Debug)] pub enum DeviceError { /// The buffer is too small. @@ -48,19 +52,28 @@ pub enum DeviceError { NotSupported, } +/// A type alias for the result of a device operation. pub type DeviceResult = core::result::Result; +/// Static shell of shared dynamic device [`Scheme`](crate::scheme::Scheme) types. #[derive(Clone)] pub enum Device { + /// Block device Block(Arc), + /// Display device Display(Arc), + /// Input device Input(Arc), + /// Interrupt request and handle Irq(Arc), + /// Network device Net(Arc), + /// Uart port Uart(Arc), } impl Device { + /// Get a general [`Scheme`](scheme::Scheme) from the device. pub fn inner(&self) -> Arc { match self { Self::Block(d) => d.clone().upcast(), diff --git a/drivers/src/mock/mod.rs b/drivers/src/mock/mod.rs index 4e59256d..25e14078 100644 --- a/drivers/src/mock/mod.rs +++ b/drivers/src/mock/mod.rs @@ -1,3 +1,5 @@ +//! Mock devices, including display, input, uart and graphic. + pub mod display; pub mod input; pub mod uart; diff --git a/drivers/src/net/mod.rs b/drivers/src/net/mod.rs index f547dfe6..e8972f6c 100644 --- a/drivers/src/net/mod.rs +++ b/drivers/src/net/mod.rs @@ -1,3 +1,5 @@ +//! LAN driver, only for Realtek currently. + cfg_if::cfg_if! { if #[cfg(target_arch = "riscv64")] { mod realtek; diff --git a/drivers/src/net/realtek/rtl8211f.rs b/drivers/src/net/realtek/rtl8211f.rs index fa0799bc..548fe1b9 100644 --- a/drivers/src/net/realtek/rtl8211f.rs +++ b/drivers/src/net/realtek/rtl8211f.rs @@ -235,7 +235,7 @@ where mac[i] = u8::from_str_radix(s, 16).unwrap(); } } else { - mac = mac_addr.clone(); + mac = *mac_addr; } info!( @@ -1144,10 +1144,10 @@ where #[allow(clippy::collapsible_if)] /* 正常的 TX/RX NORMAL interrupts */ - if (intr_status & (TX_INT | RX_INT | RX_EARLY_INT | TX_UA_INT)) != 0 { - if (intr_status & (TX_INT | RX_INT)) != 0 { - status = tx_dma_irq_status::handle_tx_rx as i32; - } + if (intr_status & (TX_INT | RX_INT | RX_EARLY_INT | TX_UA_INT)) != 0 + && (intr_status & (TX_INT | RX_INT)) != 0 + { + status = tx_dma_irq_status::handle_tx_rx as i32; } /* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */ write_volatile((self.base + GETH_INT_STA) as *mut u32, intr_status & 0x3FFF); @@ -1434,7 +1434,14 @@ where match speed { 1000 => ctrl &= !0x0C, - /*100 | 10 |*/ + 100 | 10 => { + ctrl |= 0x08; + if (speed == 100) { + ctrl |= 0x04; + } else { + ctrl &= !0x04; + } + } _ => { ctrl |= 0x08; if (speed == 100) { diff --git a/drivers/src/net/rtlx.rs b/drivers/src/net/rtlx.rs index 68b9d93f..991a9b41 100644 --- a/drivers/src/net/rtlx.rs +++ b/drivers/src/net/rtlx.rs @@ -1,14 +1,14 @@ use alloc::collections::BTreeMap; use alloc::string::String; use alloc::sync::Arc; -use alloc::vec; +// use alloc::vec; use alloc::vec::Vec; // use spin::Mutex; use lock::Mutex; use smoltcp::iface::*; use smoltcp::phy::{self, Device, DeviceCapabilities, Medium}; -use smoltcp::socket::SocketSet; +// use smoltcp::socket::SocketSet; use smoltcp::time::Instant; use smoltcp::wire::*; use smoltcp::Result; @@ -19,6 +19,7 @@ use super::ProviderImpl; use super::PAGE_SIZE; //use kernel_hal::drivers::{Driver, DeviceType, NetDriver, DRIVERS, NET_DRIVERS, SOCKETS}; +use crate::net::get_sockets; use crate::scheme::{NetScheme, Scheme}; use crate::{DeviceError, DeviceResult}; @@ -49,13 +50,13 @@ impl Scheme for RTLxInterface { let handle_tx_rx = 3; if status == handle_tx_rx { let timestamp = Instant::from_millis(0); - let mut sockets = SOCKETS.lock(); //引发死锁? + let sockets = get_sockets(); + let mut sockets = sockets.lock(); self.driver.0.lock().int_disable(); match self.iface.lock().poll(&mut sockets, timestamp) { - Ok(_) => { - //SOCKET_ACTIVITY.notify_all(); - debug!("try_handle_interrupt SOCKET_ACTIVITY unimplemented"); + Ok(b) => { + debug!("nic poll, is changed ?: {}", b); } Err(err) => { error!("poll got err {}", err); @@ -82,11 +83,11 @@ impl NetScheme for RTLxInterface { fn poll(&self) -> DeviceResult { let timestamp = Instant::from_millis(0); - let mut sockets = SOCKETS.lock(); + let sockets = get_sockets(); + let mut sockets = sockets.lock(); match self.iface.lock().poll(&mut sockets, timestamp) { - Ok(_) => { - //SOCKET_ACTIVITY.notify_all(); - error!("poll, SOCKET_ACTIVITY unimplemented"); + Ok(b) => { + debug!("nic poll, is changed ?: {}", b); Ok(()) } Err(err) => { @@ -193,14 +194,20 @@ pub fn rtlx_init Option>( let ethernet_addr = EthernetAddress::from_bytes(&mac); let ip_addrs = [IpCidr::new(IpAddress::v4(192, 168, 0, 123), 24)]; + let default_gateway = Ipv4Address::new(192, 168, 0, 1); + static mut ROUTES_STORAGE: [Option<(IpCidr, Route)>; 1] = [None; 1]; + let mut routes = unsafe { Routes::new(&mut ROUTES_STORAGE[..]) }; + routes.add_default_ipv4_route(default_gateway).unwrap(); let neighbor_cache = NeighborCache::new(BTreeMap::new()); let iface = InterfaceBuilder::new(net_driver.clone()) .ethernet_addr(ethernet_addr) .neighbor_cache(neighbor_cache) .ip_addrs(ip_addrs) + .routes(routes) .finalize(); info!("rtl8211f interface up with addr 192.168.0.123/24"); + info!("rtl8211f interface up with route 192.168.0.1/24"); let rtl8211f_iface = RTLxInterface { iface: Arc::new(Mutex::new(iface)), driver: net_driver, @@ -212,7 +219,7 @@ pub fn rtlx_init Option>( } //TODO: Global SocketSet -lazy_static::lazy_static! { - pub static ref SOCKETS: Mutex> = - Mutex::new(SocketSet::new(vec![])); -} +// lazy_static::lazy_static! { +// pub static ref SOCKETS: Mutex> = +// Mutex::new(SocketSet::new(vec![])); +// } diff --git a/drivers/src/prelude.rs b/drivers/src/prelude.rs index 5c7fbecb..316e8a2d 100644 --- a/drivers/src/prelude.rs +++ b/drivers/src/prelude.rs @@ -1,8 +1,11 @@ +//! Re-export most commonly used driver types. + pub use crate::scheme::display::{ColorFormat, DisplayInfo, FrameBuffer, Rectangle, RgbColor}; pub use crate::scheme::input::{CapabilityType, InputCapability, InputEvent, InputEventType}; pub use crate::scheme::irq::{IrqHandler, IrqPolarity, IrqTriggerMode}; pub use crate::{Device, DeviceError, DeviceResult}; +/// Re-export types from [`input`](crate::input). pub mod input { pub use crate::input::{Mouse, MouseFlags, MouseState}; } diff --git a/drivers/src/scheme/irq.rs b/drivers/src/scheme/irq.rs index 9e913f51..ba481029 100644 --- a/drivers/src/scheme/irq.rs +++ b/drivers/src/scheme/irq.rs @@ -5,6 +5,7 @@ use core::ops::Range; use super::Scheme; use crate::DeviceResult; +/// A type alias for pub type IrqHandler = Box; #[derive(Debug)] diff --git a/drivers/src/scheme/mod.rs b/drivers/src/scheme/mod.rs index 67125af5..b25f1982 100644 --- a/drivers/src/scheme/mod.rs +++ b/drivers/src/scheme/mod.rs @@ -1,5 +1,5 @@ -//! The [`Scheme`] describe some functions must be implemented for device, there are -//! many [`Scheme`] traits in this mod. +//! The [`Scheme`] describe some functions must be implemented for different type of devices, +//! there are many [`Scheme`] traits in this mod. //! //! If you need to develop a new device, just implement the corresponding trait. //! @@ -26,12 +26,20 @@ pub use irq::IrqScheme; pub use net::NetScheme; pub use uart::UartScheme; +/// Common of all device drivers. +/// +/// Every device must says its name and handles interrupts. pub trait Scheme: SchemeUpcast + Send + Sync { + /// Returns name of the driver. fn name(&self) -> &str; + + /// Handles an interrupt. fn handle_irq(&self, _irq_num: usize) {} } +/// Used to convert a concrete type pointer to a general [`Scheme`] pointer. pub trait SchemeUpcast { + /// Performs the conversion. fn upcast<'a>(self: Arc) -> Arc where Self: 'a; diff --git a/drivers/src/uart/mod.rs b/drivers/src/uart/mod.rs index a4b4b655..a805b0d3 100644 --- a/drivers/src/uart/mod.rs +++ b/drivers/src/uart/mod.rs @@ -1,3 +1,5 @@ +//! Uart device driver. + mod buffered; mod uart_16550; @@ -5,4 +7,4 @@ pub use buffered::BufferedUart; pub use uart_16550::Uart16550Mmio; #[cfg(target_arch = "x86_64")] -pub use uart_16550::Uart16550Pio; +pub use uart_16550::Uart16550Pmio; diff --git a/drivers/src/uart/uart_16550.rs b/drivers/src/uart/uart_16550.rs index 41587f99..89260125 100644 --- a/drivers/src/uart/uart_16550.rs +++ b/drivers/src/uart/uart_16550.rs @@ -107,6 +107,7 @@ where } } +/// MMIO driver for UART 16550 pub struct Uart16550Mmio where V: Copy + BitAnd + BitOr + Not, @@ -201,20 +202,21 @@ impl Uart16550Mmio { } #[cfg(target_arch = "x86_64")] -mod pio { +mod pmio { use super::*; - use crate::io::Pio; + use crate::io::Pmio; - pub struct Uart16550Pio { - inner: Mutex>>, + /// Pmio driver for UART 16550 + pub struct Uart16550Pmio { + inner: Mutex>>, listener: EventListener, } - impl_event_scheme!(Uart16550Pio); + impl_event_scheme!(Uart16550Pmio); - impl Scheme for Uart16550Pio { + impl Scheme for Uart16550Pmio { fn name(&self) -> &str { - "uart16550-pio" + "uart16550-Pmio" } fn handle_irq(&self, _irq_num: usize) { @@ -222,7 +224,7 @@ mod pio { } } - impl UartScheme for Uart16550Pio { + impl UartScheme for Uart16550Pmio { fn try_recv(&self) -> DeviceResult> { self.inner.lock().try_recv() } @@ -236,16 +238,17 @@ mod pio { } } - impl Uart16550Pio { + impl Uart16550Pmio { + /// Construct a `Uart16550Pmio` whose address starts at `base`. pub fn new(base: u16) -> Self { - let mut uart = Uart16550Inner::> { - data: Pio::new(base), - int_en: Pio::new(base + 1), - fifo_ctrl: Pio::new(base + 2), - line_ctrl: Pio::new(base + 3), - modem_ctrl: Pio::new(base + 4), - line_sts: ReadOnly::new(Pio::new(base + 5)), - modem_sts: ReadOnly::new(Pio::new(base + 6)), + let mut uart = Uart16550Inner::> { + data: Pmio::new(base), + int_en: Pmio::new(base + 1), + fifo_ctrl: Pmio::new(base + 2), + line_ctrl: Pmio::new(base + 3), + modem_ctrl: Pmio::new(base + 4), + line_sts: ReadOnly::new(Pmio::new(base + 5)), + modem_sts: ReadOnly::new(Pmio::new(base + 6)), }; uart.init(); Self { @@ -257,4 +260,4 @@ mod pio { } #[cfg(target_arch = "x86_64")] -pub use pio::Uart16550Pio; +pub use pmio::Uart16550Pmio; diff --git a/drivers/src/utils/devicetree.rs b/drivers/src/utils/devicetree.rs index 34380cd8..4fa3841a 100644 --- a/drivers/src/utils/devicetree.rs +++ b/drivers/src/utils/devicetree.rs @@ -1,9 +1,9 @@ -use alloc::vec::Vec; -use core::ops::Range; - -use device_tree::{DeviceTree as DeviceTreeInner, PropError}; +//! Package of [`device_tree`]. use crate::{DeviceError, DeviceResult, PhysAddr, VirtAddr}; +use alloc::vec::Vec; +use core::ops::Range; +use device_tree::{DeviceTree as DeviceTreeInner, PropError}; pub use device_tree::{util::StringList, Node}; diff --git a/drivers/src/utils/event_listener.rs b/drivers/src/utils/event_listener.rs index 4b556f3d..360d9783 100644 --- a/drivers/src/utils/event_listener.rs +++ b/drivers/src/utils/event_listener.rs @@ -1,25 +1,35 @@ use alloc::{boxed::Box, vec::Vec}; -// use spin::Mutex; use lock::Mutex; +/// A type alias for the closure to handle device event. pub type EventHandler = Box; +/// Device event listener. +/// +/// It keeps a series of [`EventHandler`]s that handle events of one single type. pub struct EventListener { events: Mutex, bool)>>, } impl EventListener { + /// Construct a new, empty `EventListener`. pub fn new() -> Self { Self { events: Mutex::new(Vec::new()), } } + /// Register a new `handler` into this `EventListener`. + /// + /// If `once` is `true`, the `handler` will be removed once it handles an event. pub fn subscribe(&self, handler: EventHandler, once: bool) { self.events.lock().push((handler, once)); } + /// Send an event to the `EventListener`. + /// + /// All the handlers handle the event, and those marked `once` will be removed immediately. pub fn trigger(&self, event: T) { self.events.lock().retain(|(f, once)| { f(&event); diff --git a/drivers/src/utils/mod.rs b/drivers/src/utils/mod.rs index 6a67b29f..4b2b5388 100644 --- a/drivers/src/utils/mod.rs +++ b/drivers/src/utils/mod.rs @@ -1,3 +1,5 @@ +//! Event handler and device tree. + #![allow(unused_imports)] mod event_listener; diff --git a/drivers/src/virtio/mod.rs b/drivers/src/virtio/mod.rs index 9bcea918..ab929d09 100644 --- a/drivers/src/virtio/mod.rs +++ b/drivers/src/virtio/mod.rs @@ -1,3 +1,5 @@ +//! Packaging of [`virtio-drivers` library](https://github.com/rcore-os/virtio-drivers). + mod blk; mod console; mod gpu; diff --git a/kernel-hal/Cargo.toml b/kernel-hal/Cargo.toml index 9a470ea8..2aa6c167 100644 --- a/kernel-hal/Cargo.toml +++ b/kernel-hal/Cargo.toml @@ -13,6 +13,8 @@ smp = [] libos = ["nix", "tempfile", "async-std", "bitmap-allocator", "zcore-drivers/mock"] graphic = ["zcore-drivers/graphic"] +loopback = [] + [dependencies] log = "0.4" spin = "0.9" @@ -26,7 +28,6 @@ zcore-drivers = { path = "../drivers", features = ["virtio"] } lock = { git = "https://github.com/DeathWish5/kernel-sync" } smoltcp = { git = "https://gitee.com/gcyyfun/smoltcp", rev="043eb60", default-features = false, features = ["alloc","log", "async", "medium-ethernet","proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw"] } - # LibOS mode [target.'cfg(not(target_os = "none"))'.dependencies] nix = { version = "0.23", optional = true } diff --git a/kernel-hal/src/bare/arch/riscv/drivers.rs b/kernel-hal/src/bare/arch/riscv/drivers.rs index 1be9cc7a..b428818c 100644 --- a/kernel-hal/src/bare/arch/riscv/drivers.rs +++ b/kernel-hal/src/bare/arch/riscv/drivers.rs @@ -92,5 +92,21 @@ pub(super) fn intc_init() -> DeviceResult { )?; irq.unmask(ScauseIntCode::SupervisorSoft as _)?; irq.unmask(ScauseIntCode::SupervisorTimer as _)?; + + #[cfg(feature = "graphic")] + if let Some(display) = drivers::all_display().first() { + crate::console::init_graphic_console(display.clone()); + if display.need_flush() { + // TODO: support nested interrupt to render in time + crate::thread::spawn(crate::common::future::DisplayFlushFuture::new(display, 30)); + } + } + + #[cfg(feature = "loopback")] + { + use crate::net; + net::init(); + } + Ok(()) } diff --git a/kernel-hal/src/bare/arch/x86_64/cpu.rs b/kernel-hal/src/bare/arch/x86_64/cpu.rs index 2ccd3abd..5d802d96 100644 --- a/kernel-hal/src/bare/arch/x86_64/cpu.rs +++ b/kernel-hal/src/bare/arch/x86_64/cpu.rs @@ -26,8 +26,8 @@ hal_fn_impl! { fn reset() -> ! { info!("shutdown..."); loop { - use zcore_drivers::io::{Io, Pio}; - Pio::::new(0x604).write(0x2000); + use zcore_drivers::io::{Io, Pmio}; + Pmio::::new(0x604).write(0x2000); super::interrupt::wait_for_interrupt(); } } diff --git a/kernel-hal/src/bare/arch/x86_64/drivers.rs b/kernel-hal/src/bare/arch/x86_64/drivers.rs index 59bc1164..a07ffcb8 100644 --- a/kernel-hal/src/bare/arch/x86_64/drivers.rs +++ b/kernel-hal/src/bare/arch/x86_64/drivers.rs @@ -1,15 +1,18 @@ use alloc::{boxed::Box, sync::Arc}; +use zcore_drivers::bus::pci; use zcore_drivers::irq::x86::Apic; use zcore_drivers::scheme::IrqScheme; -use zcore_drivers::uart::{BufferedUart, Uart16550Pio}; +use zcore_drivers::uart::{BufferedUart, Uart16550Pmio}; use zcore_drivers::{Device, DeviceResult}; use super::trap; use crate::drivers; pub(super) fn init_early() -> DeviceResult { - let uart = Arc::new(Uart16550Pio::new(0x3F8)); + let uart = Arc::new(Uart16550Pmio::new(0x3F8)); + drivers::add_device(Device::Uart(BufferedUart::new(uart))); + let uart = Arc::new(Uart16550Pmio::new(0x2F8)); drivers::add_device(Device::Uart(BufferedUart::new(uart))); Ok(()) } @@ -20,14 +23,22 @@ pub(super) fn init() -> DeviceResult { super::special::pc_firmware_tables().0 as usize, crate::mem::phys_to_virt, )); - irq.register_device( - trap::X86_ISA_IRQ_COM1, - drivers::all_uart().first_unwrap().upcast(), - )?; - irq.unmask(trap::X86_ISA_IRQ_COM1)?; + let uarts = drivers::all_uart(); + if let Some(u) = uarts.try_get(0) { + irq.register_device(trap::X86_ISA_IRQ_COM1, u.clone().upcast())?; + irq.unmask(trap::X86_ISA_IRQ_COM1)?; + + if let Some(u) = uarts.try_get(1) { + irq.register_device(trap::X86_ISA_IRQ_COM2, u.clone().upcast())?; + irq.unmask(trap::X86_ISA_IRQ_COM2)?; + } + } irq.register_local_apic_handler(trap::X86_INT_APIC_TIMER, Box::new(super::trap::super_timer))?; drivers::add_device(Device::Irq(irq)); + // PCI scan + pci::init(); + #[cfg(feature = "graphic")] { use crate::KCONFIG; @@ -46,6 +57,12 @@ pub(super) fn init() -> DeviceResult { crate::console::init_graphic_console(display); } + #[cfg(feature = "loopback")] + { + use crate::net; + net::init(); + } + info!("Drivers init end."); Ok(()) } diff --git a/kernel-hal/src/bare/arch/x86_64/special.rs b/kernel-hal/src/bare/arch/x86_64/special.rs index c472fb8e..d41faf1f 100644 --- a/kernel-hal/src/bare/arch/x86_64/special.rs +++ b/kernel-hal/src/bare/arch/x86_64/special.rs @@ -1,6 +1,6 @@ //! Functions only available on x86 platforms. -pub use zcore_drivers::io::{Io, Pio}; +pub use zcore_drivers::io::{Io, Pmio}; /// Get physical address of `acpi_rsdp` and `smbios` on x86_64. pub fn pc_firmware_tables() -> (u64, u64) { diff --git a/kernel-hal/src/bare/boot.rs b/kernel-hal/src/bare/boot.rs index 0aab1b03..b6149cbf 100644 --- a/kernel-hal/src/bare/boot.rs +++ b/kernel-hal/src/bare/boot.rs @@ -1,6 +1,5 @@ //! Bootstrap and initialization. -use super::net; use crate::{KernelConfig, KernelHandler, KCONFIG, KHANDLER}; hal_fn_impl! { @@ -24,7 +23,6 @@ hal_fn_impl! { info!("Primary CPU {} init...", crate::cpu::cpu_id()); unsafe { trapframe::init() }; super::arch::primary_init(); - net::init(); } fn secondary_init() { diff --git a/kernel-hal/src/bare/net.rs b/kernel-hal/src/bare/net.rs index 206d515f..598d0579 100644 --- a/kernel-hal/src/bare/net.rs +++ b/kernel-hal/src/bare/net.rs @@ -1,3 +1,4 @@ +// May need move to drivers use smoltcp::{ iface::{InterfaceBuilder, NeighborCache, Route, Routes}, phy::{Loopback, Medium}, diff --git a/kernel-hal/src/common/user.rs b/kernel-hal/src/common/user.rs index a4be3cd5..6940b3c5 100644 --- a/kernel-hal/src/common/user.rs +++ b/kernel-hal/src/common/user.rs @@ -1,23 +1,42 @@ -//! Read/write user space pointer. +// 来自用户空间的裸指针 +//! Raw pointer from user land. -use alloc::string::String; -use alloc::vec::Vec; -use core::fmt::{Debug, Formatter}; -use core::marker::PhantomData; -use core::ops::{Deref, DerefMut}; +use crate::VirtAddr; +use alloc::{string::String, vec::Vec}; +use core::{ + fmt::{Debug, Formatter}, + marker::PhantomData, + ops::{Deref, DerefMut}, +}; -#[repr(C)] -pub struct UserPtr { - ptr: *mut T, - mark: PhantomData

, -} +// 来自用户空间的裸指针 +/// Raw pointer from user land. +#[repr(transparent)] +pub struct UserPtr(*mut T, PhantomData

); +// 标识用户指针功能的基特征。 +/// Base trait for Markers of user pointer policy. pub trait Policy {} + +// 标记一个用于输入的指针。 +/// Marks a pointer used to read. pub trait Read: Policy {} + +// 标记一个用于输出的指针。 +/// Marks a pointer used to write. pub trait Write: Policy {} -pub enum In {} -pub enum Out {} -pub enum InOut {} + +// 输入指针的类型参数。 +/// Type argument for user pointer used to read. +pub struct In; + +// 输出指针的类型参数。 +/// Type argument for user pointer used to write. +pub struct Out; + +// 既用于输入有用于输出的指针的类型参数。 +/// Type argument for user pointer used to both read and write. +pub struct InOut; impl Policy for In {} impl Policy for Out {} @@ -31,9 +50,8 @@ pub type UserInPtr = UserPtr; pub type UserOutPtr = UserPtr; pub type UserInOutPtr = UserPtr; -type Result = core::result::Result; - -/// The error type which is returned from user pointer. +// 用户指针操作的异常类型。 +/// The error type which is returned from user pointer operation. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Error { InvalidUtf8, @@ -43,9 +61,13 @@ pub enum Error { InvalidVectorAddress, } +// 本模块用到的只是用户指针操作结果的类型。 +type Result = core::result::Result; + impl Debug for UserPtr { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - write!(f, "{:?}", self.ptr) + // 打印用户指针就是打印裸指针 + write!(f, "{:?}", self.0) } } @@ -54,154 +76,210 @@ unsafe impl Send for UserPtr {} unsafe impl Sync for UserPtr {} impl From for UserPtr { - fn from(x: usize) -> Self { - UserPtr { - ptr: x as _, - mark: PhantomData, - } + fn from(ptr: usize) -> Self { + UserPtr(ptr as _, PhantomData) } } impl UserPtr { + // 检查 `size` 是否足够放下一个 `T` 的值, + // 并从 `addr` 构造一个用户指针。 + /// Checks if `size` is enough to save a value of `T`, + /// then constructs a user pointer from its value `addr`. pub fn from_addr_size(addr: usize, size: usize) -> Result { - if size < core::mem::size_of::() { - return Err(Error::BufferTooSmall); + if size >= core::mem::size_of::() { + Ok(Self::from(addr)) + } else { + Err(Error::BufferTooSmall) } - Ok(Self::from(addr)) } + // 如果指针为空,返回 `true`。 + /// Returns `true` if the pointer is null. pub fn is_null(&self) -> bool { - self.ptr.is_null() + self.0.is_null() } + // 偏移指针。 + // `count` 表示 `T` 的数量; + // 例如,`count` 为 3 表示将指针移动 `3 * size_of::()` 个字节。 + /// Calculates the offset from a pointer. + /// `count` is in units of `T`; + /// e.g., a `count` of 3 represents a pointer offset of `3 * size_of::()` bytes. pub fn add(&self, count: usize) -> Self { - UserPtr { - ptr: unsafe { self.ptr.add(count) }, - mark: PhantomData, - } + Self(unsafe { self.0.add(count) }, PhantomData) } - pub fn as_ptr(&self) -> *mut T { - self.ptr + // 返回指针对应的虚地址。 + /// Returns the virtual address represented by the pointer. + pub fn as_addr(&self) -> VirtAddr { + self.0 as _ } + // 检查用户指针是否合法。 + // + // 如果指针非空且对齐则返回 `OK(())`。 + /// Checks avaliability of the user pointer. + /// + /// Returns [`Ok(())`] if it is neither null nor unaligned. pub fn check(&self) -> Result<()> { - if self.ptr.is_null() { - return Err(Error::InvalidPointer); + if !self.0.is_null() && (self.0 as usize) % core::mem::align_of::() == 0 { + Ok(()) + } else { + Err(Error::InvalidPointer) } - if (self.ptr as usize) % core::mem::align_of::() != 0 { - return Err(Error::InvalidPointer); - } - Ok(()) } } impl UserPtr { - pub fn as_ref(&self) -> Result<&'static T> { - Ok(unsafe { &*self.ptr }) + // 取出指针值的引用(不要用于小于 8 字节的类型)。 + /// Converts to reference. + #[allow(clippy::should_implement_trait)] + pub fn as_ref(&self) -> &'static T { + unsafe { &*self.0 } } + // 读取但不移动指针所指的值(通过逐字节拷贝,但不需要 `Copy` 特征)。 + // 指针所指的值保持不变。 + /// Reads the value from `self` without moving it. + /// This leaves the memory in self unchanged. pub fn read(&self) -> Result { - // TODO: check ptr and return err self.check()?; - Ok(unsafe { self.ptr.read() }) + Ok(unsafe { self.0.read() }) } + // 和读取一样, + // 但若指针为空,返回 `None`。 + /// Same as [`read`](Self::read), + /// but returns [`None`] when pointer is null. pub fn read_if_not_null(&self) -> Result> { - if self.ptr.is_null() { - return Ok(None); + if !self.0.is_null() { + Ok(Some(self.read()?)) + } else { + Ok(None) } - let value = self.read()?; - Ok(Some(value)) } + // 构造一个从指针指向开始,长度为 `len` 的切片。 + /// Forms a slice from a user pointer and a `len`. + pub fn as_slice(&self, len: usize) -> Result<&'static [T]> { + if len == 0 { + Ok(&[]) + } else { + self.check()?; + Ok(unsafe { core::slice::from_raw_parts(self.0, len) }) + } + } + + // 拷贝对象来构造一个 `Vec`。 + // + // `len` 是成员的数量,而不是字节数。 + /// Copies elements into a new [`Vec`]. + /// + /// The `len` argument is the number of **elements**, not the number of bytes. pub fn read_array(&self, len: usize) -> Result> { if len == 0 { - return Ok(Vec::default()); + Ok(Vec::default()) + } else { + self.check()?; + let mut ret = Vec::::with_capacity(len); + unsafe { + ret.set_len(len); + ret.as_mut_ptr().copy_from_nonoverlapping(self.0, len); + } + Ok(ret) } - self.check()?; - let mut ret = Vec::::with_capacity(len); - unsafe { - ret.set_len(len); - ret.as_mut_ptr().copy_from_nonoverlapping(self.ptr, len); - } - Ok(ret) } } impl UserPtr { - pub fn read_string(&self, len: usize) -> Result { - self.check()?; - let src = unsafe { core::slice::from_raw_parts(self.ptr, len) }; - let s = core::str::from_utf8(src).map_err(|_| Error::InvalidUtf8)?; - Ok(String::from(s)) + // 构造一个从指针指向开始,长度为 `len` 的字符切片。 + /// Forms an utf-8 string slice from a user pointer and a `len`. + pub fn as_str(&self, len: usize) -> Result<&'static str> { + core::str::from_utf8(self.as_slice(len)?).map_err(|_| Error::InvalidUtf8) } - pub fn read_cstring(&self) -> Result { - self.check()?; - let len = unsafe { (0usize..).find(|&i| *self.ptr.add(i) == 0).unwrap() }; - self.read_string(len) + // 从一个 C 风格的零结尾字符串构造一个字符切片。 + /// Forms a zero-terminated string slice from a user pointer to a c style string. + pub fn as_c_str(&self) -> Result<&'static str> { + self.as_str(unsafe { (0usize..).find(|&i| *self.0.add(i) == 0).unwrap() }) } } -impl UserPtr, P> { +impl UserPtr, P> { + // 拷贝一组 C 风格的零结尾字符串到 `String`, + // 并收集到一个 `Vec` 中。 + /// Copies a group of zero-terminated string into [`String`]s, + /// and collect them into a [`Vec`]. pub fn read_cstring_array(&self) -> Result> { self.check()?; - let len = unsafe { - (0usize..) - .find(|&i| self.ptr.add(i).read().is_null()) - .unwrap() - }; - self.read_array(len)? - .into_iter() - .map(|ptr| ptr.read_cstring()) - .collect() + let mut result = Vec::new(); + let mut pptr = self.0; + loop { + let sptr = unsafe { pptr.read() }; + if sptr.is_null() { + break; + } + result.push(sptr.as_c_str()?.into()); + pptr = unsafe { pptr.add(1) }; + } + Ok(result) } } impl UserPtr { + // 用指定的值覆盖指针位置。 + // 旧的值直接被覆盖,不会调用释放逻辑。 + /// Overwrites a memory location with the given `value` + /// **without** reading or dropping the old value. pub fn write(&mut self, value: T) -> Result<()> { self.check()?; - unsafe { - self.ptr.write(value); - } + unsafe { self.0.write(value) }; Ok(()) } + // 类似于写, + // 但指针为空时返回 `Ok(())`。 + /// Same as [`write`](Self::write), + /// but does nothing and returns [`Ok`] when pointer is null. pub fn write_if_not_null(&mut self, value: T) -> Result<()> { - if self.ptr.is_null() { - return Ok(()); + if !self.0.is_null() { + self.write(value) + } else { + Ok(()) } - self.write(value) } + // 写入 `values.len() * size_of` 字节到指针位置。 + // 写入的区间与目标区间不可重叠。 + /// Copies `values.len() * size_of` bytes from `values` to `self`. + /// The source and destination may not overlap. pub fn write_array(&mut self, values: &[T]) -> Result<()> { - if values.is_empty() { - return Ok(()); - } - self.check()?; - unsafe { - self.ptr - .copy_from_nonoverlapping(values.as_ptr(), values.len()); + if !values.is_empty() { + self.check()?; + unsafe { + self.0 + .copy_from_nonoverlapping(values.as_ptr(), values.len()) + }; } Ok(()) } } impl UserPtr { + // 拷贝指定字符串到目标位置并写入一个 `\0` 来模拟 C 风格零结尾字符串。 + /// Copies `s` to `self`, then write a `'\0'` for c style string. pub fn write_cstring(&mut self, s: &str) -> Result<()> { let bytes = s.as_bytes(); self.write_array(bytes)?; - unsafe { - self.ptr.add(bytes.len()).write(0); - } + unsafe { self.0.add(bytes.len()).write(0) }; Ok(()) } } #[derive(Debug)] #[repr(C)] -pub struct IoVec { +pub struct IoVec { /// Starting address ptr: UserPtr, /// Number of bytes to transfer @@ -213,13 +291,13 @@ pub type IoVecOut = IoVec; /// A valid IoVecs request from user #[derive(Debug)] -pub struct IoVecs { +pub struct IoVecs { vec: Vec>, } impl UserInPtr> { pub fn read_iovecs(&self, count: usize) -> Result> { - if self.ptr.is_null() { + if self.0.is_null() { return Err(Error::InvalidPointer); } let vec = self.read_array(count)?; @@ -246,7 +324,7 @@ impl IoVecs

{ pub fn read_to_vec(&self) -> Result> { let mut buf = Vec::new(); for vec in self.vec.iter() { - buf.extend(vec.ptr.read_array(vec.len)?); + buf.extend_from_slice(vec.ptr.as_slice(vec.len)?); } Ok(buf) } @@ -299,20 +377,14 @@ impl IoVec

{ } pub fn as_slice(&self) -> Result<&[u8]> { - if self.ptr.is_null() { - return Err(Error::InvalidVectorAddress); - } - let slice = unsafe { core::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }; - Ok(slice) + self.as_mut_slice().map(|s| &*s) } -} -impl IoVec

{ - pub fn as_mut_slice(&mut self) -> Result<&mut [u8]> { - if self.ptr.is_null() { - return Err(Error::InvalidVectorAddress); + pub fn as_mut_slice(&self) -> Result<&mut [u8]> { + if !self.ptr.is_null() { + Ok(unsafe { core::slice::from_raw_parts_mut(self.ptr.0, self.len) }) + } else { + Err(Error::InvalidVectorAddress) } - let slice = unsafe { core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }; - Ok(slice) } } diff --git a/kernel-hal/src/libos/boot.rs b/kernel-hal/src/libos/boot.rs index 155391a7..2b58657d 100644 --- a/kernel-hal/src/libos/boot.rs +++ b/kernel-hal/src/libos/boot.rs @@ -1,6 +1,5 @@ //! Bootstrap and initialization. -use super::net; use crate::{KernelConfig, KernelHandler, KCONFIG, KHANDLER}; hal_fn_impl! { @@ -19,7 +18,6 @@ hal_fn_impl! { super::macos::register_sigsegv_handler(); } - net::init(); } } } diff --git a/kernel-hal/src/libos/drivers.rs b/kernel-hal/src/libos/drivers.rs index 141132d5..892b50fa 100644 --- a/kernel-hal/src/libos/drivers.rs +++ b/kernel-hal/src/libos/drivers.rs @@ -45,4 +45,10 @@ pub(super) fn init() { crate::console::init_graphic_console(display); } + + #[cfg(feature = "loopback")] + { + use crate::net; + net::init(); + } } diff --git a/kernel-hal/src/libos/net.rs b/kernel-hal/src/libos/net.rs index 206d515f..598d0579 100644 --- a/kernel-hal/src/libos/net.rs +++ b/kernel-hal/src/libos/net.rs @@ -1,3 +1,4 @@ +// May need move to drivers use smoltcp::{ iface::{InterfaceBuilder, NeighborCache, Route, Routes}, phy::{Loopback, Medium}, diff --git a/kernel-hal/src/libos/vm.rs b/kernel-hal/src/libos/vm.rs index bf40ed25..581fbd83 100644 --- a/kernel-hal/src/libos/vm.rs +++ b/kernel-hal/src/libos/vm.rs @@ -95,7 +95,7 @@ mod tests { use super::*; /// A valid virtual address base to mmap. - const VBASE: VirtAddr = 0x2_00000000; + const VBASE: VirtAddr = 0x0002_0000_0000; #[test] fn map_unmap() { diff --git a/linux-object/Cargo.toml b/linux-object/Cargo.toml index 401e2c9d..5ae6eba6 100644 --- a/linux-object/Cargo.toml +++ b/linux-object/Cargo.toml @@ -19,13 +19,24 @@ zircon-object = { path = "../zircon-object", features = ["elf"] } kernel-hal = { path = "../kernel-hal", default-features = false } downcast-rs = { version = "1.2", default-features = false } lazy_static = { version = "1.4", features = ["spin_no_std"] } -rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" } -rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" } -rcore-fs-ramfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" } -rcore-fs-mountfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" } -rcore-fs-devfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" } +rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" } +rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" } +rcore-fs-ramfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" } +rcore-fs-mountfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" } +rcore-fs-devfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" } cfg-if = "1.0" -smoltcp = { git = "https://gitee.com/gcyyfun/smoltcp", rev="043eb60", default-features = false, features = ["alloc","log", "async", "medium-ethernet","proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw"] } +smoltcp = { git = "https://gitee.com/gcyyfun/smoltcp", rev = "043eb60", default-features = false, features = [ + "alloc", + "log", + "async", + "medium-ethernet", + "proto-ipv4", + "proto-igmp", + "socket-icmp", + "socket-udp", + "socket-tcp", + "socket-raw", +] } zcore-drivers = { path = "../drivers", features = ["virtio"] } lock = { git = "https://github.com/DeathWish5/kernel-sync" } diff --git a/linux-object/src/fs/devfs/mod.rs b/linux-object/src/fs/devfs/mod.rs index 34ef7d26..e401a13e 100644 --- a/linux-object/src/fs/devfs/mod.rs +++ b/linux-object/src/fs/devfs/mod.rs @@ -1,7 +1,9 @@ mod fbdev; mod input; mod random; +mod uartdev; pub use fbdev::FbDev; pub use input::{EventDev, MiceDev}; pub use random::RandomINode; +pub use uartdev::UartDev; diff --git a/linux-object/src/fs/devfs/uartdev.rs b/linux-object/src/fs/devfs/uartdev.rs new file mode 100644 index 00000000..d0bd2058 --- /dev/null +++ b/linux-object/src/fs/devfs/uartdev.rs @@ -0,0 +1,109 @@ +use alloc::sync::Arc; +use core::any::Any; +use rcore_fs::vfs::{make_rdev, FileType, FsError, INode, Metadata, PollStatus, Result, Timespec}; +use rcore_fs_devfs::DevFS; +use zcore_drivers::{scheme::UartScheme, DeviceError}; + +/// Uart device. +pub struct UartDev { + index: usize, + port: Arc, + inode_id: usize, +} + +impl UartDev { + pub fn new(index: usize, port: Arc) -> Self { + Self { + index, + port, + inode_id: DevFS::new_inode_id(), + } + } +} + +impl INode for UartDev { + fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { + info!( + "uart read_at: offset={:#x} buf_len={:#x}", + offset, + buf.len() + ); + + let mut len = 0; + for b in buf.iter_mut() { + match self.port.try_recv() { + Ok(Some(b_)) => { + *b = b_; + len += 1; + } + Ok(None) => break, + Err(e) => return Err(convert_error(e)), + } + } + Ok(len) + } + + fn write_at(&self, offset: usize, buf: &[u8]) -> Result { + info!( + "uart write_at: offset={:#x} buf_len={:#x}", + offset, + buf.len() + ); + + for b in buf { + self.port.send(*b).map_err(convert_error)?; + } + Ok(buf.len()) + } + + fn poll(&self) -> Result { + Ok(PollStatus { + // TOKNOW and TODO + read: true, + write: false, + error: false, + }) + } + + fn metadata(&self) -> Result { + Ok(Metadata { + dev: 1, + inode: self.inode_id, + size: 0, + blk_size: 0, + blocks: 0, + atime: Timespec { sec: 0, nsec: 0 }, + mtime: Timespec { sec: 0, nsec: 0 }, + ctime: Timespec { sec: 0, nsec: 0 }, + type_: FileType::CharDevice, + mode: 0o600, // owner read & write + nlinks: 1, + uid: 0, + gid: 0, + rdev: make_rdev(4, self.index), + }) + } + + #[allow(unsafe_code)] + fn io_control(&self, _cmd: u32, _data: usize) -> Result { + warn!("uart ioctl unimplemented"); + Ok(0) + } + + fn as_any_ref(&self) -> &dyn Any { + self + } +} + +fn convert_error(e: DeviceError) -> FsError { + match e { + DeviceError::NotSupported => FsError::NotSupported, + DeviceError::NotReady => FsError::Busy, + DeviceError::InvalidParam => FsError::InvalidParam, + DeviceError::BufferTooSmall + | DeviceError::DmaError + | DeviceError::IoError + | DeviceError::AlreadyExists + | DeviceError::NoResources => FsError::DeviceError, + } +} diff --git a/linux-object/src/fs/mod.rs b/linux-object/src/fs/mod.rs index 2b560dc0..fc90b936 100644 --- a/linux-object/src/fs/mod.rs +++ b/linux-object/src/fs/mod.rs @@ -17,15 +17,18 @@ use downcast_rs::impl_downcast; use kernel_hal::drivers; use rcore_fs::vfs::{FileSystem, FileType, INode, PollStatus, Result}; -use rcore_fs_devfs::special::{NullINode, ZeroINode}; -use rcore_fs_devfs::DevFS; +use rcore_fs_devfs::{ + special::{NullINode, ZeroINode}, + DevFS, +}; use rcore_fs_mountfs::MountFS; use rcore_fs_ramfs::RamFS; use zircon_object::{object::KernelObject, vm::VmObject}; -use self::{devfs::RandomINode, pseudo::Pseudo}; use crate::error::{LxError, LxResult}; use crate::process::LinuxProcess; +use devfs::RandomINode; +use pseudo::Pseudo; pub use file::{File, OpenFlags, SeekFrom}; pub use pipe::Pipe; @@ -128,7 +131,7 @@ pub fn create_root_fs(rootfs: Arc) -> Arc { .expect("failed to mknod /dev/urandom"); if let Some(display) = drivers::all_display().first() { - use self::devfs::{EventDev, FbDev, MiceDev}; + use devfs::{EventDev, FbDev, MiceDev}; // Add framebuffer device at `/dev/fb0` if let Err(e) = devfs_root.add("fb0", Arc::new(FbDev::new(display.clone()))) { @@ -156,6 +159,14 @@ pub fn create_root_fs(rootfs: Arc) -> Arc { } } + // Add uart devices at `/dev/ttyS{i}` + for (i, uart) in drivers::all_uart().as_vec().iter().enumerate() { + let fname = format!("ttyS{}", i); + if let Err(e) = devfs_root.add(&fname, Arc::new(devfs::UartDev::new(i, uart.clone()))) { + warn!("failed to mknod /dev/{}: {:?}", &fname, e); + } + } + // mount DevFS at /dev let dev = root.find(true, "dev").unwrap_or_else(|_| { root.create("dev", FileType::Dir, 0o666) diff --git a/linux-object/src/net/mod.rs b/linux-object/src/net/mod.rs index bf9b2f41..2d1f0322 100644 --- a/linux-object/src/net/mod.rs +++ b/linux-object/src/net/mod.rs @@ -3,6 +3,7 @@ /// missing documentation pub mod socket_address; +use smoltcp::wire::IpEndpoint; pub use socket_address::*; /// missing documentation @@ -113,24 +114,8 @@ impl Drop for GlobalSocketHandle { } } -// #[cfg(feature = "e1000")] use kernel_hal::net::get_net_device; -#[cfg(feature = "loopback")] -use hashbrown::HashMap; -#[cfg(feature = "loopback")] -use kernel_hal::timer_now; -// #[cfg(feature = "loopback")] -// use net_stack::{NetStack, NET_STACK}; -#[cfg(feature = "loopback")] -use smoltcp::time::Instant; - -// /// miss doc -// #[cfg(feature = "loopback")] -// pub fn get_net_stack() -> HashMap> { -// NET_STACK.read().clone() -// } - /// miss doc fn poll_ifaces() { for iface in get_net_device().iter() { @@ -143,67 +128,8 @@ fn poll_ifaces() { } } -// use core::future::Future; -// use core::pin::Pin; -// use core::task::Context; -// use core::task::Poll; - -// use smoltcp::socket::TcpSocket; - // ============= SocketHandle ============= -// ============= Endpoint ============= - -use smoltcp::wire::IpEndpoint; - -/// missing documentation -#[derive(Clone, Debug)] -pub enum Endpoint { - /// missing documentation - Ip(IpEndpoint), - /// missing documentation - LinkLevel(LinkLevelEndpoint), - /// missing documentation - Netlink(NetlinkEndpoint), -} - -/// missing documentation -#[derive(Clone, Debug)] -pub struct LinkLevelEndpoint { - /// missing documentation - pub interface_index: usize, -} - -impl LinkLevelEndpoint { - /// missing documentation - pub fn new(ifindex: usize) -> Self { - LinkLevelEndpoint { - interface_index: ifindex, - } - } -} - -/// missing documentation -#[derive(Clone, Debug)] -pub struct NetlinkEndpoint { - /// missing documentation - pub port_id: u32, - /// missing documentation - pub multicast_groups_mask: u32, -} - -impl NetlinkEndpoint { - /// missing documentation - pub fn new(port_id: u32, multicast_groups_mask: u32) -> Self { - NetlinkEndpoint { - port_id, - multicast_groups_mask, - } - } -} - -// ============= Endpoint ============= - // ============= Rand Port ============= /// !!!! need riscv rng diff --git a/linux-object/src/net/socket_address.rs b/linux-object/src/net/socket_address.rs index 59f39b61..2a8cbf66 100644 --- a/linux-object/src/net/socket_address.rs +++ b/linux-object/src/net/socket_address.rs @@ -5,12 +5,11 @@ use core::mem::size_of; // crate use crate::error::LxError; -use crate::net::Endpoint; +// use crate::net::Endpoint; // smoltcp pub use smoltcp::wire::{IpAddress, Ipv4Address}; -// # use crate::net::*; use kernel_hal::user::{UserInOutPtr, UserOutPtr}; // use numeric_enum_macro::numeric_enum; @@ -91,6 +90,58 @@ pub struct SockAddrPlaceholder { pub data: [u8; 14], } +// ============= Endpoint ============= + +use smoltcp::wire::IpEndpoint; + +/// missing documentation +#[derive(Clone, Debug)] +pub enum Endpoint { + /// missing documentation + Ip(IpEndpoint), + /// missing documentation + LinkLevel(LinkLevelEndpoint), + /// missing documentation + Netlink(NetlinkEndpoint), +} + +/// missing documentation +#[derive(Clone, Debug)] +pub struct LinkLevelEndpoint { + /// missing documentation + pub interface_index: usize, +} + +impl LinkLevelEndpoint { + /// missing documentation + pub fn new(ifindex: usize) -> Self { + LinkLevelEndpoint { + interface_index: ifindex, + } + } +} + +/// missing documentation +#[derive(Clone, Debug)] +pub struct NetlinkEndpoint { + /// missing documentation + pub port_id: u32, + /// missing documentation + pub multicast_groups_mask: u32, +} + +impl NetlinkEndpoint { + /// missing documentation + pub fn new(port_id: u32, multicast_groups_mask: u32) -> Self { + NetlinkEndpoint { + port_id, + multicast_groups_mask, + } + } +} + +// ============= Endpoint ============= + impl From for SockAddr { fn from(endpoint: Endpoint) -> Self { #[allow(warnings)] @@ -112,32 +163,29 @@ impl From for SockAddr { }, _ => unimplemented!("only ipv4"), } - - // unix socket 暂时 未开启 - - // } 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 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"); + unimplemented!("not match"); } } } diff --git a/linux-object/src/net/tcp.rs b/linux-object/src/net/tcp.rs index 8a143b4f..597adda0 100644 --- a/linux-object/src/net/tcp.rs +++ b/linux-object/src/net/tcp.rs @@ -97,57 +97,6 @@ impl TcpSocketState { } } - /// missing documentation - #[cfg(feature = "e1000")] - pub async fn read(&self, data: &mut [u8]) -> (LxResult, Endpoint) { - warn!("tcp read"); - use core::task::Poll; - futures::future::poll_fn(|cx| { - self.with(|s| { - if s.can_recv() { - warn!("can recv ok"); - if let Ok(size) = s.recv_slice(data) { - warn!("--------------Ok size {}", size); - if size > 0 { - let endpoint = s.remote_endpoint(); - Poll::Ready((Ok(size), Endpoint::Ip(endpoint))) - } else { - warn!("wait size > 0"); - s.register_recv_waker(cx.waker()); - s.register_send_waker(cx.waker()); - Poll::Pending - } - } else { - warn!("recv_slice not Ok(size)"); - Poll::Ready(( - Err(LxError::ENOTCONN), - Endpoint::Ip(IpEndpoint::UNSPECIFIED), - )) - } - } else { - error!("can not recv"); - s.register_recv_waker(cx.waker()); - s.register_send_waker(cx.waker()); - Poll::Pending - } - }) - }) - .await - // let net_sockets = get_net_sockets(); - // let mut sockets = net_sockets.lock(); - // let mut socket = sockets.get::(self.handle.0); - // // if socket.may_recv() { - // if let Ok(size) = socket.recv_slice(data) { - // let endpoint = socket.remote_endpoint(); - // return (Ok(size), Endpoint::Ip(endpoint)); - // } else { - // return ( - // Err(LxError::ENOTCONN), - // Endpoint::Ip(IpEndpoint::UNSPECIFIED), - // ); - // } - } - /// missing documentation pub fn write(&self, data: &[u8], _sendto_endpoint: Option) -> SysResult { warn!("tcp write"); @@ -242,194 +191,6 @@ impl TcpSocketState { Err(LxError::EINVAL) } } - /// missing documentation - #[cfg(feature = "e1000")] - pub async fn connect(&self, endpoint: Endpoint) -> SysResult { - warn!("tcp connect"); - // if let Endpoint::Ip(ip) = endpoint { - // let local_port = get_ephemeral_port(); - // self.with(|ss| ss.connect(ip, local_port).map_err(|_| LxError::ENOBUFS))?; - // // use crate::net::IFaceFuture; - // // IFaceFuture { flag: false }.await; - // // warn!("no"); - // // use smoltcp::socket::TcpState; - // // let ret = self.with(|ss| match ss.state() { - // // TcpState::SynSent => { - // // // still connecting - // // warn!("SynSent"); - // // Ok(0) - // // } - // // TcpState::Established => Ok(0), - // // _ => Err(LxError::ECONNREFUSED), - // // }); - - // // Ok(0) - // // socket - // // .connect(ip, local_port) - // // .map_err(|_| LxError::ENOBUFS)?; - - // // use crate::net::ConnectFuture; - // // use smoltcp::socket::SocketRef; - // // let c = ConnectFuture { - // // socket: SocketRef::into_inner(socket), - // // } - // // .await; - // // drop(c); - - // // use core::future::Future; - // // use core::pin::Pin; - // // use core::task::Context; - // use crate::net::IFaceFuture; - // IFaceFuture.await; - // // warn!("no"); - // // IFaceFuture.await; - // // warn!("no"); - // // IFaceFuture.await; - // // warn!("no"); - // // IFaceFuture.await; - // // warn!("no"); - - // use core::task::Poll; - // use smoltcp::socket::TcpState; - // let ret = futures::future::poll_fn(|cx| { - // self.with(|s| { - // // s.connect(ip, local_port).map_err(|_| LxError::ENOBUFS)?; - // match s.state() { - // TcpState::Closed | TcpState::TimeWait => { - // warn!("Closed|TimeWait"); - // Poll::Ready(Err(LxError::ECONNREFUSED)) - // } - // TcpState::Listen => { - // warn!("Listen"); - // Poll::Ready(Err(LxError::ECONNREFUSED)) - // } - // TcpState::SynSent => { - // warn!("SynSent"); - // s.register_recv_waker(cx.waker()); - // s.register_send_waker(cx.waker()); - // // drop(s); - // // #[cfg(feature = "e1000")] - // // poll_ifaces_e1000(); - // // IFaceFuture.await - // Poll::Pending - // } - // TcpState::SynReceived => { - // warn!("SynReceived"); - // s.register_recv_waker(cx.waker()); - // s.register_send_waker(cx.waker()); - // Poll::Pending - // } - // TcpState::Established => { - // warn!("Established"); - // // s.register_recv_waker(cx.waker()); - // // s.register_send_waker(cx.waker()); - // Poll::Ready(Ok(0)) - // // Poll::Pending - // } - // // TcpState::TimeWait => { - // // warn!("TimeWait"); - // // // s.register_recv_waker(cx.waker()); - // // // s.register_send_waker(cx.waker()); - // // Poll::Ready(Ok(0)) - // // // Poll::Pending - // // } - // TcpState::FinWait1 => { - // warn!("------------------------------------FinWait1"); - // // s.register_recv_waker(cx.waker()); - // // s.register_send_waker(cx.waker()); - // Poll::Ready(Ok(0)) - // // Poll::Pending - // } - // TcpState::FinWait2 => { - // warn!("----------------------------------------FinWait2"); - // // s.register_recv_waker(cx.waker()); - // // s.register_send_waker(cx.waker()); - // Poll::Ready(Ok(0)) - // // Poll::Pending - // } - // TcpState::Closing => { - // warn!("-------------------------------------------Closing"); - // // s.register_recv_waker(cx.waker()); - // // s.register_send_waker(cx.waker()); - // Poll::Ready(Ok(0)) - // // Poll::Pending - // } - // TcpState::LastAck => { - // warn!("-------------------------------------------LastAck"); - // // s.register_recv_waker(cx.waker()); - // // s.register_send_waker(cx.waker()); - // Poll::Ready(Ok(0)) - // // Poll::Pending - // } - // _ => { - // warn!("_"); - // Poll::Ready(Err(LxError::ECONNREFUSED)) - // } - // } - // }) - // }) - // .await; - // // #[cfg(feature = "e1000")] - // // poll_ifaces_e1000(); - // IFaceFuture.await; - // warn!("ret {:?}", ret); - // ret - // // Ok(0) - // } else { - // return Err(LxError::EINVAL); - // } - - let net_sockets = get_net_sockets(); - let mut sockets = net_sockets.lock(); - let mut socket = sockets.get::(self.handle.0); - #[allow(warnings)] - if let Endpoint::Ip(ip) = endpoint { - let local_port = get_ephemeral_port(); - socket - .connect(ip, local_port) - .map_err(|_| LxError::ENOBUFS)?; - - // avoid deadlock - drop(socket); - drop(sockets); - #[cfg(feature = "e1000")] - poll_ifaces_e1000(); - #[cfg(feature = "loopback")] - poll_ifaces_loopback(); - // wait for connection result - loop { - warn!("loop"); - let net_sockets = get_net_sockets(); - let mut sockets = net_sockets.lock(); - let socket = sockets.get::(self.handle.0); - use smoltcp::socket::TcpState; - match socket.state() { - TcpState::SynSent => { - // still connecting - warn!("SynSent"); - drop(socket); - drop(sockets); - - #[cfg(feature = "e1000")] - poll_ifaces_e1000(); - #[cfg(feature = "loopback")] - poll_ifaces_loopback(); - } - TcpState::Established => { - warn!("estab"); - break Ok(0); - } - _ => { - break Err(LxError::ECONNREFUSED); - } - } - } - } else { - drop(socket); - drop(sockets); - return Err(LxError::EINVAL); - } - } /// missing documentation fn bind(&mut self, endpoint: Endpoint) -> SysResult { @@ -512,54 +273,6 @@ impl TcpSocketState { drop(sockets); } } - #[cfg(feature = "e1000")] - async fn accept(&mut self) -> Result<(Arc>, Endpoint), LxError> { - let endpoint = self.local_endpoint.ok_or(LxError::EINVAL)?; - - // let net_sockets = get_net_sockets(); - // let mut sockets = net_sockets.lock(); - // let socket = sockets.get::(self.handle.0); - - // if socket.is_active() { - // use crate::net::AcceptFuture; - // AcceptFuture { - // socket: &mut socket, - // } - // .await; - - use core::task::Poll; - futures::future::poll_fn(|cx| { - self.with(|s| { - if s.is_active() { - Poll::Ready(()) - } else { - s.register_recv_waker(cx.waker()); - s.register_send_waker(cx.waker()); - Poll::Pending - } - }) - }) - .await; - let remote_endpoint = self.with(|s| s.remote_endpoint()); - // drop(socket); - let new_socket = { - let rx_buffer = TcpSocketBuffer::new(vec![0; TCP_RECVBUF]); - let tx_buffer = TcpSocketBuffer::new(vec![0; TCP_SENDBUF]); - let mut socket = TcpSocket::new(rx_buffer, tx_buffer); - socket.listen(endpoint).unwrap(); - let net_sockets = get_net_sockets(); - let mut sockets = net_sockets.lock(); - let new_handle = GlobalSocketHandle(sockets.add(socket)); - let old_handle = ::core::mem::replace(&mut self.handle, new_handle); - Arc::new(Mutex::new(TcpSocketState { - // base: KObjectBase::new(), - handle: old_handle, - local_endpoint: self.local_endpoint, - is_listening: false, - })) - }; - return Ok((new_socket, Endpoint::Ip(remote_endpoint))); - } /// missing documentation fn endpoint(&self) -> Option { diff --git a/linux-object/src/net/udp.rs b/linux-object/src/net/udp.rs index 5cdb87bd..4e5c124a 100644 --- a/linux-object/src/net/udp.rs +++ b/linux-object/src/net/udp.rs @@ -122,34 +122,6 @@ impl UdpSocketState { drop(sockets); } } - /// missing documentation - #[cfg(feature = "e1000")] - pub async fn read(&self, data: &mut [u8]) -> (SysResult, Endpoint) { - use core::task::Poll; - futures::future::poll_fn(|cx| { - self.with(|s| { - if s.can_recv() { - if let Ok((size, remote_endpoint)) = s.recv_slice(data) { - let endpoint = remote_endpoint; - warn!("udp read => size : {} , enpoint : {} ", size, endpoint); - Poll::Ready((Ok(size), Endpoint::Ip(endpoint))) - } else { - warn!("recv faill message"); - Poll::Ready(( - Err(LxError::ENOTCONN), - Endpoint::Ip(IpEndpoint::UNSPECIFIED), - )) - } - } else { - warn!("udp can not recv ,because rx buffer is null"); - s.register_recv_waker(cx.waker()); - s.register_send_waker(cx.waker()); - Poll::Pending - } - }) - }) - .await - } /// missing documentation pub fn write(&self, data: &[u8], sendto_endpoint: Option) -> SysResult { diff --git a/linux-object/src/process.rs b/linux-object/src/process.rs index 99f2e213..08ff2b2b 100644 --- a/linux-object/src/process.rs +++ b/linux-object/src/process.rs @@ -1,5 +1,12 @@ //! Linux Process +use crate::{ + error::{LxError, LxResult}, + fs::{File, FileDesc, FileLike, OpenFlags, STDIN, STDOUT}, + ipc::*, + net::Socket, + signal::{Signal as LinuxSignal, SignalAction}, +}; use alloc::{ boxed::Box, string::String, @@ -7,15 +14,12 @@ use alloc::{ vec::Vec, }; use core::sync::atomic::AtomicI32; - -use crate::net::Socket; use hashbrown::HashMap; +use kernel_hal::VirtAddr; use rcore_fs::vfs::{FileSystem, INode}; use smoltcp::socket::SocketHandle; use spin::{Mutex, MutexGuard}; -// use lock::mutex::{Mutex, MutexGuard}; -use kernel_hal::VirtAddr; use zircon_object::{ object::{KernelObject, KoID, Signal}, signal::Futex, @@ -23,10 +27,7 @@ use zircon_object::{ ZxResult, }; -use crate::error::{LxError, LxResult}; -use crate::fs::{File, FileDesc, FileLike, OpenFlags, STDIN, STDOUT}; -use crate::ipc::*; -use crate::signal::{Signal as LinuxSignal, SignalAction}; +pub use rcore_fs::vfs::FsInfo; /// Process extension for linux pub trait ProcessExt { @@ -508,9 +509,12 @@ impl LinuxProcessInner { } fn get_free_hd(&self) -> SocketHandle { - (10000usize..) + (SOCKET_FD..) .map(|i| i.into()) .find(|fd| !self.sockets.contains_key(fd)) .unwrap() } } + +// Temp , TODO warp a struct impl into/from with FileDesc and SocketHandle +const SOCKET_FD: usize = 10000; diff --git a/linux-object/src/thread.rs b/linux-object/src/thread.rs index 23b8baf0..b27682e9 100644 --- a/linux-object/src/thread.rs +++ b/linux-object/src/thread.rs @@ -4,7 +4,6 @@ use crate::process::ProcessExt; use crate::signal::{SignalStack, Sigset}; use alloc::sync::Arc; use kernel_hal::user::{Out, UserOutPtr, UserPtr}; -use kernel_hal::VirtAddr; use spin::{Mutex, MutexGuard}; // use lock::mutex::{Mutex, MutexGuard}; use zircon_object::task::{CurrentThread, Process, Thread}; @@ -59,7 +58,7 @@ impl CurrentThreadExt for CurrentThread { if !clear_child_tid.is_null() { info!("exit: do futex {:?} wake 1", clear_child_tid); clear_child_tid.write(0).unwrap(); - let uaddr = clear_child_tid.as_ptr() as VirtAddr; + let uaddr = clear_child_tid.as_addr(); let futex = self.proc().linux().get_futex(uaddr); futex.wake(1); } diff --git a/linux-object/src/time.rs b/linux-object/src/time.rs index 2874d3b8..c7b0a6bb 100644 --- a/linux-object/src/time.rs +++ b/linux-object/src/time.rs @@ -64,24 +64,33 @@ impl TimeSpec { } } +impl From for TimeSpec { + fn from(t: Timespec) -> Self { + Self { + sec: t.sec as _, + nsec: t.nsec as _, + } + } +} + impl From for Timespec { fn from(t: TimeSpec) -> Self { - Timespec { - sec: t.sec as i64, - nsec: t.nsec as i32, + Self { + sec: t.sec as _, + nsec: t.nsec as _, } } } impl From for Duration { fn from(t: TimeSpec) -> Self { - Duration::new(t.sec as u64, t.nsec as u32) + Self::new(t.sec as _, t.nsec as _) } } impl From for TimeVal { fn from(t: TimeSpec) -> Self { - TimeVal { + Self { sec: t.sec, usec: t.nsec / 1_000, } @@ -111,3 +120,73 @@ pub struct Tms { /// system time of children pub tms_cstime: u64, } + +/// Clock id +#[derive(Debug)] +#[repr(usize)] +pub enum ClockId { + /// missing documentation + ClockRealTime = 0, + /// missing documentation + ClockMonotonic = 1, + /// missing documentation + ClockProcessCpuTimeId = 2, + /// missing documentation + ClockThreadCpuTimeId = 3, + /// missing documentation + ClockMonotonicRaw = 4, + /// missing documentation + ClockRealTimeCoarse = 5, + /// missing documentation + ClockMonotonicCoarse = 6, + /// missing documentation + ClockBootTime = 7, + /// missing documentation + ClockRealTimeAlarm = 8, + /// missing documentation + ClockBootTimeAlarm = 9, +} + +impl From for ClockId { + fn from(t: usize) -> ClockId { + match t { + 0 => ClockId::ClockRealTime, + 1 => ClockId::ClockMonotonic, + 2 => ClockId::ClockProcessCpuTimeId, + 3 => ClockId::ClockThreadCpuTimeId, + 4 => ClockId::ClockMonotonicRaw, + 5 => ClockId::ClockRealTimeCoarse, + 6 => ClockId::ClockMonotonicCoarse, + 7 => ClockId::ClockBootTime, + 8 => ClockId::ClockRealTimeAlarm, + 9 => ClockId::ClockBootTimeAlarm, + _ => unreachable!(), + } + } +} + +/// Clock Flags +#[derive(Debug)] +#[repr(usize)] +pub enum ClockFlags { + /// missing documentation + ZeroFlag = 0, + /// missing documentation + TimerAbsTime = 1, +} + +impl From for ClockFlags { + fn from(t: usize) -> ClockFlags { + match t { + 0 => ClockFlags::ZeroFlag, + 1 => ClockFlags::TimerAbsTime, + _ => unreachable!(), + } + } +} + +/// nanosleep +pub async fn nanosleep(dur: Duration) { + use kernel_hal::thread; + thread::sleep_until(dur).await; +} diff --git a/linux-syscall/Cargo.toml b/linux-syscall/Cargo.toml index 0c18d4f1..abb74806 100644 --- a/linux-syscall/Cargo.toml +++ b/linux-syscall/Cargo.toml @@ -12,10 +12,11 @@ log = "0.4" spin = "0.9" bitflags = "1.3" numeric-enum-macro = "0.2" +static_assertions = "1.1.0" zircon-object = { path = "../zircon-object" } linux-object = { path = "../linux-object" } kernel-hal = { path = "../kernel-hal", default-features = false } -rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" } +rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" } lazy_static = { version = "1.4", features = ["spin_no_std"] } bitvec = { version = "0.22", default-features = false, features = ["alloc"] } lock = { git = "https://github.com/DeathWish5/kernel-sync" } diff --git a/linux-syscall/src/file/dir.rs b/linux-syscall/src/file/dir.rs index ef200801..2577a455 100644 --- a/linux-syscall/src/file/dir.rs +++ b/linux-syscall/src/file/dir.rs @@ -1,4 +1,4 @@ -//! Directory operations +//! Directory operations //! //! - getcwd //! - chdir @@ -28,22 +28,22 @@ impl Syscall<'_> { return Err(LxError::ERANGE); } buf.write_cstring(&cwd)?; - Ok(buf.as_ptr() as usize) + Ok(buf.as_addr()) } /// Change the current directory. /// - `path` – pointer to string with name of path pub fn sys_chdir(&self, path: UserInPtr) -> SysResult { - let path = path.read_cstring()?; + let path = path.as_c_str()?; info!("chdir: path={:?}", path); let proc = self.linux_process(); - let inode = proc.lookup_inode(&path)?; + let inode = proc.lookup_inode(path)?; let info = inode.metadata()?; if info.type_ != FileType::Dir { return Err(LxError::ENOTDIR); } - proc.change_directory(&path); + proc.change_directory(path); Ok(0) } @@ -56,14 +56,14 @@ impl Syscall<'_> { /// create directory relative to directory file descriptor pub fn sys_mkdirat(&self, dirfd: FileDesc, path: UserInPtr, mode: usize) -> SysResult { - let path = path.read_cstring()?; + let path = path.as_c_str()?; // TODO: check pathname 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 proc = self.linux_process(); let inode = proc.lookup_inode_at(dirfd, dir_path, true)?; if inode.find(file_name).is_ok() { @@ -75,10 +75,10 @@ impl Syscall<'_> { /// Remove a directory. /// - path – pointer to string with directory name pub fn sys_rmdir(&self, path: UserInPtr) -> SysResult { - let path = path.read_cstring()?; + let path = path.as_c_str()?; info!("rmdir: path={:?}", path); - let (dir_path, file_name) = split_path(&path); + let (dir_path, file_name) = split_path(path); let proc = self.linux_process(); let dir_inode = proc.lookup_inode(dir_path)?; let file_inode = dir_inode.find(file_name)?; @@ -141,8 +141,8 @@ impl Syscall<'_> { newpath: UserInPtr, flags: usize, ) -> SysResult { - let oldpath = oldpath.read_cstring()?; - let newpath = newpath.read_cstring()?; + let oldpath = oldpath.as_c_str()?; + let newpath = newpath.as_c_str()?; let flags = AtFlags::from_bits_truncate(flags); info!( "linkat: olddirfd={:?}, oldpath={:?}, newdirfd={:?}, newpath={:?}, flags={:?}", @@ -150,8 +150,8 @@ impl Syscall<'_> { ); let proc = self.linux_process(); - let (new_dir_path, new_file_name) = split_path(&newpath); - let inode = proc.lookup_inode_at(olddirfd, &oldpath, true)?; + let (new_dir_path, new_file_name) = split_path(newpath); + let inode = proc.lookup_inode_at(olddirfd, oldpath, true)?; let new_dir_inode = proc.lookup_inode_at(newdirfd, new_dir_path, true)?; new_dir_inode.link(new_file_name, &inode)?; Ok(0) @@ -168,7 +168,7 @@ impl Syscall<'_> { /// remove directory entry relative to directory file descriptor /// The unlinkat() system call operates in exactly the same way as either unlink or rmdir. pub fn sys_unlinkat(&self, dirfd: FileDesc, path: UserInPtr, flags: usize) -> SysResult { - let path = path.read_cstring()?; + let path = path.as_c_str()?; let flags = AtFlags::from_bits_truncate(flags); info!( "unlinkat: dirfd={:?}, path={:?}, flags={:?}", @@ -176,7 +176,7 @@ impl Syscall<'_> { ); let proc = self.linux_process(); - let (dir_path, file_name) = split_path(&path); + let (dir_path, file_name) = split_path(path); let dir_inode = proc.lookup_inode_at(dirfd, dir_path, true)?; let file_inode = dir_inode.find(file_name)?; if file_inode.metadata()?.type_ == FileType::Dir { @@ -199,16 +199,16 @@ impl Syscall<'_> { newdirfd: FileDesc, newpath: UserInPtr, ) -> SysResult { - let oldpath = oldpath.read_cstring()?; - let newpath = newpath.read_cstring()?; + let oldpath = oldpath.as_c_str()?; + let newpath = newpath.as_c_str()?; info!( "renameat: olddirfd={:?}, oldpath={:?}, newdirfd={:?}, newpath={:?}", olddirfd, oldpath, newdirfd, newpath ); let proc = self.linux_process(); - let (old_dir_path, old_file_name) = split_path(&oldpath); - let (new_dir_path, new_file_name) = split_path(&newpath); + let (old_dir_path, old_file_name) = split_path(oldpath); + let (new_dir_path, new_file_name) = split_path(newpath); let old_dir_inode = proc.lookup_inode_at(olddirfd, old_dir_path, false)?; let new_dir_inode = proc.lookup_inode_at(newdirfd, new_dir_path, false)?; old_dir_inode.move_(old_file_name, &new_dir_inode, new_file_name)?; @@ -230,14 +230,14 @@ impl Syscall<'_> { mut base: UserOutPtr, len: usize, ) -> SysResult { - let path = path.read_cstring()?; + let path = path.as_c_str()?; info!( "readlinkat: dirfd={:?}, path={:?}, base={:?}, len={}", dirfd, path, base, len ); let proc = self.linux_process(); - let inode = proc.lookup_inode_at(dirfd, &path, false)?; + let inode = proc.lookup_inode_at(dirfd, path, false)?; if inode.metadata()?.type_ != FileType::SymLink { return Err(LxError::EINVAL); } diff --git a/linux-syscall/src/file/fd.rs b/linux-syscall/src/file/fd.rs index 91f9f3bd..782c3af0 100644 --- a/linux-syscall/src/file/fd.rs +++ b/linux-syscall/src/file/fd.rs @@ -23,7 +23,7 @@ impl Syscall<'_> { mode: usize, ) -> SysResult { let proc = self.linux_process(); - let path = path.read_cstring()?; + let path = path.as_c_str()?; let flags = OpenFlags::from_bits_truncate(flags); info!( "openat: dir_fd={:?}, path={:?}, flags={:?}, mode={:#o}", @@ -31,7 +31,7 @@ impl Syscall<'_> { ); let inode = if flags.contains(OpenFlags::CREATE) { - let (dir_path, file_name) = split_path(&path); + let (dir_path, file_name) = split_path(path); // relative to cwd let dir_inode = proc.lookup_inode_at(dir_fd, dir_path, true)?; match dir_inode.find(file_name) { @@ -47,10 +47,10 @@ impl Syscall<'_> { Err(e) => return Err(LxError::from(e)), } } else { - proc.lookup_inode_at(dir_fd, &path, true)? + proc.lookup_inode_at(dir_fd, path, true)? }; - let file = File::new(inode, flags, path); + let file = File::new(inode, flags, path.into()); let fd = proc.add_file(file)?; Ok(fd.into()) } diff --git a/linux-syscall/src/file/file.rs b/linux-syscall/src/file/file.rs index 013a17e9..695f5ea4 100644 --- a/linux-syscall/src/file/file.rs +++ b/linux-syscall/src/file/file.rs @@ -10,7 +10,7 @@ //! - access, faccessat use super::*; -use linux_object::time::TimeSpec; +use linux_object::{process::FsInfo, time::TimeSpec}; impl Syscall<'_> { /// Reads from a specified file using a file descriptor. Before using this call, @@ -21,11 +21,23 @@ impl Syscall<'_> { pub async fn sys_read(&self, fd: FileDesc, mut base: UserOutPtr, len: usize) -> SysResult { info!("read: fd={:?}, base={:?}, len={:#x}", fd, base, len); let proc = self.linux_process(); - let file_like = proc.get_file_like(fd)?; - let mut buf = vec![0u8; len]; - let len = file_like.read(&mut buf).await?; - base.write_array(&buf[..len])?; - Ok(len) + + // TODO wait a new struct to refactor + if usize::from(fd) >= SOCKET_FD { + let x = usize::from(fd); + let socket = proc.get_socket(x.into())?; + let mut buf = vec![0u8; len]; + let (len, _) = socket.lock().read(&mut buf).await; + let len = len.unwrap_or(0); + base.write_array(&buf[..len])?; + Ok(len) + } else { + let file_like = proc.get_file_like(fd)?; + let mut buf = vec![0u8; len]; + let len = file_like.read(&mut buf).await?; + base.write_array(&buf[..len])?; + Ok(len) + } } /// Writes to a specified file using a file descriptor. Before using this call, @@ -35,11 +47,9 @@ impl Syscall<'_> { /// - len – number of bytes to write pub fn sys_write(&self, fd: FileDesc, base: UserInPtr, len: usize) -> SysResult { info!("write: fd={:?}, base={:?}, len={:#x}", fd, base, len); - let proc = self.linux_process(); - let buf = base.read_array(len)?; - let file_like = proc.get_file_like(fd)?; - let len = file_like.write(&buf)?; - Ok(len) + self.linux_process() + .get_file_like(fd)? + .write(base.as_slice(len)?) } /// read from or write to a file descriptor at a given offset @@ -77,11 +87,9 @@ impl Syscall<'_> { "pwrite: fd={:?}, base={:?}, len={}, offset={}", fd, base, len, offset ); - let proc = self.linux_process(); - let buf = base.read_array(len)?; - let file_like = proc.get_file_like(fd)?; - let len = file_like.write_at(offset, &buf)?; - Ok(len) + self.linux_process() + .get_file_like(fd)? + .write_at(offset, base.as_slice(len)?) } /// works just like read except that multiple buffers are filled. @@ -96,11 +104,23 @@ impl Syscall<'_> { info!("readv: fd={:?}, iov={:?}, count={}", fd, iov_ptr, iov_count); let mut iovs = iov_ptr.read_iovecs(iov_count)?; let proc = self.linux_process(); - let file_like = proc.get_file_like(fd)?; - let mut buf = vec![0u8; iovs.total_len()]; - let len = file_like.read(&mut buf).await?; - iovs.write_from_buf(&buf)?; - Ok(len) + + // TODO wait a new struct to refactor + if usize::from(fd) >= SOCKET_FD { + let x = usize::from(fd); + let socket = proc.get_socket(x.into())?; + let mut buf = vec![0u8; iovs.total_len()]; + let (len, _) = socket.lock().read(&mut buf).await; + let len = len.unwrap(); + iovs.write_from_buf(&buf)?; + Ok(len) + } else { + let file_like = proc.get_file_like(fd)?; + let mut buf = vec![0u8; iovs.total_len()]; + let len = file_like.read(&mut buf).await?; + iovs.write_from_buf(&buf)?; + Ok(len) + } } /// works just like write except that multiple buffers are written out. @@ -119,9 +139,18 @@ impl Syscall<'_> { let iovs = iov_ptr.read_iovecs(iov_count)?; let buf = iovs.read_to_vec()?; let proc = self.linux_process(); - let file_like = proc.get_file_like(fd)?; - let len = file_like.write(&buf)?; - Ok(len) + + // TODO wait a new struct to refactor + if usize::from(fd) >= SOCKET_FD { + let x = usize::from(fd); + let socket = proc.get_socket(x.into())?; + let len = socket.lock().write(&buf, None)?; + Ok(len) + } else { + let file_like = proc.get_file_like(fd)?; + let len = file_like.write(&buf)?; + Ok(len) + } } /// repositions the offset of the open file associated with the file descriptor fd @@ -147,10 +176,9 @@ impl Syscall<'_> { /// cause the regular file named by path to be truncated to a size of precisely length bytes. pub fn sys_truncate(&self, path: UserInPtr, len: usize) -> SysResult { - let path = path.read_cstring()?; + let path = path.as_c_str()?; info!("truncate: path={:?}, len={}", path, len); - let proc = self.linux_process(); - proc.lookup_inode(&path)?.resize(len)?; + self.linux_process().lookup_inode(path)?.resize(len)?; Ok(0) } @@ -291,8 +319,17 @@ impl Syscall<'_> { fd, request, arg1, arg2, arg3 ); let proc = self.linux_process(); - let file_like = proc.get_file_like(fd)?; - file_like.ioctl(request, arg1, arg2, arg3) + + // TODO wait a new struct to refactor + if usize::from(fd) >= SOCKET_FD { + let f = usize::from(fd); + let socket = proc.get_socket(f.into())?; + let x = socket.lock(); + x.ioctl(request, arg1, arg2, arg3) + } else { + let file_like = proc.get_file_like(fd)?; + file_like.ioctl(request, arg1, arg2, arg3) + } } /// Manipulate a file descriptor. @@ -301,43 +338,52 @@ impl Syscall<'_> { pub fn sys_fcntl(&self, fd: FileDesc, cmd: usize, arg: usize) -> SysResult { info!("fcntl: fd={:?}, cmd={:x}, arg={}", fd, cmd, arg); let proc = self.linux_process(); - let file_like = proc.get_file_like(fd)?; - if let Ok(cmd) = FcntlCmd::try_from(cmd) { - match cmd { - FcntlCmd::GETFD => Ok(file_like.flags().close_on_exec() as usize), - FcntlCmd::SETFD => { - let mut flags = file_like.flags(); - if (arg & 1) != 0 { - flags |= OpenFlags::CLOEXEC; - } else { - flags -= OpenFlags::CLOEXEC; - } - file_like.set_flags(flags)?; - Ok(0) - } - FcntlCmd::GETFL => Ok(file_like.flags().bits()), - FcntlCmd::SETFL => { - file_like.set_flags(OpenFlags::from_bits_truncate(arg))?; - Ok(0) - } - FcntlCmd::DUPFD | FcntlCmd::DUPFD_CLOEXEC => { - let new_fd = proc.get_free_fd_from(arg); - self.sys_dup2(fd, new_fd)?; - let dup = proc.get_file_like(new_fd)?; - let mut flags = dup.flags(); - if cmd == FcntlCmd::DUPFD_CLOEXEC { - flags |= OpenFlags::CLOEXEC; - } else { - flags -= OpenFlags::CLOEXEC; - } - dup.set_flags(flags)?; - Ok(new_fd.into()) - } - _ => Err(LxError::EINVAL), - } + // TODO wait a new struct to refactor + if usize::from(fd) >= SOCKET_FD { + let f = usize::from(fd); + let socket = proc.get_socket(f.into())?; + let x = socket.lock(); + x.fcntl(cmd, arg) } else { - Err(LxError::EINVAL) + let file_like = proc.get_file_like(fd)?; + + if let Ok(cmd) = FcntlCmd::try_from(cmd) { + match cmd { + FcntlCmd::GETFD => Ok(file_like.flags().close_on_exec() as usize), + FcntlCmd::SETFD => { + let mut flags = file_like.flags(); + if (arg & 1) != 0 { + flags |= OpenFlags::CLOEXEC; + } else { + flags -= OpenFlags::CLOEXEC; + } + file_like.set_flags(flags)?; + Ok(0) + } + FcntlCmd::GETFL => Ok(file_like.flags().bits()), + FcntlCmd::SETFL => { + file_like.set_flags(OpenFlags::from_bits_truncate(arg))?; + Ok(0) + } + FcntlCmd::DUPFD | FcntlCmd::DUPFD_CLOEXEC => { + let new_fd = proc.get_free_fd_from(arg); + self.sys_dup2(fd, new_fd)?; + let dup = proc.get_file_like(new_fd)?; + let mut flags = dup.flags(); + if cmd == FcntlCmd::DUPFD_CLOEXEC { + flags |= OpenFlags::CLOEXEC; + } else { + flags -= OpenFlags::CLOEXEC; + } + dup.set_flags(flags)?; + Ok(new_fd.into()) + } + _ => Err(LxError::EINVAL), + } + } else { + Err(LxError::EINVAL) + } } } @@ -356,7 +402,7 @@ impl Syscall<'_> { flags: usize, ) -> SysResult { // TODO: check permissions based on uid/gid - let path = path.read_cstring()?; + let path = path.as_c_str()?; let flags = AtFlags::from_bits_truncate(flags); info!( "faccessat: dirfd={:?}, path={:?}, mode={:#o}, flags={:?}", @@ -364,7 +410,7 @@ impl Syscall<'_> { ); let proc = self.linux_process(); let follow = !flags.contains(AtFlags::SYMLINK_NOFOLLOW); - let _inode = proc.lookup_inode_at(dirfd, &path, follow)?; + let _inode = proc.lookup_inode_at(dirfd, path, follow)?; Ok(0) } @@ -395,7 +441,7 @@ impl Syscall<'_> { info!("futimens: fd: {:?}, times: {:?}", fd, times); proc.get_file(fd)?.inode() } else { - let pathname = pathname.read_cstring()?; + let pathname = pathname.as_c_str()?; info!( "utimensat: dirfd: {:?}, pathname: {:?}, times: {:?}, flags: {:#x}", dirfd, pathname, times, flags @@ -407,7 +453,7 @@ impl Syscall<'_> { } else { return Err(LxError::EINVAL); }; - proc.lookup_inode_at(dirfd, &pathname[..], follow)? + proc.lookup_inode_at(dirfd, pathname, follow)? }; let mut metadata = inode.metadata()?; if times[0].nsec != UTIME_OMIT { @@ -431,10 +477,88 @@ impl Syscall<'_> { inode.set_metadata(&metadata)?; Ok(0) } + + /// Get filesystem statistics + /// (see [linux man statfs(2)](https://man7.org/linux/man-pages/man2/statfs.2.html)). + /// + /// The `statfs` system call returns information about a mounted filesystem. + /// `path` is the pathname of **any file** within the mounted filesystem. + /// `buf` is a pointer to a `StatFs` structure. + pub fn sys_statfs(&self, path: UserInPtr, mut buf: UserOutPtr) -> SysResult { + let path = path.as_c_str()?; + info!("statfs: path={:?}, buf={:?}", path, buf); + + // TODO + // 现在 `path` 没用到,因为没实现真正的挂载,不可能搞一个非主要文件系统的路径。 + // 实现挂载之后,要用 `path` 分辨路径在哪个文件系统里,根据对应文件系统的特性返回统计信息。 + // (以及根据挂载选项填写 `StatFs::f_flags`!) + + let info = self.linux_process().root_inode().fs().info(); + buf.write(info.into())?; + Ok(0) + } + + /// Get filesystem statistics + /// (see [linux man statfs(2)](https://man7.org/linux/man-pages/man2/statfs.2.html)). + /// + /// The `fstatfs` system call returns information about a mounted filesystem. + /// `fd` is the descriptor referencing an open file. + /// `buf` is a pointer to a `StatFs` structure. + pub fn sys_fstatfs(&self, fd: FileDesc, mut buf: UserOutPtr) -> SysResult { + info!("statfs: fd={:?}, buf={:?}", fd, buf); + + let info = self.linux_process().get_file(fd)?.inode().fs().info(); + buf.write(info.into())?; + Ok(0) + } } const F_LINUX_SPECIFIC_BASE: usize = 1024; +/// The file system statistics struct defined in linux +/// (see [linux man statfs(2)](https://man7.org/linux/man-pages/man2/statfs.2.html)). +#[repr(C)] +pub struct StatFs { + f_type: i64, + f_bsize: i64, + f_blocks: u64, + f_bfree: u64, + f_bavail: u64, + f_files: u64, + f_ffree: u64, + f_fsid: (i32, i32), + f_namelen: isize, + f_frsize: isize, + f_flags: isize, + f_spare: [isize; 4], +} + +// 保证 `StatFs` 的定义和常见的 linux 一致 +static_assertions::const_assert_eq!(120, core::mem::size_of::()); + +impl From for StatFs { + fn from(info: FsInfo) -> Self { + StatFs { + // TODO 文件系统的魔数,需要 rcore-fs 提供一个渠道获取 + // 但是这个似乎并没有什么用处,新的 vfs 相关函数都去掉了,也许永远填个常数就好了 + f_type: 0, + f_bsize: info.bsize as _, + f_blocks: info.blocks as _, + f_bfree: info.bfree as _, + f_bavail: info.bavail as _, + f_files: info.files as _, + f_ffree: info.ffree as _, + // 一个由 OS 决定的号码,用于区分文件系统 + f_fsid: (0, 0), + f_namelen: info.namemax as _, + f_frsize: info.frsize as _, + // TODO 需要先实现挂载 + f_flags: 0, + f_spare: [0; 4], + } + } +} + numeric_enum_macro::numeric_enum! { #[repr(usize)] #[allow(non_camel_case_types)] @@ -461,3 +585,6 @@ numeric_enum_macro::numeric_enum! { DUPFD_CLOEXEC = F_LINUX_SPECIFIC_BASE + 6, } } + +// Temp , TODO warp a struct impl into/from with FileDesc and SocketHandle +const SOCKET_FD: usize = 10000; diff --git a/linux-syscall/src/file/poll.rs b/linux-syscall/src/file/poll.rs index 82e0aa8a..ef08715c 100644 --- a/linux-syscall/src/file/poll.rs +++ b/linux-syscall/src/file/poll.rs @@ -307,10 +307,8 @@ impl FdSet { if len > MAX_FDSET_SIZE { return Err(LxError::EINVAL); } - let slice = addr.read_array(len)?; - // save the fdset, and clear it - let origin = BitVec::from_vec(slice); + let origin = BitVec::from_slice(addr.as_slice(len)?).unwrap(); let mut vec0 = Vec::::new(); vec0.resize(len, 0); addr.write_array(&vec0)?; diff --git a/linux-syscall/src/file/stat.rs b/linux-syscall/src/file/stat.rs index baf090f0..98c23c5c 100644 --- a/linux-syscall/src/file/stat.rs +++ b/linux-syscall/src/file/stat.rs @@ -26,10 +26,9 @@ impl Syscall<'_> { /// - `stat_ptr` – pointer to stat buffer pub fn sys_fstat(&self, fd: FileDesc, mut stat_ptr: UserOutPtr) -> SysResult { info!("fstat: fd={:?}, stat_ptr={:?}", fd, stat_ptr); - let proc = self.linux_process(); - let file = proc.get_file(fd)?; - let stat = Stat::from(file.metadata()?); - stat_ptr.write(stat)?; + + let meta = self.linux_process().get_file(fd)?.metadata()?; + stat_ptr.write(meta.into())?; Ok(0) } @@ -41,18 +40,17 @@ impl Syscall<'_> { mut stat_ptr: UserOutPtr, flags: usize, ) -> SysResult { - let path = path.read_cstring()?; + let path = path.as_c_str()?; let flags = AtFlags::from_bits_truncate(flags); info!( "fstatat: dirfd={:?}, path={:?}, stat_ptr={:?}, flags={:?}", dirfd, path, stat_ptr, flags ); - let proc = self.linux_process(); let follow = !flags.contains(AtFlags::SYMLINK_NOFOLLOW); - let inode = proc.lookup_inode_at(dirfd, &path, follow)?; - let stat = Stat::from(inode.metadata()?); - stat_ptr.write(stat)?; + let inode = self.linux_process().lookup_inode_at(dirfd, path, follow)?; + let stat = inode.metadata()?; + stat_ptr.write(stat.into())?; Ok(0) } @@ -65,21 +63,21 @@ impl Syscall<'_> { } #[cfg(not(target_arch = "mips"))] -use linux_object::fs::vfs::Timespec; +use linux_object::time::TimeSpec; #[cfg(target_arch = "mips")] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct Timespec { +pub struct TimeSpec { pub sec: i32, pub nsec: i32, } #[cfg(target_arch = "mips")] -impl From for Timespec { - fn from(t: Timespec) -> Self { - Timespec { +impl From for TimeSpec { + fn from(t: TimeSpec) -> Self { + TimeSpec { sec: t.sec as _, - nsec: t.nsec, + nsec: t.nsec as _, } } } @@ -113,11 +111,11 @@ pub struct Stat { blocks: u64, /// last access time - atime: Timespec, + atime: TimeSpec, /// last modification time - mtime: Timespec, + mtime: TimeSpec, /// last status change time - ctime: Timespec, + ctime: TimeSpec, } #[cfg(target_arch = "mips")] @@ -147,11 +145,11 @@ pub struct Stat { size: u64, /// last access time - atime: Timespec, + atime: TimeSpec, /// last modification time - mtime: Timespec, + mtime: TimeSpec, /// last status change time - ctime: Timespec, + ctime: TimeSpec, /// blocksize for filesystem I/O blksize: u32, @@ -192,27 +190,26 @@ pub struct Stat { blocks: u64, /// last access time - atime: Timespec, + atime: TimeSpec, /// last modification time - mtime: Timespec, + mtime: TimeSpec, /// last status change time - ctime: Timespec, + ctime: TimeSpec, } impl From for Stat { - #[allow(clippy::useless_conversion)] fn from(info: Metadata) -> Self { Stat { - dev: info.dev as u64, - ino: info.inode as u64, - mode: StatMode::from_type_mode(info.type_, info.mode as u16), + dev: info.dev as _, + ino: info.inode as _, + mode: StatMode::from_type_mode(info.type_, info.mode as _), nlink: info.nlinks as _, - uid: info.uid as u32, - gid: info.gid as u32, - rdev: info.rdev as u64, - size: info.size as u64, + uid: info.uid as _, + gid: info.gid as _, + rdev: info.rdev as _, + size: info.size as _, blksize: info.blk_size as _, - blocks: info.blocks as u64, + blocks: info.blocks as _, atime: info.atime.into(), mtime: info.mtime.into(), ctime: info.ctime.into(), diff --git a/linux-syscall/src/ipc.rs b/linux-syscall/src/ipc.rs index 2471df75..fe915a46 100644 --- a/linux-syscall/src/ipc.rs +++ b/linux-syscall/src/ipc.rs @@ -1,4 +1,3 @@ -//! Syscalls of Inter-Process Communication #![allow(dead_code)] use bitflags::*; @@ -9,8 +8,55 @@ use zircon_object::vm::*; use super::*; +/// Syscalls of inter-process communication and System V semaphore Set operation. +/// +/// # Menu +/// +/// - [`semget`](Self::sys_semget) +/// - [`semop`](Self::sys_semop) +/// - [`semctl`](Self::sys_semctl) +/// - [`shmget`](Self::sys_shmget) +/// - [`shmat`](Self::sys_shmat) +/// - [`shmdt`](Self::sys_shmdt) +/// - [`shmctl`](Self::sys_shmctl) impl Syscall<'_> { - /// returns the semaphore set identifier associated with the argument key + /// Get a System V semaphore set identifier + /// (see [linux man semget(2)](https://www.man7.org/linux/man-pages/man2/semget.2.html)). + /// + /// The `sys_semget` system call returns + /// the System V semaphore set identifier associated with the argument `key`. + /// It may be used either to obtain the identifier of a previously created semaphore set + /// (when `flags` is zero and `key` is not zero), + /// or to create a new set. + /// + /// A new set of `nsems` (number of semaphores) semaphores is created if `key` is zero + /// or if no existing semaphore set is associated with `key` and `IpcGetFlag::CREAT` is specified in `semflg`. + /// + /// If `flags` specifies both `IpcGetFlag::CREAT` and `IpcGetFlag::EXCLUSIVE` + /// and a semaphore set already exists for key, then `sys_semget` fails with [`EEXIST`](LxError::EEXIST). + /// (This is analogous to the effect of the combination `OpenFlags::CREATE | OpenFlags::EXCLUSIVE` for [`sys_open`](Self::sys_open).) + /// + /// Upon creation, the least significant 9 bits of the argument `flags` define + /// the permissions (for owner, group, and others) for the semaphore set. + /// These bits have the same format, and the same meaning, as the `mode` argument of [`sys_open`](Self::sys_open) + /// (though the execute permissions are not meaningful for semaphores, + /// and write permissions mean permission to alter semaphore values). + /// + /// When creating a new semaphore set, `sys_semget` initializes the set's associated data structure, + /// semid_ds (see [`sys_semctl`](Self::sys_semctl)), as follows: + /// + /// - sem_perm.cuid and sem_perm.uid are set to the effective user ID of the calling process. + /// - sem_perm.cgid and sem_perm.gid are set to the effective group ID of the calling process. + /// - The least significant 9 bits of sem_perm.mode are set to the least significant 9 bits of `flags`. + /// - sem_nsems is set to the value of nsems. + /// - sem_otime is set to 0. + /// - sem_ctime is set to the current time. + /// + /// The argument nsems can be 0 (a don't care) when a semaphore set is not being created. + /// Otherwise, nsems must be greater than 0 and + /// less than or equal to the maximum number of semaphores per semaphore set (SEMMSL, constant 256). + /// + /// If the semaphore set already exists, the permissions are verified. pub fn sys_semget(&self, key: usize, nsems: usize, flags: usize) -> SysResult { info!("semget: key: {} nsems: {} flags: {:#x}", key, nsems, flags); @@ -26,19 +72,40 @@ impl Syscall<'_> { Ok(id) } - /// semaphore operations + /// System V semaphore operations + /// (see [linux man semop(2)](https://www.man7.org/linux/man-pages/man2/semop.2.html)). /// - /// performs operations on selected semaphores in the set indicated by semid + /// `semop` performs operations on selected semaphores in the set indicated by `id`. + /// An array `[SemBuf; num_ops]` pointed to by `ops` specifies an operation to be performed on a single semaphore. + /// The declaration of `SemBuf` is like this: + /// + /// ```rust + /// struct SemBuf { + /// num: u16, + /// op: i16, + /// flags: i16, + /// } + /// ``` + /// + /// Flags recognized in `SemBuf::flags` are `SemFlags::IPC_NOWAIT` and `SemFlags::SEM_UNDO`. + /// If an operation specifies `SEM_UNDO`, it will be automatically undone when the process terminates. + /// + /// Each operation is performed on the `SemBuf::num`-th semaphore of the semaphore set, + /// where the first semaphore of the set is numbered 0. + /// There are two types of operation, distinguished by the value of `SemBuf::op`. + /// + /// - If `op` is +1, see [`acquire`](linux_object::sync::Semaphore::acquire). + /// - If `op` is -1, see [`release`](linux_object::sync::Semaphore::release). pub async fn sys_semop(&self, id: usize, ops: UserInPtr, num_ops: usize) -> SysResult { info!("semop: id: {}", id); - let ops = ops.read_array(num_ops)?; + let ops = ops.as_slice(num_ops)?; let sem_array = self .linux_process() .semaphores_get(id) .ok_or(LxError::EINVAL)?; sem_array.otime(); - for &SemBuf { num, op, flags } in ops.iter() { + for &SemBuf { num, op, flags } in ops { let flags = SemFlags::from_bits_truncate(flags); if flags.contains(SemFlags::IPC_NOWAIT) { unimplemented!("Semaphore: semop.IPC_NOWAIT"); @@ -58,10 +125,15 @@ impl Syscall<'_> { Ok(0) } - /// semaphore control operations + /// System V semaphore control operations + /// (see [linux man semctl(2)](https://www.man7.org/linux/man-pages/man2/semctl.2.html)). /// - /// performs the control operation specified by cmd on the semaphore set identified by semid, - /// or on the semnum-th semaphore of that set. + /// `semctl` performs the control operation specified by cmd + /// on the System V semaphore set identified by `id`, + /// or on the `num`-th semaphore of that set + /// (The semaphores in a set are numbered starting at 0). + /// + /// TODO pub fn sys_semctl(&self, id: usize, num: usize, cmd: usize, arg: usize) -> SysResult { info!( "semctl: id: {}, num: {}, cmd: {} arg: {:#x}", @@ -119,9 +191,12 @@ impl Syscall<'_> { } } - /// allocates a shared memory segment + /// Allocates a System V shared memory segment + /// (see [linux man shmget(2)](https://www.man7.org/linux/man-pages/man2/shmget.2.html)). /// - /// returns the identifier of the shared memory segment associated with the value of the argument key + /// `shmget` returns the identifier of the System V shared memory segment + /// associated with the value of the argument key. + /// Differ from linux, this syscall always create a new set. pub fn sys_shmget(&self, key: usize, size: usize, shmflg: usize) -> SysResult { info!( "shmget: key: {}, size: {}, shmflg: {:#x}", @@ -138,7 +213,13 @@ impl Syscall<'_> { Ok(id) } - /// attaches the shared memory segment identified by shmid to the address space of the calling process. + /// System V shared memory operations + /// (see [linux man shmat(2)](https://www.man7.org/linux/man-pages/man2/shmat.2.html)). + /// + /// `shmat` attaches the System V shared memory segment identified by `id` + /// to the address space of the calling process. + /// The attaching address is specified by `addr`. + /// If `addr` is zero, the system chooses a suitable page-aligned address to attach the segment. pub fn sys_shmat(&self, id: usize, mut addr: VirtAddr, shmflg: usize) -> SysResult { let mut shm_identifier = self.linux_process().shm_get(id).ok_or(LxError::EINVAL)?; @@ -173,8 +254,13 @@ impl Syscall<'_> { Ok(addr) } - /// detaches the shared memory segment located at the address specified by shmaddr + /// System V shared memory operations + /// (see [linux man shmdt(2)](https://www.man7.org/linux/man-pages/man2/shmdt.2.html)). + /// + /// `shmdt` detaches the shared memory segment located at the address specified by `addr` /// from the address space of the calling process. + /// The to-be-detached segment must be currently attached with `addr` + /// equal to the value returned by the attaching [`sys_shmat`](Self::sys_shmat) call. pub fn sys_shmdt(&self, id: usize, addr: VirtAddr, shmflg: usize) -> SysResult { info!( "shmdt: id = {}, addr = {:#x}, flag = {:#x}", @@ -193,7 +279,8 @@ impl Syscall<'_> { Ok(0) } - /// shared memory control + /// System V shared memory operations + /// (see [linux man shmctl(2)](https://www.man7.org/linux/man-pages/man2/shmctl.2.html)). /// /// performs the control operation specified by cmd on the shared memory segment whose identifier is given in id pub fn sys_shmctl(&self, id: usize, cmd: usize, buffer: usize) -> SysResult { diff --git a/linux-syscall/src/lib.rs b/linux-syscall/src/lib.rs index d4777c8f..30a799f9 100644 --- a/linux-syscall/src/lib.rs +++ b/linux-syscall/src/lib.rs @@ -282,8 +282,11 @@ impl Syscall<'_> { // Sys::SOCKETPAIR => self.unimplemented("socketpair", Err(LxError::EACCES)), // file system - Sys::STATFS => self.unimplemented("statfs", Err(LxError::EACCES)), - Sys::FSTATFS => self.unimplemented("fstatfs", Err(LxError::EACCES)), + Sys::STATFS => self.sys_statfs( + self.into_in_userptr(a0).unwrap(), + self.into_out_userptr(a1).unwrap(), + ), + Sys::FSTATFS => self.sys_fstatfs(a0.into(), self.into_out_userptr(a1).unwrap()), Sys::SYNC => self.sys_sync(), Sys::MOUNT => self.unimplemented("mount", Err(LxError::EACCES)), Sys::UMOUNT2 => self.unimplemented("umount2", Err(LxError::EACCES)), @@ -318,6 +321,7 @@ impl Syscall<'_> { // schedule Sys::SCHED_YIELD => self.unimplemented("yield", Ok(0)), Sys::SCHED_GETAFFINITY => self.unimplemented("sched_getaffinity", Ok(0)), + Sys::SCHED_SETAFFINITY => self.unimplemented("sched_setaffinity", Ok(0)), // socket Sys::SOCKET => self.sys_socket(a0, a1, a2), @@ -348,19 +352,22 @@ impl Syscall<'_> { Sys::SHUTDOWN => self.sys_shutdown(a0, a1), Sys::BIND => self.sys_bind(a0, self.into_in_userptr(a1).unwrap(), a2), Sys::LISTEN => self.sys_listen(a0, a1), + Sys::GETSOCKNAME => self.sys_getsockname( a0, self.into_out_userptr(a1).unwrap(), self.into_inout_userptr(a2).unwrap(), ), - Sys::GETPEERNAME => { - self.unimplemented("sys_getpeername(a0, a1.into(), a2.into()),", Ok(0)) - } + Sys::GETPEERNAME => self.sys_getpeername( + a0, + self.into_out_userptr(a1).unwrap(), + self.into_inout_userptr(a2).unwrap(), + ), Sys::SETSOCKOPT => { self.sys_setsockopt(a0, a1, a2, self.into_in_userptr(a3).unwrap(), a4) } Sys::GETSOCKOPT => { - self.unimplemented("sys_getsockopt(a0, a1, a2, a3.into(), a4.into()),", Ok(0)) + self.sys_getsockopt(a0, a1, a2, self.into_out_userptr(a3).unwrap(), a4) } // process @@ -395,12 +402,22 @@ impl Syscall<'_> { // time Sys::NANOSLEEP => self.sys_nanosleep(self.into_in_userptr(a0).unwrap()).await, + Sys::CLOCK_NANOSLEEP => { + self.sys_clock_nanosleep( + a0, + a1, + self.into_in_userptr(a2).unwrap(), + self.into_out_userptr(a3).unwrap(), + ) + .await + } Sys::SETITIMER => self.unimplemented("setitimer", Ok(0)), Sys::GETTIMEOFDAY => self.sys_gettimeofday( self.into_out_userptr(a0).unwrap(), self.into_in_userptr(a1).unwrap(), ), Sys::CLOCK_GETTIME => self.sys_clock_gettime(a0, self.into_out_userptr(a1).unwrap()), + Sys::CLOCK_GETRES => self.unimplemented("clock_getres", Ok(0)), // sem #[cfg(not(target_arch = "mips"))] diff --git a/linux-syscall/src/net.rs b/linux-syscall/src/net.rs index 253df0f0..7968923b 100644 --- a/linux-syscall/src/net.rs +++ b/linux-syscall/src/net.rs @@ -82,11 +82,26 @@ impl Syscall<'_> { "sys_setsockopt : sockfd : {:?}, level : {:?}, optname : {:?}, optval : {:?} , optlen : {:?}", sockfd, level, optname,optval,optlen ); - let proc = self.linux_process(); - let data = optval.read_array(optlen)?; - let socket = proc.get_socket(sockfd.into())?; - let len = socket.lock().setsockopt(level, optname, &data)?; - Ok(len) + self.linux_process() + .get_socket(sockfd.into())? + .lock() + .setsockopt(level, optname, optval.as_slice(optlen)?) + } + + /// net getsockopt + pub fn sys_getsockopt( + &mut self, + sockfd: usize, + level: usize, + optname: usize, + optval: UserOutPtr, + optlen: usize, + ) -> SysResult { + warn!( + "sys_getsockopt : sockfd : {:?}, level : {:?}, optname : {:?}, optval : {:?} , optlen : {:?}", + sockfd, level, optname,optval,optlen + ); + Ok(0) } /// net setsockopt @@ -103,8 +118,6 @@ impl Syscall<'_> { "sys_sendto : sockfd : {:?}, buffer : {:?}, length : {:?}, flags : {:?} , optlen : {:?}, addrlen : {:?}", sockfd,buffer,length,flags,dest_addr,addrlen ); - let proc = self.linux_process(); - let data = buffer.read_array(length)?; let endpoint = if dest_addr.is_null() { None } else { @@ -112,8 +125,9 @@ impl Syscall<'_> { let endpoint = sockaddr_to_endpoint(dest_addr.read()?, addrlen)?; Some(endpoint) }; + let proc = self.linux_process(); let socket = proc.get_socket(sockfd.into())?; - let len = socket.lock().write(&data, endpoint)?; + let len = socket.lock().write(buffer.as_slice(length)?, endpoint)?; Ok(len) } diff --git a/linux-syscall/src/task.rs b/linux-syscall/src/task.rs index 4c9325b7..45e04b67 100644 --- a/linux-syscall/src/task.rs +++ b/linux-syscall/src/task.rs @@ -1,26 +1,62 @@ -//! Syscalls for process -//! -//! - fork -//! - vfork -//! - clone -//! - wait4 -//! - execve -//! - gettid -//! - getpid -//! - getppid - use super::*; use core::fmt::Debug; +use alloc::string::ToString; use bitflags::bitflags; use kernel_hal::context::UserContextField; use linux_object::thread::{CurrentThreadExt, ThreadExt}; -use linux_object::time::TimeSpec; +// use linux_object::time::TimeSpec; use linux_object::{fs::INodeExt, loader::LinuxElfLoader}; +/// Syscalls for process. +/// +/// # Menu +/// +/// - [`fork`](Self::sys_fork) +/// - [`vfork`](Self::sys_vfork) +/// - [`clone`](Self::sys_clone) +/// - [`wait4`](Self::sys_wait4) +/// - [`execve`](Self::sys_execve) +/// - [`gettid`](Self::sys_gettid) +/// - [`getpid`](Self::sys_getpid) +/// - [`getppid`](Self::sys_getppid) +/// - [`exit`](Self::sys_exit) +/// - [`exit_group`](Self::sys_exit_group) +/// - [`nanosleep`](Self::sys_nanosleep) +/// - [`set_tid_address`](Self::sys_set_tid_address) impl Syscall<'_> { - /// Fork the current process. Return the child's PID. + /// `fork` creates a new process by duplicating the calling process + /// (see [linux man fork(2)](https://www.man7.org/linux/man-pages/man2/fork.2.html)). + /// The new process is referred to as the child process. + /// The calling process is referred to as the parent process. + /// + /// The child process and the parent process run in separate memory spaces. + /// At the time of `fork` both memory spaces have the same content. + /// Memory writes, file mappings ([`Self::sys_mmap`]) and unmappings ([`Self::sys_munmap`]) + /// performed by one of the processes do not affect the other. + /// + /// The child process is an exact duplicate of the parent process except for the following points: + /// + /// - The child has its own unique process ID, and this PID does not match the ID of any existing process. + /// - The child's parent process ID is the same as the parent's process ID. + /// - Process resource utilizations ([`Self::sys_getrusage`]) and CPU time counters ([`Self::sys_times`]) are reset to zero in the child. + /// - The child does not inherit semaphore adjustments from its parent ([`Self::sys_semop`]). + /// - The child does not inherit process-associated record locks from its parent ([`Self::sys_fcntl`]). + /// (On the other hand, it does inherit [`Self::sys_fcntl`] open file description locks and [`Self::sys_flock`] locks from its parent.) + /// + /// Note the following further points: + /// + /// - The child process is created with a single thread—the one that called fork(). + /// The entire virtual address space of the parent is replicated in the child, + /// including the states of mutexes and condition variables. + /// - After a `fork` in a multithreaded program, + /// the child can safely call only async-signal-safe functions + /// until such time as it calls [`Self::sys_execve`]. + /// - The child inherits copies of the parent's set of open file descriptors. + /// Each file descriptor in the child refers to the same open file description (see [`Self::sys_open`]) + /// as the corresponding file descriptor in the parent. + /// This means that the two file descriptors share open file status flags and file offset. pub fn sys_fork(&self) -> SysResult { info!("fork:"); let new_proc = Process::fork_from(self.zircon_process(), false)?; // old pt NULL here @@ -34,7 +70,13 @@ impl Syscall<'_> { Ok(new_proc.id() as usize) } - /// creates a child process of the calling process, similar to fork but wait for execve + /// `sys_vfork`, just like [`Self::sys_fork`], creates a child process of the calling process + /// (see [linux man vfork(2)](https://www.man7.org/linux/man-pages/man2/vfork.2.html)). + /// For details, see [`Self::sys_fork`]. + /// + /// `sys_vfork` differs from [`Self::sys_fork`] in that the calling thread is suspended until the child terminates + /// (either normally, by calling [`Self::sys_exit`], or abnormally, after delivery of a fatal signal), + /// or it makes a call to [`Self::sys_execve`]. pub async fn sys_vfork(&self) -> SysResult { info!("vfork:"); let new_proc = Process::fork_from(self.zircon_process(), true)?; @@ -54,11 +96,14 @@ impl Syscall<'_> { Ok(new_proc.id() as usize) } - /// Create a new thread in the current process. + /// `sys_clone` create a new thread in the current process. /// The new thread's stack pointer will be set to `newsp`, /// and thread pointer will be set to `newtls`. - /// The child tid will be stored at both `parent_tid` and `child_tid`. - /// This is partially implemented for musl only. + /// The child TID will be stored at both `parent_tid` and `child_tid`. + /// + /// > **NOTE!** This system call is not exactly the same as `clone` in Linux. + /// + /// > **NOTE!** This is partially implemented for `musl` only. pub fn sys_clone( &self, flags: usize, @@ -99,9 +144,45 @@ impl Syscall<'_> { Ok(tid as usize) } - /// Wait for a child process exited. + /// `sys_wait4` suspends execution of the calling thread + /// until a child specified by `pid` argument has changed state + /// (see [linux man wait4(2)](https://www.man7.org/linux/man-pages/man2/wait4.2.html)). + /// By default, `sys_wait4` waits only for terminated children, + /// but this behavior is modifiable via the options argument, as described below. /// - /// Return the PID. Store exit code to `wstatus` if it's not null. + /// The value of `pid` can be: + /// + /// - **-1**: meaning wait for any child process. + /// - **0**: meaning wait for any child process whose process group ID is equal to + /// that of the calling process at the time of the call to `sys_wait4`. + /// - **>0**: meaning wait for the child whose process ID is equal to the value of `pid`. + /// + /// The value of options is an OR of zero or more of the following constants: + /// + /// - **NOHANG** = 0x000_0001; + /// + /// TODO + /// + /// - **STOPPED** = 0x000_0002; + /// + /// TODO + /// + /// - **EXITED** = 0x000_0004; + /// + /// TODO + /// + /// - **CONTINUED** = 0x000_0008; + /// + /// TODO + /// + /// - **NOWAIT** = 0x100_0000; + /// + /// TODO + /// + /// On success, returns the process ID of the child whose state has changed; + /// if `NOHANG` flag was specified and one or more child(ren) specified by pid exist, + /// but have not yet changed state, then 0 is returned. + /// On failure, -1 is returned. pub async fn sys_wait4( &self, pid: i32, @@ -145,25 +226,34 @@ impl Syscall<'_> { Ok(pid as usize) } - /// Replaces the current ** process ** with a new process image + /// `sys_execve` executes the program referred to by `path` + /// (see [linux man execve(2)](https://www.man7.org/linux/man-pages/man2/execve.2.html)). + /// This causes the program that is currently being run + /// by the calling process to be replaced with a new program, + /// with newly initialized stack, heap, and (initialized and uninitialized) data segments. + /// + /// `path` argument must be a binary executable file. /// /// `argv` is an array of argument strings passed to the new program. + /// By convention, the first of these strings (i.e., `argv[0]`) + /// should contain the filename associated with the file being executed. + /// /// `envp` is an array of strings, conventionally of the form `key=value`, /// which are passed as environment to the new program. /// - /// NOTICE: `argv` & `envp` can not be NULL (different from Linux) + /// > **NOTE!** Differ from linux, `argv` & `envp` can not be NULL. /// - /// NOTICE: for multi-thread programs - /// A call to any exec function from a process with more than one thread - /// shall result in all threads being terminated and the new executable image - /// being loaded and executed. + /// > **NOTE!** For multi-thread programs, + /// A call to any exec function from a process with more than one thread + /// shall result in all threads being terminated and the new executable image + /// being loaded and executed. pub fn sys_execve( &mut self, path: UserInPtr, argv: UserInPtr>, envp: UserInPtr>, ) -> SysResult { - let path = path.read_cstring()?; + let path = path.as_c_str()?; let args = argv.read_cstring_array()?; let envs = envp.read_cstring_array()?; info!( @@ -179,23 +269,27 @@ impl Syscall<'_> { // Read program file let proc = self.linux_process(); - let inode = proc.lookup_inode(&path)?; + let inode = proc.lookup_inode(path)?; let data = inode.read_as_vec()?; proc.remove_cloexec_files(); + // 注意!即将销毁旧应用程序的用户空间,现在将必要的信息拷贝到内核! + // Notice! About to destroy the user space of the old application, now copy the necessary information into kernel! + let path = path.to_string(); let vmar = self.zircon_process().vmar(); vmar.clear()?; - let loader = LinuxElfLoader { - syscall_entry: self.syscall_entry, - stack_pages: 8, - root_inode: proc.root_inode().clone(), - }; - let (entry, sp) = loader.load(&vmar, &data, args, envs, path.clone())?; // Modify exec path proc.set_execute_path(&path); + let (entry, sp) = LinuxElfLoader { + syscall_entry: self.syscall_entry, + stack_pages: 8, + root_inode: proc.root_inode().clone(), + } + .load(&vmar, &data, args, envs, path)?; + // TODO: use right signal // self.zircon_process().signal_set(Signal::SIGNALED); // Workaround, the child process could NOT exit correctly @@ -232,14 +326,18 @@ impl Syscall<'_> { // } // } - /// Get the current thread ID. + /// `sys_gettid` returns the caller's thread ID (TID) + /// (see [linux man gettid(2)](https://www.man7.org/linux/man-pages/man2/gettid.2.html)). + /// In a single-threaded process, the thread ID is equal to the process ID (PID, as returned by [`Self::sys_getpid`]). + /// In a multithreaded process, all threads have the same PID, but each one has a unique TID. pub fn sys_gettid(&self) -> SysResult { info!("gettid:"); let tid = self.thread.id(); Ok(tid as usize) } - /// Get the current process ID. + /// `sys_getpid` returns the process ID (PID) of the calling process + /// (see [linux man getpid(2)](https://www.man7.org/linux/man-pages/man2/getpid.2.html)). pub fn sys_getpid(&self) -> SysResult { info!("getpid:"); let proc = self.zircon_process(); @@ -247,7 +345,10 @@ impl Syscall<'_> { Ok(pid as usize) } - /// Get the parent process ID. + /// `sys_getppid` returns the process ID of the parent of the calling process + /// (see [linux man getppid(2)](https://www.man7.org/linux/man-pages/man2/getpid.2.html)). + /// This will be either the ID of the process that created this process using fork(), + /// or, if that process has already terminated, 0. pub fn sys_getppid(&self) -> SysResult { info!("getppid:"); let proc = self.linux_process(); @@ -255,14 +356,23 @@ impl Syscall<'_> { Ok(ppid as usize) } - /// Exit the current thread + /// `sys_exit` system call terminates only the calling thread + /// (see [linux man _exit(2)](https://www.man7.org/linux/man-pages/man2/exit.2.html), + /// this syscall is same as a raw `_exit` in glibc), + /// and actions such as reparenting child processes or sending + /// SIGCHLD to the parent process are performed only if this is the + /// last thread in the thread group. pub fn sys_exit(&mut self, exit_code: i32) -> SysResult { info!("exit: code={}", exit_code); self.thread.exit_linux(exit_code); Err(LxError::ENOSYS) } - /// Exit the current thread group (i.e. process) + /// `sys_exit_group` is equivalent to [`Self::sys_exit`] + /// except that it terminates not only the calling thread + /// (see [linux man exit_group(2)](https://www.man7.org/linux/man-pages/man2/exit_group.2.html), + /// but all threads in the calling process's thread group. + /// As a result, the entire calling process will exit. pub fn sys_exit_group(&mut self, exit_code: i32) -> SysResult { info!("exit_group: code={}", exit_code); let proc = self.zircon_process(); @@ -272,6 +382,16 @@ impl Syscall<'_> { /// Allows the calling thread to sleep for /// an interval specified with nanosecond precision + /// (see [linux man nanosleep(2)](https://www.man7.org/linux/man-pages/man2/nanosleep.2.html). + /// + /// `nanosleep` suspends the execution of the calling thread + /// until either at least the time specified in `req` has elapsed, + /// or the delivery of a signal that triggers the invocation of a handler + /// in the calling thread or that terminates the process. + /// + /// To represent a duration, see TimeSpec. + + /* Deleted by 8278dc13 in Jan 28, 2022 pub async fn sys_nanosleep(&self, req: UserInPtr) -> SysResult { info!("nanosleep: deadline={:?}", req); let duration = req.read()?.into(); @@ -279,15 +399,16 @@ impl Syscall<'_> { thread::sleep_until(timer::deadline_after(duration)).await; Ok(0) } - + */ // pub fn sys_set_priority(&self, priority: usize) -> SysResult { // let pid = thread::current().id(); // thread_manager().set_priority(pid, priority as u8); // Ok(0) // } - /// set pointer to thread ID - /// returns the caller's thread ID + /// `set_tid_address` sets the clear_child_tid value for the calling thread to `tidptr`, + /// and return the caller's thread ID + /// (see [linux man set_tid_address(2)](https://www.man7.org/linux/man-pages/man2/set_tid_address.2.html). pub fn sys_set_tid_address(&self, tidptr: UserOutPtr) -> SysResult { info!("set_tid_address: {:?}", tidptr); self.thread.set_tid_address(tidptr); diff --git a/linux-syscall/src/time.rs b/linux-syscall/src/time.rs index 94188791..7f342673 100644 --- a/linux-syscall/src/time.rs +++ b/linux-syscall/src/time.rs @@ -103,4 +103,68 @@ impl Syscall<'_> { info!("tick: {:?}", tick); Ok(tick as usize) } + + /// Allows the calling thread to sleep for + /// an interval specified with nanosecond precision + pub async fn sys_nanosleep(&self, req: UserInPtr) -> SysResult { + info!("nanosleep: deadline={:?}", req); + let duration = req.read()?.into(); + nanosleep(duration).await; + Ok(0) + } + + /// clock nanosleep + pub async fn sys_clock_nanosleep( + &self, + clockid: usize, + flags: usize, + req: UserInPtr, + rem: UserOutPtr, + ) -> SysResult { + warn!( + "clock_nanosleep: clockid={:?},flags={:?},req={:?},,rem={:?}", + clockid, + flags, + req.read()?, + rem + ); + use core::time::Duration; + let duration: Duration = req.read()?.into(); + let clockid = ClockId::from(clockid); + let flags = ClockFlags::from(flags); + warn!("clockid={:?},flags={:?}", clockid, flags,); + match clockid { + ClockId::ClockRealTime => { + match flags { + ClockFlags::ZeroFlag => { + nanosleep(duration).await; + } + ClockFlags::TimerAbsTime => { + // 目前统一由nanosleep代替了、之后再修改 + nanosleep(duration).await; + } + } + } + ClockId::ClockMonotonic => { + match flags { + ClockFlags::ZeroFlag => { + nanosleep(duration).await; + } + ClockFlags::TimerAbsTime => { + // 目前统一由nanosleep代替了、之后再修改 + nanosleep(duration).await; + } + } + } + ClockId::ClockProcessCpuTimeId => {} + ClockId::ClockThreadCpuTimeId => {} + ClockId::ClockMonotonicRaw => {} + ClockId::ClockRealTimeCoarse => {} + ClockId::ClockMonotonicCoarse => {} + ClockId::ClockBootTime => {} + ClockId::ClockRealTimeAlarm => {} + ClockId::ClockBootTimeAlarm => {} + } + Ok(0) + } } diff --git a/linux-syscall/src/vm.rs b/linux-syscall/src/vm.rs index 6082be28..34dc7919 100644 --- a/linux-syscall/src/vm.rs +++ b/linux-syscall/src/vm.rs @@ -2,15 +2,75 @@ use super::*; use bitflags::bitflags; use zircon_object::vm::{pages, MMUFlags, VmObject}; +/// Syscalls for virtual memory. +/// +/// # Menu +/// +/// - [`mmap`](Self::sys_mmap) +/// - [`mprotect`](Self::sys_mprotect) +/// - [`munmap`](Self::sys_munmap) impl Syscall<'_> { - /// creates a new mapping in the virtual address space of the calling process. - /// - `addr` - The starting address for the new mapping - /// - `len` - specifies the length of the mapping - /// - `prot ` - describes the desired memory protection of the mapping - /// - `flags` - determines whether updates to the mapping are visible to other processes mapping the same region, - /// and whether updates are carried through to the underlying file. - /// - `fd` - mapping file descriptor - /// - `offset` - offset in the file + /// Map files or devices into memory + /// (see [linux man mmap(2)](https://www.man7.org/linux/man-pages/man2/mmap.2.html)). + /// + /// `sys_mmap` creates a new mapping in the virtual address space of the calling process. + /// + /// The starting address for the new mapping is specified in `addr`. + /// + /// The `len` argument specifies the length of the mapping (which must be greater than 0). + /// + /// Arguments `fd` and `offset` specifies mapping file descriptor and offset in the file. + /// + /// The `prot` argument describes the desired memory protection of the mapping + /// (and must not conflict with the open mode of the file). + /// It is either 0 or the bitwise OR of one or more of the following flags: + /// + /// - **`MmapProt::READ`** + /// + /// Pages may be read + /// + /// - **`MmapProt::WRITE`** + /// + /// Pages may be written + /// + /// - **`MmapProt::EXEC`** + /// + /// Pages may be executed + /// + /// The `flags` argument determines whether updates to the mapping are visible to other processes mapping the same region, + /// and whether updates are carried through to the underlying file. + /// This behavior is determined by including exactly one of the following values: + /// + /// - **`MmapFlags::SHARED`** + /// + /// Share this mapping. Updates to the mapping are visible to other processes mapping the same region, + /// and (in the case of file-backed mappings) are carried through to the underlying file. + /// (To precisely control when updates are carried through to the underlying file requires the use of `msync`, + /// which has not been implemented in zcore). + /// + /// - **`MmapFlags::PRIVATE`** + /// + /// Create a private copy-on-write mapping. + /// Updates to the mapping are not visible to other processes mapping the same file, + /// and are not carried through to the underlying file. + /// It is unspecified whether changes made to the file after the `sys_mmap` call are visible in the mapped region. + /// + /// - **`MmapFlags::FIXED`** + /// + /// Don't interpret `addr` as a hint: place the mapping at exactly that address. + /// `addr` must be suitably aligned: + /// for most architectures a multiple of the page size is sufficient; + /// however, some architectures may impose additional restrictions. + /// If the memory region specified by `addr` and `len` overlaps pages of any existing mapping(s), + /// then the overlapped part of the existing mapping(s) will be discarded. + /// If the specified address cannot be used, `sys_mmap` will fail. + /// + /// - **`MmapFlags::ANONYMOUS`** + /// + /// The mapping is not backed by any file; its contents are initialized to zero. + /// Both `fd` and `offset` arguments are ignored. + /// The use of `MmapFlags::ANONYMOUS` in conjunction with `MmapFlags::SHARED` + /// causes an [`EINVAL`](LxError::EINVAL) to be returned. pub async fn sys_mmap( &self, addr: usize, @@ -50,9 +110,34 @@ impl Syscall<'_> { } } - /// changes the access protections for the calling process's memory pages - /// containing any part of the address range in the interval [addr, addr+len-1] - /// TODO: unimplemented + /// Set protection on a region of memory + /// (see [linux man mprotect(2)](https://www.man7.org/linux/man-pages/man2/mprotect.2.html)). + /// + /// **NOTE!** This syscall is now unimplemented. Calling it always return `Ok(0)`. + /// + /// `sys_mprotect` changes the access protections for the calling process's memory pages + /// containing any part of the address range in the interval `[addr, addr+len-1]`. + /// `addr` must be aligned to a page boundary. + /// + /// If the calling process tries to access memory in a manner that violates the protections, + /// then the kernel generates a SIGSEGV signal for the process. + /// + /// `prot` is a combination of the following access flags: + /// 0 or a bitwise-or of the other values in the following list: + /// + /// - **`MmapProt::READ`** + /// + /// The memory can be read. + /// + /// - **`MmapProt::WRITE`** + /// + /// The memory can be modified. + /// + /// - **`MmapProt::EXEC`** + /// + /// The memory can be executed. + /// + /// If `prot` is 0, the memory cannot be accessed at all. pub fn sys_mprotect(&self, addr: usize, len: usize, prot: usize) -> SysResult { let prot = MmapProt::from_bits_truncate(prot); info!( @@ -63,8 +148,19 @@ impl Syscall<'_> { Ok(0) } + /// Unmap files or devices into memory + /// (see [linux man munmap(2)](https://www.man7.org/linux/man-pages/man2/munmap.2.html)). + /// /// Deletes the mappings for the specified address range, and causes further references to addresses /// within the range to generate invalid memory references. + /// + /// The `sys_munmap` system call deletes the mappings for the specified address range, + /// and causes further references to addresses within the range to generate invalid memory references. + /// The region is also automatically unmapped when the process is terminated. + /// On the other hand, closing the file descriptor does not unmap the region. + /// + /// Both `addr` and `len` must be aligned to the page size, additionally, `len` must greater than 0. + /// Otherwise, an [`EINVAL`](LxError::EINVAL) is returned. pub fn sys_munmap(&self, addr: usize, len: usize) -> SysResult { info!("munmap: addr={:#x}, size={:#x}", addr, len); let proc = self.thread.proc(); diff --git a/loader/Cargo.toml b/loader/Cargo.toml index 2df23729..da715224 100644 --- a/loader/Cargo.toml +++ b/loader/Cargo.toml @@ -1,7 +1,10 @@ [package] name = "zcore-loader" version = "0.1.0" -authors = ["Runji Wang ", "Yuekai Jia "] +authors = [ + "Runji Wang ", + "Yuekai Jia ", +] edition = "2018" description = "Linux and Zircon user programs loader and runner." @@ -27,7 +30,7 @@ libos = ["kernel-hal/libos", "zircon-object/aspace-separate"] [dev-dependencies] env_logger = "0.9" async-std = { version = "1.10", features = ["attributes"] } -rcore-fs-hostfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" } +rcore-fs-hostfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" } [[example]] name = "linux-libos" diff --git a/zCore/Cargo.toml b/zCore/Cargo.toml index 6a1e8f82..def1316e 100644 --- a/zCore/Cargo.toml +++ b/zCore/Cargo.toml @@ -36,24 +36,34 @@ zircon = ["zcore-loader/zircon"] linux = ["zcore-loader/linux", "linux-object", "rcore-fs", "rcore-fs-sfs"] # Run as LibOS -libos = ["kernel-hal/libos", "zcore-loader/libos", "async-std", "chrono", "rcore-fs-hostfs"] +libos = [ + "kernel-hal/libos", + "zcore-loader/libos", + "async-std", + "chrono", + "rcore-fs-hostfs", +] # Run on QEMU board-qemu = [] # Run on Allwinner d1 (riscv only) board-d1 = ["link-user-img"] +loopback = ["kernel-hal/loopback"] + [dependencies] log = "0.4" spin = "0.9" cfg-if = "1.0" -lazy_static = { version = "1.4", features = ["spin_no_std" ] } +lazy_static = { version = "1.4", features = ["spin_no_std"] } bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev = "b3f9f51" } -kernel-hal = { path = "../kernel-hal", default-features = false, features = ["smp"] } +kernel-hal = { path = "../kernel-hal", default-features = false, features = [ + "smp", +] } zcore-loader = { path = "../loader", default-features = false } zircon-object = { path = "../zircon-object" } linux-object = { path = "../linux-object", optional = true } -rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec", optional = true } -rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec", optional = true } +rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b", optional = true } +rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b", optional = true } lock = { git = "https://github.com/DeathWish5/kernel-sync" } executor = { git = "https://github.com/DeathWish5/PreemptiveScheduler" } @@ -61,7 +71,7 @@ executor = { git = "https://github.com/DeathWish5/PreemptiveScheduler" } [target.'cfg(not(target_os = "none"))'.dependencies] async-std = { version = "1.10", optional = true } chrono = { version = "0.4", optional = true } -rcore-fs-hostfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec", optional = true } +rcore-fs-hostfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b", optional = true } # Bare-metal mode [target.'cfg(target_os = "none")'.dependencies] @@ -70,4 +80,4 @@ buddy_system_allocator = "0.8" # Bare-metal mode on x86_64 [target.'cfg(all(target_os = "none", target_arch = "x86_64"))'.dependencies] rboot = { git = "https://github.com/rcore-os/rboot.git", rev = "39d6e24", default-features = false } -# rvm = { git = "https://github.com/rcore-os/RVM", rev = "e91d625", optional = true } \ No newline at end of file +# rvm = { git = "https://github.com/rcore-os/RVM", rev = "e91d625", optional = true } diff --git a/zCore/Makefile b/zCore/Makefile index 23b6aca2..7e718d95 100644 --- a/zCore/Makefile +++ b/zCore/Makefile @@ -18,7 +18,7 @@ ZBI ?= bringup SMP ?= 1 ACCEL ?= - +NET ?= OBJDUMP := OBJCOPY ?= rust-objcopy --binary-architecture=$(ARCH) @@ -105,6 +105,7 @@ endif ifeq ($(TEST), 1) features += baremetal-test + NET := loopback endif ifeq ($(GRAPHIC), on) @@ -118,6 +119,10 @@ ifeq ($(HYPERVISOR), 1) ACCEL := 1 endif +ifeq ($(NET), loopback) + features += loopback +endif + ################ Cargo build args ################ build_args := --features "$(features)" @@ -144,6 +149,7 @@ ifeq ($(ARCH), x86_64) -cpu Haswell,+smap,-check,-fsgsbase \ -m 1G \ -serial mon:stdio \ + -serial file:/tmp/serial.out \ -drive format=raw,if=pflash,readonly=on,file=$(ovmf) \ -drive format=raw,file=fat:rw:$(esp) \ -nic none @@ -154,6 +160,7 @@ else ifeq ($(ARCH), riscv64) -m 512M \ -no-reboot \ -serial mon:stdio \ + -serial file:/tmp/serial.out \ -kernel $(kernel_img) \ -initrd $(USER_IMG) \ -append "$(CMDLINE)" diff --git a/zCore/rboot.conf b/zCore/rboot.conf index 367ac0c1..421ea871 100644 --- a/zCore/rboot.conf +++ b/zCore/rboot.conf @@ -15,7 +15,7 @@ physical_memory_offset=0xFFFF800000000000 kernel_path=\EFI\zCore\zcore.elf # The resolution of graphic output -resolution=1024x768 +resolution=800x600 initramfs=\EFI\zCore\fuchsia.zbi # LOG=debug/info/error/warn/trace diff --git a/zCore/src/fs.rs b/zCore/src/fs.rs index 8d6a4aff..d44bc7c8 100644 --- a/zCore/src/fs.rs +++ b/zCore/src/fs.rs @@ -61,6 +61,9 @@ cfg_if! { } } +#[cfg(feature = "link-user-img")] +use core::arch::global_asm; + // Hard link rootfs img #[cfg(not(feature = "libos"))] #[cfg(feature = "link-user-img")] diff --git a/zCore/src/platform/riscv/boot/entry64.asm b/zCore/src/platform/riscv/boot/entry64.asm index d60410e7..eb6e4ae2 100644 --- a/zCore/src/platform/riscv/boot/entry64.asm +++ b/zCore/src/platform/riscv/boot/entry64.asm @@ -55,8 +55,16 @@ init_vm: #刷新TLB sfence.vma - li t0, 4096 * 16 - mul t0, t0, a0 + # t0 = 0 + xor t0, t0, t0 + mv t1, a0 + beqz t1, 2f + li t2, 4096 * 16 +1: + add t0, t0, t2 + addi t1, t1, -1 + bgtz t1, 1b +2: #此时在虚拟内存空间,设置sp为虚拟地址 lui sp, %hi(bootstacktop) sub sp, sp, t0 diff --git a/zCore/x86_64.json b/zCore/x86_64.json index 6763c692..5d7d35c5 100644 --- a/zCore/x86_64.json +++ b/zCore/x86_64.json @@ -1,6 +1,6 @@ { "llvm-target": "x86_64-unknown-none", - "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", + "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128", "linker-flavor": "ld.lld", "target-endian": "little", "target-pointer-width": "64", diff --git a/zircon-object/src/dev/pci/bus.rs b/zircon-object/src/dev/pci/bus.rs index 23616911..8e78a689 100644 --- a/zircon-object/src/dev/pci/bus.rs +++ b/zircon-object/src/dev/pci/bus.rs @@ -3,7 +3,7 @@ use super::nodes::{ SharedLegacyIrqHandler, }; use super::{ - config::PciConfig, constants::*, pci_init_args::PciIrqSwizzleLut, pio::pci_bdf_raw_addr, + config::PciConfig, constants::*, pci_init_args::PciIrqSwizzleLut, pmio::pci_bdf_raw_addr, MappedEcamRegion, PciAddrSpace, PciEcamRegion, }; use crate::dev::Interrupt; @@ -448,9 +448,9 @@ impl PCIeAddressProvider for MmioPcieAddressProvider { /// Systems that have PIO mapped Config Spaces. #[derive(Default)] -pub struct PioPcieAddressProvider; +pub struct PmioPcieAddressProvider; -impl PCIeAddressProvider for PioPcieAddressProvider { +impl PCIeAddressProvider for PmioPcieAddressProvider { fn create_config(&self, addr: u64) -> Arc { Arc::new(PciConfig { addr_space: PciAddrSpace::PIO, diff --git a/zircon-object/src/dev/pci/config.rs b/zircon-object/src/dev/pci/config.rs index af08a9d3..7f70ad1b 100644 --- a/zircon-object/src/dev/pci/config.rs +++ b/zircon-object/src/dev/pci/config.rs @@ -1,4 +1,4 @@ -use super::pio::{pio_config_read_addr, pio_config_write_addr}; +use super::pmio::{pmio_config_read_addr, pmio_config_write_addr}; use super::PciAddrSpace; use numeric_enum_macro::numeric_enum; @@ -14,21 +14,21 @@ impl PciConfig { trace!("read8 @ {:#x?}", offset); match self.addr_space { PciAddrSpace::MMIO => unsafe { u8::from_le(*(offset as *const u8)) }, - PciAddrSpace::PIO => pio_config_read_addr(offset as u32, 8).unwrap() as u8, + PciAddrSpace::PIO => pmio_config_read_addr(offset as u32, 8).unwrap() as u8, } } pub fn read16_offset(&self, addr: usize) -> u16 { trace!("read16 @ {:#x?}", addr); match self.addr_space { PciAddrSpace::MMIO => unsafe { u16::from_le(*(addr as *const u16)) }, - PciAddrSpace::PIO => pio_config_read_addr(addr as u32, 16).unwrap() as u16, + PciAddrSpace::PIO => pmio_config_read_addr(addr as u32, 16).unwrap() as u16, } } pub fn read32_offset(&self, addr: usize) -> u32 { trace!("read32 @ {:#x?}", addr); match self.addr_space { PciAddrSpace::MMIO => unsafe { u32::from_le(*(addr as *const u32)) }, - PciAddrSpace::PIO => pio_config_read_addr(addr as u32, 32).unwrap(), + PciAddrSpace::PIO => pmio_config_read_addr(addr as u32, 32).unwrap(), } } pub fn read8(&self, addr: PciReg8) -> u8 { @@ -56,7 +56,7 @@ impl PciConfig { pub fn write8_offset(&self, addr: usize, val: u8) { match self.addr_space { PciAddrSpace::MMIO => unsafe { *(addr as *mut u8) = val }, - PciAddrSpace::PIO => pio_config_write_addr(addr as u32, val as u32, 8).unwrap(), + PciAddrSpace::PIO => pmio_config_write_addr(addr as u32, val as u32, 8).unwrap(), } } pub fn write16_offset(&self, addr: usize, val: u16) { @@ -67,13 +67,13 @@ impl PciConfig { ); match self.addr_space { PciAddrSpace::MMIO => unsafe { *(addr as *mut u16) = val }, - PciAddrSpace::PIO => pio_config_write_addr(addr as u32, val as u32, 16).unwrap(), + PciAddrSpace::PIO => pmio_config_write_addr(addr as u32, val as u32, 16).unwrap(), } } pub fn write32_offset(&self, addr: usize, val: u32) { match self.addr_space { PciAddrSpace::MMIO => unsafe { *(addr as *mut u32) = val }, - PciAddrSpace::PIO => pio_config_write_addr(addr as u32, val as u32, 32).unwrap(), + PciAddrSpace::PIO => pmio_config_write_addr(addr as u32, val as u32, 32).unwrap(), } } pub fn write8(&self, addr: PciReg8, val: u8) { diff --git a/zircon-object/src/dev/pci/mod.rs b/zircon-object/src/dev/pci/mod.rs index 82ae6641..27c8132c 100644 --- a/zircon-object/src/dev/pci/mod.rs +++ b/zircon-object/src/dev/pci/mod.rs @@ -5,14 +5,14 @@ mod caps; mod config; mod nodes; pub mod pci_init_args; -mod pio; +mod pmio; pub use self::bus::{ MmioPcieAddressProvider, PCIeBusDriver, PcieDeviceInfo, PcieDeviceKObject, - PioPcieAddressProvider, + PmioPcieAddressProvider, }; pub use self::nodes::{IPciNode, PcieIrqMode}; -pub use self::pio::{pio_config_read, pio_config_write}; +pub use self::pmio::{pio_config_read, pio_config_write}; /// Type of PCI address space. #[derive(PartialEq, Debug)] diff --git a/zircon-object/src/dev/pci/pio.rs b/zircon-object/src/dev/pci/pmio.rs similarity index 71% rename from zircon-object/src/dev/pci/pio.rs rename to zircon-object/src/dev/pci/pmio.rs index a6ffe4bf..4c023a1f 100644 --- a/zircon-object/src/dev/pci/pio.rs +++ b/zircon-object/src/dev/pci/pmio.rs @@ -12,18 +12,17 @@ pub fn pci_bdf_raw_addr(bus: u8, dev: u8, func: u8, offset: u8) -> u32 { cfg_if::cfg_if! { if #[cfg(all(target_arch = "x86_64", target_os = "none"))] { -use kernel_hal::x86_64::{Io, Pio}; -use spin::Mutex; -// use lock::Mutex; + use kernel_hal::x86_64::{Io, Pmio}; + use spin::Mutex; static PIO_LOCK: Mutex<()> = Mutex::new(()); const PCI_CONFIG_ADDR: u16 = 0xcf8; const PCI_CONFIG_DATA: u16 = 0xcfc; const PCI_CONFIG_ENABLE: u32 = 1 << 31; - pub fn pio_config_read_addr(addr: u32, width: usize) -> ZxResult { - let mut port_cfg = Pio::::new(PCI_CONFIG_ADDR); - let port_data = Pio::::new(PCI_CONFIG_DATA); + pub fn pmio_config_read_addr(addr: u32, width: usize) -> ZxResult { + let mut port_cfg = Pmio::::new(PCI_CONFIG_ADDR); + let port_data = Pmio::::new(PCI_CONFIG_DATA); let _lock = PIO_LOCK.lock(); let shift = ((addr & 0x3) << 3) as usize; @@ -34,9 +33,9 @@ use spin::Mutex; let tmp_val = u32::from_le(port_data.read()); Ok((tmp_val >> shift) & (((1u64 << width) - 1) as u32)) } - pub fn pio_config_write_addr(addr: u32, val: u32, width: usize) -> ZxResult { - let mut port_cfg = Pio::::new(PCI_CONFIG_ADDR); - let mut port_data = Pio::::new(PCI_CONFIG_DATA); + pub fn pmio_config_write_addr(addr: u32, val: u32, width: usize) -> ZxResult { + let mut port_cfg = Pmio::::new(PCI_CONFIG_ADDR); + let mut port_data = Pmio::::new(PCI_CONFIG_DATA); let _lock = PIO_LOCK.lock(); let shift = ((addr & 0x3) << 3) as usize; @@ -55,17 +54,17 @@ use spin::Mutex; Ok(()) } } else { - pub fn pio_config_read_addr(_addr: u32, _width: usize) -> ZxResult { + pub fn pmio_config_read_addr(_addr: u32, _width: usize) -> ZxResult { Err(ZxError::NOT_SUPPORTED) } - pub fn pio_config_write_addr(_addr: u32, _val: u32, _width: usize) -> ZxResult { + pub fn pmio_config_write_addr(_addr: u32, _val: u32, _width: usize) -> ZxResult { Err(ZxError::NOT_SUPPORTED) } } } // cfg_if! pub fn pio_config_read(bus: u8, dev: u8, func: u8, offset: u8, width: usize) -> ZxResult { - pio_config_read_addr(pci_bdf_raw_addr(bus, dev, func, offset), width) + pmio_config_read_addr(pci_bdf_raw_addr(bus, dev, func, offset), width) } pub fn pio_config_write( @@ -76,5 +75,5 @@ pub fn pio_config_write( val: u32, width: usize, ) -> ZxResult { - pio_config_write_addr(pci_bdf_raw_addr(bus, dev, func, offset), val, width) + pmio_config_write_addr(pci_bdf_raw_addr(bus, dev, func, offset), val, width) } diff --git a/zircon-object/src/util/elf_loader.rs b/zircon-object/src/util/elf_loader.rs index b483d794..a698dd42 100644 --- a/zircon-object/src/util/elf_loader.rs +++ b/zircon-object/src/util/elf_loader.rs @@ -208,14 +208,14 @@ impl ElfExt for ElfFile<'_> { }; let value = symval + entry.get_addend() as usize; let addr = base + entry.get_offset() as usize; - debug!("GOT write: {:#x} @ {:#x}", value, addr); + trace!("GOT write: {:#x} @ {:#x}", value, addr); vmar.write_memory(addr, &value.to_ne_bytes()) .map_err(|_| "Invalid Vmar")?; } REL_RELATIVE | R_RISCV_RELATIVE => { let value = base + entry.get_addend() as usize; let addr = base + entry.get_offset() as usize; - debug!("RELATIVE write: {:#x} @ {:#x}", value, addr); + trace!("RELATIVE write: {:#x} @ {:#x}", value, addr); vmar.write_memory(addr, &value.to_ne_bytes()) .map_err(|_| "Invalid Vmar")?; } diff --git a/zircon-syscall/src/channel.rs b/zircon-syscall/src/channel.rs index c8cec3aa..d21de162 100644 --- a/zircon-syscall/src/channel.rs +++ b/zircon-syscall/src/channel.rs @@ -12,7 +12,7 @@ use { impl Syscall<'_> { #[allow(clippy::too_many_arguments)] - /// Read/Receive a message from a channel. + /// Read/Receive a message from a channel. pub fn sys_channel_read( &self, handle_value: HandleValue, @@ -76,7 +76,7 @@ impl Syscall<'_> { } Ok(()) } - /// Write a message to a channel. + /// Write a message to a channel. pub fn sys_channel_write( &self, handle_value: HandleValue, @@ -98,9 +98,9 @@ impl Syscall<'_> { } let proc = self.thread.proc(); let data = user_bytes.read_array(num_bytes as usize)?; - let handles = user_handles.read_array(num_handles as usize)?; + let handles = user_handles.as_slice(num_handles as usize)?; let transfer_self = handles.iter().any(|&handle| handle == handle_value); - let handles = proc.remove_handles(&handles)?; + let handles = proc.remove_handles(handles)?; if transfer_self { return Err(ZxError::NOT_SUPPORTED); } @@ -116,7 +116,7 @@ impl Syscall<'_> { channel.write(MessagePacket { data, handles })?; Ok(()) } - /// Create a new channel. + /// Create a new channel. pub fn sys_channel_create( &self, options: u32, @@ -136,7 +136,7 @@ impl Syscall<'_> { Ok(()) } - /// + /// pub async fn sys_channel_call_noretry( &self, handle_value: HandleValue, @@ -163,8 +163,8 @@ impl Syscall<'_> { let wr_msg = MessagePacket { data: args.wr_bytes.read_array(args.wr_num_bytes as usize)?, handles: { - let handles = args.wr_handles.read_array(args.wr_num_handles as usize)?; - let handles = proc.remove_handles(&handles)?; + let handles = args.wr_handles.as_slice(args.wr_num_handles as usize)?; + let handles = proc.remove_handles(handles)?; for handle in handles.iter() { if !handle.rights.contains(Rights::TRANSFER) { return Err(ZxError::ACCESS_DENIED); @@ -213,7 +213,7 @@ impl Syscall<'_> { Err(ZxError::BAD_STATE) } } - /// Write a message to a channel. + /// Write a message to a channel. pub fn sys_channel_write_etc( &self, handle: HandleValue, diff --git a/zircon-syscall/src/debug.rs b/zircon-syscall/src/debug.rs index 1f2859f1..432b1a5f 100644 --- a/zircon-syscall/src/debug.rs +++ b/zircon-syscall/src/debug.rs @@ -5,8 +5,7 @@ impl Syscall<'_> { /// Write debug info to the serial port. pub fn sys_debug_write(&self, buf: UserInPtr, len: usize) -> ZxResult { info!("debug.write: buf=({:?}; {:#x})", buf, len); - let data = buf.read_array(len)?; - kernel_hal::console::console_write_str(core::str::from_utf8(&data).unwrap()); + kernel_hal::console::console_write_str(buf.as_str(len)?); Ok(()) } diff --git a/zircon-syscall/src/debuglog.rs b/zircon-syscall/src/debuglog.rs index 59cfa9e5..7aa193b2 100644 --- a/zircon-syscall/src/debuglog.rs +++ b/zircon-syscall/src/debuglog.rs @@ -49,12 +49,12 @@ impl Syscall<'_> { return Err(ZxError::INVALID_ARGS); } let datalen = len.min(224); - let data = buf.read_string(datalen as usize)?; + let data = buf.as_str(datalen as usize)?; let proc = self.thread.proc(); let dlog = proc.get_object_with_rights::(handle_value, Rights::WRITE)?; - dlog.write(Severity::Info, options, self.thread.id(), proc.id(), &data); + dlog.write(Severity::Info, options, self.thread.id(), proc.id(), data); // print to kernel console - kernel_hal::console::console_write_str(&data); + kernel_hal::console::console_write_str(data); if data.as_bytes().last() != Some(&b'\n') { kernel_hal::console::console_write_str("\n"); } diff --git a/zircon-syscall/src/fifo.rs b/zircon-syscall/src/fifo.rs index 2e9af66a..d757cef3 100644 --- a/zircon-syscall/src/fifo.rs +++ b/zircon-syscall/src/fifo.rs @@ -42,15 +42,18 @@ impl Syscall<'_> { "fifo.write: handle={:?}, item_size={}, count={:#x}", handle_value, elem_size, count ); - if count == 0 { - return Err(ZxError::OUT_OF_RANGE); + if count != 0 { + let data = user_bytes.as_slice(count * elem_size)?; + let actual_count = self + .thread + .proc() + .get_object_with_rights::(handle_value, Rights::WRITE)? + .write(elem_size, data, count)?; + actual_count_ptr.write_if_not_null(actual_count)?; + Ok(()) + } else { + Err(ZxError::OUT_OF_RANGE) } - let proc = self.thread.proc(); - let fifo = proc.get_object_with_rights::(handle_value, Rights::WRITE)?; - let data = user_bytes.read_array(count * elem_size)?; - let actual_count = fifo.write(elem_size, &data, count)?; - actual_count_ptr.write_if_not_null(actual_count)?; - Ok(()) } /// Read data from a fifo. diff --git a/zircon-syscall/src/futex.rs b/zircon-syscall/src/futex.rs index 726d7479..3a0a8a8e 100644 --- a/zircon-syscall/src/futex.rs +++ b/zircon-syscall/src/futex.rs @@ -19,10 +19,10 @@ impl Syscall<'_> { "futex.wait: value_ptr={:#x?}, current_value={:#x}, new_futex_owner={:#x}, deadline={:?}", value_ptr, current_value, new_futex_owner, deadline ); - if value_ptr.is_null() || value_ptr.as_ptr() as usize % 4 != 0 { + if value_ptr.is_null() || value_ptr.as_addr() % 4 != 0 { return Err(ZxError::INVALID_ARGS); } - let value = value_ptr.as_ref()?; + let value = value_ptr.as_ref(); let proc = self.thread.proc(); let futex = proc.get_futex(value); let new_owner = if new_futex_owner == INVALID_HANDLE { @@ -52,12 +52,12 @@ impl Syscall<'_> { "futex.requeue: value_ptr={:?}, wake_count={:#x}, current_value={:#x}, requeue_ptr={:?}, requeue_count={:#x}, new_requeue_owner={:?}", value_ptr, wake_count, current_value, requeue_ptr, requeue_count, new_requeue_owner ); - if value_ptr.is_null() || value_ptr.as_ptr() as usize % 4 != 0 { + if value_ptr.is_null() || value_ptr.as_addr() % 4 != 0 { return Err(ZxError::INVALID_ARGS); } - let value = value_ptr.as_ref()?; - let requeue = requeue_ptr.as_ref()?; - if value_ptr.as_ptr() == requeue_ptr.as_ptr() { + let value = value_ptr.as_ref(); + let requeue = requeue_ptr.as_ref(); + if value_ptr.as_addr() == requeue_ptr.as_addr() { return Err(ZxError::INVALID_ARGS); } let proc = self.thread.proc(); @@ -83,10 +83,10 @@ impl Syscall<'_> { /// > Waking up zero threads is not an error condition. Passing in an unallocated address for value_ptr is not an error condition. pub fn sys_futex_wake(&self, value_ptr: UserInPtr, count: u32) -> ZxResult { info!("futex.wake: value_ptr={:?}, count={:#x}", value_ptr, count); - if value_ptr.is_null() || value_ptr.as_ptr() as usize % 4 != 0 { + if value_ptr.is_null() || value_ptr.as_addr() % 4 != 0 { return Err(ZxError::INVALID_ARGS); } - let value = value_ptr.as_ref()?; + let value = value_ptr.as_ref(); let proc = self.thread.proc(); let futex = proc.get_futex(value); futex.wake(count as usize); @@ -96,10 +96,10 @@ impl Syscall<'_> { /// Wake some number of threads waiting on a futex, and move more waiters to another wait queue. pub fn sys_futex_wake_single_owner(&self, value_ptr: UserInPtr) -> ZxResult { info!("futex.wake_single_owner: value_ptr={:?}", value_ptr); - if value_ptr.is_null() || value_ptr.as_ptr() as usize % 4 != 0 { + if value_ptr.is_null() || value_ptr.as_addr() % 4 != 0 { return Err(ZxError::INVALID_ARGS); } - let value = value_ptr.as_ref()?; + let value = value_ptr.as_ref(); let proc = self.thread.proc(); proc.get_futex(value).wake_single_owner(); Ok(()) diff --git a/zircon-syscall/src/handle.rs b/zircon-syscall/src/handle.rs index bfb370a8..568c1e0e 100644 --- a/zircon-syscall/src/handle.rs +++ b/zircon-syscall/src/handle.rs @@ -1,9 +1,9 @@ use {super::*, core::convert::TryFrom}; impl Syscall<'_> { - /// Creates a duplicate of handle. + /// Creates a duplicate of handle. /// - /// Referring to the same underlying object, with new access rights rights. + /// Referring to the same underlying object, with new access rights rights. pub fn sys_handle_duplicate( &self, handle_value: HandleValue, @@ -33,7 +33,7 @@ impl Syscall<'_> { Ok(()) } - /// Close a handle and reclaim the underlying object if no other handles to it exist. + /// Close a handle and reclaim the underlying object if no other handles to it exist. pub fn sys_handle_close(&self, handle: HandleValue) -> ZxResult { info!("handle.close: handle={:?}", handle); if handle == INVALID_HANDLE { @@ -44,7 +44,7 @@ impl Syscall<'_> { Ok(()) } - /// Close a number of handles. + /// Close a number of handles. pub fn sys_handle_close_many( &self, handles: UserInPtr, @@ -55,19 +55,17 @@ impl Syscall<'_> { handles, num_handles, ); let proc = self.thread.proc(); - let handles = handles.read_array(num_handles)?; - for handle in handles { - if handle == INVALID_HANDLE { - continue; + for handle in handles.as_slice(num_handles)? { + if *handle != INVALID_HANDLE { + proc.remove_handle(*handle)?; } - proc.remove_handle(handle)?; } Ok(()) } - /// Creates a replacement for handle. + /// Creates a replacement for handle. /// - /// Referring to the same underlying object, with new access rights rights. + /// Referring to the same underlying object, with new access rights rights. pub fn sys_handle_replace( &self, handle_value: HandleValue, diff --git a/zircon-syscall/src/lib.rs b/zircon-syscall/src/lib.rs index 2a67c6bc..11806cbb 100644 --- a/zircon-syscall/src/lib.rs +++ b/zircon-syscall/src/lib.rs @@ -308,7 +308,6 @@ impl Syscall<'_> { // atomic_store_explicit(value_ptr, new_value, memory_order_release) UserInPtr::::from(a0) .as_ref() - .unwrap() .store(a2 as i32, Ordering::Release); let _ = self.sys_futex_wake(a0.into(), a1 as _); let _ = self.sys_handle_close(a3 as _); diff --git a/zircon-syscall/src/object.rs b/zircon-syscall/src/object.rs index d7dc418c..6edcd355 100644 --- a/zircon-syscall/src/object.rs +++ b/zircon-syscall/src/object.rs @@ -125,8 +125,7 @@ impl Syscall<'_> { match property { Property::Name => { let length = buffer_size.min(MAX_NAME_LEN) as usize; - let s = UserInPtr::::from(buffer).read_string(length)?; - object.set_name(&s); + object.set_name(UserInPtr::::from(buffer).as_str(length)?); Ok(()) } Property::ProcessDebugAddr => { diff --git a/zircon-syscall/src/pci.rs b/zircon-syscall/src/pci.rs index c11b00d4..3692faff 100644 --- a/zircon-syscall/src/pci.rs +++ b/zircon-syscall/src/pci.rs @@ -6,7 +6,7 @@ use zircon_object::{ constants::*, pci_init_args::{PciInitArgsAddrWindows, PciInitArgsHeader, PCI_INIT_ARG_MAX_SIZE}, MmioPcieAddressProvider, PCIeBusDriver, PciAddrSpace, PciEcamRegion, PcieDeviceInfo, - PcieDeviceKObject, PcieIrqMode, PioPcieAddressProvider, + PcieDeviceKObject, PcieIrqMode, PmioPcieAddressProvider, }, dev::{Resource, ResourceKind}, vm::{pages, VmObject}, @@ -143,7 +143,7 @@ impl Syscall<'_> { })?; PCIeBusDriver::set_address_translation_provider(addr_provider)?; } else if addr_win.cfg_space_type == PCI_CFG_SPACE_TYPE_PIO { - let addr_provider = Arc::new(PioPcieAddressProvider::default()); + let addr_provider = Arc::new(PmioPcieAddressProvider::default()); PCIeBusDriver::set_address_translation_provider(addr_provider)?; } else { return Err(ZxError::INVALID_ARGS); diff --git a/zircon-syscall/src/resource.rs b/zircon-syscall/src/resource.rs index 9d4de032..18dec16e 100644 --- a/zircon-syscall/src/resource.rs +++ b/zircon-syscall/src/resource.rs @@ -2,7 +2,7 @@ use {super::*, core::convert::TryFrom, zircon_object::dev::*}; impl Syscall<'_> { #[allow(clippy::too_many_arguments)] - /// Create a resource object for use with other DDK syscalls. + /// Create a resource object for use with other DDK syscalls. pub fn sys_resource_create( &self, parent_rsrc: HandleValue, @@ -17,7 +17,7 @@ impl Syscall<'_> { "resource.create: parent={:#x}, options={:#x}, base={:#X}, size={:#x}", parent_rsrc, options, base, size ); - let name = name.read_string(name_size as usize)?; + let name = name.as_str(name_size as usize)?; info!("name={:?}", name); let proc = self.thread.proc(); let parent_rsrc = proc.get_object_with_rights::(parent_rsrc, Rights::WRITE)?; @@ -25,7 +25,7 @@ impl Syscall<'_> { let flags = ResourceFlags::from_bits(options & 0xFFFF_0000).ok_or(ZxError::INVALID_ARGS)?; parent_rsrc.validate_ranged_resource(kind, base as usize, size as usize)?; parent_rsrc.check_exclusive(flags)?; - let rsrc = Resource::create(&name, kind, base as usize, size as usize, flags); + let rsrc = Resource::create(name, kind, base as usize, size as usize, flags); let handle = proc.add_handle(Handle::new(rsrc, Rights::DEFAULT_RESOURCE)); out.write(handle)?; Ok(()) diff --git a/zircon-syscall/src/socket.rs b/zircon-syscall/src/socket.rs index 5eac6078..ea00f292 100644 --- a/zircon-syscall/src/socket.rs +++ b/zircon-syscall/src/socket.rs @@ -1,8 +1,8 @@ use {super::*, zircon_object::ipc::Socket, zircon_object::ipc::SocketFlags}; impl Syscall<'_> { - /// Create a socket. - /// + /// Create a socket. + /// /// Socket is a connected pair of bidirectional stream transports, that can move only data, and that have a maximum capacity. pub fn sys_socket_create( &self, @@ -20,9 +20,9 @@ impl Syscall<'_> { Ok(()) } - /// Write data to a socket. - /// - /// Attempts to write `count: usize` bytes to the socket specified by `handle_value`. + /// Write data to a socket. + /// + /// Attempts to write `count: usize` bytes to the socket specified by `handle_value`. pub fn sys_socket_write( &self, handle_value: HandleValue, @@ -35,21 +35,20 @@ impl Syscall<'_> { "socket.write: socket={:#x?}, options={:#x?}, buffer={:#x?}, size={:#x?}", handle_value, options, user_bytes, count, ); - if count > 0 && user_bytes.is_null() { - return Err(ZxError::INVALID_ARGS); + if (count == 0 || !user_bytes.is_null()) && options == 0 { + let actual_count = self + .thread + .proc() + .get_object_with_rights::(handle_value, Rights::WRITE)? + .write(user_bytes.as_slice(count)?)?; + actual_count_ptr.write_if_not_null(actual_count)?; + Ok(()) + } else { + Err(ZxError::INVALID_ARGS) } - if options != 0 { - return Err(ZxError::INVALID_ARGS); - } - let proc = self.thread.proc(); - let socket = proc.get_object_with_rights::(handle_value, Rights::WRITE)?; - let data = user_bytes.read_array(count)?; - let actual_count = socket.write(&data)?; - actual_count_ptr.write_if_not_null(actual_count)?; - Ok(()) } - /// Read data from a socket. + /// Read data from a socket. pub fn sys_socket_read( &self, handle_value: HandleValue, @@ -79,7 +78,7 @@ impl Syscall<'_> { Ok(()) } - /// Prevent future reading or writing on a socket. + /// Prevent future reading or writing on a socket. pub fn sys_socket_shutdown(&self, socket: HandleValue, options: u32) -> ZxResult { let options = SocketFlags::from_bits_truncate(options); info!( diff --git a/zircon-syscall/src/task.rs b/zircon-syscall/src/task.rs index 9700a724..153eeb0b 100644 --- a/zircon-syscall/src/task.rs +++ b/zircon-syscall/src/task.rs @@ -14,7 +14,7 @@ impl Syscall<'_> { mut proc_handle: UserOutPtr, mut vmar_handle: UserOutPtr, ) -> ZxResult { - let name = name.read_string(name_size)?; + let name = name.as_str(name_size)?; info!( "proc.create: job={:#x?}, name={:?}, options={:#x?}", job, name, options, @@ -26,7 +26,7 @@ impl Syscall<'_> { let job = proc .get_object_with_rights::(job, Rights::MANAGE_PROCESS) .or_else(|_| proc.get_object_with_rights::(job, Rights::WRITE))?; - let new_proc = Process::create(&job, &name)?; + let new_proc = Process::create(&job, name)?; let new_vmar = new_proc.vmar(); let proc_handle_value = proc.add_handle(Handle::new(new_proc, Rights::DEFAULT_PROCESS)); let vmar_handle_value = proc.add_handle(Handle::new( @@ -57,7 +57,7 @@ impl Syscall<'_> { options: u32, mut thread_handle: UserOutPtr, ) -> ZxResult { - let name = name.read_string(name_size)?; + let name = name.as_str(name_size)?; info!( "thread.create: proc={:#x?}, name={:?}, options={:#x?}", proc_handle, name, options, @@ -67,7 +67,7 @@ impl Syscall<'_> { } let proc = self.thread.proc(); let process = proc.get_object_with_rights::(proc_handle, Rights::MANAGE_THREAD)?; - let thread = Thread::create(&process, &name)?; + let thread = Thread::create(&process, name)?; let handle = proc.add_handle(Handle::new(thread, Rights::DEFAULT_THREAD)); thread_handle.write(handle)?; Ok(()) @@ -146,11 +146,10 @@ impl Syscall<'_> { "thread.write_state: handle={:#x?}, kind={:#x?}, buf=({:#x?}; {:#x?})", handle, kind, buffer, buffer_size, ); - let proc = self.thread.proc(); - let thread = proc.get_object_with_rights::(handle, Rights::WRITE)?; - let buf = buffer.read_array(buffer_size)?; - thread.write_state(kind, &buf)?; - Ok(()) + self.thread + .proc() + .get_object_with_rights::(handle, Rights::WRITE)? + .write_state(kind, buffer.as_slice(buffer_size)?) } /// Sets process as critical to job. @@ -304,9 +303,10 @@ impl Syscall<'_> { JOB_POL_ABSOLUTE => SetPolicyOptions::Absolute, _ => return Err(ZxError::INVALID_ARGS), }; - let all_policy = - UserInPtr::::from(policy).read_array(count as usize)?; - job.set_policy_basic(policy_option, &all_policy) + job.set_policy_basic( + policy_option, + UserInPtr::from(policy).as_slice(count as usize)?, + ) } //JOB_POL_BASE_V2 => unimplemented!(), JOB_POL_TIMER_SLACK => { @@ -357,15 +357,17 @@ impl Syscall<'_> { mut actual: UserOutPtr, ) -> ZxResult { if buffer.is_null() || buffer_size == 0 || buffer_size > MAX_BLOCK { - return Err(ZxError::INVALID_ARGS); + Err(ZxError::INVALID_ARGS) + } else { + let len = self + .thread + .proc() + .get_object_with_rights::(handle_value, Rights::READ | Rights::WRITE)? + .vmar() + .write_memory(vaddr, buffer.as_slice(buffer_size)?)?; + actual.write(len)?; + Ok(()) } - let proc = self.thread.proc(); - let process = - proc.get_object_with_rights::(handle_value, Rights::READ | Rights::WRITE)?; - let data = buffer.read_array(buffer_size)?; - let len = process.vmar().write_memory(vaddr, &data)?; - actual.write(len)?; - Ok(()) } } diff --git a/zircon-syscall/src/vmo.rs b/zircon-syscall/src/vmo.rs index b5cdd32d..69d79ba7 100644 --- a/zircon-syscall/src/vmo.rs +++ b/zircon-syscall/src/vmo.rs @@ -71,8 +71,7 @@ impl Syscall<'_> { if offset as usize > vmo.len() || buf_size > vmo.len() - (offset as usize) { return Err(ZxError::OUT_OF_RANGE); } - vmo.write(offset as usize, &buf.read_array(buf_size)?)?; - Ok(()) + vmo.write(offset as usize, buf.as_slice(buf_size)?) } /// Add execute rights to a VMO.