merge master

This commit is contained in:
DeathWish5 2022-04-12 21:39:50 +08:00
commit 16206b1a52
87 changed files with 1986 additions and 1010 deletions

View File

@ -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_TAR := prebuild.tar.xz
RISCV64_ROOTFS_URL := https://github.com/rcore-os/libc-test-prebuilt/releases/download/0.1/$(RISCV64_ROOTFS_TAR) 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 ARCH ?= x86_64
rcore_fs_fuse_revision := 7f5eeac rcore_fs_fuse_revision := 7f5eeac
@ -38,9 +39,14 @@ riscv-rootfs:prebuilt/linux/riscv64/$(RISCV64_ROOTFS_TAR)
@ln -s busybox riscv_rootfs/bin/ls @ln -s busybox riscv_rootfs/bin/ls
libc-test: 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 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: rcore-fs-fuse:
ifneq ($(shell rcore-fs-fuse dir image git-version), $(rcore_fs_fuse_revision)) ifneq ($(shell rcore-fs-fuse dir image git-version), $(rcore_fs_fuse_revision))
@echo Installing rcore-fs-fuse @echo Installing rcore-fs-fuse
@ -89,7 +95,7 @@ baremetal-test-img: prebuilt/linux/$(ROOTFS_TAR) rcore-fs-fuse
@tar xf $< -C $(TMP_ROOTFS) @tar xf $< -C $(TMP_ROOTFS)
@mkdir -p rootfs/lib @mkdir -p rootfs/lib
@cp $(TMP_ROOTFS)/lib/ld-musl-x86_64.so.1 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 @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 @rcore-fs-fuse $(OUT_IMG) rootfs zip
# recover rootfs/ld-musl-x86_64.so.1 for zcore usr libos # 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 @cp prebuilt/linux/libc-libos.so rootfs/lib/ld-musl-x86_64.so.1
@echo Resizing $(ARCH).img @echo Resizing $(ARCH).img
@qemu-img resize $(OUT_IMG) +5M @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

View File

@ -21,6 +21,7 @@ lazy_static = "1.4"
numeric-enum-macro = "0.2" numeric-enum-macro = "0.2"
device_tree = { git = "https://github.com/rcore-os/device_tree-rs", rev = "2f2e55f" } 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" } 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 } 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 } 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" } 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] [target.'cfg(target_arch = "x86_64")'.dependencies]
acpi = "4.1" acpi = "4.1"
x2apic = "0.4" x2apic = "0.4"
x86_64 = "0.14"
[target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies] [target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies]
riscv = { git = "https://github.com/rust-embedded/riscv", rev = "cd31989", features = ["inline-asm"] } riscv = { git = "https://github.com/rust-embedded/riscv", rev = "cd31989", features = ["inline-asm"] }

24
drivers/src/bus/mod.rs Normal file
View File

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

274
drivers/src/bus/pci.rs Normal file
View File

@ -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<usize> {
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<Location> {
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<BTreeMap<Location, Arc<dyn Driver>>> =
Mutex::new(BTreeMap::new());
}
*/
// all devices stored inAllDeviceList

View File

@ -1,3 +1,5 @@
//! Only UEFI Display currently.
mod uefi; mod uefi;
pub use uefi::UefiDisplay; pub use uefi::UefiDisplay;

View File

@ -1,3 +1,5 @@
//! Only Mouse currently.
mod mouse; mod mouse;
pub mod input_event_codes; pub mod input_event_codes;

View File

@ -1,12 +1,10 @@
use core::mem::MaybeUninit; use super::Io;
use core::ops::{BitAnd, BitOr, Not}; use core::ops::{BitAnd, BitOr, Not};
use super::Io; // 主存映射 I/O。
/// Memory-mapped I/O.
#[repr(transparent)] #[repr(transparent)]
pub struct Mmio<T> { pub struct Mmio<T>(T);
value: MaybeUninit<T>,
}
impl<T> Mmio<T> { impl<T> Mmio<T> {
/// # Safety /// # Safety
@ -25,9 +23,7 @@ impl<T> Mmio<T> {
} }
pub fn add<'a>(&self, offset: usize) -> &'a mut Self { pub fn add<'a>(&self, offset: usize) -> &'a mut Self {
unsafe { unsafe { Self::from_base((&self.0 as *const T).add(offset) as _) }
Self::from_base(self.value.as_ptr() as usize + offset * core::mem::size_of::<T>())
}
} }
} }
@ -38,10 +34,19 @@ where
type Value = T; type Value = T;
fn read(&self) -> 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) { 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)
};
} }
} }

View File

@ -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}; use core::ops::{BitAnd, BitOr, Not};
mod mmio; mod mmio;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
mod pio; mod pmio;
pub use mmio::Mmio; pub use mmio::Mmio;
#[cfg(target_arch = "x86_64")] #[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 { pub trait Io {
// 可访问的对象的类型。
/// The type of object to access.
type Value: Copy type Value: Copy
+ BitAnd<Output = Self::Value> + BitAnd<Output = Self::Value>
+ BitOr<Output = Self::Value> + BitOr<Output = Self::Value>
+ Not<Output = Self::Value>; + Not<Output = Self::Value>;
// 从外设读取值。
/// Reads value from device.
fn read(&self) -> Self::Value; fn read(&self) -> Self::Value;
// 向外设写入值。
/// Writes `value` to device.
fn write(&mut self, value: Self::Value); fn write(&mut self, value: Self::Value);
} }
// 外设地址空间的一个只读单元。
/// A readonly unit in device address space.
#[repr(transparent)] #[repr(transparent)]
pub struct ReadOnly<I> { pub struct ReadOnly<I>(I);
inner: I,
}
impl<I> ReadOnly<I> { impl<I> ReadOnly<I> {
pub const fn new(inner: I) -> ReadOnly<I> { // 构造外设地址空间的一个只读单元。
ReadOnly { inner } /// Constructs a readonly unit in device address space.
pub const fn new(inner: I) -> Self {
Self(inner)
} }
} }
impl<I: Io> ReadOnly<I> { impl<I: Io> ReadOnly<I> {
// 从外设读取值。
/// Reads value from device.
#[inline(always)] #[inline(always)]
pub fn read(&self) -> I::Value { pub fn read(&self) -> I::Value {
self.inner.read() self.0.read()
} }
} }
// 外设地址空间的一个只写单元。
/// A write-only unit in device address space.
#[repr(transparent)] #[repr(transparent)]
pub struct WriteOnly<I> { pub struct WriteOnly<I>(I);
inner: I,
}
impl<I> WriteOnly<I> { impl<I> WriteOnly<I> {
pub const fn new(inner: I) -> WriteOnly<I> { // 构造外设地址空间的一个只写单元。
WriteOnly { inner } /// Constructs a write-only unit in device address space.
pub const fn new(inner: I) -> Self {
Self(inner)
} }
} }
impl<I: Io> WriteOnly<I> { impl<I: Io> WriteOnly<I> {
// 向外设写入值。
/// Writes `value` to device.
#[inline(always)] #[inline(always)]
pub fn write(&mut self, value: I::Value) { pub fn write(&mut self, value: I::Value) {
self.inner.write(value) self.0.write(value);
} }
} }

View File

@ -1,30 +1,35 @@
use core::arch::asm; // 端口映射 I/O。
use core::marker::PhantomData; //! Port-mapped I/O.
use super::Io; use super::Io;
use core::{arch::asm, marker::PhantomData};
/// Generic PIO // 端口映射 I/O。
/// Port-mapped I/O.
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct Pio<T> { pub struct Pmio<T> {
port: u16, port: u16,
_phantom: PhantomData<T>, _phantom: PhantomData<T>,
} }
impl<T> Pio<T> { impl<T> Pmio<T> {
/// Create a PIO from a given port // 映射指定端口进行外设访问。
/// Maps a given port to assess device.
pub const fn new(port: u16) -> Self { pub const fn new(port: u16) -> Self {
Pio::<T> { Self {
port, port,
_phantom: PhantomData, _phantom: PhantomData,
} }
} }
} }
/// Read/Write for byte PIO // 逐字节端口映射读写。
impl Io for Pio<u8> { /// Read/Write for byte PMIO.
impl Io for Pmio<u8> {
type Value = u8; type Value = u8;
/// Read // 读。
/// Read.
#[inline(always)] #[inline(always)]
fn read(&self) -> u8 { fn read(&self) -> u8 {
let value: u8; let value: u8;
@ -34,7 +39,8 @@ impl Io for Pio<u8> {
value value
} }
/// Write // 写。
/// Write.
#[inline(always)] #[inline(always)]
fn write(&mut self, value: u8) { fn write(&mut self, value: u8) {
unsafe { unsafe {
@ -43,11 +49,13 @@ impl Io for Pio<u8> {
} }
} }
/// Read/Write for word PIO // 逐字端口映射读写。
impl Io for Pio<u16> { /// Read/Write for word PMIO.
impl Io for Pmio<u16> {
type Value = u16; type Value = u16;
/// Read // 读。
/// Read.
#[inline(always)] #[inline(always)]
fn read(&self) -> u16 { fn read(&self) -> u16 {
let value: u16; let value: u16;
@ -57,7 +65,8 @@ impl Io for Pio<u16> {
value value
} }
/// Write // 写。
/// Write.
#[inline(always)] #[inline(always)]
fn write(&mut self, value: u16) { fn write(&mut self, value: u16) {
unsafe { unsafe {
@ -66,11 +75,13 @@ impl Io for Pio<u16> {
} }
} }
/// Read/Write for doubleword PIO // 逐双字端口映射读写。
impl Io for Pio<u32> { /// Read/Write for double-word PMIO.
impl Io for Pmio<u32> {
type Value = u32; type Value = u32;
/// Read // 读。
/// Read.
#[inline(always)] #[inline(always)]
fn read(&self) -> u32 { fn read(&self) -> u32 {
let value: u32; let value: u32;
@ -80,7 +91,8 @@ impl Io for Pio<u32> {
value value
} }
/// Write // 写。
/// Write.
#[inline(always)] #[inline(always)]
fn write(&mut self, value: u32) { fn write(&mut self, value: u32) {
unsafe { unsafe {

View File

@ -1,8 +1,11 @@
//! External interrupt request and handle.
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] { if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
mod riscv_intc; mod riscv_intc;
mod riscv_plic; mod riscv_plic;
/// Implementation of risc-v interrupt controller.
#[doc(cfg(any(target_arch = "riscv32", target_arch = "riscv64")))] #[doc(cfg(any(target_arch = "riscv32", target_arch = "riscv64")))]
pub mod riscv { pub mod riscv {
pub use super::riscv_intc::{Intc, ScauseIntCode}; 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"))] { } else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
mod x86_apic; mod x86_apic;
/// Implementation of x86 Advanced Programmable Interrupt Controller.
#[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))] #[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))]
pub mod x86 { pub mod x86 {
pub use super::x86_apic::Apic; pub use super::x86_apic::Apic;

View File

@ -40,8 +40,7 @@ impl PlicUnlocked {
let hart_id = cpu_id() as usize; let hart_id = cpu_id() as usize;
let mmio = self let mmio = self
.enable_base .enable_base
.add(PLIC_ENABLE_HART_OFFSET * hart_id) .add(PLIC_ENABLE_HART_OFFSET * hart_id + irq_num / 32);
.add(irq_num / 32);
let mask = 1 << (irq_num % 32); let mask = 1 << (irq_num % 32);
if enable { if enable {
@ -56,8 +55,7 @@ impl PlicUnlocked {
let hart_id = cpu_id() as usize; let hart_id = cpu_id() as usize;
let irq_num = self let irq_num = self
.context_base .context_base
.add(PLIC_CONTEXT_CLAIM_HART_OFFSET * hart_id) .add(PLIC_CONTEXT_CLAIM_HART_OFFSET * hart_id + PLIC_CONTEXT_CLAIM)
.add(PLIC_CONTEXT_CLAIM)
.read() as usize; .read() as usize;
if irq_num == 0 { if irq_num == 0 {
None None
@ -71,8 +69,7 @@ impl PlicUnlocked {
debug_assert!(IRQ_RANGE.contains(&irq_num)); debug_assert!(IRQ_RANGE.contains(&irq_num));
let hart_id = cpu_id() as usize; let hart_id = cpu_id() as usize;
self.context_base self.context_base
.add(PLIC_CONTEXT_CLAIM) .add(PLIC_CONTEXT_CLAIM + PLIC_CONTEXT_CLAIM_HART_OFFSET * hart_id)
.add(PLIC_CONTEXT_CLAIM_HART_OFFSET * hart_id)
.write(irq_num as _); .write(irq_num as _);
} }
@ -86,8 +83,7 @@ impl PlicUnlocked {
fn set_threshold(&mut self, threshold: u8) { fn set_threshold(&mut self, threshold: u8) {
let hart_id = cpu_id() as usize; let hart_id = cpu_id() as usize;
self.context_base self.context_base
.add(PLIC_PRIORITY_HART_OFFSET * hart_id) .add(PLIC_PRIORITY_HART_OFFSET * hart_id + PLIC_CONTEXT_THRESHOLD)
.add(PLIC_CONTEXT_THRESHOLD)
.write(threshold as _); .write(threshold as _);
} }

View File

@ -67,9 +67,23 @@ impl IoApic {
let mut inner = unsafe { IoApicInner::new(base_vaddr as u64) }; let mut inner = unsafe { IoApicInner::new(base_vaddr as u64) };
let max_entry = unsafe { inner.max_table_entry() }; let max_entry = unsafe { inner.max_table_entry() };
unsafe { assert_eq!(id, inner.id()) }; 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 { 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 { Self {
id, id,

View File

@ -19,6 +19,7 @@ const LAPIC_IRQ_RANGE: Range<usize> = 0..16;
type Phys2VirtFn = fn(paddr: PhysAddr) -> VirtAddr; type Phys2VirtFn = fn(paddr: PhysAddr) -> VirtAddr;
/// Advanced Programmable Interrupt Controller
pub struct Apic { pub struct Apic {
ioapic_list: IoApicList, ioapic_list: IoApicList,
manager_ioapic: Mutex<IrqManager<256>>, manager_ioapic: Mutex<IrqManager<256>>,
@ -26,6 +27,7 @@ pub struct Apic {
} }
impl Apic { impl Apic {
/// Construct a new `Apic`.
pub fn new(acpi_rsdp: usize, phys_to_virt: Phys2VirtFn) -> Self { pub fn new(acpi_rsdp: usize, phys_to_virt: Phys2VirtFn) -> Self {
Self { Self {
ioapic_list: IoApicList::new(acpi_rsdp, phys_to_virt), ioapic_list: IoApicList::new(acpi_rsdp, phys_to_virt),

View File

@ -1,3 +1,5 @@
//! Device drivers of zCore.
#![cfg_attr(not(feature = "mock"), no_std)] #![cfg_attr(not(feature = "mock"), no_std)]
#![feature(doc_cfg)] #![feature(doc_cfg)]
@ -18,6 +20,7 @@ pub mod mock;
pub mod virtio; pub mod virtio;
pub mod builder; pub mod builder;
pub mod bus;
pub mod display; pub mod display;
pub mod input; pub mod input;
pub mod io; pub mod io;
@ -28,6 +31,7 @@ pub mod scheme;
pub mod uart; pub mod uart;
pub mod utils; pub mod utils;
/// The error type for external device.
#[derive(Debug)] #[derive(Debug)]
pub enum DeviceError { pub enum DeviceError {
/// The buffer is too small. /// The buffer is too small.
@ -48,19 +52,28 @@ pub enum DeviceError {
NotSupported, NotSupported,
} }
/// A type alias for the result of a device operation.
pub type DeviceResult<T = ()> = core::result::Result<T, DeviceError>; pub type DeviceResult<T = ()> = core::result::Result<T, DeviceError>;
/// Static shell of shared dynamic device [`Scheme`](crate::scheme::Scheme) types.
#[derive(Clone)] #[derive(Clone)]
pub enum Device { pub enum Device {
/// Block device
Block(Arc<dyn scheme::BlockScheme>), Block(Arc<dyn scheme::BlockScheme>),
/// Display device
Display(Arc<dyn scheme::DisplayScheme>), Display(Arc<dyn scheme::DisplayScheme>),
/// Input device
Input(Arc<dyn scheme::InputScheme>), Input(Arc<dyn scheme::InputScheme>),
/// Interrupt request and handle
Irq(Arc<dyn scheme::IrqScheme>), Irq(Arc<dyn scheme::IrqScheme>),
/// Network device
Net(Arc<dyn scheme::NetScheme>), Net(Arc<dyn scheme::NetScheme>),
/// Uart port
Uart(Arc<dyn scheme::UartScheme>), Uart(Arc<dyn scheme::UartScheme>),
} }
impl Device { impl Device {
/// Get a general [`Scheme`](scheme::Scheme) from the device.
pub fn inner(&self) -> Arc<dyn scheme::Scheme> { pub fn inner(&self) -> Arc<dyn scheme::Scheme> {
match self { match self {
Self::Block(d) => d.clone().upcast(), Self::Block(d) => d.clone().upcast(),

View File

@ -1,3 +1,5 @@
//! Mock devices, including display, input, uart and graphic.
pub mod display; pub mod display;
pub mod input; pub mod input;
pub mod uart; pub mod uart;

View File

@ -1,3 +1,5 @@
//! LAN driver, only for Realtek currently.
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(target_arch = "riscv64")] { if #[cfg(target_arch = "riscv64")] {
mod realtek; mod realtek;

View File

@ -235,7 +235,7 @@ where
mac[i] = u8::from_str_radix(s, 16).unwrap(); mac[i] = u8::from_str_radix(s, 16).unwrap();
} }
} else { } else {
mac = mac_addr.clone(); mac = *mac_addr;
} }
info!( info!(
@ -1144,10 +1144,10 @@ where
#[allow(clippy::collapsible_if)] #[allow(clippy::collapsible_if)]
/* 正常的 TX/RX NORMAL interrupts */ /* 正常的 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 | RX_EARLY_INT | TX_UA_INT)) != 0
if (intr_status & (TX_INT | RX_INT)) != 0 { && (intr_status & (TX_INT | RX_INT)) != 0
status = tx_dma_irq_status::handle_tx_rx as i32; {
} status = tx_dma_irq_status::handle_tx_rx as i32;
} }
/* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */ /* 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); write_volatile((self.base + GETH_INT_STA) as *mut u32, intr_status & 0x3FFF);
@ -1434,7 +1434,14 @@ where
match speed { match speed {
1000 => ctrl &= !0x0C, 1000 => ctrl &= !0x0C,
/*100 | 10 |*/ 100 | 10 => {
ctrl |= 0x08;
if (speed == 100) {
ctrl |= 0x04;
} else {
ctrl &= !0x04;
}
}
_ => { _ => {
ctrl |= 0x08; ctrl |= 0x08;
if (speed == 100) { if (speed == 100) {

View File

@ -1,14 +1,14 @@
use alloc::collections::BTreeMap; use alloc::collections::BTreeMap;
use alloc::string::String; use alloc::string::String;
use alloc::sync::Arc; use alloc::sync::Arc;
use alloc::vec; // use alloc::vec;
use alloc::vec::Vec; use alloc::vec::Vec;
// use spin::Mutex; // use spin::Mutex;
use lock::Mutex; use lock::Mutex;
use smoltcp::iface::*; use smoltcp::iface::*;
use smoltcp::phy::{self, Device, DeviceCapabilities, Medium}; use smoltcp::phy::{self, Device, DeviceCapabilities, Medium};
use smoltcp::socket::SocketSet; // use smoltcp::socket::SocketSet;
use smoltcp::time::Instant; use smoltcp::time::Instant;
use smoltcp::wire::*; use smoltcp::wire::*;
use smoltcp::Result; use smoltcp::Result;
@ -19,6 +19,7 @@ use super::ProviderImpl;
use super::PAGE_SIZE; use super::PAGE_SIZE;
//use kernel_hal::drivers::{Driver, DeviceType, NetDriver, DRIVERS, NET_DRIVERS, SOCKETS}; //use kernel_hal::drivers::{Driver, DeviceType, NetDriver, DRIVERS, NET_DRIVERS, SOCKETS};
use crate::net::get_sockets;
use crate::scheme::{NetScheme, Scheme}; use crate::scheme::{NetScheme, Scheme};
use crate::{DeviceError, DeviceResult}; use crate::{DeviceError, DeviceResult};
@ -49,13 +50,13 @@ impl Scheme for RTLxInterface {
let handle_tx_rx = 3; let handle_tx_rx = 3;
if status == handle_tx_rx { if status == handle_tx_rx {
let timestamp = Instant::from_millis(0); 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(); self.driver.0.lock().int_disable();
match self.iface.lock().poll(&mut sockets, timestamp) { match self.iface.lock().poll(&mut sockets, timestamp) {
Ok(_) => { Ok(b) => {
//SOCKET_ACTIVITY.notify_all(); debug!("nic poll, is changed ?: {}", b);
debug!("try_handle_interrupt SOCKET_ACTIVITY unimplemented");
} }
Err(err) => { Err(err) => {
error!("poll got err {}", err); error!("poll got err {}", err);
@ -82,11 +83,11 @@ impl NetScheme for RTLxInterface {
fn poll(&self) -> DeviceResult { fn poll(&self) -> DeviceResult {
let timestamp = Instant::from_millis(0); 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) { match self.iface.lock().poll(&mut sockets, timestamp) {
Ok(_) => { Ok(b) => {
//SOCKET_ACTIVITY.notify_all(); debug!("nic poll, is changed ?: {}", b);
error!("poll, SOCKET_ACTIVITY unimplemented");
Ok(()) Ok(())
} }
Err(err) => { Err(err) => {
@ -193,14 +194,20 @@ pub fn rtlx_init<F: Fn(usize, usize) -> Option<usize>>(
let ethernet_addr = EthernetAddress::from_bytes(&mac); let ethernet_addr = EthernetAddress::from_bytes(&mac);
let ip_addrs = [IpCidr::new(IpAddress::v4(192, 168, 0, 123), 24)]; 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 neighbor_cache = NeighborCache::new(BTreeMap::new());
let iface = InterfaceBuilder::new(net_driver.clone()) let iface = InterfaceBuilder::new(net_driver.clone())
.ethernet_addr(ethernet_addr) .ethernet_addr(ethernet_addr)
.neighbor_cache(neighbor_cache) .neighbor_cache(neighbor_cache)
.ip_addrs(ip_addrs) .ip_addrs(ip_addrs)
.routes(routes)
.finalize(); .finalize();
info!("rtl8211f interface up with addr 192.168.0.123/24"); 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 { let rtl8211f_iface = RTLxInterface {
iface: Arc::new(Mutex::new(iface)), iface: Arc::new(Mutex::new(iface)),
driver: net_driver, driver: net_driver,
@ -212,7 +219,7 @@ pub fn rtlx_init<F: Fn(usize, usize) -> Option<usize>>(
} }
//TODO: Global SocketSet //TODO: Global SocketSet
lazy_static::lazy_static! { // lazy_static::lazy_static! {
pub static ref SOCKETS: Mutex<SocketSet<'static>> = // pub static ref SOCKETS: Mutex<SocketSet<'static>> =
Mutex::new(SocketSet::new(vec![])); // Mutex::new(SocketSet::new(vec![]));
} // }

View File

@ -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::display::{ColorFormat, DisplayInfo, FrameBuffer, Rectangle, RgbColor};
pub use crate::scheme::input::{CapabilityType, InputCapability, InputEvent, InputEventType}; pub use crate::scheme::input::{CapabilityType, InputCapability, InputEvent, InputEventType};
pub use crate::scheme::irq::{IrqHandler, IrqPolarity, IrqTriggerMode}; pub use crate::scheme::irq::{IrqHandler, IrqPolarity, IrqTriggerMode};
pub use crate::{Device, DeviceError, DeviceResult}; pub use crate::{Device, DeviceError, DeviceResult};
/// Re-export types from [`input`](crate::input).
pub mod input { pub mod input {
pub use crate::input::{Mouse, MouseFlags, MouseState}; pub use crate::input::{Mouse, MouseFlags, MouseState};
} }

View File

@ -5,6 +5,7 @@ use core::ops::Range;
use super::Scheme; use super::Scheme;
use crate::DeviceResult; use crate::DeviceResult;
/// A type alias for
pub type IrqHandler = Box<dyn Fn() + Send + Sync>; pub type IrqHandler = Box<dyn Fn() + Send + Sync>;
#[derive(Debug)] #[derive(Debug)]

View File

@ -1,5 +1,5 @@
//! The [`Scheme`] describe some functions must be implemented for device, there are //! The [`Scheme`] describe some functions must be implemented for different type of devices,
//! many [`Scheme`] traits in this mod. //! there are many [`Scheme`] traits in this mod.
//! //!
//! If you need to develop a new device, just implement the corresponding trait. //! 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 net::NetScheme;
pub use uart::UartScheme; pub use uart::UartScheme;
/// Common of all device drivers.
///
/// Every device must says its name and handles interrupts.
pub trait Scheme: SchemeUpcast + Send + Sync { pub trait Scheme: SchemeUpcast + Send + Sync {
/// Returns name of the driver.
fn name(&self) -> &str; fn name(&self) -> &str;
/// Handles an interrupt.
fn handle_irq(&self, _irq_num: usize) {} fn handle_irq(&self, _irq_num: usize) {}
} }
/// Used to convert a concrete type pointer to a general [`Scheme`] pointer.
pub trait SchemeUpcast { pub trait SchemeUpcast {
/// Performs the conversion.
fn upcast<'a>(self: Arc<Self>) -> Arc<dyn Scheme + 'a> fn upcast<'a>(self: Arc<Self>) -> Arc<dyn Scheme + 'a>
where where
Self: 'a; Self: 'a;

View File

@ -1,3 +1,5 @@
//! Uart device driver.
mod buffered; mod buffered;
mod uart_16550; mod uart_16550;
@ -5,4 +7,4 @@ pub use buffered::BufferedUart;
pub use uart_16550::Uart16550Mmio; pub use uart_16550::Uart16550Mmio;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
pub use uart_16550::Uart16550Pio; pub use uart_16550::Uart16550Pmio;

View File

@ -107,6 +107,7 @@ where
} }
} }
/// MMIO driver for UART 16550
pub struct Uart16550Mmio<V: 'static> pub struct Uart16550Mmio<V: 'static>
where where
V: Copy + BitAnd<Output = V> + BitOr<Output = V> + Not<Output = V>, V: Copy + BitAnd<Output = V> + BitOr<Output = V> + Not<Output = V>,
@ -201,20 +202,21 @@ impl Uart16550Mmio<u32> {
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
mod pio { mod pmio {
use super::*; use super::*;
use crate::io::Pio; use crate::io::Pmio;
pub struct Uart16550Pio { /// Pmio driver for UART 16550
inner: Mutex<Uart16550Inner<Pio<u8>>>, pub struct Uart16550Pmio {
inner: Mutex<Uart16550Inner<Pmio<u8>>>,
listener: EventListener, listener: EventListener,
} }
impl_event_scheme!(Uart16550Pio); impl_event_scheme!(Uart16550Pmio);
impl Scheme for Uart16550Pio { impl Scheme for Uart16550Pmio {
fn name(&self) -> &str { fn name(&self) -> &str {
"uart16550-pio" "uart16550-Pmio"
} }
fn handle_irq(&self, _irq_num: usize) { 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<Option<u8>> { fn try_recv(&self) -> DeviceResult<Option<u8>> {
self.inner.lock().try_recv() 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 { pub fn new(base: u16) -> Self {
let mut uart = Uart16550Inner::<Pio<u8>> { let mut uart = Uart16550Inner::<Pmio<u8>> {
data: Pio::new(base), data: Pmio::new(base),
int_en: Pio::new(base + 1), int_en: Pmio::new(base + 1),
fifo_ctrl: Pio::new(base + 2), fifo_ctrl: Pmio::new(base + 2),
line_ctrl: Pio::new(base + 3), line_ctrl: Pmio::new(base + 3),
modem_ctrl: Pio::new(base + 4), modem_ctrl: Pmio::new(base + 4),
line_sts: ReadOnly::new(Pio::new(base + 5)), line_sts: ReadOnly::new(Pmio::new(base + 5)),
modem_sts: ReadOnly::new(Pio::new(base + 6)), modem_sts: ReadOnly::new(Pmio::new(base + 6)),
}; };
uart.init(); uart.init();
Self { Self {
@ -257,4 +260,4 @@ mod pio {
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
pub use pio::Uart16550Pio; pub use pmio::Uart16550Pmio;

View File

@ -1,9 +1,9 @@
use alloc::vec::Vec; //! Package of [`device_tree`].
use core::ops::Range;
use device_tree::{DeviceTree as DeviceTreeInner, PropError};
use crate::{DeviceError, DeviceResult, PhysAddr, VirtAddr}; 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}; pub use device_tree::{util::StringList, Node};

View File

@ -1,25 +1,35 @@
use alloc::{boxed::Box, vec::Vec}; use alloc::{boxed::Box, vec::Vec};
// use spin::Mutex;
use lock::Mutex; use lock::Mutex;
/// A type alias for the closure to handle device event.
pub type EventHandler<T = ()> = Box<dyn Fn(&T) + Send + Sync>; pub type EventHandler<T = ()> = Box<dyn Fn(&T) + Send + Sync>;
/// Device event listener.
///
/// It keeps a series of [`EventHandler`]s that handle events of one single type.
pub struct EventListener<T = ()> { pub struct EventListener<T = ()> {
events: Mutex<Vec<(EventHandler<T>, bool)>>, events: Mutex<Vec<(EventHandler<T>, bool)>>,
} }
impl<T> EventListener<T> { impl<T> EventListener<T> {
/// Construct a new, empty `EventListener`.
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
events: Mutex::new(Vec::new()), 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<T>, once: bool) { pub fn subscribe(&self, handler: EventHandler<T>, once: bool) {
self.events.lock().push((handler, once)); 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) { pub fn trigger(&self, event: T) {
self.events.lock().retain(|(f, once)| { self.events.lock().retain(|(f, once)| {
f(&event); f(&event);

View File

@ -1,3 +1,5 @@
//! Event handler and device tree.
#![allow(unused_imports)] #![allow(unused_imports)]
mod event_listener; mod event_listener;

View File

@ -1,3 +1,5 @@
//! Packaging of [`virtio-drivers` library](https://github.com/rcore-os/virtio-drivers).
mod blk; mod blk;
mod console; mod console;
mod gpu; mod gpu;

View File

@ -13,6 +13,8 @@ smp = []
libos = ["nix", "tempfile", "async-std", "bitmap-allocator", "zcore-drivers/mock"] libos = ["nix", "tempfile", "async-std", "bitmap-allocator", "zcore-drivers/mock"]
graphic = ["zcore-drivers/graphic"] graphic = ["zcore-drivers/graphic"]
loopback = []
[dependencies] [dependencies]
log = "0.4" log = "0.4"
spin = "0.9" spin = "0.9"
@ -26,7 +28,6 @@ zcore-drivers = { path = "../drivers", features = ["virtio"] }
lock = { git = "https://github.com/DeathWish5/kernel-sync" } 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"] } 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 # LibOS mode
[target.'cfg(not(target_os = "none"))'.dependencies] [target.'cfg(not(target_os = "none"))'.dependencies]
nix = { version = "0.23", optional = true } nix = { version = "0.23", optional = true }

View File

@ -92,5 +92,21 @@ pub(super) fn intc_init() -> DeviceResult {
)?; )?;
irq.unmask(ScauseIntCode::SupervisorSoft as _)?; irq.unmask(ScauseIntCode::SupervisorSoft as _)?;
irq.unmask(ScauseIntCode::SupervisorTimer 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(()) Ok(())
} }

View File

@ -26,8 +26,8 @@ hal_fn_impl! {
fn reset() -> ! { fn reset() -> ! {
info!("shutdown..."); info!("shutdown...");
loop { loop {
use zcore_drivers::io::{Io, Pio}; use zcore_drivers::io::{Io, Pmio};
Pio::<u16>::new(0x604).write(0x2000); Pmio::<u16>::new(0x604).write(0x2000);
super::interrupt::wait_for_interrupt(); super::interrupt::wait_for_interrupt();
} }
} }

View File

@ -1,15 +1,18 @@
use alloc::{boxed::Box, sync::Arc}; use alloc::{boxed::Box, sync::Arc};
use zcore_drivers::bus::pci;
use zcore_drivers::irq::x86::Apic; use zcore_drivers::irq::x86::Apic;
use zcore_drivers::scheme::IrqScheme; use zcore_drivers::scheme::IrqScheme;
use zcore_drivers::uart::{BufferedUart, Uart16550Pio}; use zcore_drivers::uart::{BufferedUart, Uart16550Pmio};
use zcore_drivers::{Device, DeviceResult}; use zcore_drivers::{Device, DeviceResult};
use super::trap; use super::trap;
use crate::drivers; use crate::drivers;
pub(super) fn init_early() -> DeviceResult { 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))); drivers::add_device(Device::Uart(BufferedUart::new(uart)));
Ok(()) Ok(())
} }
@ -20,14 +23,22 @@ pub(super) fn init() -> DeviceResult {
super::special::pc_firmware_tables().0 as usize, super::special::pc_firmware_tables().0 as usize,
crate::mem::phys_to_virt, crate::mem::phys_to_virt,
)); ));
irq.register_device( let uarts = drivers::all_uart();
trap::X86_ISA_IRQ_COM1, if let Some(u) = uarts.try_get(0) {
drivers::all_uart().first_unwrap().upcast(), irq.register_device(trap::X86_ISA_IRQ_COM1, u.clone().upcast())?;
)?; irq.unmask(trap::X86_ISA_IRQ_COM1)?;
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))?; irq.register_local_apic_handler(trap::X86_INT_APIC_TIMER, Box::new(super::trap::super_timer))?;
drivers::add_device(Device::Irq(irq)); drivers::add_device(Device::Irq(irq));
// PCI scan
pci::init();
#[cfg(feature = "graphic")] #[cfg(feature = "graphic")]
{ {
use crate::KCONFIG; use crate::KCONFIG;
@ -46,6 +57,12 @@ pub(super) fn init() -> DeviceResult {
crate::console::init_graphic_console(display); crate::console::init_graphic_console(display);
} }
#[cfg(feature = "loopback")]
{
use crate::net;
net::init();
}
info!("Drivers init end."); info!("Drivers init end.");
Ok(()) Ok(())
} }

View File

@ -1,6 +1,6 @@
//! Functions only available on x86 platforms. //! 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. /// Get physical address of `acpi_rsdp` and `smbios` on x86_64.
pub fn pc_firmware_tables() -> (u64, u64) { pub fn pc_firmware_tables() -> (u64, u64) {

View File

@ -1,6 +1,5 @@
//! Bootstrap and initialization. //! Bootstrap and initialization.
use super::net;
use crate::{KernelConfig, KernelHandler, KCONFIG, KHANDLER}; use crate::{KernelConfig, KernelHandler, KCONFIG, KHANDLER};
hal_fn_impl! { hal_fn_impl! {
@ -24,7 +23,6 @@ hal_fn_impl! {
info!("Primary CPU {} init...", crate::cpu::cpu_id()); info!("Primary CPU {} init...", crate::cpu::cpu_id());
unsafe { trapframe::init() }; unsafe { trapframe::init() };
super::arch::primary_init(); super::arch::primary_init();
net::init();
} }
fn secondary_init() { fn secondary_init() {

View File

@ -1,3 +1,4 @@
// May need move to drivers
use smoltcp::{ use smoltcp::{
iface::{InterfaceBuilder, NeighborCache, Route, Routes}, iface::{InterfaceBuilder, NeighborCache, Route, Routes},
phy::{Loopback, Medium}, phy::{Loopback, Medium},

View File

@ -1,23 +1,42 @@
//! Read/write user space pointer. // 来自用户空间的裸指针
//! Raw pointer from user land.
use alloc::string::String; use crate::VirtAddr;
use alloc::vec::Vec; use alloc::{string::String, vec::Vec};
use core::fmt::{Debug, Formatter}; use core::{
use core::marker::PhantomData; fmt::{Debug, Formatter},
use core::ops::{Deref, DerefMut}; marker::PhantomData,
ops::{Deref, DerefMut},
};
#[repr(C)] // 来自用户空间的裸指针
pub struct UserPtr<T, P: Policy> { /// Raw pointer from user land.
ptr: *mut T, #[repr(transparent)]
mark: PhantomData<P>, pub struct UserPtr<T, P: Policy>(*mut T, PhantomData<P>);
}
// 标识用户指针功能的基特征。
/// Base trait for Markers of user pointer policy.
pub trait Policy {} pub trait Policy {}
// 标记一个用于输入的指针。
/// Marks a pointer used to read.
pub trait Read: Policy {} pub trait Read: Policy {}
// 标记一个用于输出的指针。
/// Marks a pointer used to write.
pub trait Write: Policy {} 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 In {}
impl Policy for Out {} impl Policy for Out {}
@ -31,9 +50,8 @@ pub type UserInPtr<T> = UserPtr<T, In>;
pub type UserOutPtr<T> = UserPtr<T, Out>; pub type UserOutPtr<T> = UserPtr<T, Out>;
pub type UserInOutPtr<T> = UserPtr<T, InOut>; pub type UserInOutPtr<T> = UserPtr<T, InOut>;
type Result<T> = core::result::Result<T, Error>; // 用户指针操作的异常类型。
/// The error type which is returned from user pointer operation.
/// The error type which is returned from user pointer.
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Error { pub enum Error {
InvalidUtf8, InvalidUtf8,
@ -43,9 +61,13 @@ pub enum Error {
InvalidVectorAddress, InvalidVectorAddress,
} }
// 本模块用到的只是用户指针操作结果的类型。
type Result<T> = core::result::Result<T, Error>;
impl<T, P: Policy> Debug for UserPtr<T, P> { impl<T, P: Policy> Debug for UserPtr<T, P> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self.ptr) // 打印用户指针就是打印裸指针
write!(f, "{:?}", self.0)
} }
} }
@ -54,154 +76,210 @@ unsafe impl<T, P: Policy> Send for UserPtr<T, P> {}
unsafe impl<T, P: Policy> Sync for UserPtr<T, P> {} unsafe impl<T, P: Policy> Sync for UserPtr<T, P> {}
impl<T, P: Policy> From<usize> for UserPtr<T, P> { impl<T, P: Policy> From<usize> for UserPtr<T, P> {
fn from(x: usize) -> Self { fn from(ptr: usize) -> Self {
UserPtr { UserPtr(ptr as _, PhantomData)
ptr: x as _,
mark: PhantomData,
}
} }
} }
impl<T, P: Policy> UserPtr<T, P> { impl<T, P: Policy> UserPtr<T, P> {
// 检查 `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<Self> { pub fn from_addr_size(addr: usize, size: usize) -> Result<Self> {
if size < core::mem::size_of::<T>() { if size >= core::mem::size_of::<T>() {
return Err(Error::BufferTooSmall); 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 { pub fn is_null(&self) -> bool {
self.ptr.is_null() self.0.is_null()
} }
// 偏移指针。
// `count` 表示 `T` 的数量;
// 例如,`count` 为 3 表示将指针移动 `3 * size_of::<T>()` 个字节。
/// 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::<T>()` bytes.
pub fn add(&self, count: usize) -> Self { pub fn add(&self, count: usize) -> Self {
UserPtr { Self(unsafe { self.0.add(count) }, PhantomData)
ptr: unsafe { self.ptr.add(count) },
mark: 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<()> { pub fn check(&self) -> Result<()> {
if self.ptr.is_null() { if !self.0.is_null() && (self.0 as usize) % core::mem::align_of::<T>() == 0 {
return Err(Error::InvalidPointer); Ok(())
} else {
Err(Error::InvalidPointer)
} }
if (self.ptr as usize) % core::mem::align_of::<T>() != 0 {
return Err(Error::InvalidPointer);
}
Ok(())
} }
} }
impl<T, P: Read> UserPtr<T, P> { impl<T, P: Read> UserPtr<T, P> {
pub fn as_ref(&self) -> Result<&'static T> { // 取出指针值的引用(不要用于小于 8 字节的类型)。
Ok(unsafe { &*self.ptr }) /// 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<T> { pub fn read(&self) -> Result<T> {
// TODO: check ptr and return err
self.check()?; 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<Option<T>> { pub fn read_if_not_null(&self) -> Result<Option<T>> {
if self.ptr.is_null() { if !self.0.is_null() {
return Ok(None); 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<Vec<T>> { pub fn read_array(&self, len: usize) -> Result<Vec<T>> {
if len == 0 { if len == 0 {
return Ok(Vec::default()); Ok(Vec::default())
} else {
self.check()?;
let mut ret = Vec::<T>::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::<T>::with_capacity(len);
unsafe {
ret.set_len(len);
ret.as_mut_ptr().copy_from_nonoverlapping(self.ptr, len);
}
Ok(ret)
} }
} }
impl<P: Read> UserPtr<u8, P> { impl<P: Read> UserPtr<u8, P> {
pub fn read_string(&self, len: usize) -> Result<String> { // 构造一个从指针指向开始,长度为 `len` 的字符切片。
self.check()?; /// Forms an utf-8 string slice from a user pointer and a `len`.
let src = unsafe { core::slice::from_raw_parts(self.ptr, len) }; pub fn as_str(&self, len: usize) -> Result<&'static str> {
let s = core::str::from_utf8(src).map_err(|_| Error::InvalidUtf8)?; core::str::from_utf8(self.as_slice(len)?).map_err(|_| Error::InvalidUtf8)
Ok(String::from(s))
} }
pub fn read_cstring(&self) -> Result<String> { // 从一个 C 风格的零结尾字符串构造一个字符切片。
self.check()?; /// Forms a zero-terminated string slice from a user pointer to a c style string.
let len = unsafe { (0usize..).find(|&i| *self.ptr.add(i) == 0).unwrap() }; pub fn as_c_str(&self) -> Result<&'static str> {
self.read_string(len) self.as_str(unsafe { (0usize..).find(|&i| *self.0.add(i) == 0).unwrap() })
} }
} }
impl<P: Read> UserPtr<UserPtr<u8, P>, P> { impl<P: 'static + Read> UserPtr<UserPtr<u8, P>, 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<Vec<String>> { pub fn read_cstring_array(&self) -> Result<Vec<String>> {
self.check()?; self.check()?;
let len = unsafe { let mut result = Vec::new();
(0usize..) let mut pptr = self.0;
.find(|&i| self.ptr.add(i).read().is_null()) loop {
.unwrap() let sptr = unsafe { pptr.read() };
}; if sptr.is_null() {
self.read_array(len)? break;
.into_iter() }
.map(|ptr| ptr.read_cstring()) result.push(sptr.as_c_str()?.into());
.collect() pptr = unsafe { pptr.add(1) };
}
Ok(result)
} }
} }
impl<T, P: Write> UserPtr<T, P> { impl<T, P: Write> UserPtr<T, P> {
// 用指定的值覆盖指针位置。
// 旧的值直接被覆盖,不会调用释放逻辑。
/// Overwrites a memory location with the given `value`
/// **without** reading or dropping the old value.
pub fn write(&mut self, value: T) -> Result<()> { pub fn write(&mut self, value: T) -> Result<()> {
self.check()?; self.check()?;
unsafe { unsafe { self.0.write(value) };
self.ptr.write(value);
}
Ok(()) 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<()> { pub fn write_if_not_null(&mut self, value: T) -> Result<()> {
if self.ptr.is_null() { if !self.0.is_null() {
return Ok(()); self.write(value)
} else {
Ok(())
} }
self.write(value)
} }
// 写入 `values.len() * size_of<T>` 字节到指针位置。
// 写入的区间与目标区间不可重叠。
/// Copies `values.len() * size_of<T>` bytes from `values` to `self`.
/// The source and destination may not overlap.
pub fn write_array(&mut self, values: &[T]) -> Result<()> { pub fn write_array(&mut self, values: &[T]) -> Result<()> {
if values.is_empty() { if !values.is_empty() {
return Ok(()); self.check()?;
} unsafe {
self.check()?; self.0
unsafe { .copy_from_nonoverlapping(values.as_ptr(), values.len())
self.ptr };
.copy_from_nonoverlapping(values.as_ptr(), values.len());
} }
Ok(()) Ok(())
} }
} }
impl<P: Write> UserPtr<u8, P> { impl<P: Write> UserPtr<u8, P> {
// 拷贝指定字符串到目标位置并写入一个 `\0` 来模拟 C 风格零结尾字符串。
/// Copies `s` to `self`, then write a `'\0'` for c style string.
pub fn write_cstring(&mut self, s: &str) -> Result<()> { pub fn write_cstring(&mut self, s: &str) -> Result<()> {
let bytes = s.as_bytes(); let bytes = s.as_bytes();
self.write_array(bytes)?; self.write_array(bytes)?;
unsafe { unsafe { self.0.add(bytes.len()).write(0) };
self.ptr.add(bytes.len()).write(0);
}
Ok(()) Ok(())
} }
} }
#[derive(Debug)] #[derive(Debug)]
#[repr(C)] #[repr(C)]
pub struct IoVec<P: Policy> { pub struct IoVec<P: 'static + Policy> {
/// Starting address /// Starting address
ptr: UserPtr<u8, P>, ptr: UserPtr<u8, P>,
/// Number of bytes to transfer /// Number of bytes to transfer
@ -213,13 +291,13 @@ pub type IoVecOut = IoVec<Out>;
/// A valid IoVecs request from user /// A valid IoVecs request from user
#[derive(Debug)] #[derive(Debug)]
pub struct IoVecs<P: Policy> { pub struct IoVecs<P: 'static + Policy> {
vec: Vec<IoVec<P>>, vec: Vec<IoVec<P>>,
} }
impl<P: Policy> UserInPtr<IoVec<P>> { impl<P: Policy> UserInPtr<IoVec<P>> {
pub fn read_iovecs(&self, count: usize) -> Result<IoVecs<P>> { pub fn read_iovecs(&self, count: usize) -> Result<IoVecs<P>> {
if self.ptr.is_null() { if self.0.is_null() {
return Err(Error::InvalidPointer); return Err(Error::InvalidPointer);
} }
let vec = self.read_array(count)?; let vec = self.read_array(count)?;
@ -246,7 +324,7 @@ impl<P: Read> IoVecs<P> {
pub fn read_to_vec(&self) -> Result<Vec<u8>> { pub fn read_to_vec(&self) -> Result<Vec<u8>> {
let mut buf = Vec::new(); let mut buf = Vec::new();
for vec in self.vec.iter() { 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) Ok(buf)
} }
@ -299,20 +377,14 @@ impl<P: Policy> IoVec<P> {
} }
pub fn as_slice(&self) -> Result<&[u8]> { pub fn as_slice(&self) -> Result<&[u8]> {
if self.ptr.is_null() { self.as_mut_slice().map(|s| &*s)
return Err(Error::InvalidVectorAddress);
}
let slice = unsafe { core::slice::from_raw_parts(self.ptr.as_ptr(), self.len) };
Ok(slice)
} }
}
impl<P: Write> IoVec<P> { pub fn as_mut_slice(&self) -> Result<&mut [u8]> {
pub fn as_mut_slice(&mut self) -> Result<&mut [u8]> { if !self.ptr.is_null() {
if self.ptr.is_null() { Ok(unsafe { core::slice::from_raw_parts_mut(self.ptr.0, self.len) })
return Err(Error::InvalidVectorAddress); } else {
Err(Error::InvalidVectorAddress)
} }
let slice = unsafe { core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) };
Ok(slice)
} }
} }

View File

@ -1,6 +1,5 @@
//! Bootstrap and initialization. //! Bootstrap and initialization.
use super::net;
use crate::{KernelConfig, KernelHandler, KCONFIG, KHANDLER}; use crate::{KernelConfig, KernelHandler, KCONFIG, KHANDLER};
hal_fn_impl! { hal_fn_impl! {
@ -19,7 +18,6 @@ hal_fn_impl! {
super::macos::register_sigsegv_handler(); super::macos::register_sigsegv_handler();
} }
net::init();
} }
} }
} }

View File

@ -45,4 +45,10 @@ pub(super) fn init() {
crate::console::init_graphic_console(display); crate::console::init_graphic_console(display);
} }
#[cfg(feature = "loopback")]
{
use crate::net;
net::init();
}
} }

View File

@ -1,3 +1,4 @@
// May need move to drivers
use smoltcp::{ use smoltcp::{
iface::{InterfaceBuilder, NeighborCache, Route, Routes}, iface::{InterfaceBuilder, NeighborCache, Route, Routes},
phy::{Loopback, Medium}, phy::{Loopback, Medium},

View File

@ -95,7 +95,7 @@ mod tests {
use super::*; use super::*;
/// A valid virtual address base to mmap. /// A valid virtual address base to mmap.
const VBASE: VirtAddr = 0x2_00000000; const VBASE: VirtAddr = 0x0002_0000_0000;
#[test] #[test]
fn map_unmap() { fn map_unmap() {

View File

@ -19,13 +19,24 @@ zircon-object = { path = "../zircon-object", features = ["elf"] }
kernel-hal = { path = "../kernel-hal", default-features = false } kernel-hal = { path = "../kernel-hal", default-features = false }
downcast-rs = { version = "1.2", default-features = false } downcast-rs = { version = "1.2", default-features = false }
lazy_static = { version = "1.4", features = ["spin_no_std"] } lazy_static = { version = "1.4", features = ["spin_no_std"] }
rcore-fs = { 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 = "7c232ec" } 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 = "7c232ec" } 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 = "7c232ec" } 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 = "7c232ec" } rcore-fs-devfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
cfg-if = "1.0" 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"] } zcore-drivers = { path = "../drivers", features = ["virtio"] }
lock = { git = "https://github.com/DeathWish5/kernel-sync" } lock = { git = "https://github.com/DeathWish5/kernel-sync" }

View File

@ -1,7 +1,9 @@
mod fbdev; mod fbdev;
mod input; mod input;
mod random; mod random;
mod uartdev;
pub use fbdev::FbDev; pub use fbdev::FbDev;
pub use input::{EventDev, MiceDev}; pub use input::{EventDev, MiceDev};
pub use random::RandomINode; pub use random::RandomINode;
pub use uartdev::UartDev;

View File

@ -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<dyn UartScheme>,
inode_id: usize,
}
impl UartDev {
pub fn new(index: usize, port: Arc<dyn UartScheme>) -> Self {
Self {
index,
port,
inode_id: DevFS::new_inode_id(),
}
}
}
impl INode for UartDev {
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
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<usize> {
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<PollStatus> {
Ok(PollStatus {
// TOKNOW and TODO
read: true,
write: false,
error: false,
})
}
fn metadata(&self) -> Result<Metadata> {
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<usize> {
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,
}
}

View File

@ -17,15 +17,18 @@ use downcast_rs::impl_downcast;
use kernel_hal::drivers; use kernel_hal::drivers;
use rcore_fs::vfs::{FileSystem, FileType, INode, PollStatus, Result}; use rcore_fs::vfs::{FileSystem, FileType, INode, PollStatus, Result};
use rcore_fs_devfs::special::{NullINode, ZeroINode}; use rcore_fs_devfs::{
use rcore_fs_devfs::DevFS; special::{NullINode, ZeroINode},
DevFS,
};
use rcore_fs_mountfs::MountFS; use rcore_fs_mountfs::MountFS;
use rcore_fs_ramfs::RamFS; use rcore_fs_ramfs::RamFS;
use zircon_object::{object::KernelObject, vm::VmObject}; use zircon_object::{object::KernelObject, vm::VmObject};
use self::{devfs::RandomINode, pseudo::Pseudo};
use crate::error::{LxError, LxResult}; use crate::error::{LxError, LxResult};
use crate::process::LinuxProcess; use crate::process::LinuxProcess;
use devfs::RandomINode;
use pseudo::Pseudo;
pub use file::{File, OpenFlags, SeekFrom}; pub use file::{File, OpenFlags, SeekFrom};
pub use pipe::Pipe; pub use pipe::Pipe;
@ -128,7 +131,7 @@ pub fn create_root_fs(rootfs: Arc<dyn FileSystem>) -> Arc<dyn INode> {
.expect("failed to mknod /dev/urandom"); .expect("failed to mknod /dev/urandom");
if let Some(display) = drivers::all_display().first() { 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` // Add framebuffer device at `/dev/fb0`
if let Err(e) = devfs_root.add("fb0", Arc::new(FbDev::new(display.clone()))) { 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<dyn FileSystem>) -> Arc<dyn INode> {
} }
} }
// 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 // mount DevFS at /dev
let dev = root.find(true, "dev").unwrap_or_else(|_| { let dev = root.find(true, "dev").unwrap_or_else(|_| {
root.create("dev", FileType::Dir, 0o666) root.create("dev", FileType::Dir, 0o666)

View File

@ -3,6 +3,7 @@
/// missing documentation /// missing documentation
pub mod socket_address; pub mod socket_address;
use smoltcp::wire::IpEndpoint;
pub use socket_address::*; pub use socket_address::*;
/// missing documentation /// missing documentation
@ -113,24 +114,8 @@ impl Drop for GlobalSocketHandle {
} }
} }
// #[cfg(feature = "e1000")]
use kernel_hal::net::get_net_device; 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<usize, Arc<dyn NetStack>> {
// NET_STACK.read().clone()
// }
/// miss doc /// miss doc
fn poll_ifaces() { fn poll_ifaces() {
for iface in get_net_device().iter() { 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 ============= // ============= 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 ============= // ============= Rand Port =============
/// !!!! need riscv rng /// !!!! need riscv rng

View File

@ -5,12 +5,11 @@ use core::mem::size_of;
// crate // crate
use crate::error::LxError; use crate::error::LxError;
use crate::net::Endpoint; // use crate::net::Endpoint;
// smoltcp // smoltcp
pub use smoltcp::wire::{IpAddress, Ipv4Address}; pub use smoltcp::wire::{IpAddress, Ipv4Address};
// #
use crate::net::*; use crate::net::*;
use kernel_hal::user::{UserInOutPtr, UserOutPtr}; use kernel_hal::user::{UserInOutPtr, UserOutPtr};
// use numeric_enum_macro::numeric_enum; // use numeric_enum_macro::numeric_enum;
@ -91,6 +90,58 @@ pub struct SockAddrPlaceholder {
pub data: [u8; 14], 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<Endpoint> for SockAddr { impl From<Endpoint> for SockAddr {
fn from(endpoint: Endpoint) -> Self { fn from(endpoint: Endpoint) -> Self {
#[allow(warnings)] #[allow(warnings)]
@ -112,32 +163,29 @@ impl From<Endpoint> for SockAddr {
}, },
_ => unimplemented!("only ipv4"), _ => unimplemented!("only ipv4"),
} }
} else if let Endpoint::LinkLevel(link_level) = endpoint {
// unix socket 暂时 未开启 SockAddr {
addr_ll: SockAddrLl {
// } else if let Endpoint::LinkLevel(link_level) = endpoint { sll_family: AddressFamily::Packet.into(),
// SockAddr { sll_protocol: 0,
// addr_ll: SockAddrLl { sll_ifindex: link_level.interface_index as u32,
// sll_family: AddressFamily::Packet.into(), sll_hatype: 0,
// sll_protocol: 0, sll_pkttype: 0,
// sll_ifindex: link_level.interface_index as u32, sll_halen: 0,
// sll_hatype: 0, sll_addr: [0; 8],
// sll_pkttype: 0, },
// sll_halen: 0, }
// sll_addr: [0; 8], } else if let Endpoint::Netlink(netlink) = endpoint {
// }, SockAddr {
// } addr_nl: SockAddrNl {
// } else if let Endpoint::Netlink(netlink) = endpoint { nl_family: AddressFamily::Netlink.into(),
// SockAddr { nl_pad: 0,
// addr_nl: SockAddrNl { nl_pid: netlink.port_id,
// nl_family: AddressFamily::Netlink.into(), nl_groups: netlink.multicast_groups_mask,
// nl_pad: 0, },
// nl_pid: netlink.port_id, }
// nl_groups: netlink.multicast_groups_mask,
// },
// }
} else { } else {
unimplemented!("only ip"); unimplemented!("not match");
} }
} }
} }

View File

@ -97,57 +97,6 @@ impl TcpSocketState {
} }
} }
/// missing documentation
#[cfg(feature = "e1000")]
pub async fn read(&self, data: &mut [u8]) -> (LxResult<usize>, 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 Oksize");
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::<TcpSocket>(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 /// missing documentation
pub fn write(&self, data: &[u8], _sendto_endpoint: Option<Endpoint>) -> SysResult { pub fn write(&self, data: &[u8], _sendto_endpoint: Option<Endpoint>) -> SysResult {
warn!("tcp write"); warn!("tcp write");
@ -242,194 +191,6 @@ impl TcpSocketState {
Err(LxError::EINVAL) 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::<TcpSocket>(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::<TcpSocket>(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 /// missing documentation
fn bind(&mut self, endpoint: Endpoint) -> SysResult { fn bind(&mut self, endpoint: Endpoint) -> SysResult {
@ -512,54 +273,6 @@ impl TcpSocketState {
drop(sockets); drop(sockets);
} }
} }
#[cfg(feature = "e1000")]
async fn accept(&mut self) -> Result<(Arc<Mutex<dyn Socket>>, 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::<TcpSocket>(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 /// missing documentation
fn endpoint(&self) -> Option<Endpoint> { fn endpoint(&self) -> Option<Endpoint> {

View File

@ -122,34 +122,6 @@ impl UdpSocketState {
drop(sockets); 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 /// missing documentation
pub fn write(&self, data: &[u8], sendto_endpoint: Option<Endpoint>) -> SysResult { pub fn write(&self, data: &[u8], sendto_endpoint: Option<Endpoint>) -> SysResult {

View File

@ -1,5 +1,12 @@
//! Linux Process //! Linux Process
use crate::{
error::{LxError, LxResult},
fs::{File, FileDesc, FileLike, OpenFlags, STDIN, STDOUT},
ipc::*,
net::Socket,
signal::{Signal as LinuxSignal, SignalAction},
};
use alloc::{ use alloc::{
boxed::Box, boxed::Box,
string::String, string::String,
@ -7,15 +14,12 @@ use alloc::{
vec::Vec, vec::Vec,
}; };
use core::sync::atomic::AtomicI32; use core::sync::atomic::AtomicI32;
use crate::net::Socket;
use hashbrown::HashMap; use hashbrown::HashMap;
use kernel_hal::VirtAddr;
use rcore_fs::vfs::{FileSystem, INode}; use rcore_fs::vfs::{FileSystem, INode};
use smoltcp::socket::SocketHandle; use smoltcp::socket::SocketHandle;
use spin::{Mutex, MutexGuard}; use spin::{Mutex, MutexGuard};
// use lock::mutex::{Mutex, MutexGuard};
use kernel_hal::VirtAddr;
use zircon_object::{ use zircon_object::{
object::{KernelObject, KoID, Signal}, object::{KernelObject, KoID, Signal},
signal::Futex, signal::Futex,
@ -23,10 +27,7 @@ use zircon_object::{
ZxResult, ZxResult,
}; };
use crate::error::{LxError, LxResult}; pub use rcore_fs::vfs::FsInfo;
use crate::fs::{File, FileDesc, FileLike, OpenFlags, STDIN, STDOUT};
use crate::ipc::*;
use crate::signal::{Signal as LinuxSignal, SignalAction};
/// Process extension for linux /// Process extension for linux
pub trait ProcessExt { pub trait ProcessExt {
@ -508,9 +509,12 @@ impl LinuxProcessInner {
} }
fn get_free_hd(&self) -> SocketHandle { fn get_free_hd(&self) -> SocketHandle {
(10000usize..) (SOCKET_FD..)
.map(|i| i.into()) .map(|i| i.into())
.find(|fd| !self.sockets.contains_key(fd)) .find(|fd| !self.sockets.contains_key(fd))
.unwrap() .unwrap()
} }
} }
// Temp , TODO warp a struct impl into/from with FileDesc and SocketHandle
const SOCKET_FD: usize = 10000;

View File

@ -4,7 +4,6 @@ use crate::process::ProcessExt;
use crate::signal::{SignalStack, Sigset}; use crate::signal::{SignalStack, Sigset};
use alloc::sync::Arc; use alloc::sync::Arc;
use kernel_hal::user::{Out, UserOutPtr, UserPtr}; use kernel_hal::user::{Out, UserOutPtr, UserPtr};
use kernel_hal::VirtAddr;
use spin::{Mutex, MutexGuard}; use spin::{Mutex, MutexGuard};
// use lock::mutex::{Mutex, MutexGuard}; // use lock::mutex::{Mutex, MutexGuard};
use zircon_object::task::{CurrentThread, Process, Thread}; use zircon_object::task::{CurrentThread, Process, Thread};
@ -59,7 +58,7 @@ impl CurrentThreadExt for CurrentThread {
if !clear_child_tid.is_null() { if !clear_child_tid.is_null() {
info!("exit: do futex {:?} wake 1", clear_child_tid); info!("exit: do futex {:?} wake 1", clear_child_tid);
clear_child_tid.write(0).unwrap(); 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); let futex = self.proc().linux().get_futex(uaddr);
futex.wake(1); futex.wake(1);
} }

View File

@ -64,24 +64,33 @@ impl TimeSpec {
} }
} }
impl From<Timespec> for TimeSpec {
fn from(t: Timespec) -> Self {
Self {
sec: t.sec as _,
nsec: t.nsec as _,
}
}
}
impl From<TimeSpec> for Timespec { impl From<TimeSpec> for Timespec {
fn from(t: TimeSpec) -> Self { fn from(t: TimeSpec) -> Self {
Timespec { Self {
sec: t.sec as i64, sec: t.sec as _,
nsec: t.nsec as i32, nsec: t.nsec as _,
} }
} }
} }
impl From<TimeSpec> for Duration { impl From<TimeSpec> for Duration {
fn from(t: TimeSpec) -> Self { 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<TimeSpec> for TimeVal { impl From<TimeSpec> for TimeVal {
fn from(t: TimeSpec) -> Self { fn from(t: TimeSpec) -> Self {
TimeVal { Self {
sec: t.sec, sec: t.sec,
usec: t.nsec / 1_000, usec: t.nsec / 1_000,
} }
@ -111,3 +120,73 @@ pub struct Tms {
/// system time of children /// system time of children
pub tms_cstime: u64, 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<usize> 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<usize> 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;
}

View File

@ -12,10 +12,11 @@ log = "0.4"
spin = "0.9" spin = "0.9"
bitflags = "1.3" bitflags = "1.3"
numeric-enum-macro = "0.2" numeric-enum-macro = "0.2"
static_assertions = "1.1.0"
zircon-object = { path = "../zircon-object" } zircon-object = { path = "../zircon-object" }
linux-object = { path = "../linux-object" } linux-object = { path = "../linux-object" }
kernel-hal = { path = "../kernel-hal", default-features = false } 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"] } lazy_static = { version = "1.4", features = ["spin_no_std"] }
bitvec = { version = "0.22", default-features = false, features = ["alloc"] } bitvec = { version = "0.22", default-features = false, features = ["alloc"] }
lock = { git = "https://github.com/DeathWish5/kernel-sync" } lock = { git = "https://github.com/DeathWish5/kernel-sync" }

View File

@ -1,4 +1,4 @@
//! Directory operations //! Directory operations
//! //!
//! - getcwd //! - getcwd
//! - chdir //! - chdir
@ -28,22 +28,22 @@ impl Syscall<'_> {
return Err(LxError::ERANGE); return Err(LxError::ERANGE);
} }
buf.write_cstring(&cwd)?; buf.write_cstring(&cwd)?;
Ok(buf.as_ptr() as usize) Ok(buf.as_addr())
} }
/// Change the current directory. /// Change the current directory.
/// - `path` pointer to string with name of path /// - `path` pointer to string with name of path
pub fn sys_chdir(&self, path: UserInPtr<u8>) -> SysResult { pub fn sys_chdir(&self, path: UserInPtr<u8>) -> SysResult {
let path = path.read_cstring()?; let path = path.as_c_str()?;
info!("chdir: path={:?}", path); info!("chdir: path={:?}", path);
let proc = self.linux_process(); let proc = self.linux_process();
let inode = proc.lookup_inode(&path)?; let inode = proc.lookup_inode(path)?;
let info = inode.metadata()?; let info = inode.metadata()?;
if info.type_ != FileType::Dir { if info.type_ != FileType::Dir {
return Err(LxError::ENOTDIR); return Err(LxError::ENOTDIR);
} }
proc.change_directory(&path); proc.change_directory(path);
Ok(0) Ok(0)
} }
@ -56,14 +56,14 @@ impl Syscall<'_> {
/// create directory relative to directory file descriptor /// create directory relative to directory file descriptor
pub fn sys_mkdirat(&self, dirfd: FileDesc, path: UserInPtr<u8>, mode: usize) -> SysResult { pub fn sys_mkdirat(&self, dirfd: FileDesc, path: UserInPtr<u8>, mode: usize) -> SysResult {
let path = path.read_cstring()?; let path = path.as_c_str()?;
// TODO: check pathname // TODO: check pathname
info!( info!(
"mkdirat: dirfd={:?}, path={:?}, mode={:#o}", "mkdirat: dirfd={:?}, path={:?}, mode={:#o}",
dirfd, path, mode 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 proc = self.linux_process();
let inode = proc.lookup_inode_at(dirfd, dir_path, true)?; let inode = proc.lookup_inode_at(dirfd, dir_path, true)?;
if inode.find(file_name).is_ok() { if inode.find(file_name).is_ok() {
@ -75,10 +75,10 @@ impl Syscall<'_> {
/// Remove a directory. /// Remove a directory.
/// - path pointer to string with directory name /// - path pointer to string with directory name
pub fn sys_rmdir(&self, path: UserInPtr<u8>) -> SysResult { pub fn sys_rmdir(&self, path: UserInPtr<u8>) -> SysResult {
let path = path.read_cstring()?; let path = path.as_c_str()?;
info!("rmdir: path={:?}", path); 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 proc = self.linux_process();
let dir_inode = proc.lookup_inode(dir_path)?; let dir_inode = proc.lookup_inode(dir_path)?;
let file_inode = dir_inode.find(file_name)?; let file_inode = dir_inode.find(file_name)?;
@ -141,8 +141,8 @@ impl Syscall<'_> {
newpath: UserInPtr<u8>, newpath: UserInPtr<u8>,
flags: usize, flags: usize,
) -> SysResult { ) -> SysResult {
let oldpath = oldpath.read_cstring()?; let oldpath = oldpath.as_c_str()?;
let newpath = newpath.read_cstring()?; let newpath = newpath.as_c_str()?;
let flags = AtFlags::from_bits_truncate(flags); let flags = AtFlags::from_bits_truncate(flags);
info!( info!(
"linkat: olddirfd={:?}, oldpath={:?}, newdirfd={:?}, newpath={:?}, flags={:?}", "linkat: olddirfd={:?}, oldpath={:?}, newdirfd={:?}, newpath={:?}, flags={:?}",
@ -150,8 +150,8 @@ impl Syscall<'_> {
); );
let proc = self.linux_process(); let proc = self.linux_process();
let (new_dir_path, new_file_name) = split_path(&newpath); let (new_dir_path, new_file_name) = split_path(newpath);
let inode = proc.lookup_inode_at(olddirfd, &oldpath, true)?; let inode = proc.lookup_inode_at(olddirfd, oldpath, true)?;
let new_dir_inode = proc.lookup_inode_at(newdirfd, new_dir_path, true)?; let new_dir_inode = proc.lookup_inode_at(newdirfd, new_dir_path, true)?;
new_dir_inode.link(new_file_name, &inode)?; new_dir_inode.link(new_file_name, &inode)?;
Ok(0) Ok(0)
@ -168,7 +168,7 @@ impl Syscall<'_> {
/// remove directory entry relative to directory file descriptor /// remove directory entry relative to directory file descriptor
/// The unlinkat() system call operates in exactly the same way as either unlink or rmdir. /// The unlinkat() system call operates in exactly the same way as either unlink or rmdir.
pub fn sys_unlinkat(&self, dirfd: FileDesc, path: UserInPtr<u8>, flags: usize) -> SysResult { pub fn sys_unlinkat(&self, dirfd: FileDesc, path: UserInPtr<u8>, flags: usize) -> SysResult {
let path = path.read_cstring()?; let path = path.as_c_str()?;
let flags = AtFlags::from_bits_truncate(flags); let flags = AtFlags::from_bits_truncate(flags);
info!( info!(
"unlinkat: dirfd={:?}, path={:?}, flags={:?}", "unlinkat: dirfd={:?}, path={:?}, flags={:?}",
@ -176,7 +176,7 @@ impl Syscall<'_> {
); );
let proc = self.linux_process(); 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 dir_inode = proc.lookup_inode_at(dirfd, dir_path, true)?;
let file_inode = dir_inode.find(file_name)?; let file_inode = dir_inode.find(file_name)?;
if file_inode.metadata()?.type_ == FileType::Dir { if file_inode.metadata()?.type_ == FileType::Dir {
@ -199,16 +199,16 @@ impl Syscall<'_> {
newdirfd: FileDesc, newdirfd: FileDesc,
newpath: UserInPtr<u8>, newpath: UserInPtr<u8>,
) -> SysResult { ) -> SysResult {
let oldpath = oldpath.read_cstring()?; let oldpath = oldpath.as_c_str()?;
let newpath = newpath.read_cstring()?; let newpath = newpath.as_c_str()?;
info!( info!(
"renameat: olddirfd={:?}, oldpath={:?}, newdirfd={:?}, newpath={:?}", "renameat: olddirfd={:?}, oldpath={:?}, newdirfd={:?}, newpath={:?}",
olddirfd, oldpath, newdirfd, newpath olddirfd, oldpath, newdirfd, newpath
); );
let proc = self.linux_process(); let proc = self.linux_process();
let (old_dir_path, old_file_name) = split_path(&oldpath); let (old_dir_path, old_file_name) = split_path(oldpath);
let (new_dir_path, new_file_name) = split_path(&newpath); let (new_dir_path, new_file_name) = split_path(newpath);
let old_dir_inode = proc.lookup_inode_at(olddirfd, old_dir_path, false)?; 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)?; 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)?; old_dir_inode.move_(old_file_name, &new_dir_inode, new_file_name)?;
@ -230,14 +230,14 @@ impl Syscall<'_> {
mut base: UserOutPtr<u8>, mut base: UserOutPtr<u8>,
len: usize, len: usize,
) -> SysResult { ) -> SysResult {
let path = path.read_cstring()?; let path = path.as_c_str()?;
info!( info!(
"readlinkat: dirfd={:?}, path={:?}, base={:?}, len={}", "readlinkat: dirfd={:?}, path={:?}, base={:?}, len={}",
dirfd, path, base, len dirfd, path, base, len
); );
let proc = self.linux_process(); 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 { if inode.metadata()?.type_ != FileType::SymLink {
return Err(LxError::EINVAL); return Err(LxError::EINVAL);
} }

View File

@ -23,7 +23,7 @@ impl Syscall<'_> {
mode: usize, mode: usize,
) -> SysResult { ) -> SysResult {
let proc = self.linux_process(); let proc = self.linux_process();
let path = path.read_cstring()?; let path = path.as_c_str()?;
let flags = OpenFlags::from_bits_truncate(flags); let flags = OpenFlags::from_bits_truncate(flags);
info!( info!(
"openat: dir_fd={:?}, path={:?}, flags={:?}, mode={:#o}", "openat: dir_fd={:?}, path={:?}, flags={:?}, mode={:#o}",
@ -31,7 +31,7 @@ impl Syscall<'_> {
); );
let inode = if flags.contains(OpenFlags::CREATE) { 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 // relative to cwd
let dir_inode = proc.lookup_inode_at(dir_fd, dir_path, true)?; let dir_inode = proc.lookup_inode_at(dir_fd, dir_path, true)?;
match dir_inode.find(file_name) { match dir_inode.find(file_name) {
@ -47,10 +47,10 @@ impl Syscall<'_> {
Err(e) => return Err(LxError::from(e)), Err(e) => return Err(LxError::from(e)),
} }
} else { } 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)?; let fd = proc.add_file(file)?;
Ok(fd.into()) Ok(fd.into())
} }

View File

@ -10,7 +10,7 @@
//! - access, faccessat //! - access, faccessat
use super::*; use super::*;
use linux_object::time::TimeSpec; use linux_object::{process::FsInfo, time::TimeSpec};
impl Syscall<'_> { impl Syscall<'_> {
/// Reads from a specified file using a file descriptor. Before using this call, /// 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<u8>, len: usize) -> SysResult { pub async fn sys_read(&self, fd: FileDesc, mut base: UserOutPtr<u8>, len: usize) -> SysResult {
info!("read: fd={:?}, base={:?}, len={:#x}", fd, base, len); info!("read: fd={:?}, base={:?}, len={:#x}", fd, base, len);
let proc = self.linux_process(); let proc = self.linux_process();
let file_like = proc.get_file_like(fd)?;
let mut buf = vec![0u8; len]; // TODO wait a new struct to refactor
let len = file_like.read(&mut buf).await?; if usize::from(fd) >= SOCKET_FD {
base.write_array(&buf[..len])?; let x = usize::from(fd);
Ok(len) 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, /// 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 /// - len number of bytes to write
pub fn sys_write(&self, fd: FileDesc, base: UserInPtr<u8>, len: usize) -> SysResult { pub fn sys_write(&self, fd: FileDesc, base: UserInPtr<u8>, len: usize) -> SysResult {
info!("write: fd={:?}, base={:?}, len={:#x}", fd, base, len); info!("write: fd={:?}, base={:?}, len={:#x}", fd, base, len);
let proc = self.linux_process(); self.linux_process()
let buf = base.read_array(len)?; .get_file_like(fd)?
let file_like = proc.get_file_like(fd)?; .write(base.as_slice(len)?)
let len = file_like.write(&buf)?;
Ok(len)
} }
/// read from or write to a file descriptor at a given offset /// read from or write to a file descriptor at a given offset
@ -77,11 +87,9 @@ impl Syscall<'_> {
"pwrite: fd={:?}, base={:?}, len={}, offset={}", "pwrite: fd={:?}, base={:?}, len={}, offset={}",
fd, base, len, offset fd, base, len, offset
); );
let proc = self.linux_process(); self.linux_process()
let buf = base.read_array(len)?; .get_file_like(fd)?
let file_like = proc.get_file_like(fd)?; .write_at(offset, base.as_slice(len)?)
let len = file_like.write_at(offset, &buf)?;
Ok(len)
} }
/// works just like read except that multiple buffers are filled. /// 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); info!("readv: fd={:?}, iov={:?}, count={}", fd, iov_ptr, iov_count);
let mut iovs = iov_ptr.read_iovecs(iov_count)?; let mut iovs = iov_ptr.read_iovecs(iov_count)?;
let proc = self.linux_process(); let proc = self.linux_process();
let file_like = proc.get_file_like(fd)?;
let mut buf = vec![0u8; iovs.total_len()]; // TODO wait a new struct to refactor
let len = file_like.read(&mut buf).await?; if usize::from(fd) >= SOCKET_FD {
iovs.write_from_buf(&buf)?; let x = usize::from(fd);
Ok(len) 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. /// 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 iovs = iov_ptr.read_iovecs(iov_count)?;
let buf = iovs.read_to_vec()?; let buf = iovs.read_to_vec()?;
let proc = self.linux_process(); let proc = self.linux_process();
let file_like = proc.get_file_like(fd)?;
let len = file_like.write(&buf)?; // TODO wait a new struct to refactor
Ok(len) 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 /// 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. /// cause the regular file named by path to be truncated to a size of precisely length bytes.
pub fn sys_truncate(&self, path: UserInPtr<u8>, len: usize) -> SysResult { pub fn sys_truncate(&self, path: UserInPtr<u8>, len: usize) -> SysResult {
let path = path.read_cstring()?; let path = path.as_c_str()?;
info!("truncate: path={:?}, len={}", path, len); info!("truncate: path={:?}, len={}", path, len);
let proc = self.linux_process(); self.linux_process().lookup_inode(path)?.resize(len)?;
proc.lookup_inode(&path)?.resize(len)?;
Ok(0) Ok(0)
} }
@ -291,8 +319,17 @@ impl Syscall<'_> {
fd, request, arg1, arg2, arg3 fd, request, arg1, arg2, arg3
); );
let proc = self.linux_process(); 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. /// Manipulate a file descriptor.
@ -301,43 +338,52 @@ impl Syscall<'_> {
pub fn sys_fcntl(&self, fd: FileDesc, cmd: usize, arg: usize) -> SysResult { pub fn sys_fcntl(&self, fd: FileDesc, cmd: usize, arg: usize) -> SysResult {
info!("fcntl: fd={:?}, cmd={:x}, arg={}", fd, cmd, arg); info!("fcntl: fd={:?}, cmd={:x}, arg={}", fd, cmd, arg);
let proc = self.linux_process(); let proc = self.linux_process();
let file_like = proc.get_file_like(fd)?;
if let Ok(cmd) = FcntlCmd::try_from(cmd) { // TODO wait a new struct to refactor
match cmd { if usize::from(fd) >= SOCKET_FD {
FcntlCmd::GETFD => Ok(file_like.flags().close_on_exec() as usize), let f = usize::from(fd);
FcntlCmd::SETFD => { let socket = proc.get_socket(f.into())?;
let mut flags = file_like.flags(); let x = socket.lock();
if (arg & 1) != 0 { x.fcntl(cmd, arg)
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 { } 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, flags: usize,
) -> SysResult { ) -> SysResult {
// TODO: check permissions based on uid/gid // 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); let flags = AtFlags::from_bits_truncate(flags);
info!( info!(
"faccessat: dirfd={:?}, path={:?}, mode={:#o}, flags={:?}", "faccessat: dirfd={:?}, path={:?}, mode={:#o}, flags={:?}",
@ -364,7 +410,7 @@ impl Syscall<'_> {
); );
let proc = self.linux_process(); let proc = self.linux_process();
let follow = !flags.contains(AtFlags::SYMLINK_NOFOLLOW); 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) Ok(0)
} }
@ -395,7 +441,7 @@ impl Syscall<'_> {
info!("futimens: fd: {:?}, times: {:?}", fd, times); info!("futimens: fd: {:?}, times: {:?}", fd, times);
proc.get_file(fd)?.inode() proc.get_file(fd)?.inode()
} else { } else {
let pathname = pathname.read_cstring()?; let pathname = pathname.as_c_str()?;
info!( info!(
"utimensat: dirfd: {:?}, pathname: {:?}, times: {:?}, flags: {:#x}", "utimensat: dirfd: {:?}, pathname: {:?}, times: {:?}, flags: {:#x}",
dirfd, pathname, times, flags dirfd, pathname, times, flags
@ -407,7 +453,7 @@ impl Syscall<'_> {
} else { } else {
return Err(LxError::EINVAL); return Err(LxError::EINVAL);
}; };
proc.lookup_inode_at(dirfd, &pathname[..], follow)? proc.lookup_inode_at(dirfd, pathname, follow)?
}; };
let mut metadata = inode.metadata()?; let mut metadata = inode.metadata()?;
if times[0].nsec != UTIME_OMIT { if times[0].nsec != UTIME_OMIT {
@ -431,10 +477,88 @@ impl Syscall<'_> {
inode.set_metadata(&metadata)?; inode.set_metadata(&metadata)?;
Ok(0) 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<u8>, mut buf: UserOutPtr<StatFs>) -> 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<StatFs>) -> 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; 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::<StatFs>());
impl From<FsInfo> 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! { numeric_enum_macro::numeric_enum! {
#[repr(usize)] #[repr(usize)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
@ -461,3 +585,6 @@ numeric_enum_macro::numeric_enum! {
DUPFD_CLOEXEC = F_LINUX_SPECIFIC_BASE + 6, DUPFD_CLOEXEC = F_LINUX_SPECIFIC_BASE + 6,
} }
} }
// Temp , TODO warp a struct impl into/from with FileDesc and SocketHandle
const SOCKET_FD: usize = 10000;

View File

@ -307,10 +307,8 @@ impl FdSet {
if len > MAX_FDSET_SIZE { if len > MAX_FDSET_SIZE {
return Err(LxError::EINVAL); return Err(LxError::EINVAL);
} }
let slice = addr.read_array(len)?;
// save the fdset, and clear it // 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::<u32>::new(); let mut vec0 = Vec::<u32>::new();
vec0.resize(len, 0); vec0.resize(len, 0);
addr.write_array(&vec0)?; addr.write_array(&vec0)?;

View File

@ -26,10 +26,9 @@ impl Syscall<'_> {
/// - `stat_ptr` pointer to stat buffer /// - `stat_ptr` pointer to stat buffer
pub fn sys_fstat(&self, fd: FileDesc, mut stat_ptr: UserOutPtr<Stat>) -> SysResult { pub fn sys_fstat(&self, fd: FileDesc, mut stat_ptr: UserOutPtr<Stat>) -> SysResult {
info!("fstat: fd={:?}, stat_ptr={:?}", fd, stat_ptr); info!("fstat: fd={:?}, stat_ptr={:?}", fd, stat_ptr);
let proc = self.linux_process();
let file = proc.get_file(fd)?; let meta = self.linux_process().get_file(fd)?.metadata()?;
let stat = Stat::from(file.metadata()?); stat_ptr.write(meta.into())?;
stat_ptr.write(stat)?;
Ok(0) Ok(0)
} }
@ -41,18 +40,17 @@ impl Syscall<'_> {
mut stat_ptr: UserOutPtr<Stat>, mut stat_ptr: UserOutPtr<Stat>,
flags: usize, flags: usize,
) -> SysResult { ) -> SysResult {
let path = path.read_cstring()?; let path = path.as_c_str()?;
let flags = AtFlags::from_bits_truncate(flags); let flags = AtFlags::from_bits_truncate(flags);
info!( info!(
"fstatat: dirfd={:?}, path={:?}, stat_ptr={:?}, flags={:?}", "fstatat: dirfd={:?}, path={:?}, stat_ptr={:?}, flags={:?}",
dirfd, path, stat_ptr, flags dirfd, path, stat_ptr, flags
); );
let proc = self.linux_process();
let follow = !flags.contains(AtFlags::SYMLINK_NOFOLLOW); let follow = !flags.contains(AtFlags::SYMLINK_NOFOLLOW);
let inode = proc.lookup_inode_at(dirfd, &path, follow)?; let inode = self.linux_process().lookup_inode_at(dirfd, path, follow)?;
let stat = Stat::from(inode.metadata()?); let stat = inode.metadata()?;
stat_ptr.write(stat)?; stat_ptr.write(stat.into())?;
Ok(0) Ok(0)
} }
@ -65,21 +63,21 @@ impl Syscall<'_> {
} }
#[cfg(not(target_arch = "mips"))] #[cfg(not(target_arch = "mips"))]
use linux_object::fs::vfs::Timespec; use linux_object::time::TimeSpec;
#[cfg(target_arch = "mips")] #[cfg(target_arch = "mips")]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Timespec { pub struct TimeSpec {
pub sec: i32, pub sec: i32,
pub nsec: i32, pub nsec: i32,
} }
#[cfg(target_arch = "mips")] #[cfg(target_arch = "mips")]
impl From<linux_object::fs::vfs::Timespec> for Timespec { impl From<linux_object::fs::vfs::TimeSpec> for TimeSpec {
fn from(t: Timespec) -> Self { fn from(t: TimeSpec) -> Self {
Timespec { TimeSpec {
sec: t.sec as _, sec: t.sec as _,
nsec: t.nsec, nsec: t.nsec as _,
} }
} }
} }
@ -113,11 +111,11 @@ pub struct Stat {
blocks: u64, blocks: u64,
/// last access time /// last access time
atime: Timespec, atime: TimeSpec,
/// last modification time /// last modification time
mtime: Timespec, mtime: TimeSpec,
/// last status change time /// last status change time
ctime: Timespec, ctime: TimeSpec,
} }
#[cfg(target_arch = "mips")] #[cfg(target_arch = "mips")]
@ -147,11 +145,11 @@ pub struct Stat {
size: u64, size: u64,
/// last access time /// last access time
atime: Timespec, atime: TimeSpec,
/// last modification time /// last modification time
mtime: Timespec, mtime: TimeSpec,
/// last status change time /// last status change time
ctime: Timespec, ctime: TimeSpec,
/// blocksize for filesystem I/O /// blocksize for filesystem I/O
blksize: u32, blksize: u32,
@ -192,27 +190,26 @@ pub struct Stat {
blocks: u64, blocks: u64,
/// last access time /// last access time
atime: Timespec, atime: TimeSpec,
/// last modification time /// last modification time
mtime: Timespec, mtime: TimeSpec,
/// last status change time /// last status change time
ctime: Timespec, ctime: TimeSpec,
} }
impl From<Metadata> for Stat { impl From<Metadata> for Stat {
#[allow(clippy::useless_conversion)]
fn from(info: Metadata) -> Self { fn from(info: Metadata) -> Self {
Stat { Stat {
dev: info.dev as u64, dev: info.dev as _,
ino: info.inode as u64, ino: info.inode as _,
mode: StatMode::from_type_mode(info.type_, info.mode as u16), mode: StatMode::from_type_mode(info.type_, info.mode as _),
nlink: info.nlinks as _, nlink: info.nlinks as _,
uid: info.uid as u32, uid: info.uid as _,
gid: info.gid as u32, gid: info.gid as _,
rdev: info.rdev as u64, rdev: info.rdev as _,
size: info.size as u64, size: info.size as _,
blksize: info.blk_size as _, blksize: info.blk_size as _,
blocks: info.blocks as u64, blocks: info.blocks as _,
atime: info.atime.into(), atime: info.atime.into(),
mtime: info.mtime.into(), mtime: info.mtime.into(),
ctime: info.ctime.into(), ctime: info.ctime.into(),

View File

@ -1,4 +1,3 @@
//! Syscalls of Inter-Process Communication
#![allow(dead_code)] #![allow(dead_code)]
use bitflags::*; use bitflags::*;
@ -9,8 +8,55 @@ use zircon_object::vm::*;
use super::*; 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<'_> { 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 { pub fn sys_semget(&self, key: usize, nsems: usize, flags: usize) -> SysResult {
info!("semget: key: {} nsems: {} flags: {:#x}", key, nsems, flags); info!("semget: key: {} nsems: {} flags: {:#x}", key, nsems, flags);
@ -26,19 +72,40 @@ impl Syscall<'_> {
Ok(id) 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<SemBuf>, num_ops: usize) -> SysResult { pub async fn sys_semop(&self, id: usize, ops: UserInPtr<SemBuf>, num_ops: usize) -> SysResult {
info!("semop: id: {}", id); info!("semop: id: {}", id);
let ops = ops.read_array(num_ops)?; let ops = ops.as_slice(num_ops)?;
let sem_array = self let sem_array = self
.linux_process() .linux_process()
.semaphores_get(id) .semaphores_get(id)
.ok_or(LxError::EINVAL)?; .ok_or(LxError::EINVAL)?;
sem_array.otime(); 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); let flags = SemFlags::from_bits_truncate(flags);
if flags.contains(SemFlags::IPC_NOWAIT) { if flags.contains(SemFlags::IPC_NOWAIT) {
unimplemented!("Semaphore: semop.IPC_NOWAIT"); unimplemented!("Semaphore: semop.IPC_NOWAIT");
@ -58,10 +125,15 @@ impl Syscall<'_> {
Ok(0) 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, /// `semctl` performs the control operation specified by cmd
/// or on the semnum-th semaphore of that set. /// 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 { pub fn sys_semctl(&self, id: usize, num: usize, cmd: usize, arg: usize) -> SysResult {
info!( info!(
"semctl: id: {}, num: {}, cmd: {} arg: {:#x}", "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 { pub fn sys_shmget(&self, key: usize, size: usize, shmflg: usize) -> SysResult {
info!( info!(
"shmget: key: {}, size: {}, shmflg: {:#x}", "shmget: key: {}, size: {}, shmflg: {:#x}",
@ -138,7 +213,13 @@ impl Syscall<'_> {
Ok(id) 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 { 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)?; let mut shm_identifier = self.linux_process().shm_get(id).ok_or(LxError::EINVAL)?;
@ -173,8 +254,13 @@ impl Syscall<'_> {
Ok(addr) 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. /// 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 { pub fn sys_shmdt(&self, id: usize, addr: VirtAddr, shmflg: usize) -> SysResult {
info!( info!(
"shmdt: id = {}, addr = {:#x}, flag = {:#x}", "shmdt: id = {}, addr = {:#x}, flag = {:#x}",
@ -193,7 +279,8 @@ impl Syscall<'_> {
Ok(0) 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 /// 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 { pub fn sys_shmctl(&self, id: usize, cmd: usize, buffer: usize) -> SysResult {

View File

@ -282,8 +282,11 @@ impl Syscall<'_> {
// Sys::SOCKETPAIR => self.unimplemented("socketpair", Err(LxError::EACCES)), // Sys::SOCKETPAIR => self.unimplemented("socketpair", Err(LxError::EACCES)),
// file system // file system
Sys::STATFS => self.unimplemented("statfs", Err(LxError::EACCES)), Sys::STATFS => self.sys_statfs(
Sys::FSTATFS => self.unimplemented("fstatfs", Err(LxError::EACCES)), 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::SYNC => self.sys_sync(),
Sys::MOUNT => self.unimplemented("mount", Err(LxError::EACCES)), Sys::MOUNT => self.unimplemented("mount", Err(LxError::EACCES)),
Sys::UMOUNT2 => self.unimplemented("umount2", Err(LxError::EACCES)), Sys::UMOUNT2 => self.unimplemented("umount2", Err(LxError::EACCES)),
@ -318,6 +321,7 @@ impl Syscall<'_> {
// schedule // schedule
Sys::SCHED_YIELD => self.unimplemented("yield", Ok(0)), Sys::SCHED_YIELD => self.unimplemented("yield", Ok(0)),
Sys::SCHED_GETAFFINITY => self.unimplemented("sched_getaffinity", Ok(0)), Sys::SCHED_GETAFFINITY => self.unimplemented("sched_getaffinity", Ok(0)),
Sys::SCHED_SETAFFINITY => self.unimplemented("sched_setaffinity", Ok(0)),
// socket // socket
Sys::SOCKET => self.sys_socket(a0, a1, a2), Sys::SOCKET => self.sys_socket(a0, a1, a2),
@ -348,19 +352,22 @@ impl Syscall<'_> {
Sys::SHUTDOWN => self.sys_shutdown(a0, a1), Sys::SHUTDOWN => self.sys_shutdown(a0, a1),
Sys::BIND => self.sys_bind(a0, self.into_in_userptr(a1).unwrap(), a2), Sys::BIND => self.sys_bind(a0, self.into_in_userptr(a1).unwrap(), a2),
Sys::LISTEN => self.sys_listen(a0, a1), Sys::LISTEN => self.sys_listen(a0, a1),
Sys::GETSOCKNAME => self.sys_getsockname( Sys::GETSOCKNAME => self.sys_getsockname(
a0, a0,
self.into_out_userptr(a1).unwrap(), self.into_out_userptr(a1).unwrap(),
self.into_inout_userptr(a2).unwrap(), self.into_inout_userptr(a2).unwrap(),
), ),
Sys::GETPEERNAME => { Sys::GETPEERNAME => self.sys_getpeername(
self.unimplemented("sys_getpeername(a0, a1.into(), a2.into()),", Ok(0)) a0,
} self.into_out_userptr(a1).unwrap(),
self.into_inout_userptr(a2).unwrap(),
),
Sys::SETSOCKOPT => { Sys::SETSOCKOPT => {
self.sys_setsockopt(a0, a1, a2, self.into_in_userptr(a3).unwrap(), a4) self.sys_setsockopt(a0, a1, a2, self.into_in_userptr(a3).unwrap(), a4)
} }
Sys::GETSOCKOPT => { 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 // process
@ -395,12 +402,22 @@ impl Syscall<'_> {
// time // time
Sys::NANOSLEEP => self.sys_nanosleep(self.into_in_userptr(a0).unwrap()).await, 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::SETITIMER => self.unimplemented("setitimer", Ok(0)),
Sys::GETTIMEOFDAY => self.sys_gettimeofday( Sys::GETTIMEOFDAY => self.sys_gettimeofday(
self.into_out_userptr(a0).unwrap(), self.into_out_userptr(a0).unwrap(),
self.into_in_userptr(a1).unwrap(), self.into_in_userptr(a1).unwrap(),
), ),
Sys::CLOCK_GETTIME => self.sys_clock_gettime(a0, self.into_out_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 // sem
#[cfg(not(target_arch = "mips"))] #[cfg(not(target_arch = "mips"))]

View File

@ -82,11 +82,26 @@ impl Syscall<'_> {
"sys_setsockopt : sockfd : {:?}, level : {:?}, optname : {:?}, optval : {:?} , optlen : {:?}", "sys_setsockopt : sockfd : {:?}, level : {:?}, optname : {:?}, optval : {:?} , optlen : {:?}",
sockfd, level, optname,optval,optlen sockfd, level, optname,optval,optlen
); );
let proc = self.linux_process(); self.linux_process()
let data = optval.read_array(optlen)?; .get_socket(sockfd.into())?
let socket = proc.get_socket(sockfd.into())?; .lock()
let len = socket.lock().setsockopt(level, optname, &data)?; .setsockopt(level, optname, optval.as_slice(optlen)?)
Ok(len) }
/// net getsockopt
pub fn sys_getsockopt(
&mut self,
sockfd: usize,
level: usize,
optname: usize,
optval: UserOutPtr<u8>,
optlen: usize,
) -> SysResult {
warn!(
"sys_getsockopt : sockfd : {:?}, level : {:?}, optname : {:?}, optval : {:?} , optlen : {:?}",
sockfd, level, optname,optval,optlen
);
Ok(0)
} }
/// net setsockopt /// net setsockopt
@ -103,8 +118,6 @@ impl Syscall<'_> {
"sys_sendto : sockfd : {:?}, buffer : {:?}, length : {:?}, flags : {:?} , optlen : {:?}, addrlen : {:?}", "sys_sendto : sockfd : {:?}, buffer : {:?}, length : {:?}, flags : {:?} , optlen : {:?}, addrlen : {:?}",
sockfd,buffer,length,flags,dest_addr,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() { let endpoint = if dest_addr.is_null() {
None None
} else { } else {
@ -112,8 +125,9 @@ impl Syscall<'_> {
let endpoint = sockaddr_to_endpoint(dest_addr.read()?, addrlen)?; let endpoint = sockaddr_to_endpoint(dest_addr.read()?, addrlen)?;
Some(endpoint) Some(endpoint)
}; };
let proc = self.linux_process();
let socket = proc.get_socket(sockfd.into())?; 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) Ok(len)
} }

View File

@ -1,26 +1,62 @@
//! Syscalls for process
//!
//! - fork
//! - vfork
//! - clone
//! - wait4
//! - execve
//! - gettid
//! - getpid
//! - getppid
use super::*; use super::*;
use core::fmt::Debug; use core::fmt::Debug;
use alloc::string::ToString;
use bitflags::bitflags; use bitflags::bitflags;
use kernel_hal::context::UserContextField; use kernel_hal::context::UserContextField;
use linux_object::thread::{CurrentThreadExt, ThreadExt}; use linux_object::thread::{CurrentThreadExt, ThreadExt};
use linux_object::time::TimeSpec; // use linux_object::time::TimeSpec;
use linux_object::{fs::INodeExt, loader::LinuxElfLoader}; 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<'_> { 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 { pub fn sys_fork(&self) -> SysResult {
info!("fork:"); info!("fork:");
let new_proc = Process::fork_from(self.zircon_process(), false)?; // old pt NULL here 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) 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 { pub async fn sys_vfork(&self) -> SysResult {
info!("vfork:"); info!("vfork:");
let new_proc = Process::fork_from(self.zircon_process(), true)?; let new_proc = Process::fork_from(self.zircon_process(), true)?;
@ -54,11 +96,14 @@ impl Syscall<'_> {
Ok(new_proc.id() as usize) 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`, /// The new thread's stack pointer will be set to `newsp`,
/// and thread pointer will be set to `newtls`. /// and thread pointer will be set to `newtls`.
/// The child tid will be stored at both `parent_tid` and `child_tid`. /// The child TID will be stored at both `parent_tid` and `child_tid`.
/// This is partially implemented for musl only. ///
/// > **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( pub fn sys_clone(
&self, &self,
flags: usize, flags: usize,
@ -99,9 +144,45 @@ impl Syscall<'_> {
Ok(tid as usize) 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( pub async fn sys_wait4(
&self, &self,
pid: i32, pid: i32,
@ -145,25 +226,34 @@ impl Syscall<'_> {
Ok(pid as usize) 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. /// `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`, /// `envp` is an array of strings, conventionally of the form `key=value`,
/// which are passed as environment to the new program. /// 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 /// > **NOTE!** For multi-thread programs,
/// A call to any exec function from a process with more than one thread /// 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 /// shall result in all threads being terminated and the new executable image
/// being loaded and executed. /// being loaded and executed.
pub fn sys_execve( pub fn sys_execve(
&mut self, &mut self,
path: UserInPtr<u8>, path: UserInPtr<u8>,
argv: UserInPtr<UserInPtr<u8>>, argv: UserInPtr<UserInPtr<u8>>,
envp: UserInPtr<UserInPtr<u8>>, envp: UserInPtr<UserInPtr<u8>>,
) -> SysResult { ) -> SysResult {
let path = path.read_cstring()?; let path = path.as_c_str()?;
let args = argv.read_cstring_array()?; let args = argv.read_cstring_array()?;
let envs = envp.read_cstring_array()?; let envs = envp.read_cstring_array()?;
info!( info!(
@ -179,23 +269,27 @@ impl Syscall<'_> {
// Read program file // Read program file
let proc = self.linux_process(); let proc = self.linux_process();
let inode = proc.lookup_inode(&path)?; let inode = proc.lookup_inode(path)?;
let data = inode.read_as_vec()?; let data = inode.read_as_vec()?;
proc.remove_cloexec_files(); 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(); let vmar = self.zircon_process().vmar();
vmar.clear()?; 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 // Modify exec path
proc.set_execute_path(&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 // TODO: use right signal
// self.zircon_process().signal_set(Signal::SIGNALED); // self.zircon_process().signal_set(Signal::SIGNALED);
// Workaround, the child process could NOT exit correctly // 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 { pub fn sys_gettid(&self) -> SysResult {
info!("gettid:"); info!("gettid:");
let tid = self.thread.id(); let tid = self.thread.id();
Ok(tid as usize) 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 { pub fn sys_getpid(&self) -> SysResult {
info!("getpid:"); info!("getpid:");
let proc = self.zircon_process(); let proc = self.zircon_process();
@ -247,7 +345,10 @@ impl Syscall<'_> {
Ok(pid as usize) 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 { pub fn sys_getppid(&self) -> SysResult {
info!("getppid:"); info!("getppid:");
let proc = self.linux_process(); let proc = self.linux_process();
@ -255,14 +356,23 @@ impl Syscall<'_> {
Ok(ppid as usize) 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 { pub fn sys_exit(&mut self, exit_code: i32) -> SysResult {
info!("exit: code={}", exit_code); info!("exit: code={}", exit_code);
self.thread.exit_linux(exit_code); self.thread.exit_linux(exit_code);
Err(LxError::ENOSYS) 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 { pub fn sys_exit_group(&mut self, exit_code: i32) -> SysResult {
info!("exit_group: code={}", exit_code); info!("exit_group: code={}", exit_code);
let proc = self.zircon_process(); let proc = self.zircon_process();
@ -272,6 +382,16 @@ impl Syscall<'_> {
/// Allows the calling thread to sleep for /// Allows the calling thread to sleep for
/// an interval specified with nanosecond precision /// 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<TimeSpec>) -> SysResult { pub async fn sys_nanosleep(&self, req: UserInPtr<TimeSpec>) -> SysResult {
info!("nanosleep: deadline={:?}", req); info!("nanosleep: deadline={:?}", req);
let duration = req.read()?.into(); let duration = req.read()?.into();
@ -279,15 +399,16 @@ impl Syscall<'_> {
thread::sleep_until(timer::deadline_after(duration)).await; thread::sleep_until(timer::deadline_after(duration)).await;
Ok(0) Ok(0)
} }
*/
// pub fn sys_set_priority(&self, priority: usize) -> SysResult { // pub fn sys_set_priority(&self, priority: usize) -> SysResult {
// let pid = thread::current().id(); // let pid = thread::current().id();
// thread_manager().set_priority(pid, priority as u8); // thread_manager().set_priority(pid, priority as u8);
// Ok(0) // Ok(0)
// } // }
/// set pointer to thread ID /// `set_tid_address` sets the clear_child_tid value for the calling thread to `tidptr`,
/// returns the caller's thread ID /// 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<i32>) -> SysResult { pub fn sys_set_tid_address(&self, tidptr: UserOutPtr<i32>) -> SysResult {
info!("set_tid_address: {:?}", tidptr); info!("set_tid_address: {:?}", tidptr);
self.thread.set_tid_address(tidptr); self.thread.set_tid_address(tidptr);

View File

@ -103,4 +103,68 @@ impl Syscall<'_> {
info!("tick: {:?}", tick); info!("tick: {:?}", tick);
Ok(tick as usize) 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<TimeSpec>) -> 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<TimeSpec>,
rem: UserOutPtr<TimeSpec>,
) -> 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)
}
} }

View File

@ -2,15 +2,75 @@ use super::*;
use bitflags::bitflags; use bitflags::bitflags;
use zircon_object::vm::{pages, MMUFlags, VmObject}; 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<'_> { impl Syscall<'_> {
/// creates a new mapping in the virtual address space of the calling process. /// Map files or devices into memory
/// - `addr` - The starting address for the new mapping /// (see [linux man mmap(2)](https://www.man7.org/linux/man-pages/man2/mmap.2.html)).
/// - `len` - specifies the length of the mapping ///
/// - `prot ` - describes the desired memory protection of the mapping /// `sys_mmap` creates a new mapping in the virtual address space of the calling process.
/// - `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. /// The starting address for the new mapping is specified in `addr`.
/// - `fd` - mapping file descriptor ///
/// - `offset` - offset in the file /// 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( pub async fn sys_mmap(
&self, &self,
addr: usize, addr: usize,
@ -50,9 +110,34 @@ impl Syscall<'_> {
} }
} }
/// changes the access protections for the calling process's memory pages /// Set protection on a region of memory
/// containing any part of the address range in the interval [addr, addr+len-1] /// (see [linux man mprotect(2)](https://www.man7.org/linux/man-pages/man2/mprotect.2.html)).
/// TODO: unimplemented ///
/// **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 { pub fn sys_mprotect(&self, addr: usize, len: usize, prot: usize) -> SysResult {
let prot = MmapProt::from_bits_truncate(prot); let prot = MmapProt::from_bits_truncate(prot);
info!( info!(
@ -63,8 +148,19 @@ impl Syscall<'_> {
Ok(0) 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 /// Deletes the mappings for the specified address range, and causes further references to addresses
/// within the range to generate invalid memory references. /// 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 { pub fn sys_munmap(&self, addr: usize, len: usize) -> SysResult {
info!("munmap: addr={:#x}, size={:#x}", addr, len); info!("munmap: addr={:#x}, size={:#x}", addr, len);
let proc = self.thread.proc(); let proc = self.thread.proc();

View File

@ -1,7 +1,10 @@
[package] [package]
name = "zcore-loader" name = "zcore-loader"
version = "0.1.0" version = "0.1.0"
authors = ["Runji Wang <wangrunji0408@163.com>", "Yuekai Jia <equation618@gmail.com>"] authors = [
"Runji Wang <wangrunji0408@163.com>",
"Yuekai Jia <equation618@gmail.com>",
]
edition = "2018" edition = "2018"
description = "Linux and Zircon user programs loader and runner." description = "Linux and Zircon user programs loader and runner."
@ -27,7 +30,7 @@ libos = ["kernel-hal/libos", "zircon-object/aspace-separate"]
[dev-dependencies] [dev-dependencies]
env_logger = "0.9" env_logger = "0.9"
async-std = { version = "1.10", features = ["attributes"] } 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]] [[example]]
name = "linux-libos" name = "linux-libos"

View File

@ -36,24 +36,34 @@ zircon = ["zcore-loader/zircon"]
linux = ["zcore-loader/linux", "linux-object", "rcore-fs", "rcore-fs-sfs"] linux = ["zcore-loader/linux", "linux-object", "rcore-fs", "rcore-fs-sfs"]
# Run as LibOS # 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 # Run on QEMU
board-qemu = [] board-qemu = []
# Run on Allwinner d1 (riscv only) # Run on Allwinner d1 (riscv only)
board-d1 = ["link-user-img"] board-d1 = ["link-user-img"]
loopback = ["kernel-hal/loopback"]
[dependencies] [dependencies]
log = "0.4" log = "0.4"
spin = "0.9" spin = "0.9"
cfg-if = "1.0" 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" } 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 } zcore-loader = { path = "../loader", default-features = false }
zircon-object = { path = "../zircon-object" } zircon-object = { path = "../zircon-object" }
linux-object = { path = "../linux-object", optional = true } linux-object = { path = "../linux-object", optional = true }
rcore-fs = { 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 = "7c232ec", 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" } lock = { git = "https://github.com/DeathWish5/kernel-sync" }
executor = { git = "https://github.com/DeathWish5/PreemptiveScheduler" } 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] [target.'cfg(not(target_os = "none"))'.dependencies]
async-std = { version = "1.10", optional = true } async-std = { version = "1.10", optional = true }
chrono = { version = "0.4", 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 # Bare-metal mode
[target.'cfg(target_os = "none")'.dependencies] [target.'cfg(target_os = "none")'.dependencies]
@ -70,4 +80,4 @@ buddy_system_allocator = "0.8"
# Bare-metal mode on x86_64 # Bare-metal mode on x86_64
[target.'cfg(all(target_os = "none", target_arch = "x86_64"))'.dependencies] [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 } 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 } # rvm = { git = "https://github.com/rcore-os/RVM", rev = "e91d625", optional = true }

View File

@ -18,7 +18,7 @@ ZBI ?= bringup
SMP ?= 1 SMP ?= 1
ACCEL ?= ACCEL ?=
NET ?=
OBJDUMP := OBJDUMP :=
OBJCOPY ?= rust-objcopy --binary-architecture=$(ARCH) OBJCOPY ?= rust-objcopy --binary-architecture=$(ARCH)
@ -105,6 +105,7 @@ endif
ifeq ($(TEST), 1) ifeq ($(TEST), 1)
features += baremetal-test features += baremetal-test
NET := loopback
endif endif
ifeq ($(GRAPHIC), on) ifeq ($(GRAPHIC), on)
@ -118,6 +119,10 @@ ifeq ($(HYPERVISOR), 1)
ACCEL := 1 ACCEL := 1
endif endif
ifeq ($(NET), loopback)
features += loopback
endif
################ Cargo build args ################ ################ Cargo build args ################
build_args := --features "$(features)" build_args := --features "$(features)"
@ -144,6 +149,7 @@ ifeq ($(ARCH), x86_64)
-cpu Haswell,+smap,-check,-fsgsbase \ -cpu Haswell,+smap,-check,-fsgsbase \
-m 1G \ -m 1G \
-serial mon:stdio \ -serial mon:stdio \
-serial file:/tmp/serial.out \
-drive format=raw,if=pflash,readonly=on,file=$(ovmf) \ -drive format=raw,if=pflash,readonly=on,file=$(ovmf) \
-drive format=raw,file=fat:rw:$(esp) \ -drive format=raw,file=fat:rw:$(esp) \
-nic none -nic none
@ -154,6 +160,7 @@ else ifeq ($(ARCH), riscv64)
-m 512M \ -m 512M \
-no-reboot \ -no-reboot \
-serial mon:stdio \ -serial mon:stdio \
-serial file:/tmp/serial.out \
-kernel $(kernel_img) \ -kernel $(kernel_img) \
-initrd $(USER_IMG) \ -initrd $(USER_IMG) \
-append "$(CMDLINE)" -append "$(CMDLINE)"

View File

@ -15,7 +15,7 @@ physical_memory_offset=0xFFFF800000000000
kernel_path=\EFI\zCore\zcore.elf kernel_path=\EFI\zCore\zcore.elf
# The resolution of graphic output # The resolution of graphic output
resolution=1024x768 resolution=800x600
initramfs=\EFI\zCore\fuchsia.zbi initramfs=\EFI\zCore\fuchsia.zbi
# LOG=debug/info/error/warn/trace # LOG=debug/info/error/warn/trace

View File

@ -61,6 +61,9 @@ cfg_if! {
} }
} }
#[cfg(feature = "link-user-img")]
use core::arch::global_asm;
// Hard link rootfs img // Hard link rootfs img
#[cfg(not(feature = "libos"))] #[cfg(not(feature = "libos"))]
#[cfg(feature = "link-user-img")] #[cfg(feature = "link-user-img")]

View File

@ -55,8 +55,16 @@ init_vm:
#TLB #TLB
sfence.vma sfence.vma
li t0, 4096 * 16 # t0 = 0
mul t0, t0, a0 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为虚拟地址 #sp为虚拟地址
lui sp, %hi(bootstacktop) lui sp, %hi(bootstacktop)
sub sp, sp, t0 sub sp, sp, t0

View File

@ -1,6 +1,6 @@
{ {
"llvm-target": "x86_64-unknown-none", "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", "linker-flavor": "ld.lld",
"target-endian": "little", "target-endian": "little",
"target-pointer-width": "64", "target-pointer-width": "64",

View File

@ -3,7 +3,7 @@ use super::nodes::{
SharedLegacyIrqHandler, SharedLegacyIrqHandler,
}; };
use super::{ 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, MappedEcamRegion, PciAddrSpace, PciEcamRegion,
}; };
use crate::dev::Interrupt; use crate::dev::Interrupt;
@ -448,9 +448,9 @@ impl PCIeAddressProvider for MmioPcieAddressProvider {
/// Systems that have PIO mapped Config Spaces. /// Systems that have PIO mapped Config Spaces.
#[derive(Default)] #[derive(Default)]
pub struct PioPcieAddressProvider; pub struct PmioPcieAddressProvider;
impl PCIeAddressProvider for PioPcieAddressProvider { impl PCIeAddressProvider for PmioPcieAddressProvider {
fn create_config(&self, addr: u64) -> Arc<PciConfig> { fn create_config(&self, addr: u64) -> Arc<PciConfig> {
Arc::new(PciConfig { Arc::new(PciConfig {
addr_space: PciAddrSpace::PIO, addr_space: PciAddrSpace::PIO,

View File

@ -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 super::PciAddrSpace;
use numeric_enum_macro::numeric_enum; use numeric_enum_macro::numeric_enum;
@ -14,21 +14,21 @@ impl PciConfig {
trace!("read8 @ {:#x?}", offset); trace!("read8 @ {:#x?}", offset);
match self.addr_space { match self.addr_space {
PciAddrSpace::MMIO => unsafe { u8::from_le(*(offset as *const u8)) }, 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 { pub fn read16_offset(&self, addr: usize) -> u16 {
trace!("read16 @ {:#x?}", addr); trace!("read16 @ {:#x?}", addr);
match self.addr_space { match self.addr_space {
PciAddrSpace::MMIO => unsafe { u16::from_le(*(addr as *const u16)) }, 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 { pub fn read32_offset(&self, addr: usize) -> u32 {
trace!("read32 @ {:#x?}", addr); trace!("read32 @ {:#x?}", addr);
match self.addr_space { match self.addr_space {
PciAddrSpace::MMIO => unsafe { u32::from_le(*(addr as *const u32)) }, 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 { pub fn read8(&self, addr: PciReg8) -> u8 {
@ -56,7 +56,7 @@ impl PciConfig {
pub fn write8_offset(&self, addr: usize, val: u8) { pub fn write8_offset(&self, addr: usize, val: u8) {
match self.addr_space { match self.addr_space {
PciAddrSpace::MMIO => unsafe { *(addr as *mut u8) = val }, 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) { pub fn write16_offset(&self, addr: usize, val: u16) {
@ -67,13 +67,13 @@ impl PciConfig {
); );
match self.addr_space { match self.addr_space {
PciAddrSpace::MMIO => unsafe { *(addr as *mut u16) = val }, 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) { pub fn write32_offset(&self, addr: usize, val: u32) {
match self.addr_space { match self.addr_space {
PciAddrSpace::MMIO => unsafe { *(addr as *mut u32) = val }, 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) { pub fn write8(&self, addr: PciReg8, val: u8) {

View File

@ -5,14 +5,14 @@ mod caps;
mod config; mod config;
mod nodes; mod nodes;
pub mod pci_init_args; pub mod pci_init_args;
mod pio; mod pmio;
pub use self::bus::{ pub use self::bus::{
MmioPcieAddressProvider, PCIeBusDriver, PcieDeviceInfo, PcieDeviceKObject, MmioPcieAddressProvider, PCIeBusDriver, PcieDeviceInfo, PcieDeviceKObject,
PioPcieAddressProvider, PmioPcieAddressProvider,
}; };
pub use self::nodes::{IPciNode, PcieIrqMode}; 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. /// Type of PCI address space.
#[derive(PartialEq, Debug)] #[derive(PartialEq, Debug)]

View File

@ -12,18 +12,17 @@ pub fn pci_bdf_raw_addr(bus: u8, dev: u8, func: u8, offset: u8) -> u32 {
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(all(target_arch = "x86_64", target_os = "none"))] { if #[cfg(all(target_arch = "x86_64", target_os = "none"))] {
use kernel_hal::x86_64::{Io, Pio}; use kernel_hal::x86_64::{Io, Pmio};
use spin::Mutex; use spin::Mutex;
// use lock::Mutex;
static PIO_LOCK: Mutex<()> = Mutex::new(()); static PIO_LOCK: Mutex<()> = Mutex::new(());
const PCI_CONFIG_ADDR: u16 = 0xcf8; const PCI_CONFIG_ADDR: u16 = 0xcf8;
const PCI_CONFIG_DATA: u16 = 0xcfc; const PCI_CONFIG_DATA: u16 = 0xcfc;
const PCI_CONFIG_ENABLE: u32 = 1 << 31; const PCI_CONFIG_ENABLE: u32 = 1 << 31;
pub fn pio_config_read_addr(addr: u32, width: usize) -> ZxResult<u32> { pub fn pmio_config_read_addr(addr: u32, width: usize) -> ZxResult<u32> {
let mut port_cfg = Pio::<u32>::new(PCI_CONFIG_ADDR); let mut port_cfg = Pmio::<u32>::new(PCI_CONFIG_ADDR);
let port_data = Pio::<u32>::new(PCI_CONFIG_DATA); let port_data = Pmio::<u32>::new(PCI_CONFIG_DATA);
let _lock = PIO_LOCK.lock(); let _lock = PIO_LOCK.lock();
let shift = ((addr & 0x3) << 3) as usize; let shift = ((addr & 0x3) << 3) as usize;
@ -34,9 +33,9 @@ use spin::Mutex;
let tmp_val = u32::from_le(port_data.read()); let tmp_val = u32::from_le(port_data.read());
Ok((tmp_val >> shift) & (((1u64 << width) - 1) as u32)) Ok((tmp_val >> shift) & (((1u64 << width) - 1) as u32))
} }
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 {
let mut port_cfg = Pio::<u32>::new(PCI_CONFIG_ADDR); let mut port_cfg = Pmio::<u32>::new(PCI_CONFIG_ADDR);
let mut port_data = Pio::<u32>::new(PCI_CONFIG_DATA); let mut port_data = Pmio::<u32>::new(PCI_CONFIG_DATA);
let _lock = PIO_LOCK.lock(); let _lock = PIO_LOCK.lock();
let shift = ((addr & 0x3) << 3) as usize; let shift = ((addr & 0x3) << 3) as usize;
@ -55,17 +54,17 @@ use spin::Mutex;
Ok(()) Ok(())
} }
} else { } else {
pub fn pio_config_read_addr(_addr: u32, _width: usize) -> ZxResult<u32> { pub fn pmio_config_read_addr(_addr: u32, _width: usize) -> ZxResult<u32> {
Err(ZxError::NOT_SUPPORTED) 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) Err(ZxError::NOT_SUPPORTED)
} }
} }
} // cfg_if! } // cfg_if!
pub fn pio_config_read(bus: u8, dev: u8, func: u8, offset: u8, width: usize) -> ZxResult<u32> { pub fn pio_config_read(bus: u8, dev: u8, func: u8, offset: u8, width: usize) -> ZxResult<u32> {
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( pub fn pio_config_write(
@ -76,5 +75,5 @@ pub fn pio_config_write(
val: u32, val: u32,
width: usize, width: usize,
) -> ZxResult { ) -> 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)
} }

View File

@ -208,14 +208,14 @@ impl ElfExt for ElfFile<'_> {
}; };
let value = symval + entry.get_addend() as usize; let value = symval + entry.get_addend() as usize;
let addr = base + entry.get_offset() 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()) vmar.write_memory(addr, &value.to_ne_bytes())
.map_err(|_| "Invalid Vmar")?; .map_err(|_| "Invalid Vmar")?;
} }
REL_RELATIVE | R_RISCV_RELATIVE => { REL_RELATIVE | R_RISCV_RELATIVE => {
let value = base + entry.get_addend() as usize; let value = base + entry.get_addend() as usize;
let addr = base + entry.get_offset() 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()) vmar.write_memory(addr, &value.to_ne_bytes())
.map_err(|_| "Invalid Vmar")?; .map_err(|_| "Invalid Vmar")?;
} }

View File

@ -12,7 +12,7 @@ use {
impl Syscall<'_> { impl Syscall<'_> {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
/// Read/Receive a message from a channel. /// Read/Receive a message from a channel.
pub fn sys_channel_read( pub fn sys_channel_read(
&self, &self,
handle_value: HandleValue, handle_value: HandleValue,
@ -76,7 +76,7 @@ impl Syscall<'_> {
} }
Ok(()) Ok(())
} }
/// Write a message to a channel. /// Write a message to a channel.
pub fn sys_channel_write( pub fn sys_channel_write(
&self, &self,
handle_value: HandleValue, handle_value: HandleValue,
@ -98,9 +98,9 @@ impl Syscall<'_> {
} }
let proc = self.thread.proc(); let proc = self.thread.proc();
let data = user_bytes.read_array(num_bytes as usize)?; 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 transfer_self = handles.iter().any(|&handle| handle == handle_value);
let handles = proc.remove_handles(&handles)?; let handles = proc.remove_handles(handles)?;
if transfer_self { if transfer_self {
return Err(ZxError::NOT_SUPPORTED); return Err(ZxError::NOT_SUPPORTED);
} }
@ -116,7 +116,7 @@ impl Syscall<'_> {
channel.write(MessagePacket { data, handles })?; channel.write(MessagePacket { data, handles })?;
Ok(()) Ok(())
} }
/// Create a new channel. /// Create a new channel.
pub fn sys_channel_create( pub fn sys_channel_create(
&self, &self,
options: u32, options: u32,
@ -136,7 +136,7 @@ impl Syscall<'_> {
Ok(()) Ok(())
} }
/// ///
pub async fn sys_channel_call_noretry( pub async fn sys_channel_call_noretry(
&self, &self,
handle_value: HandleValue, handle_value: HandleValue,
@ -163,8 +163,8 @@ impl Syscall<'_> {
let wr_msg = MessagePacket { let wr_msg = MessagePacket {
data: args.wr_bytes.read_array(args.wr_num_bytes as usize)?, data: args.wr_bytes.read_array(args.wr_num_bytes as usize)?,
handles: { handles: {
let handles = args.wr_handles.read_array(args.wr_num_handles as usize)?; let handles = args.wr_handles.as_slice(args.wr_num_handles as usize)?;
let handles = proc.remove_handles(&handles)?; let handles = proc.remove_handles(handles)?;
for handle in handles.iter() { for handle in handles.iter() {
if !handle.rights.contains(Rights::TRANSFER) { if !handle.rights.contains(Rights::TRANSFER) {
return Err(ZxError::ACCESS_DENIED); return Err(ZxError::ACCESS_DENIED);
@ -213,7 +213,7 @@ impl Syscall<'_> {
Err(ZxError::BAD_STATE) Err(ZxError::BAD_STATE)
} }
} }
/// Write a message to a channel. /// Write a message to a channel.
pub fn sys_channel_write_etc( pub fn sys_channel_write_etc(
&self, &self,
handle: HandleValue, handle: HandleValue,

View File

@ -5,8 +5,7 @@ impl Syscall<'_> {
/// Write debug info to the serial port. /// Write debug info to the serial port.
pub fn sys_debug_write(&self, buf: UserInPtr<u8>, len: usize) -> ZxResult { pub fn sys_debug_write(&self, buf: UserInPtr<u8>, len: usize) -> ZxResult {
info!("debug.write: buf=({:?}; {:#x})", buf, len); info!("debug.write: buf=({:?}; {:#x})", buf, len);
let data = buf.read_array(len)?; kernel_hal::console::console_write_str(buf.as_str(len)?);
kernel_hal::console::console_write_str(core::str::from_utf8(&data).unwrap());
Ok(()) Ok(())
} }

View File

@ -49,12 +49,12 @@ impl Syscall<'_> {
return Err(ZxError::INVALID_ARGS); return Err(ZxError::INVALID_ARGS);
} }
let datalen = len.min(224); 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 proc = self.thread.proc();
let dlog = proc.get_object_with_rights::<DebugLog>(handle_value, Rights::WRITE)?; let dlog = proc.get_object_with_rights::<DebugLog>(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 // 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') { if data.as_bytes().last() != Some(&b'\n') {
kernel_hal::console::console_write_str("\n"); kernel_hal::console::console_write_str("\n");
} }

View File

@ -42,15 +42,18 @@ impl Syscall<'_> {
"fifo.write: handle={:?}, item_size={}, count={:#x}", "fifo.write: handle={:?}, item_size={}, count={:#x}",
handle_value, elem_size, count handle_value, elem_size, count
); );
if count == 0 { if count != 0 {
return Err(ZxError::OUT_OF_RANGE); let data = user_bytes.as_slice(count * elem_size)?;
let actual_count = self
.thread
.proc()
.get_object_with_rights::<Fifo>(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::<Fifo>(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. /// Read data from a fifo.

View File

@ -19,10 +19,10 @@ impl Syscall<'_> {
"futex.wait: value_ptr={:#x?}, current_value={:#x}, new_futex_owner={:#x}, deadline={:?}", "futex.wait: value_ptr={:#x?}, current_value={:#x}, new_futex_owner={:#x}, deadline={:?}",
value_ptr, current_value, new_futex_owner, 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); return Err(ZxError::INVALID_ARGS);
} }
let value = value_ptr.as_ref()?; let value = value_ptr.as_ref();
let proc = self.thread.proc(); let proc = self.thread.proc();
let futex = proc.get_futex(value); let futex = proc.get_futex(value);
let new_owner = if new_futex_owner == INVALID_HANDLE { 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={:?}", "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 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); return Err(ZxError::INVALID_ARGS);
} }
let value = value_ptr.as_ref()?; let value = value_ptr.as_ref();
let requeue = requeue_ptr.as_ref()?; let requeue = requeue_ptr.as_ref();
if value_ptr.as_ptr() == requeue_ptr.as_ptr() { if value_ptr.as_addr() == requeue_ptr.as_addr() {
return Err(ZxError::INVALID_ARGS); return Err(ZxError::INVALID_ARGS);
} }
let proc = self.thread.proc(); 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. /// > 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<AtomicI32>, count: u32) -> ZxResult { pub fn sys_futex_wake(&self, value_ptr: UserInPtr<AtomicI32>, count: u32) -> ZxResult {
info!("futex.wake: value_ptr={:?}, count={:#x}", value_ptr, count); 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); return Err(ZxError::INVALID_ARGS);
} }
let value = value_ptr.as_ref()?; let value = value_ptr.as_ref();
let proc = self.thread.proc(); let proc = self.thread.proc();
let futex = proc.get_futex(value); let futex = proc.get_futex(value);
futex.wake(count as usize); 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. /// 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<AtomicI32>) -> ZxResult { pub fn sys_futex_wake_single_owner(&self, value_ptr: UserInPtr<AtomicI32>) -> ZxResult {
info!("futex.wake_single_owner: value_ptr={:?}", value_ptr); 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); return Err(ZxError::INVALID_ARGS);
} }
let value = value_ptr.as_ref()?; let value = value_ptr.as_ref();
let proc = self.thread.proc(); let proc = self.thread.proc();
proc.get_futex(value).wake_single_owner(); proc.get_futex(value).wake_single_owner();
Ok(()) Ok(())

View File

@ -1,9 +1,9 @@
use {super::*, core::convert::TryFrom}; use {super::*, core::convert::TryFrom};
impl Syscall<'_> { 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( pub fn sys_handle_duplicate(
&self, &self,
handle_value: HandleValue, handle_value: HandleValue,
@ -33,7 +33,7 @@ impl Syscall<'_> {
Ok(()) 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 { pub fn sys_handle_close(&self, handle: HandleValue) -> ZxResult {
info!("handle.close: handle={:?}", handle); info!("handle.close: handle={:?}", handle);
if handle == INVALID_HANDLE { if handle == INVALID_HANDLE {
@ -44,7 +44,7 @@ impl Syscall<'_> {
Ok(()) Ok(())
} }
/// Close a number of handles. /// Close a number of handles.
pub fn sys_handle_close_many( pub fn sys_handle_close_many(
&self, &self,
handles: UserInPtr<HandleValue>, handles: UserInPtr<HandleValue>,
@ -55,19 +55,17 @@ impl Syscall<'_> {
handles, num_handles, handles, num_handles,
); );
let proc = self.thread.proc(); let proc = self.thread.proc();
let handles = handles.read_array(num_handles)?; for handle in handles.as_slice(num_handles)? {
for handle in handles { if *handle != INVALID_HANDLE {
if handle == INVALID_HANDLE { proc.remove_handle(*handle)?;
continue;
} }
proc.remove_handle(handle)?;
} }
Ok(()) 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( pub fn sys_handle_replace(
&self, &self,
handle_value: HandleValue, handle_value: HandleValue,

View File

@ -308,7 +308,6 @@ impl Syscall<'_> {
// atomic_store_explicit(value_ptr, new_value, memory_order_release) // atomic_store_explicit(value_ptr, new_value, memory_order_release)
UserInPtr::<AtomicI32>::from(a0) UserInPtr::<AtomicI32>::from(a0)
.as_ref() .as_ref()
.unwrap()
.store(a2 as i32, Ordering::Release); .store(a2 as i32, Ordering::Release);
let _ = self.sys_futex_wake(a0.into(), a1 as _); let _ = self.sys_futex_wake(a0.into(), a1 as _);
let _ = self.sys_handle_close(a3 as _); let _ = self.sys_handle_close(a3 as _);

View File

@ -125,8 +125,7 @@ impl Syscall<'_> {
match property { match property {
Property::Name => { Property::Name => {
let length = buffer_size.min(MAX_NAME_LEN) as usize; let length = buffer_size.min(MAX_NAME_LEN) as usize;
let s = UserInPtr::<u8>::from(buffer).read_string(length)?; object.set_name(UserInPtr::<u8>::from(buffer).as_str(length)?);
object.set_name(&s);
Ok(()) Ok(())
} }
Property::ProcessDebugAddr => { Property::ProcessDebugAddr => {

View File

@ -6,7 +6,7 @@ use zircon_object::{
constants::*, constants::*,
pci_init_args::{PciInitArgsAddrWindows, PciInitArgsHeader, PCI_INIT_ARG_MAX_SIZE}, pci_init_args::{PciInitArgsAddrWindows, PciInitArgsHeader, PCI_INIT_ARG_MAX_SIZE},
MmioPcieAddressProvider, PCIeBusDriver, PciAddrSpace, PciEcamRegion, PcieDeviceInfo, MmioPcieAddressProvider, PCIeBusDriver, PciAddrSpace, PciEcamRegion, PcieDeviceInfo,
PcieDeviceKObject, PcieIrqMode, PioPcieAddressProvider, PcieDeviceKObject, PcieIrqMode, PmioPcieAddressProvider,
}, },
dev::{Resource, ResourceKind}, dev::{Resource, ResourceKind},
vm::{pages, VmObject}, vm::{pages, VmObject},
@ -143,7 +143,7 @@ impl Syscall<'_> {
})?; })?;
PCIeBusDriver::set_address_translation_provider(addr_provider)?; PCIeBusDriver::set_address_translation_provider(addr_provider)?;
} else if addr_win.cfg_space_type == PCI_CFG_SPACE_TYPE_PIO { } 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)?; PCIeBusDriver::set_address_translation_provider(addr_provider)?;
} else { } else {
return Err(ZxError::INVALID_ARGS); return Err(ZxError::INVALID_ARGS);

View File

@ -2,7 +2,7 @@ use {super::*, core::convert::TryFrom, zircon_object::dev::*};
impl Syscall<'_> { impl Syscall<'_> {
#[allow(clippy::too_many_arguments)] #[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( pub fn sys_resource_create(
&self, &self,
parent_rsrc: HandleValue, parent_rsrc: HandleValue,
@ -17,7 +17,7 @@ impl Syscall<'_> {
"resource.create: parent={:#x}, options={:#x}, base={:#X}, size={:#x}", "resource.create: parent={:#x}, options={:#x}, base={:#X}, size={:#x}",
parent_rsrc, options, base, size 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); info!("name={:?}", name);
let proc = self.thread.proc(); let proc = self.thread.proc();
let parent_rsrc = proc.get_object_with_rights::<Resource>(parent_rsrc, Rights::WRITE)?; let parent_rsrc = proc.get_object_with_rights::<Resource>(parent_rsrc, Rights::WRITE)?;
@ -25,7 +25,7 @@ impl Syscall<'_> {
let flags = ResourceFlags::from_bits(options & 0xFFFF_0000).ok_or(ZxError::INVALID_ARGS)?; 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.validate_ranged_resource(kind, base as usize, size as usize)?;
parent_rsrc.check_exclusive(flags)?; 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)); let handle = proc.add_handle(Handle::new(rsrc, Rights::DEFAULT_RESOURCE));
out.write(handle)?; out.write(handle)?;
Ok(()) Ok(())

View File

@ -1,8 +1,8 @@
use {super::*, zircon_object::ipc::Socket, zircon_object::ipc::SocketFlags}; use {super::*, zircon_object::ipc::Socket, zircon_object::ipc::SocketFlags};
impl Syscall<'_> { 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. /// 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( pub fn sys_socket_create(
&self, &self,
@ -20,9 +20,9 @@ impl Syscall<'_> {
Ok(()) Ok(())
} }
/// Write data to a socket. /// Write data to a socket.
/// ///
/// Attempts to write `count: usize` bytes to the socket specified by `handle_value`. /// Attempts to write `count: usize` bytes to the socket specified by `handle_value`.
pub fn sys_socket_write( pub fn sys_socket_write(
&self, &self,
handle_value: HandleValue, handle_value: HandleValue,
@ -35,21 +35,20 @@ impl Syscall<'_> {
"socket.write: socket={:#x?}, options={:#x?}, buffer={:#x?}, size={:#x?}", "socket.write: socket={:#x?}, options={:#x?}, buffer={:#x?}, size={:#x?}",
handle_value, options, user_bytes, count, handle_value, options, user_bytes, count,
); );
if count > 0 && user_bytes.is_null() { if (count == 0 || !user_bytes.is_null()) && options == 0 {
return Err(ZxError::INVALID_ARGS); let actual_count = self
.thread
.proc()
.get_object_with_rights::<Socket>(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::<Socket>(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( pub fn sys_socket_read(
&self, &self,
handle_value: HandleValue, handle_value: HandleValue,
@ -79,7 +78,7 @@ impl Syscall<'_> {
Ok(()) 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 { pub fn sys_socket_shutdown(&self, socket: HandleValue, options: u32) -> ZxResult {
let options = SocketFlags::from_bits_truncate(options); let options = SocketFlags::from_bits_truncate(options);
info!( info!(

View File

@ -14,7 +14,7 @@ impl Syscall<'_> {
mut proc_handle: UserOutPtr<HandleValue>, mut proc_handle: UserOutPtr<HandleValue>,
mut vmar_handle: UserOutPtr<HandleValue>, mut vmar_handle: UserOutPtr<HandleValue>,
) -> ZxResult { ) -> ZxResult {
let name = name.read_string(name_size)?; let name = name.as_str(name_size)?;
info!( info!(
"proc.create: job={:#x?}, name={:?}, options={:#x?}", "proc.create: job={:#x?}, name={:?}, options={:#x?}",
job, name, options, job, name, options,
@ -26,7 +26,7 @@ impl Syscall<'_> {
let job = proc let job = proc
.get_object_with_rights::<Job>(job, Rights::MANAGE_PROCESS) .get_object_with_rights::<Job>(job, Rights::MANAGE_PROCESS)
.or_else(|_| proc.get_object_with_rights::<Job>(job, Rights::WRITE))?; .or_else(|_| proc.get_object_with_rights::<Job>(job, Rights::WRITE))?;
let new_proc = Process::create(&job, &name)?; let new_proc = Process::create(&job, name)?;
let new_vmar = new_proc.vmar(); let new_vmar = new_proc.vmar();
let proc_handle_value = proc.add_handle(Handle::new(new_proc, Rights::DEFAULT_PROCESS)); let proc_handle_value = proc.add_handle(Handle::new(new_proc, Rights::DEFAULT_PROCESS));
let vmar_handle_value = proc.add_handle(Handle::new( let vmar_handle_value = proc.add_handle(Handle::new(
@ -57,7 +57,7 @@ impl Syscall<'_> {
options: u32, options: u32,
mut thread_handle: UserOutPtr<HandleValue>, mut thread_handle: UserOutPtr<HandleValue>,
) -> ZxResult { ) -> ZxResult {
let name = name.read_string(name_size)?; let name = name.as_str(name_size)?;
info!( info!(
"thread.create: proc={:#x?}, name={:?}, options={:#x?}", "thread.create: proc={:#x?}, name={:?}, options={:#x?}",
proc_handle, name, options, proc_handle, name, options,
@ -67,7 +67,7 @@ impl Syscall<'_> {
} }
let proc = self.thread.proc(); let proc = self.thread.proc();
let process = proc.get_object_with_rights::<Process>(proc_handle, Rights::MANAGE_THREAD)?; let process = proc.get_object_with_rights::<Process>(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)); let handle = proc.add_handle(Handle::new(thread, Rights::DEFAULT_THREAD));
thread_handle.write(handle)?; thread_handle.write(handle)?;
Ok(()) Ok(())
@ -146,11 +146,10 @@ impl Syscall<'_> {
"thread.write_state: handle={:#x?}, kind={:#x?}, buf=({:#x?}; {:#x?})", "thread.write_state: handle={:#x?}, kind={:#x?}, buf=({:#x?}; {:#x?})",
handle, kind, buffer, buffer_size, handle, kind, buffer, buffer_size,
); );
let proc = self.thread.proc(); self.thread
let thread = proc.get_object_with_rights::<Thread>(handle, Rights::WRITE)?; .proc()
let buf = buffer.read_array(buffer_size)?; .get_object_with_rights::<Thread>(handle, Rights::WRITE)?
thread.write_state(kind, &buf)?; .write_state(kind, buffer.as_slice(buffer_size)?)
Ok(())
} }
/// Sets process as critical to job. /// Sets process as critical to job.
@ -304,9 +303,10 @@ impl Syscall<'_> {
JOB_POL_ABSOLUTE => SetPolicyOptions::Absolute, JOB_POL_ABSOLUTE => SetPolicyOptions::Absolute,
_ => return Err(ZxError::INVALID_ARGS), _ => return Err(ZxError::INVALID_ARGS),
}; };
let all_policy = job.set_policy_basic(
UserInPtr::<BasicPolicy>::from(policy).read_array(count as usize)?; policy_option,
job.set_policy_basic(policy_option, &all_policy) UserInPtr::from(policy).as_slice(count as usize)?,
)
} }
//JOB_POL_BASE_V2 => unimplemented!(), //JOB_POL_BASE_V2 => unimplemented!(),
JOB_POL_TIMER_SLACK => { JOB_POL_TIMER_SLACK => {
@ -357,15 +357,17 @@ impl Syscall<'_> {
mut actual: UserOutPtr<usize>, mut actual: UserOutPtr<usize>,
) -> ZxResult { ) -> ZxResult {
if buffer.is_null() || buffer_size == 0 || buffer_size > MAX_BLOCK { 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::<Process>(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::<Process>(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(())
} }
} }

View File

@ -71,8 +71,7 @@ impl Syscall<'_> {
if offset as usize > vmo.len() || buf_size > vmo.len() - (offset as usize) { if offset as usize > vmo.len() || buf_size > vmo.len() - (offset as usize) {
return Err(ZxError::OUT_OF_RANGE); return Err(ZxError::OUT_OF_RANGE);
} }
vmo.write(offset as usize, &buf.read_array(buf_size)?)?; vmo.write(offset as usize, buf.as_slice(buf_size)?)
Ok(())
} }
/// Add execute rights to a VMO. /// Add execute rights to a VMO.