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_URL := https://github.com/rcore-os/libc-test-prebuilt/releases/download/0.1/$(RISCV64_ROOTFS_TAR)
LIBC_TEST_URL := https://github.com/rcore-os/libc-test.git
ARCH ?= x86_64
rcore_fs_fuse_revision := 7f5eeac
@ -38,9 +39,14 @@ riscv-rootfs:prebuilt/linux/riscv64/$(RISCV64_ROOTFS_TAR)
@ln -s busybox riscv_rootfs/bin/ls
libc-test:
cd rootfs && git clone git://repo.or.cz/libc-test --depth 1
cd rootfs && git clone $(LIBC_TEST_URL) --depth 1
cd rootfs/libc-test && cp config.mak.def config.mak && echo 'CC := musl-gcc' >> config.mak && make -j
rt-test:
cd rootfs && git clone https://kernel.googlesource.com/pub/scm/linux/kernel/git/clrkwllms/rt-tests --depth 1
cd rootfs/rt-tests && make
echo x86 gcc build rt-test,now need manual modificy.
rcore-fs-fuse:
ifneq ($(shell rcore-fs-fuse dir image git-version), $(rcore_fs_fuse_revision))
@echo Installing rcore-fs-fuse
@ -89,7 +95,7 @@ baremetal-test-img: prebuilt/linux/$(ROOTFS_TAR) rcore-fs-fuse
@tar xf $< -C $(TMP_ROOTFS)
@mkdir -p rootfs/lib
@cp $(TMP_ROOTFS)/lib/ld-musl-x86_64.so.1 rootfs/lib/
@cd rootfs && rm -rf libc-test && git clone git://repo.or.cz/libc-test --depth 1
@cd rootfs && rm -rf libc-test && git clone $(LIBC_TEST_URL) --depth 1
@cd rootfs/libc-test && cp config.mak.def config.mak && echo 'CC := musl-gcc' >> config.mak && make -j
@rcore-fs-fuse $(OUT_IMG) rootfs zip
# recover rootfs/ld-musl-x86_64.so.1 for zcore usr libos
@ -97,3 +103,16 @@ baremetal-test-img: prebuilt/linux/$(ROOTFS_TAR) rcore-fs-fuse
@cp prebuilt/linux/libc-libos.so rootfs/lib/ld-musl-x86_64.so.1
@echo Resizing $(ARCH).img
@qemu-img resize $(OUT_IMG) +5M
baremetal-test:
@make -C zCore baremetal-test MODE=release LINUX=1 | tee stdout-baremetal-test
baremetal-test-rv64:
@make -C zCore baremetal-test-rv64 ARCH=riscv64 MODE=release LINUX=1 ROOTPROC=$(ROOTPROC) | tee -a stdout-baremetal-test-rv64 | tee stdout-rv64
check:
cargo fmt --all -- --check
cargo clippy --all-features
cd zCore && make clippy ARCH=x86_64
cd zCore && make clippy ARCH=riscv64 LINUX=1

View File

@ -21,6 +21,7 @@ lazy_static = "1.4"
numeric-enum-macro = "0.2"
device_tree = { git = "https://github.com/rcore-os/device_tree-rs", rev = "2f2e55f" }
bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev = "b3f9f51" }
pci = { git = "https://github.com/rcore-os/pci-rs", rev = "a4e7cea6" }
virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "2aaf7d6", optional = true }
rcore-console = { git = "https://github.com/rcore-os/rcore-console", default-features = false, rev = "ca5b1bc", optional = true }
lock = { git = "https://github.com/DeathWish5/kernel-sync" }
@ -39,6 +40,7 @@ sdl2 = { version = "0.34", optional = true }
[target.'cfg(target_arch = "x86_64")'.dependencies]
acpi = "4.1"
x2apic = "0.4"
x86_64 = "0.14"
[target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies]
riscv = { git = "https://github.com/rust-embedded/riscv", rev = "cd31989", features = ["inline-asm"] }

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;
pub use uefi::UefiDisplay;

View File

@ -1,3 +1,5 @@
//! Only Mouse currently.
mod mouse;
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 super::Io;
// 主存映射 I/O。
/// Memory-mapped I/O.
#[repr(transparent)]
pub struct Mmio<T> {
value: MaybeUninit<T>,
}
pub struct Mmio<T>(T);
impl<T> Mmio<T> {
/// # Safety
@ -25,9 +23,7 @@ impl<T> Mmio<T> {
}
pub fn add<'a>(&self, offset: usize) -> &'a mut Self {
unsafe {
Self::from_base(self.value.as_ptr() as usize + offset * core::mem::size_of::<T>())
}
unsafe { Self::from_base((&self.0 as *const T).add(offset) as _) }
}
}
@ -38,10 +34,19 @@ where
type Value = T;
fn read(&self) -> T {
unsafe { core::ptr::read_volatile(self.value.as_ptr()) }
unsafe {
let val = core::ptr::read_volatile(&self.0 as *const _);
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
core::arch::asm!("fence i,r");
val
}
}
fn write(&mut self, value: T) {
unsafe { core::ptr::write_volatile(self.value.as_mut_ptr(), value) };
unsafe {
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
core::arch::asm!("fence w,o");
core::ptr::write_volatile(&mut self.0 as *mut _, value)
};
}
}

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};
mod mmio;
#[cfg(target_arch = "x86_64")]
mod pio;
mod pmio;
pub use mmio::Mmio;
#[cfg(target_arch = "x86_64")]
pub use pio::Pio;
pub use pmio::Pmio;
// 用于处理外设地址空间访问的接口。
/// An interface for dealing with device address space access.
pub trait Io {
// 可访问的对象的类型。
/// The type of object to access.
type Value: Copy
+ BitAnd<Output = Self::Value>
+ BitOr<Output = Self::Value>
+ Not<Output = Self::Value>;
// 从外设读取值。
/// Reads value from device.
fn read(&self) -> Self::Value;
// 向外设写入值。
/// Writes `value` to device.
fn write(&mut self, value: Self::Value);
}
// 外设地址空间的一个只读单元。
/// A readonly unit in device address space.
#[repr(transparent)]
pub struct ReadOnly<I> {
inner: I,
}
pub struct ReadOnly<I>(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> {
// 从外设读取值。
/// Reads value from device.
#[inline(always)]
pub fn read(&self) -> I::Value {
self.inner.read()
self.0.read()
}
}
// 外设地址空间的一个只写单元。
/// A write-only unit in device address space.
#[repr(transparent)]
pub struct WriteOnly<I> {
inner: I,
}
pub struct WriteOnly<I>(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> {
// 向外设写入值。
/// Writes `value` to device.
#[inline(always)]
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;
use core::marker::PhantomData;
// 端口映射 I/O。
//! Port-mapped I/O.
use super::Io;
use core::{arch::asm, marker::PhantomData};
/// Generic PIO
// 端口映射 I/O。
/// Port-mapped I/O.
#[derive(Copy, Clone)]
pub struct Pio<T> {
pub struct Pmio<T> {
port: u16,
_phantom: PhantomData<T>,
}
impl<T> Pio<T> {
/// Create a PIO from a given port
impl<T> Pmio<T> {
// 映射指定端口进行外设访问。
/// Maps a given port to assess device.
pub const fn new(port: u16) -> Self {
Pio::<T> {
Self {
port,
_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;
/// Read
// 读。
/// Read.
#[inline(always)]
fn read(&self) -> u8 {
let value: u8;
@ -34,7 +39,8 @@ impl Io for Pio<u8> {
value
}
/// Write
// 写。
/// Write.
#[inline(always)]
fn write(&mut self, value: u8) {
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;
/// Read
// 读。
/// Read.
#[inline(always)]
fn read(&self) -> u16 {
let value: u16;
@ -57,7 +65,8 @@ impl Io for Pio<u16> {
value
}
/// Write
// 写。
/// Write.
#[inline(always)]
fn write(&mut self, value: u16) {
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;
/// Read
// 读。
/// Read.
#[inline(always)]
fn read(&self) -> u32 {
let value: u32;
@ -80,7 +91,8 @@ impl Io for Pio<u32> {
value
}
/// Write
// 写。
/// Write.
#[inline(always)]
fn write(&mut self, value: u32) {
unsafe {

View File

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

View File

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

View File

@ -67,9 +67,23 @@ impl IoApic {
let mut inner = unsafe { IoApicInner::new(base_vaddr as u64) };
let max_entry = unsafe { inner.max_table_entry() };
unsafe { assert_eq!(id, inner.id()) };
// disable all interrupts
unsafe {
inner.init(super::X86_INT_BASE as u8);
}
for i in 0..max_entry + 1 {
unsafe { inner.disable_irq(i) }
unsafe {
// disable all interrupts
inner.disable_irq(i);
// Clean the redirection table
let mut entry = inner.table_entry(i);
entry.set_vector(0);
entry.set_dest(0);
entry.set_mode(IrqMode::Fixed);
entry.set_flags(IrqFlags::MASKED);
inner.set_table_entry(i, entry);
}
}
Self {
id,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,25 +1,35 @@
use alloc::{boxed::Box, vec::Vec};
// use spin::Mutex;
use lock::Mutex;
/// A type alias for the closure to handle device event.
pub type EventHandler<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 = ()> {
events: Mutex<Vec<(EventHandler<T>, bool)>>,
}
impl<T> EventListener<T> {
/// Construct a new, empty `EventListener`.
pub fn new() -> Self {
Self {
events: Mutex::new(Vec::new()),
}
}
/// Register a new `handler` into this `EventListener`.
///
/// If `once` is `true`, the `handler` will be removed once it handles an event.
pub fn subscribe(&self, handler: EventHandler<T>, once: bool) {
self.events.lock().push((handler, once));
}
/// Send an event to the `EventListener`.
///
/// All the handlers handle the event, and those marked `once` will be removed immediately.
pub fn trigger(&self, event: T) {
self.events.lock().retain(|(f, once)| {
f(&event);

View File

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

View File

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

View File

@ -13,6 +13,8 @@ smp = []
libos = ["nix", "tempfile", "async-std", "bitmap-allocator", "zcore-drivers/mock"]
graphic = ["zcore-drivers/graphic"]
loopback = []
[dependencies]
log = "0.4"
spin = "0.9"
@ -26,7 +28,6 @@ zcore-drivers = { path = "../drivers", features = ["virtio"] }
lock = { git = "https://github.com/DeathWish5/kernel-sync" }
smoltcp = { git = "https://gitee.com/gcyyfun/smoltcp", rev="043eb60", default-features = false, features = ["alloc","log", "async", "medium-ethernet","proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw"] }
# LibOS mode
[target.'cfg(not(target_os = "none"))'.dependencies]
nix = { version = "0.23", optional = true }

View File

@ -92,5 +92,21 @@ pub(super) fn intc_init() -> DeviceResult {
)?;
irq.unmask(ScauseIntCode::SupervisorSoft as _)?;
irq.unmask(ScauseIntCode::SupervisorTimer as _)?;
#[cfg(feature = "graphic")]
if let Some(display) = drivers::all_display().first() {
crate::console::init_graphic_console(display.clone());
if display.need_flush() {
// TODO: support nested interrupt to render in time
crate::thread::spawn(crate::common::future::DisplayFlushFuture::new(display, 30));
}
}
#[cfg(feature = "loopback")]
{
use crate::net;
net::init();
}
Ok(())
}

View File

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

View File

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

View File

@ -1,6 +1,6 @@
//! Functions only available on x86 platforms.
pub use zcore_drivers::io::{Io, Pio};
pub use zcore_drivers::io::{Io, Pmio};
/// Get physical address of `acpi_rsdp` and `smbios` on x86_64.
pub fn pc_firmware_tables() -> (u64, u64) {

View File

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

View File

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

View File

@ -1,23 +1,42 @@
//! Read/write user space pointer.
// 来自用户空间的裸指针
//! Raw pointer from user land.
use alloc::string::String;
use alloc::vec::Vec;
use core::fmt::{Debug, Formatter};
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut};
use crate::VirtAddr;
use alloc::{string::String, vec::Vec};
use core::{
fmt::{Debug, Formatter},
marker::PhantomData,
ops::{Deref, DerefMut},
};
#[repr(C)]
pub struct UserPtr<T, P: Policy> {
ptr: *mut T,
mark: PhantomData<P>,
}
// 来自用户空间的裸指针
/// Raw pointer from user land.
#[repr(transparent)]
pub struct UserPtr<T, P: Policy>(*mut T, PhantomData<P>);
// 标识用户指针功能的基特征。
/// Base trait for Markers of user pointer policy.
pub trait Policy {}
// 标记一个用于输入的指针。
/// Marks a pointer used to read.
pub trait Read: Policy {}
// 标记一个用于输出的指针。
/// Marks a pointer used to write.
pub trait Write: Policy {}
pub enum In {}
pub enum Out {}
pub enum InOut {}
// 输入指针的类型参数。
/// Type argument for user pointer used to read.
pub struct In;
// 输出指针的类型参数。
/// Type argument for user pointer used to write.
pub struct Out;
// 既用于输入有用于输出的指针的类型参数。
/// Type argument for user pointer used to both read and write.
pub struct InOut;
impl Policy for In {}
impl Policy for Out {}
@ -31,9 +50,8 @@ pub type UserInPtr<T> = UserPtr<T, In>;
pub type UserOutPtr<T> = UserPtr<T, Out>;
pub type UserInOutPtr<T> = UserPtr<T, InOut>;
type Result<T> = core::result::Result<T, Error>;
/// The error type which is returned from user pointer.
// 用户指针操作的异常类型。
/// The error type which is returned from user pointer operation.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Error {
InvalidUtf8,
@ -43,9 +61,13 @@ pub enum Error {
InvalidVectorAddress,
}
// 本模块用到的只是用户指针操作结果的类型。
type Result<T> = core::result::Result<T, Error>;
impl<T, P: Policy> Debug for UserPtr<T, P> {
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> {}
impl<T, P: Policy> From<usize> for UserPtr<T, P> {
fn from(x: usize) -> Self {
UserPtr {
ptr: x as _,
mark: PhantomData,
}
fn from(ptr: usize) -> Self {
UserPtr(ptr as _, PhantomData)
}
}
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> {
if size < core::mem::size_of::<T>() {
return Err(Error::BufferTooSmall);
if size >= core::mem::size_of::<T>() {
Ok(Self::from(addr))
} else {
Err(Error::BufferTooSmall)
}
Ok(Self::from(addr))
}
// 如果指针为空,返回 `true`。
/// Returns `true` if the pointer is null.
pub fn is_null(&self) -> bool {
self.ptr.is_null()
self.0.is_null()
}
// 偏移指针。
// `count` 表示 `T` 的数量;
// 例如,`count` 为 3 表示将指针移动 `3 * size_of::<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 {
UserPtr {
ptr: unsafe { self.ptr.add(count) },
mark: PhantomData,
}
Self(unsafe { self.0.add(count) }, PhantomData)
}
pub fn as_ptr(&self) -> *mut T {
self.ptr
// 返回指针对应的虚地址。
/// Returns the virtual address represented by the pointer.
pub fn as_addr(&self) -> VirtAddr {
self.0 as _
}
// 检查用户指针是否合法。
//
// 如果指针非空且对齐则返回 `OK(())`。
/// Checks avaliability of the user pointer.
///
/// Returns [`Ok(())`] if it is neither null nor unaligned.
pub fn check(&self) -> Result<()> {
if self.ptr.is_null() {
return Err(Error::InvalidPointer);
if !self.0.is_null() && (self.0 as usize) % core::mem::align_of::<T>() == 0 {
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> {
pub fn as_ref(&self) -> Result<&'static T> {
Ok(unsafe { &*self.ptr })
// 取出指针值的引用(不要用于小于 8 字节的类型)。
/// Converts to reference.
#[allow(clippy::should_implement_trait)]
pub fn as_ref(&self) -> &'static T {
unsafe { &*self.0 }
}
// 读取但不移动指针所指的值(通过逐字节拷贝,但不需要 `Copy` 特征)。
// 指针所指的值保持不变。
/// Reads the value from `self` without moving it.
/// This leaves the memory in self unchanged.
pub fn read(&self) -> Result<T> {
// TODO: check ptr and return err
self.check()?;
Ok(unsafe { self.ptr.read() })
Ok(unsafe { self.0.read() })
}
// 和读取一样,
// 但若指针为空,返回 `None`。
/// Same as [`read`](Self::read),
/// but returns [`None`] when pointer is null.
pub fn read_if_not_null(&self) -> Result<Option<T>> {
if self.ptr.is_null() {
return Ok(None);
if !self.0.is_null() {
Ok(Some(self.read()?))
} else {
Ok(None)
}
let value = self.read()?;
Ok(Some(value))
}
// 构造一个从指针指向开始,长度为 `len` 的切片。
/// Forms a slice from a user pointer and a `len`.
pub fn as_slice(&self, len: usize) -> Result<&'static [T]> {
if len == 0 {
Ok(&[])
} else {
self.check()?;
Ok(unsafe { core::slice::from_raw_parts(self.0, len) })
}
}
// 拷贝对象来构造一个 `Vec`。
//
// `len` 是成员的数量,而不是字节数。
/// Copies elements into a new [`Vec`].
///
/// The `len` argument is the number of **elements**, not the number of bytes.
pub fn read_array(&self, len: usize) -> Result<Vec<T>> {
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> {
pub fn read_string(&self, len: usize) -> Result<String> {
self.check()?;
let src = unsafe { core::slice::from_raw_parts(self.ptr, len) };
let s = core::str::from_utf8(src).map_err(|_| Error::InvalidUtf8)?;
Ok(String::from(s))
// 构造一个从指针指向开始,长度为 `len` 的字符切片。
/// Forms an utf-8 string slice from a user pointer and a `len`.
pub fn as_str(&self, len: usize) -> Result<&'static str> {
core::str::from_utf8(self.as_slice(len)?).map_err(|_| Error::InvalidUtf8)
}
pub fn read_cstring(&self) -> Result<String> {
self.check()?;
let len = unsafe { (0usize..).find(|&i| *self.ptr.add(i) == 0).unwrap() };
self.read_string(len)
// 从一个 C 风格的零结尾字符串构造一个字符切片。
/// Forms a zero-terminated string slice from a user pointer to a c style string.
pub fn as_c_str(&self) -> Result<&'static str> {
self.as_str(unsafe { (0usize..).find(|&i| *self.0.add(i) == 0).unwrap() })
}
}
impl<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>> {
self.check()?;
let len = unsafe {
(0usize..)
.find(|&i| self.ptr.add(i).read().is_null())
.unwrap()
};
self.read_array(len)?
.into_iter()
.map(|ptr| ptr.read_cstring())
.collect()
let mut result = Vec::new();
let mut pptr = self.0;
loop {
let sptr = unsafe { pptr.read() };
if sptr.is_null() {
break;
}
result.push(sptr.as_c_str()?.into());
pptr = unsafe { pptr.add(1) };
}
Ok(result)
}
}
impl<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<()> {
self.check()?;
unsafe {
self.ptr.write(value);
}
unsafe { self.0.write(value) };
Ok(())
}
// 类似于写,
// 但指针为空时返回 `Ok(())`。
/// Same as [`write`](Self::write),
/// but does nothing and returns [`Ok`] when pointer is null.
pub fn write_if_not_null(&mut self, value: T) -> Result<()> {
if self.ptr.is_null() {
return Ok(());
if !self.0.is_null() {
self.write(value)
} else {
Ok(())
}
self.write(value)
}
// 写入 `values.len() * size_of<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<()> {
if values.is_empty() {
return Ok(());
}
self.check()?;
unsafe {
self.ptr
.copy_from_nonoverlapping(values.as_ptr(), values.len());
if !values.is_empty() {
self.check()?;
unsafe {
self.0
.copy_from_nonoverlapping(values.as_ptr(), values.len())
};
}
Ok(())
}
}
impl<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<()> {
let bytes = s.as_bytes();
self.write_array(bytes)?;
unsafe {
self.ptr.add(bytes.len()).write(0);
}
unsafe { self.0.add(bytes.len()).write(0) };
Ok(())
}
}
#[derive(Debug)]
#[repr(C)]
pub struct IoVec<P: Policy> {
pub struct IoVec<P: 'static + Policy> {
/// Starting address
ptr: UserPtr<u8, P>,
/// Number of bytes to transfer
@ -213,13 +291,13 @@ pub type IoVecOut = IoVec<Out>;
/// A valid IoVecs request from user
#[derive(Debug)]
pub struct IoVecs<P: Policy> {
pub struct IoVecs<P: 'static + Policy> {
vec: Vec<IoVec<P>>,
}
impl<P: Policy> UserInPtr<IoVec<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);
}
let vec = self.read_array(count)?;
@ -246,7 +324,7 @@ impl<P: Read> IoVecs<P> {
pub fn read_to_vec(&self) -> Result<Vec<u8>> {
let mut buf = Vec::new();
for vec in self.vec.iter() {
buf.extend(vec.ptr.read_array(vec.len)?);
buf.extend_from_slice(vec.ptr.as_slice(vec.len)?);
}
Ok(buf)
}
@ -299,20 +377,14 @@ impl<P: Policy> IoVec<P> {
}
pub fn as_slice(&self) -> Result<&[u8]> {
if self.ptr.is_null() {
return Err(Error::InvalidVectorAddress);
}
let slice = unsafe { core::slice::from_raw_parts(self.ptr.as_ptr(), self.len) };
Ok(slice)
self.as_mut_slice().map(|s| &*s)
}
}
impl<P: Write> IoVec<P> {
pub fn as_mut_slice(&mut self) -> Result<&mut [u8]> {
if self.ptr.is_null() {
return Err(Error::InvalidVectorAddress);
pub fn as_mut_slice(&self) -> Result<&mut [u8]> {
if !self.ptr.is_null() {
Ok(unsafe { core::slice::from_raw_parts_mut(self.ptr.0, self.len) })
} else {
Err(Error::InvalidVectorAddress)
}
let slice = unsafe { core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) };
Ok(slice)
}
}

View File

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

View File

@ -45,4 +45,10 @@ pub(super) fn init() {
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::{
iface::{InterfaceBuilder, NeighborCache, Route, Routes},
phy::{Loopback, Medium},

View File

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

View File

@ -19,13 +19,24 @@ zircon-object = { path = "../zircon-object", features = ["elf"] }
kernel-hal = { path = "../kernel-hal", default-features = false }
downcast-rs = { version = "1.2", default-features = false }
lazy_static = { version = "1.4", features = ["spin_no_std"] }
rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
rcore-fs-ramfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
rcore-fs-mountfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
rcore-fs-devfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
rcore-fs-ramfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
rcore-fs-mountfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
rcore-fs-devfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
cfg-if = "1.0"
smoltcp = { git = "https://gitee.com/gcyyfun/smoltcp", rev="043eb60", default-features = false, features = ["alloc","log", "async", "medium-ethernet","proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw"] }
smoltcp = { git = "https://gitee.com/gcyyfun/smoltcp", rev = "043eb60", default-features = false, features = [
"alloc",
"log",
"async",
"medium-ethernet",
"proto-ipv4",
"proto-igmp",
"socket-icmp",
"socket-udp",
"socket-tcp",
"socket-raw",
] }
zcore-drivers = { path = "../drivers", features = ["virtio"] }
lock = { git = "https://github.com/DeathWish5/kernel-sync" }

View File

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

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

View File

@ -3,6 +3,7 @@
/// missing documentation
pub mod socket_address;
use smoltcp::wire::IpEndpoint;
pub use socket_address::*;
/// missing documentation
@ -113,24 +114,8 @@ impl Drop for GlobalSocketHandle {
}
}
// #[cfg(feature = "e1000")]
use kernel_hal::net::get_net_device;
#[cfg(feature = "loopback")]
use hashbrown::HashMap;
#[cfg(feature = "loopback")]
use kernel_hal::timer_now;
// #[cfg(feature = "loopback")]
// use net_stack::{NetStack, NET_STACK};
#[cfg(feature = "loopback")]
use smoltcp::time::Instant;
// /// miss doc
// #[cfg(feature = "loopback")]
// pub fn get_net_stack() -> HashMap<usize, Arc<dyn NetStack>> {
// NET_STACK.read().clone()
// }
/// miss doc
fn poll_ifaces() {
for iface in get_net_device().iter() {
@ -143,67 +128,8 @@ fn poll_ifaces() {
}
}
// use core::future::Future;
// use core::pin::Pin;
// use core::task::Context;
// use core::task::Poll;
// use smoltcp::socket::TcpSocket;
// ============= SocketHandle =============
// ============= Endpoint =============
use smoltcp::wire::IpEndpoint;
/// missing documentation
#[derive(Clone, Debug)]
pub enum Endpoint {
/// missing documentation
Ip(IpEndpoint),
/// missing documentation
LinkLevel(LinkLevelEndpoint),
/// missing documentation
Netlink(NetlinkEndpoint),
}
/// missing documentation
#[derive(Clone, Debug)]
pub struct LinkLevelEndpoint {
/// missing documentation
pub interface_index: usize,
}
impl LinkLevelEndpoint {
/// missing documentation
pub fn new(ifindex: usize) -> Self {
LinkLevelEndpoint {
interface_index: ifindex,
}
}
}
/// missing documentation
#[derive(Clone, Debug)]
pub struct NetlinkEndpoint {
/// missing documentation
pub port_id: u32,
/// missing documentation
pub multicast_groups_mask: u32,
}
impl NetlinkEndpoint {
/// missing documentation
pub fn new(port_id: u32, multicast_groups_mask: u32) -> Self {
NetlinkEndpoint {
port_id,
multicast_groups_mask,
}
}
}
// ============= Endpoint =============
// ============= Rand Port =============
/// !!!! need riscv rng

View File

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

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
pub fn write(&self, data: &[u8], _sendto_endpoint: Option<Endpoint>) -> SysResult {
warn!("tcp write");
@ -242,194 +191,6 @@ impl TcpSocketState {
Err(LxError::EINVAL)
}
}
/// missing documentation
#[cfg(feature = "e1000")]
pub async fn connect(&self, endpoint: Endpoint) -> SysResult {
warn!("tcp connect");
// if let Endpoint::Ip(ip) = endpoint {
// let local_port = get_ephemeral_port();
// self.with(|ss| ss.connect(ip, local_port).map_err(|_| LxError::ENOBUFS))?;
// // use crate::net::IFaceFuture;
// // IFaceFuture { flag: false }.await;
// // warn!("no");
// // use smoltcp::socket::TcpState;
// // let ret = self.with(|ss| match ss.state() {
// // TcpState::SynSent => {
// // // still connecting
// // warn!("SynSent");
// // Ok(0)
// // }
// // TcpState::Established => Ok(0),
// // _ => Err(LxError::ECONNREFUSED),
// // });
// // Ok(0)
// // socket
// // .connect(ip, local_port)
// // .map_err(|_| LxError::ENOBUFS)?;
// // use crate::net::ConnectFuture;
// // use smoltcp::socket::SocketRef;
// // let c = ConnectFuture {
// // socket: SocketRef::into_inner(socket),
// // }
// // .await;
// // drop(c);
// // use core::future::Future;
// // use core::pin::Pin;
// // use core::task::Context;
// use crate::net::IFaceFuture;
// IFaceFuture.await;
// // warn!("no");
// // IFaceFuture.await;
// // warn!("no");
// // IFaceFuture.await;
// // warn!("no");
// // IFaceFuture.await;
// // warn!("no");
// use core::task::Poll;
// use smoltcp::socket::TcpState;
// let ret = futures::future::poll_fn(|cx| {
// self.with(|s| {
// // s.connect(ip, local_port).map_err(|_| LxError::ENOBUFS)?;
// match s.state() {
// TcpState::Closed | TcpState::TimeWait => {
// warn!("Closed|TimeWait");
// Poll::Ready(Err(LxError::ECONNREFUSED))
// }
// TcpState::Listen => {
// warn!("Listen");
// Poll::Ready(Err(LxError::ECONNREFUSED))
// }
// TcpState::SynSent => {
// warn!("SynSent");
// s.register_recv_waker(cx.waker());
// s.register_send_waker(cx.waker());
// // drop(s);
// // #[cfg(feature = "e1000")]
// // poll_ifaces_e1000();
// // IFaceFuture.await
// Poll::Pending
// }
// TcpState::SynReceived => {
// warn!("SynReceived");
// s.register_recv_waker(cx.waker());
// s.register_send_waker(cx.waker());
// Poll::Pending
// }
// TcpState::Established => {
// warn!("Established");
// // s.register_recv_waker(cx.waker());
// // s.register_send_waker(cx.waker());
// Poll::Ready(Ok(0))
// // Poll::Pending
// }
// // TcpState::TimeWait => {
// // warn!("TimeWait");
// // // s.register_recv_waker(cx.waker());
// // // s.register_send_waker(cx.waker());
// // Poll::Ready(Ok(0))
// // // Poll::Pending
// // }
// TcpState::FinWait1 => {
// warn!("------------------------------------FinWait1");
// // s.register_recv_waker(cx.waker());
// // s.register_send_waker(cx.waker());
// Poll::Ready(Ok(0))
// // Poll::Pending
// }
// TcpState::FinWait2 => {
// warn!("----------------------------------------FinWait2");
// // s.register_recv_waker(cx.waker());
// // s.register_send_waker(cx.waker());
// Poll::Ready(Ok(0))
// // Poll::Pending
// }
// TcpState::Closing => {
// warn!("-------------------------------------------Closing");
// // s.register_recv_waker(cx.waker());
// // s.register_send_waker(cx.waker());
// Poll::Ready(Ok(0))
// // Poll::Pending
// }
// TcpState::LastAck => {
// warn!("-------------------------------------------LastAck");
// // s.register_recv_waker(cx.waker());
// // s.register_send_waker(cx.waker());
// Poll::Ready(Ok(0))
// // Poll::Pending
// }
// _ => {
// warn!("_");
// Poll::Ready(Err(LxError::ECONNREFUSED))
// }
// }
// })
// })
// .await;
// // #[cfg(feature = "e1000")]
// // poll_ifaces_e1000();
// IFaceFuture.await;
// warn!("ret {:?}", ret);
// ret
// // Ok(0)
// } else {
// return Err(LxError::EINVAL);
// }
let net_sockets = get_net_sockets();
let mut sockets = net_sockets.lock();
let mut socket = sockets.get::<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
fn bind(&mut self, endpoint: Endpoint) -> SysResult {
@ -512,54 +273,6 @@ impl TcpSocketState {
drop(sockets);
}
}
#[cfg(feature = "e1000")]
async fn accept(&mut self) -> Result<(Arc<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
fn endpoint(&self) -> Option<Endpoint> {

View File

@ -122,34 +122,6 @@ impl UdpSocketState {
drop(sockets);
}
}
/// missing documentation
#[cfg(feature = "e1000")]
pub async fn read(&self, data: &mut [u8]) -> (SysResult, Endpoint) {
use core::task::Poll;
futures::future::poll_fn(|cx| {
self.with(|s| {
if s.can_recv() {
if let Ok((size, remote_endpoint)) = s.recv_slice(data) {
let endpoint = remote_endpoint;
warn!("udp read => size : {} , enpoint : {} ", size, endpoint);
Poll::Ready((Ok(size), Endpoint::Ip(endpoint)))
} else {
warn!("recv faill message");
Poll::Ready((
Err(LxError::ENOTCONN),
Endpoint::Ip(IpEndpoint::UNSPECIFIED),
))
}
} else {
warn!("udp can not recv ,because rx buffer is null");
s.register_recv_waker(cx.waker());
s.register_send_waker(cx.waker());
Poll::Pending
}
})
})
.await
}
/// missing documentation
pub fn write(&self, data: &[u8], sendto_endpoint: Option<Endpoint>) -> SysResult {

View File

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

View File

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

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 {
fn from(t: TimeSpec) -> Self {
Timespec {
sec: t.sec as i64,
nsec: t.nsec as i32,
Self {
sec: t.sec as _,
nsec: t.nsec as _,
}
}
}
impl From<TimeSpec> for Duration {
fn from(t: TimeSpec) -> Self {
Duration::new(t.sec as u64, t.nsec as u32)
Self::new(t.sec as _, t.nsec as _)
}
}
impl From<TimeSpec> for TimeVal {
fn from(t: TimeSpec) -> Self {
TimeVal {
Self {
sec: t.sec,
usec: t.nsec / 1_000,
}
@ -111,3 +120,73 @@ pub struct Tms {
/// system time of children
pub tms_cstime: u64,
}
/// Clock id
#[derive(Debug)]
#[repr(usize)]
pub enum ClockId {
/// missing documentation
ClockRealTime = 0,
/// missing documentation
ClockMonotonic = 1,
/// missing documentation
ClockProcessCpuTimeId = 2,
/// missing documentation
ClockThreadCpuTimeId = 3,
/// missing documentation
ClockMonotonicRaw = 4,
/// missing documentation
ClockRealTimeCoarse = 5,
/// missing documentation
ClockMonotonicCoarse = 6,
/// missing documentation
ClockBootTime = 7,
/// missing documentation
ClockRealTimeAlarm = 8,
/// missing documentation
ClockBootTimeAlarm = 9,
}
impl From<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"
bitflags = "1.3"
numeric-enum-macro = "0.2"
static_assertions = "1.1.0"
zircon-object = { path = "../zircon-object" }
linux-object = { path = "../linux-object" }
kernel-hal = { path = "../kernel-hal", default-features = false }
rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
lazy_static = { version = "1.4", features = ["spin_no_std"] }
bitvec = { version = "0.22", default-features = false, features = ["alloc"] }
lock = { git = "https://github.com/DeathWish5/kernel-sync" }

View File

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

View File

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

View File

@ -10,7 +10,7 @@
//! - access, faccessat
use super::*;
use linux_object::time::TimeSpec;
use linux_object::{process::FsInfo, time::TimeSpec};
impl Syscall<'_> {
/// Reads from a specified file using a file descriptor. Before using this call,
@ -21,11 +21,23 @@ impl Syscall<'_> {
pub async fn sys_read(&self, fd: FileDesc, mut base: UserOutPtr<u8>, len: usize) -> SysResult {
info!("read: fd={:?}, base={:?}, len={:#x}", fd, base, len);
let proc = self.linux_process();
let file_like = proc.get_file_like(fd)?;
let mut buf = vec![0u8; len];
let len = file_like.read(&mut buf).await?;
base.write_array(&buf[..len])?;
Ok(len)
// TODO wait a new struct to refactor
if usize::from(fd) >= SOCKET_FD {
let x = usize::from(fd);
let socket = proc.get_socket(x.into())?;
let mut buf = vec![0u8; len];
let (len, _) = socket.lock().read(&mut buf).await;
let len = len.unwrap_or(0);
base.write_array(&buf[..len])?;
Ok(len)
} else {
let file_like = proc.get_file_like(fd)?;
let mut buf = vec![0u8; len];
let len = file_like.read(&mut buf).await?;
base.write_array(&buf[..len])?;
Ok(len)
}
}
/// Writes to a specified file using a file descriptor. Before using this call,
@ -35,11 +47,9 @@ impl Syscall<'_> {
/// - len number of bytes to write
pub fn sys_write(&self, fd: FileDesc, base: UserInPtr<u8>, len: usize) -> SysResult {
info!("write: fd={:?}, base={:?}, len={:#x}", fd, base, len);
let proc = self.linux_process();
let buf = base.read_array(len)?;
let file_like = proc.get_file_like(fd)?;
let len = file_like.write(&buf)?;
Ok(len)
self.linux_process()
.get_file_like(fd)?
.write(base.as_slice(len)?)
}
/// read from or write to a file descriptor at a given offset
@ -77,11 +87,9 @@ impl Syscall<'_> {
"pwrite: fd={:?}, base={:?}, len={}, offset={}",
fd, base, len, offset
);
let proc = self.linux_process();
let buf = base.read_array(len)?;
let file_like = proc.get_file_like(fd)?;
let len = file_like.write_at(offset, &buf)?;
Ok(len)
self.linux_process()
.get_file_like(fd)?
.write_at(offset, base.as_slice(len)?)
}
/// works just like read except that multiple buffers are filled.
@ -96,11 +104,23 @@ impl Syscall<'_> {
info!("readv: fd={:?}, iov={:?}, count={}", fd, iov_ptr, iov_count);
let mut iovs = iov_ptr.read_iovecs(iov_count)?;
let proc = self.linux_process();
let file_like = proc.get_file_like(fd)?;
let mut buf = vec![0u8; iovs.total_len()];
let len = file_like.read(&mut buf).await?;
iovs.write_from_buf(&buf)?;
Ok(len)
// TODO wait a new struct to refactor
if usize::from(fd) >= SOCKET_FD {
let x = usize::from(fd);
let socket = proc.get_socket(x.into())?;
let mut buf = vec![0u8; iovs.total_len()];
let (len, _) = socket.lock().read(&mut buf).await;
let len = len.unwrap();
iovs.write_from_buf(&buf)?;
Ok(len)
} else {
let file_like = proc.get_file_like(fd)?;
let mut buf = vec![0u8; iovs.total_len()];
let len = file_like.read(&mut buf).await?;
iovs.write_from_buf(&buf)?;
Ok(len)
}
}
/// works just like write except that multiple buffers are written out.
@ -119,9 +139,18 @@ impl Syscall<'_> {
let iovs = iov_ptr.read_iovecs(iov_count)?;
let buf = iovs.read_to_vec()?;
let proc = self.linux_process();
let file_like = proc.get_file_like(fd)?;
let len = file_like.write(&buf)?;
Ok(len)
// TODO wait a new struct to refactor
if usize::from(fd) >= SOCKET_FD {
let x = usize::from(fd);
let socket = proc.get_socket(x.into())?;
let len = socket.lock().write(&buf, None)?;
Ok(len)
} else {
let file_like = proc.get_file_like(fd)?;
let len = file_like.write(&buf)?;
Ok(len)
}
}
/// repositions the offset of the open file associated with the file descriptor fd
@ -147,10 +176,9 @@ impl Syscall<'_> {
/// cause the regular file named by path to be truncated to a size of precisely length bytes.
pub fn sys_truncate(&self, path: UserInPtr<u8>, len: usize) -> SysResult {
let path = path.read_cstring()?;
let path = path.as_c_str()?;
info!("truncate: path={:?}, len={}", path, len);
let proc = self.linux_process();
proc.lookup_inode(&path)?.resize(len)?;
self.linux_process().lookup_inode(path)?.resize(len)?;
Ok(0)
}
@ -291,8 +319,17 @@ impl Syscall<'_> {
fd, request, arg1, arg2, arg3
);
let proc = self.linux_process();
let file_like = proc.get_file_like(fd)?;
file_like.ioctl(request, arg1, arg2, arg3)
// TODO wait a new struct to refactor
if usize::from(fd) >= SOCKET_FD {
let f = usize::from(fd);
let socket = proc.get_socket(f.into())?;
let x = socket.lock();
x.ioctl(request, arg1, arg2, arg3)
} else {
let file_like = proc.get_file_like(fd)?;
file_like.ioctl(request, arg1, arg2, arg3)
}
}
/// Manipulate a file descriptor.
@ -301,43 +338,52 @@ impl Syscall<'_> {
pub fn sys_fcntl(&self, fd: FileDesc, cmd: usize, arg: usize) -> SysResult {
info!("fcntl: fd={:?}, cmd={:x}, arg={}", fd, cmd, arg);
let proc = self.linux_process();
let file_like = proc.get_file_like(fd)?;
if let Ok(cmd) = FcntlCmd::try_from(cmd) {
match cmd {
FcntlCmd::GETFD => Ok(file_like.flags().close_on_exec() as usize),
FcntlCmd::SETFD => {
let mut flags = file_like.flags();
if (arg & 1) != 0 {
flags |= OpenFlags::CLOEXEC;
} else {
flags -= OpenFlags::CLOEXEC;
}
file_like.set_flags(flags)?;
Ok(0)
}
FcntlCmd::GETFL => Ok(file_like.flags().bits()),
FcntlCmd::SETFL => {
file_like.set_flags(OpenFlags::from_bits_truncate(arg))?;
Ok(0)
}
FcntlCmd::DUPFD | FcntlCmd::DUPFD_CLOEXEC => {
let new_fd = proc.get_free_fd_from(arg);
self.sys_dup2(fd, new_fd)?;
let dup = proc.get_file_like(new_fd)?;
let mut flags = dup.flags();
if cmd == FcntlCmd::DUPFD_CLOEXEC {
flags |= OpenFlags::CLOEXEC;
} else {
flags -= OpenFlags::CLOEXEC;
}
dup.set_flags(flags)?;
Ok(new_fd.into())
}
_ => Err(LxError::EINVAL),
}
// TODO wait a new struct to refactor
if usize::from(fd) >= SOCKET_FD {
let f = usize::from(fd);
let socket = proc.get_socket(f.into())?;
let x = socket.lock();
x.fcntl(cmd, arg)
} else {
Err(LxError::EINVAL)
let file_like = proc.get_file_like(fd)?;
if let Ok(cmd) = FcntlCmd::try_from(cmd) {
match cmd {
FcntlCmd::GETFD => Ok(file_like.flags().close_on_exec() as usize),
FcntlCmd::SETFD => {
let mut flags = file_like.flags();
if (arg & 1) != 0 {
flags |= OpenFlags::CLOEXEC;
} else {
flags -= OpenFlags::CLOEXEC;
}
file_like.set_flags(flags)?;
Ok(0)
}
FcntlCmd::GETFL => Ok(file_like.flags().bits()),
FcntlCmd::SETFL => {
file_like.set_flags(OpenFlags::from_bits_truncate(arg))?;
Ok(0)
}
FcntlCmd::DUPFD | FcntlCmd::DUPFD_CLOEXEC => {
let new_fd = proc.get_free_fd_from(arg);
self.sys_dup2(fd, new_fd)?;
let dup = proc.get_file_like(new_fd)?;
let mut flags = dup.flags();
if cmd == FcntlCmd::DUPFD_CLOEXEC {
flags |= OpenFlags::CLOEXEC;
} else {
flags -= OpenFlags::CLOEXEC;
}
dup.set_flags(flags)?;
Ok(new_fd.into())
}
_ => Err(LxError::EINVAL),
}
} else {
Err(LxError::EINVAL)
}
}
}
@ -356,7 +402,7 @@ impl Syscall<'_> {
flags: usize,
) -> SysResult {
// TODO: check permissions based on uid/gid
let path = path.read_cstring()?;
let path = path.as_c_str()?;
let flags = AtFlags::from_bits_truncate(flags);
info!(
"faccessat: dirfd={:?}, path={:?}, mode={:#o}, flags={:?}",
@ -364,7 +410,7 @@ impl Syscall<'_> {
);
let proc = self.linux_process();
let follow = !flags.contains(AtFlags::SYMLINK_NOFOLLOW);
let _inode = proc.lookup_inode_at(dirfd, &path, follow)?;
let _inode = proc.lookup_inode_at(dirfd, path, follow)?;
Ok(0)
}
@ -395,7 +441,7 @@ impl Syscall<'_> {
info!("futimens: fd: {:?}, times: {:?}", fd, times);
proc.get_file(fd)?.inode()
} else {
let pathname = pathname.read_cstring()?;
let pathname = pathname.as_c_str()?;
info!(
"utimensat: dirfd: {:?}, pathname: {:?}, times: {:?}, flags: {:#x}",
dirfd, pathname, times, flags
@ -407,7 +453,7 @@ impl Syscall<'_> {
} else {
return Err(LxError::EINVAL);
};
proc.lookup_inode_at(dirfd, &pathname[..], follow)?
proc.lookup_inode_at(dirfd, pathname, follow)?
};
let mut metadata = inode.metadata()?;
if times[0].nsec != UTIME_OMIT {
@ -431,10 +477,88 @@ impl Syscall<'_> {
inode.set_metadata(&metadata)?;
Ok(0)
}
/// Get filesystem statistics
/// (see [linux man statfs(2)](https://man7.org/linux/man-pages/man2/statfs.2.html)).
///
/// The `statfs` system call returns information about a mounted filesystem.
/// `path` is the pathname of **any file** within the mounted filesystem.
/// `buf` is a pointer to a `StatFs` structure.
pub fn sys_statfs(&self, path: UserInPtr<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;
/// 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! {
#[repr(usize)]
#[allow(non_camel_case_types)]
@ -461,3 +585,6 @@ numeric_enum_macro::numeric_enum! {
DUPFD_CLOEXEC = F_LINUX_SPECIFIC_BASE + 6,
}
}
// Temp , TODO warp a struct impl into/from with FileDesc and SocketHandle
const SOCKET_FD: usize = 10000;

View File

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

View File

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

View File

@ -1,4 +1,3 @@
//! Syscalls of Inter-Process Communication
#![allow(dead_code)]
use bitflags::*;
@ -9,8 +8,55 @@ use zircon_object::vm::*;
use super::*;
/// Syscalls of inter-process communication and System V semaphore Set operation.
///
/// # Menu
///
/// - [`semget`](Self::sys_semget)
/// - [`semop`](Self::sys_semop)
/// - [`semctl`](Self::sys_semctl)
/// - [`shmget`](Self::sys_shmget)
/// - [`shmat`](Self::sys_shmat)
/// - [`shmdt`](Self::sys_shmdt)
/// - [`shmctl`](Self::sys_shmctl)
impl Syscall<'_> {
/// returns the semaphore set identifier associated with the argument key
/// Get a System V semaphore set identifier
/// (see [linux man semget(2)](https://www.man7.org/linux/man-pages/man2/semget.2.html)).
///
/// The `sys_semget` system call returns
/// the System V semaphore set identifier associated with the argument `key`.
/// It may be used either to obtain the identifier of a previously created semaphore set
/// (when `flags` is zero and `key` is not zero),
/// or to create a new set.
///
/// A new set of `nsems` (number of semaphores) semaphores is created if `key` is zero
/// or if no existing semaphore set is associated with `key` and `IpcGetFlag::CREAT` is specified in `semflg`.
///
/// If `flags` specifies both `IpcGetFlag::CREAT` and `IpcGetFlag::EXCLUSIVE`
/// and a semaphore set already exists for key, then `sys_semget` fails with [`EEXIST`](LxError::EEXIST).
/// (This is analogous to the effect of the combination `OpenFlags::CREATE | OpenFlags::EXCLUSIVE` for [`sys_open`](Self::sys_open).)
///
/// Upon creation, the least significant 9 bits of the argument `flags` define
/// the permissions (for owner, group, and others) for the semaphore set.
/// These bits have the same format, and the same meaning, as the `mode` argument of [`sys_open`](Self::sys_open)
/// (though the execute permissions are not meaningful for semaphores,
/// and write permissions mean permission to alter semaphore values).
///
/// When creating a new semaphore set, `sys_semget` initializes the set's associated data structure,
/// semid_ds (see [`sys_semctl`](Self::sys_semctl)), as follows:
///
/// - sem_perm.cuid and sem_perm.uid are set to the effective user ID of the calling process.
/// - sem_perm.cgid and sem_perm.gid are set to the effective group ID of the calling process.
/// - The least significant 9 bits of sem_perm.mode are set to the least significant 9 bits of `flags`.
/// - sem_nsems is set to the value of nsems.
/// - sem_otime is set to 0.
/// - sem_ctime is set to the current time.
///
/// The argument nsems can be 0 (a don't care) when a semaphore set is not being created.
/// Otherwise, nsems must be greater than 0 and
/// less than or equal to the maximum number of semaphores per semaphore set (SEMMSL, constant 256).
///
/// If the semaphore set already exists, the permissions are verified.
pub fn sys_semget(&self, key: usize, nsems: usize, flags: usize) -> SysResult {
info!("semget: key: {} nsems: {} flags: {:#x}", key, nsems, flags);
@ -26,19 +72,40 @@ impl Syscall<'_> {
Ok(id)
}
/// semaphore operations
/// System V semaphore operations
/// (see [linux man semop(2)](https://www.man7.org/linux/man-pages/man2/semop.2.html)).
///
/// performs operations on selected semaphores in the set indicated by semid
/// `semop` performs operations on selected semaphores in the set indicated by `id`.
/// An array `[SemBuf; num_ops]` pointed to by `ops` specifies an operation to be performed on a single semaphore.
/// The declaration of `SemBuf` is like this:
///
/// ```rust
/// struct SemBuf {
/// num: u16,
/// op: i16,
/// flags: i16,
/// }
/// ```
///
/// Flags recognized in `SemBuf::flags` are `SemFlags::IPC_NOWAIT` and `SemFlags::SEM_UNDO`.
/// If an operation specifies `SEM_UNDO`, it will be automatically undone when the process terminates.
///
/// Each operation is performed on the `SemBuf::num`-th semaphore of the semaphore set,
/// where the first semaphore of the set is numbered 0.
/// There are two types of operation, distinguished by the value of `SemBuf::op`.
///
/// - If `op` is +1, see [`acquire`](linux_object::sync::Semaphore::acquire).
/// - If `op` is -1, see [`release`](linux_object::sync::Semaphore::release).
pub async fn sys_semop(&self, id: usize, ops: UserInPtr<SemBuf>, num_ops: usize) -> SysResult {
info!("semop: id: {}", id);
let ops = ops.read_array(num_ops)?;
let ops = ops.as_slice(num_ops)?;
let sem_array = self
.linux_process()
.semaphores_get(id)
.ok_or(LxError::EINVAL)?;
sem_array.otime();
for &SemBuf { num, op, flags } in ops.iter() {
for &SemBuf { num, op, flags } in ops {
let flags = SemFlags::from_bits_truncate(flags);
if flags.contains(SemFlags::IPC_NOWAIT) {
unimplemented!("Semaphore: semop.IPC_NOWAIT");
@ -58,10 +125,15 @@ impl Syscall<'_> {
Ok(0)
}
/// semaphore control operations
/// System V semaphore control operations
/// (see [linux man semctl(2)](https://www.man7.org/linux/man-pages/man2/semctl.2.html)).
///
/// performs the control operation specified by cmd on the semaphore set identified by semid,
/// or on the semnum-th semaphore of that set.
/// `semctl` performs the control operation specified by cmd
/// on the System V semaphore set identified by `id`,
/// or on the `num`-th semaphore of that set
/// (The semaphores in a set are numbered starting at 0).
///
/// TODO
pub fn sys_semctl(&self, id: usize, num: usize, cmd: usize, arg: usize) -> SysResult {
info!(
"semctl: id: {}, num: {}, cmd: {} arg: {:#x}",
@ -119,9 +191,12 @@ impl Syscall<'_> {
}
}
/// allocates a shared memory segment
/// Allocates a System V shared memory segment
/// (see [linux man shmget(2)](https://www.man7.org/linux/man-pages/man2/shmget.2.html)).
///
/// returns the identifier of the shared memory segment associated with the value of the argument key
/// `shmget` returns the identifier of the System V shared memory segment
/// associated with the value of the argument key.
/// Differ from linux, this syscall always create a new set.
pub fn sys_shmget(&self, key: usize, size: usize, shmflg: usize) -> SysResult {
info!(
"shmget: key: {}, size: {}, shmflg: {:#x}",
@ -138,7 +213,13 @@ impl Syscall<'_> {
Ok(id)
}
/// attaches the shared memory segment identified by shmid to the address space of the calling process.
/// System V shared memory operations
/// (see [linux man shmat(2)](https://www.man7.org/linux/man-pages/man2/shmat.2.html)).
///
/// `shmat` attaches the System V shared memory segment identified by `id`
/// to the address space of the calling process.
/// The attaching address is specified by `addr`.
/// If `addr` is zero, the system chooses a suitable page-aligned address to attach the segment.
pub fn sys_shmat(&self, id: usize, mut addr: VirtAddr, shmflg: usize) -> SysResult {
let mut shm_identifier = self.linux_process().shm_get(id).ok_or(LxError::EINVAL)?;
@ -173,8 +254,13 @@ impl Syscall<'_> {
Ok(addr)
}
/// detaches the shared memory segment located at the address specified by shmaddr
/// System V shared memory operations
/// (see [linux man shmdt(2)](https://www.man7.org/linux/man-pages/man2/shmdt.2.html)).
///
/// `shmdt` detaches the shared memory segment located at the address specified by `addr`
/// from the address space of the calling process.
/// The to-be-detached segment must be currently attached with `addr`
/// equal to the value returned by the attaching [`sys_shmat`](Self::sys_shmat) call.
pub fn sys_shmdt(&self, id: usize, addr: VirtAddr, shmflg: usize) -> SysResult {
info!(
"shmdt: id = {}, addr = {:#x}, flag = {:#x}",
@ -193,7 +279,8 @@ impl Syscall<'_> {
Ok(0)
}
/// shared memory control
/// System V shared memory operations
/// (see [linux man shmctl(2)](https://www.man7.org/linux/man-pages/man2/shmctl.2.html)).
///
/// performs the control operation specified by cmd on the shared memory segment whose identifier is given in id
pub fn sys_shmctl(&self, id: usize, cmd: usize, buffer: usize) -> SysResult {

View File

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

View File

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

View File

@ -1,26 +1,62 @@
//! Syscalls for process
//!
//! - fork
//! - vfork
//! - clone
//! - wait4
//! - execve
//! - gettid
//! - getpid
//! - getppid
use super::*;
use core::fmt::Debug;
use alloc::string::ToString;
use bitflags::bitflags;
use kernel_hal::context::UserContextField;
use linux_object::thread::{CurrentThreadExt, ThreadExt};
use linux_object::time::TimeSpec;
// use linux_object::time::TimeSpec;
use linux_object::{fs::INodeExt, loader::LinuxElfLoader};
/// Syscalls for process.
///
/// # Menu
///
/// - [`fork`](Self::sys_fork)
/// - [`vfork`](Self::sys_vfork)
/// - [`clone`](Self::sys_clone)
/// - [`wait4`](Self::sys_wait4)
/// - [`execve`](Self::sys_execve)
/// - [`gettid`](Self::sys_gettid)
/// - [`getpid`](Self::sys_getpid)
/// - [`getppid`](Self::sys_getppid)
/// - [`exit`](Self::sys_exit)
/// - [`exit_group`](Self::sys_exit_group)
/// - [`nanosleep`](Self::sys_nanosleep)
/// - [`set_tid_address`](Self::sys_set_tid_address)
impl Syscall<'_> {
/// Fork the current process. Return the child's PID.
/// `fork` creates a new process by duplicating the calling process
/// (see [linux man fork(2)](https://www.man7.org/linux/man-pages/man2/fork.2.html)).
/// The new process is referred to as the child process.
/// The calling process is referred to as the parent process.
///
/// The child process and the parent process run in separate memory spaces.
/// At the time of `fork` both memory spaces have the same content.
/// Memory writes, file mappings ([`Self::sys_mmap`]) and unmappings ([`Self::sys_munmap`])
/// performed by one of the processes do not affect the other.
///
/// The child process is an exact duplicate of the parent process except for the following points:
///
/// - The child has its own unique process ID, and this PID does not match the ID of any existing process.
/// - The child's parent process ID is the same as the parent's process ID.
/// - Process resource utilizations ([`Self::sys_getrusage`]) and CPU time counters ([`Self::sys_times`]) are reset to zero in the child.
/// - The child does not inherit semaphore adjustments from its parent ([`Self::sys_semop`]).
/// - The child does not inherit process-associated record locks from its parent ([`Self::sys_fcntl`]).
/// (On the other hand, it does inherit [`Self::sys_fcntl`] open file description locks and [`Self::sys_flock`] locks from its parent.)
///
/// Note the following further points:
///
/// - The child process is created with a single thread—the one that called fork().
/// The entire virtual address space of the parent is replicated in the child,
/// including the states of mutexes and condition variables.
/// - After a `fork` in a multithreaded program,
/// the child can safely call only async-signal-safe functions
/// until such time as it calls [`Self::sys_execve`].
/// - The child inherits copies of the parent's set of open file descriptors.
/// Each file descriptor in the child refers to the same open file description (see [`Self::sys_open`])
/// as the corresponding file descriptor in the parent.
/// This means that the two file descriptors share open file status flags and file offset.
pub fn sys_fork(&self) -> SysResult {
info!("fork:");
let new_proc = Process::fork_from(self.zircon_process(), false)?; // old pt NULL here
@ -34,7 +70,13 @@ impl Syscall<'_> {
Ok(new_proc.id() as usize)
}
/// creates a child process of the calling process, similar to fork but wait for execve
/// `sys_vfork`, just like [`Self::sys_fork`], creates a child process of the calling process
/// (see [linux man vfork(2)](https://www.man7.org/linux/man-pages/man2/vfork.2.html)).
/// For details, see [`Self::sys_fork`].
///
/// `sys_vfork` differs from [`Self::sys_fork`] in that the calling thread is suspended until the child terminates
/// (either normally, by calling [`Self::sys_exit`], or abnormally, after delivery of a fatal signal),
/// or it makes a call to [`Self::sys_execve`].
pub async fn sys_vfork(&self) -> SysResult {
info!("vfork:");
let new_proc = Process::fork_from(self.zircon_process(), true)?;
@ -54,11 +96,14 @@ impl Syscall<'_> {
Ok(new_proc.id() as usize)
}
/// Create a new thread in the current process.
/// `sys_clone` create a new thread in the current process.
/// The new thread's stack pointer will be set to `newsp`,
/// and thread pointer will be set to `newtls`.
/// The child tid will be stored at both `parent_tid` and `child_tid`.
/// This is partially implemented for musl only.
/// The child TID will be stored at both `parent_tid` and `child_tid`.
///
/// > **NOTE!** This system call is not exactly the same as `clone` in Linux.
///
/// > **NOTE!** This is partially implemented for `musl` only.
pub fn sys_clone(
&self,
flags: usize,
@ -99,9 +144,45 @@ impl Syscall<'_> {
Ok(tid as usize)
}
/// Wait for a child process exited.
/// `sys_wait4` suspends execution of the calling thread
/// until a child specified by `pid` argument has changed state
/// (see [linux man wait4(2)](https://www.man7.org/linux/man-pages/man2/wait4.2.html)).
/// By default, `sys_wait4` waits only for terminated children,
/// but this behavior is modifiable via the options argument, as described below.
///
/// Return the PID. Store exit code to `wstatus` if it's not null.
/// The value of `pid` can be:
///
/// - **-1**: meaning wait for any child process.
/// - **0**: meaning wait for any child process whose process group ID is equal to
/// that of the calling process at the time of the call to `sys_wait4`.
/// - **>0**: meaning wait for the child whose process ID is equal to the value of `pid`.
///
/// The value of options is an OR of zero or more of the following constants:
///
/// - **NOHANG** = 0x000_0001;
///
/// TODO
///
/// - **STOPPED** = 0x000_0002;
///
/// TODO
///
/// - **EXITED** = 0x000_0004;
///
/// TODO
///
/// - **CONTINUED** = 0x000_0008;
///
/// TODO
///
/// - **NOWAIT** = 0x100_0000;
///
/// TODO
///
/// On success, returns the process ID of the child whose state has changed;
/// if `NOHANG` flag was specified and one or more child(ren) specified by pid exist,
/// but have not yet changed state, then 0 is returned.
/// On failure, -1 is returned.
pub async fn sys_wait4(
&self,
pid: i32,
@ -145,25 +226,34 @@ impl Syscall<'_> {
Ok(pid as usize)
}
/// Replaces the current ** process ** with a new process image
/// `sys_execve` executes the program referred to by `path`
/// (see [linux man execve(2)](https://www.man7.org/linux/man-pages/man2/execve.2.html)).
/// This causes the program that is currently being run
/// by the calling process to be replaced with a new program,
/// with newly initialized stack, heap, and (initialized and uninitialized) data segments.
///
/// `path` argument must be a binary executable file.
///
/// `argv` is an array of argument strings passed to the new program.
/// By convention, the first of these strings (i.e., `argv[0]`)
/// should contain the filename associated with the file being executed.
///
/// `envp` is an array of strings, conventionally of the form `key=value`,
/// which are passed as environment to the new program.
///
/// NOTICE: `argv` & `envp` can not be NULL (different from Linux)
/// > **NOTE!** Differ from linux, `argv` & `envp` can not be NULL.
///
/// NOTICE: for multi-thread programs
/// A call to any exec function from a process with more than one thread
/// shall result in all threads being terminated and the new executable image
/// being loaded and executed.
/// > **NOTE!** For multi-thread programs,
/// A call to any exec function from a process with more than one thread
/// shall result in all threads being terminated and the new executable image
/// being loaded and executed.
pub fn sys_execve(
&mut self,
path: UserInPtr<u8>,
argv: UserInPtr<UserInPtr<u8>>,
envp: UserInPtr<UserInPtr<u8>>,
) -> SysResult {
let path = path.read_cstring()?;
let path = path.as_c_str()?;
let args = argv.read_cstring_array()?;
let envs = envp.read_cstring_array()?;
info!(
@ -179,23 +269,27 @@ impl Syscall<'_> {
// Read program file
let proc = self.linux_process();
let inode = proc.lookup_inode(&path)?;
let inode = proc.lookup_inode(path)?;
let data = inode.read_as_vec()?;
proc.remove_cloexec_files();
// 注意!即将销毁旧应用程序的用户空间,现在将必要的信息拷贝到内核!
// Notice! About to destroy the user space of the old application, now copy the necessary information into kernel!
let path = path.to_string();
let vmar = self.zircon_process().vmar();
vmar.clear()?;
let loader = LinuxElfLoader {
syscall_entry: self.syscall_entry,
stack_pages: 8,
root_inode: proc.root_inode().clone(),
};
let (entry, sp) = loader.load(&vmar, &data, args, envs, path.clone())?;
// Modify exec path
proc.set_execute_path(&path);
let (entry, sp) = LinuxElfLoader {
syscall_entry: self.syscall_entry,
stack_pages: 8,
root_inode: proc.root_inode().clone(),
}
.load(&vmar, &data, args, envs, path)?;
// TODO: use right signal
// self.zircon_process().signal_set(Signal::SIGNALED);
// Workaround, the child process could NOT exit correctly
@ -232,14 +326,18 @@ impl Syscall<'_> {
// }
// }
/// Get the current thread ID.
/// `sys_gettid` returns the caller's thread ID (TID)
/// (see [linux man gettid(2)](https://www.man7.org/linux/man-pages/man2/gettid.2.html)).
/// In a single-threaded process, the thread ID is equal to the process ID (PID, as returned by [`Self::sys_getpid`]).
/// In a multithreaded process, all threads have the same PID, but each one has a unique TID.
pub fn sys_gettid(&self) -> SysResult {
info!("gettid:");
let tid = self.thread.id();
Ok(tid as usize)
}
/// Get the current process ID.
/// `sys_getpid` returns the process ID (PID) of the calling process
/// (see [linux man getpid(2)](https://www.man7.org/linux/man-pages/man2/getpid.2.html)).
pub fn sys_getpid(&self) -> SysResult {
info!("getpid:");
let proc = self.zircon_process();
@ -247,7 +345,10 @@ impl Syscall<'_> {
Ok(pid as usize)
}
/// Get the parent process ID.
/// `sys_getppid` returns the process ID of the parent of the calling process
/// (see [linux man getppid(2)](https://www.man7.org/linux/man-pages/man2/getpid.2.html)).
/// This will be either the ID of the process that created this process using fork(),
/// or, if that process has already terminated, 0.
pub fn sys_getppid(&self) -> SysResult {
info!("getppid:");
let proc = self.linux_process();
@ -255,14 +356,23 @@ impl Syscall<'_> {
Ok(ppid as usize)
}
/// Exit the current thread
/// `sys_exit` system call terminates only the calling thread
/// (see [linux man _exit(2)](https://www.man7.org/linux/man-pages/man2/exit.2.html),
/// this syscall is same as a raw `_exit` in glibc),
/// and actions such as reparenting child processes or sending
/// SIGCHLD to the parent process are performed only if this is the
/// last thread in the thread group.
pub fn sys_exit(&mut self, exit_code: i32) -> SysResult {
info!("exit: code={}", exit_code);
self.thread.exit_linux(exit_code);
Err(LxError::ENOSYS)
}
/// Exit the current thread group (i.e. process)
/// `sys_exit_group` is equivalent to [`Self::sys_exit`]
/// except that it terminates not only the calling thread
/// (see [linux man exit_group(2)](https://www.man7.org/linux/man-pages/man2/exit_group.2.html),
/// but all threads in the calling process's thread group.
/// As a result, the entire calling process will exit.
pub fn sys_exit_group(&mut self, exit_code: i32) -> SysResult {
info!("exit_group: code={}", exit_code);
let proc = self.zircon_process();
@ -272,6 +382,16 @@ impl Syscall<'_> {
/// Allows the calling thread to sleep for
/// an interval specified with nanosecond precision
/// (see [linux man nanosleep(2)](https://www.man7.org/linux/man-pages/man2/nanosleep.2.html).
///
/// `nanosleep` suspends the execution of the calling thread
/// until either at least the time specified in `req` has elapsed,
/// or the delivery of a signal that triggers the invocation of a handler
/// in the calling thread or that terminates the process.
///
/// To represent a duration, see TimeSpec.
/* Deleted by 8278dc13 in Jan 28, 2022
pub async fn sys_nanosleep(&self, req: UserInPtr<TimeSpec>) -> SysResult {
info!("nanosleep: deadline={:?}", req);
let duration = req.read()?.into();
@ -279,15 +399,16 @@ impl Syscall<'_> {
thread::sleep_until(timer::deadline_after(duration)).await;
Ok(0)
}
*/
// pub fn sys_set_priority(&self, priority: usize) -> SysResult {
// let pid = thread::current().id();
// thread_manager().set_priority(pid, priority as u8);
// Ok(0)
// }
/// set pointer to thread ID
/// returns the caller's thread ID
/// `set_tid_address` sets the clear_child_tid value for the calling thread to `tidptr`,
/// and return the caller's thread ID
/// (see [linux man set_tid_address(2)](https://www.man7.org/linux/man-pages/man2/set_tid_address.2.html).
pub fn sys_set_tid_address(&self, tidptr: UserOutPtr<i32>) -> SysResult {
info!("set_tid_address: {:?}", tidptr);
self.thread.set_tid_address(tidptr);

View File

@ -103,4 +103,68 @@ impl Syscall<'_> {
info!("tick: {:?}", tick);
Ok(tick as usize)
}
/// Allows the calling thread to sleep for
/// an interval specified with nanosecond precision
pub async fn sys_nanosleep(&self, req: UserInPtr<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 zircon_object::vm::{pages, MMUFlags, VmObject};
/// Syscalls for virtual memory.
///
/// # Menu
///
/// - [`mmap`](Self::sys_mmap)
/// - [`mprotect`](Self::sys_mprotect)
/// - [`munmap`](Self::sys_munmap)
impl Syscall<'_> {
/// creates a new mapping in the virtual address space of the calling process.
/// - `addr` - The starting address for the new mapping
/// - `len` - specifies the length of the mapping
/// - `prot ` - describes the desired memory protection of the mapping
/// - `flags` - determines whether updates to the mapping are visible to other processes mapping the same region,
/// and whether updates are carried through to the underlying file.
/// - `fd` - mapping file descriptor
/// - `offset` - offset in the file
/// Map files or devices into memory
/// (see [linux man mmap(2)](https://www.man7.org/linux/man-pages/man2/mmap.2.html)).
///
/// `sys_mmap` creates a new mapping in the virtual address space of the calling process.
///
/// The starting address for the new mapping is specified in `addr`.
///
/// The `len` argument specifies the length of the mapping (which must be greater than 0).
///
/// Arguments `fd` and `offset` specifies mapping file descriptor and offset in the file.
///
/// The `prot` argument describes the desired memory protection of the mapping
/// (and must not conflict with the open mode of the file).
/// It is either 0 or the bitwise OR of one or more of the following flags:
///
/// - **`MmapProt::READ`**
///
/// Pages may be read
///
/// - **`MmapProt::WRITE`**
///
/// Pages may be written
///
/// - **`MmapProt::EXEC`**
///
/// Pages may be executed
///
/// The `flags` argument determines whether updates to the mapping are visible to other processes mapping the same region,
/// and whether updates are carried through to the underlying file.
/// This behavior is determined by including exactly one of the following values:
///
/// - **`MmapFlags::SHARED`**
///
/// Share this mapping. Updates to the mapping are visible to other processes mapping the same region,
/// and (in the case of file-backed mappings) are carried through to the underlying file.
/// (To precisely control when updates are carried through to the underlying file requires the use of `msync`,
/// which has not been implemented in zcore).
///
/// - **`MmapFlags::PRIVATE`**
///
/// Create a private copy-on-write mapping.
/// Updates to the mapping are not visible to other processes mapping the same file,
/// and are not carried through to the underlying file.
/// It is unspecified whether changes made to the file after the `sys_mmap` call are visible in the mapped region.
///
/// - **`MmapFlags::FIXED`**
///
/// Don't interpret `addr` as a hint: place the mapping at exactly that address.
/// `addr` must be suitably aligned:
/// for most architectures a multiple of the page size is sufficient;
/// however, some architectures may impose additional restrictions.
/// If the memory region specified by `addr` and `len` overlaps pages of any existing mapping(s),
/// then the overlapped part of the existing mapping(s) will be discarded.
/// If the specified address cannot be used, `sys_mmap` will fail.
///
/// - **`MmapFlags::ANONYMOUS`**
///
/// The mapping is not backed by any file; its contents are initialized to zero.
/// Both `fd` and `offset` arguments are ignored.
/// The use of `MmapFlags::ANONYMOUS` in conjunction with `MmapFlags::SHARED`
/// causes an [`EINVAL`](LxError::EINVAL) to be returned.
pub async fn sys_mmap(
&self,
addr: usize,
@ -50,9 +110,34 @@ impl Syscall<'_> {
}
}
/// changes the access protections for the calling process's memory pages
/// containing any part of the address range in the interval [addr, addr+len-1]
/// TODO: unimplemented
/// Set protection on a region of memory
/// (see [linux man mprotect(2)](https://www.man7.org/linux/man-pages/man2/mprotect.2.html)).
///
/// **NOTE!** This syscall is now unimplemented. Calling it always return `Ok(0)`.
///
/// `sys_mprotect` changes the access protections for the calling process's memory pages
/// containing any part of the address range in the interval `[addr, addr+len-1]`.
/// `addr` must be aligned to a page boundary.
///
/// If the calling process tries to access memory in a manner that violates the protections,
/// then the kernel generates a SIGSEGV signal for the process.
///
/// `prot` is a combination of the following access flags:
/// 0 or a bitwise-or of the other values in the following list:
///
/// - **`MmapProt::READ`**
///
/// The memory can be read.
///
/// - **`MmapProt::WRITE`**
///
/// The memory can be modified.
///
/// - **`MmapProt::EXEC`**
///
/// The memory can be executed.
///
/// If `prot` is 0, the memory cannot be accessed at all.
pub fn sys_mprotect(&self, addr: usize, len: usize, prot: usize) -> SysResult {
let prot = MmapProt::from_bits_truncate(prot);
info!(
@ -63,8 +148,19 @@ impl Syscall<'_> {
Ok(0)
}
/// Unmap files or devices into memory
/// (see [linux man munmap(2)](https://www.man7.org/linux/man-pages/man2/munmap.2.html)).
///
/// Deletes the mappings for the specified address range, and causes further references to addresses
/// within the range to generate invalid memory references.
///
/// The `sys_munmap` system call deletes the mappings for the specified address range,
/// and causes further references to addresses within the range to generate invalid memory references.
/// The region is also automatically unmapped when the process is terminated.
/// On the other hand, closing the file descriptor does not unmap the region.
///
/// Both `addr` and `len` must be aligned to the page size, additionally, `len` must greater than 0.
/// Otherwise, an [`EINVAL`](LxError::EINVAL) is returned.
pub fn sys_munmap(&self, addr: usize, len: usize) -> SysResult {
info!("munmap: addr={:#x}, size={:#x}", addr, len);
let proc = self.thread.proc();

View File

@ -1,7 +1,10 @@
[package]
name = "zcore-loader"
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"
description = "Linux and Zircon user programs loader and runner."
@ -27,7 +30,7 @@ libos = ["kernel-hal/libos", "zircon-object/aspace-separate"]
[dev-dependencies]
env_logger = "0.9"
async-std = { version = "1.10", features = ["attributes"] }
rcore-fs-hostfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
rcore-fs-hostfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
[[example]]
name = "linux-libos"

View File

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

View File

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

View File

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

View File

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

View File

@ -55,8 +55,16 @@ init_vm:
#TLB
sfence.vma
li t0, 4096 * 16
mul t0, t0, a0
# t0 = 0
xor t0, t0, t0
mv t1, a0
beqz t1, 2f
li t2, 4096 * 16
1:
add t0, t0, t2
addi t1, t1, -1
bgtz t1, 1b
2:
#sp为虚拟地址
lui sp, %hi(bootstacktop)
sub sp, sp, t0

View File

@ -1,6 +1,6 @@
{
"llvm-target": "x86_64-unknown-none",
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
"linker-flavor": "ld.lld",
"target-endian": "little",
"target-pointer-width": "64",

View File

@ -3,7 +3,7 @@ use super::nodes::{
SharedLegacyIrqHandler,
};
use super::{
config::PciConfig, constants::*, pci_init_args::PciIrqSwizzleLut, pio::pci_bdf_raw_addr,
config::PciConfig, constants::*, pci_init_args::PciIrqSwizzleLut, pmio::pci_bdf_raw_addr,
MappedEcamRegion, PciAddrSpace, PciEcamRegion,
};
use crate::dev::Interrupt;
@ -448,9 +448,9 @@ impl PCIeAddressProvider for MmioPcieAddressProvider {
/// Systems that have PIO mapped Config Spaces.
#[derive(Default)]
pub struct PioPcieAddressProvider;
pub struct PmioPcieAddressProvider;
impl PCIeAddressProvider for PioPcieAddressProvider {
impl PCIeAddressProvider for PmioPcieAddressProvider {
fn create_config(&self, addr: u64) -> Arc<PciConfig> {
Arc::new(PciConfig {
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 numeric_enum_macro::numeric_enum;
@ -14,21 +14,21 @@ impl PciConfig {
trace!("read8 @ {:#x?}", offset);
match self.addr_space {
PciAddrSpace::MMIO => unsafe { u8::from_le(*(offset as *const u8)) },
PciAddrSpace::PIO => pio_config_read_addr(offset as u32, 8).unwrap() as u8,
PciAddrSpace::PIO => pmio_config_read_addr(offset as u32, 8).unwrap() as u8,
}
}
pub fn read16_offset(&self, addr: usize) -> u16 {
trace!("read16 @ {:#x?}", addr);
match self.addr_space {
PciAddrSpace::MMIO => unsafe { u16::from_le(*(addr as *const u16)) },
PciAddrSpace::PIO => pio_config_read_addr(addr as u32, 16).unwrap() as u16,
PciAddrSpace::PIO => pmio_config_read_addr(addr as u32, 16).unwrap() as u16,
}
}
pub fn read32_offset(&self, addr: usize) -> u32 {
trace!("read32 @ {:#x?}", addr);
match self.addr_space {
PciAddrSpace::MMIO => unsafe { u32::from_le(*(addr as *const u32)) },
PciAddrSpace::PIO => pio_config_read_addr(addr as u32, 32).unwrap(),
PciAddrSpace::PIO => pmio_config_read_addr(addr as u32, 32).unwrap(),
}
}
pub fn read8(&self, addr: PciReg8) -> u8 {
@ -56,7 +56,7 @@ impl PciConfig {
pub fn write8_offset(&self, addr: usize, val: u8) {
match self.addr_space {
PciAddrSpace::MMIO => unsafe { *(addr as *mut u8) = val },
PciAddrSpace::PIO => pio_config_write_addr(addr as u32, val as u32, 8).unwrap(),
PciAddrSpace::PIO => pmio_config_write_addr(addr as u32, val as u32, 8).unwrap(),
}
}
pub fn write16_offset(&self, addr: usize, val: u16) {
@ -67,13 +67,13 @@ impl PciConfig {
);
match self.addr_space {
PciAddrSpace::MMIO => unsafe { *(addr as *mut u16) = val },
PciAddrSpace::PIO => pio_config_write_addr(addr as u32, val as u32, 16).unwrap(),
PciAddrSpace::PIO => pmio_config_write_addr(addr as u32, val as u32, 16).unwrap(),
}
}
pub fn write32_offset(&self, addr: usize, val: u32) {
match self.addr_space {
PciAddrSpace::MMIO => unsafe { *(addr as *mut u32) = val },
PciAddrSpace::PIO => pio_config_write_addr(addr as u32, val as u32, 32).unwrap(),
PciAddrSpace::PIO => pmio_config_write_addr(addr as u32, val as u32, 32).unwrap(),
}
}
pub fn write8(&self, addr: PciReg8, val: u8) {

View File

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

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

View File

@ -208,14 +208,14 @@ impl ElfExt for ElfFile<'_> {
};
let value = symval + entry.get_addend() as usize;
let addr = base + entry.get_offset() as usize;
debug!("GOT write: {:#x} @ {:#x}", value, addr);
trace!("GOT write: {:#x} @ {:#x}", value, addr);
vmar.write_memory(addr, &value.to_ne_bytes())
.map_err(|_| "Invalid Vmar")?;
}
REL_RELATIVE | R_RISCV_RELATIVE => {
let value = base + entry.get_addend() as usize;
let addr = base + entry.get_offset() as usize;
debug!("RELATIVE write: {:#x} @ {:#x}", value, addr);
trace!("RELATIVE write: {:#x} @ {:#x}", value, addr);
vmar.write_memory(addr, &value.to_ne_bytes())
.map_err(|_| "Invalid Vmar")?;
}

View File

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

View File

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

View File

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

View File

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

View File

@ -19,10 +19,10 @@ impl Syscall<'_> {
"futex.wait: value_ptr={:#x?}, current_value={:#x}, new_futex_owner={:#x}, deadline={:?}",
value_ptr, current_value, new_futex_owner, deadline
);
if value_ptr.is_null() || value_ptr.as_ptr() as usize % 4 != 0 {
if value_ptr.is_null() || value_ptr.as_addr() % 4 != 0 {
return Err(ZxError::INVALID_ARGS);
}
let value = value_ptr.as_ref()?;
let value = value_ptr.as_ref();
let proc = self.thread.proc();
let futex = proc.get_futex(value);
let new_owner = if new_futex_owner == INVALID_HANDLE {
@ -52,12 +52,12 @@ impl Syscall<'_> {
"futex.requeue: value_ptr={:?}, wake_count={:#x}, current_value={:#x}, requeue_ptr={:?}, requeue_count={:#x}, new_requeue_owner={:?}",
value_ptr, wake_count, current_value, requeue_ptr, requeue_count, new_requeue_owner
);
if value_ptr.is_null() || value_ptr.as_ptr() as usize % 4 != 0 {
if value_ptr.is_null() || value_ptr.as_addr() % 4 != 0 {
return Err(ZxError::INVALID_ARGS);
}
let value = value_ptr.as_ref()?;
let requeue = requeue_ptr.as_ref()?;
if value_ptr.as_ptr() == requeue_ptr.as_ptr() {
let value = value_ptr.as_ref();
let requeue = requeue_ptr.as_ref();
if value_ptr.as_addr() == requeue_ptr.as_addr() {
return Err(ZxError::INVALID_ARGS);
}
let proc = self.thread.proc();
@ -83,10 +83,10 @@ impl Syscall<'_> {
/// > Waking up zero threads is not an error condition. Passing in an unallocated address for value_ptr is not an error condition.
pub fn sys_futex_wake(&self, value_ptr: UserInPtr<AtomicI32>, count: u32) -> ZxResult {
info!("futex.wake: value_ptr={:?}, count={:#x}", value_ptr, count);
if value_ptr.is_null() || value_ptr.as_ptr() as usize % 4 != 0 {
if value_ptr.is_null() || value_ptr.as_addr() % 4 != 0 {
return Err(ZxError::INVALID_ARGS);
}
let value = value_ptr.as_ref()?;
let value = value_ptr.as_ref();
let proc = self.thread.proc();
let futex = proc.get_futex(value);
futex.wake(count as usize);
@ -96,10 +96,10 @@ impl Syscall<'_> {
/// Wake some number of threads waiting on a futex, and move more waiters to another wait queue.
pub fn sys_futex_wake_single_owner(&self, value_ptr: UserInPtr<AtomicI32>) -> ZxResult {
info!("futex.wake_single_owner: value_ptr={:?}", value_ptr);
if value_ptr.is_null() || value_ptr.as_ptr() as usize % 4 != 0 {
if value_ptr.is_null() || value_ptr.as_addr() % 4 != 0 {
return Err(ZxError::INVALID_ARGS);
}
let value = value_ptr.as_ref()?;
let value = value_ptr.as_ref();
let proc = self.thread.proc();
proc.get_futex(value).wake_single_owner();
Ok(())

View File

@ -1,9 +1,9 @@
use {super::*, core::convert::TryFrom};
impl Syscall<'_> {
/// Creates a duplicate of handle.
/// Creates a duplicate of handle.
///
/// Referring to the same underlying object, with new access rights rights.
/// Referring to the same underlying object, with new access rights rights.
pub fn sys_handle_duplicate(
&self,
handle_value: HandleValue,
@ -33,7 +33,7 @@ impl Syscall<'_> {
Ok(())
}
/// Close a handle and reclaim the underlying object if no other handles to it exist.
/// Close a handle and reclaim the underlying object if no other handles to it exist.
pub fn sys_handle_close(&self, handle: HandleValue) -> ZxResult {
info!("handle.close: handle={:?}", handle);
if handle == INVALID_HANDLE {
@ -44,7 +44,7 @@ impl Syscall<'_> {
Ok(())
}
/// Close a number of handles.
/// Close a number of handles.
pub fn sys_handle_close_many(
&self,
handles: UserInPtr<HandleValue>,
@ -55,19 +55,17 @@ impl Syscall<'_> {
handles, num_handles,
);
let proc = self.thread.proc();
let handles = handles.read_array(num_handles)?;
for handle in handles {
if handle == INVALID_HANDLE {
continue;
for handle in handles.as_slice(num_handles)? {
if *handle != INVALID_HANDLE {
proc.remove_handle(*handle)?;
}
proc.remove_handle(handle)?;
}
Ok(())
}
/// Creates a replacement for handle.
/// Creates a replacement for handle.
///
/// Referring to the same underlying object, with new access rights rights.
/// Referring to the same underlying object, with new access rights rights.
pub fn sys_handle_replace(
&self,
handle_value: HandleValue,

View File

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

View File

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

View File

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

View File

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

View File

@ -1,8 +1,8 @@
use {super::*, zircon_object::ipc::Socket, zircon_object::ipc::SocketFlags};
impl Syscall<'_> {
/// Create a socket.
///
/// Create a socket.
///
/// Socket is a connected pair of bidirectional stream transports, that can move only data, and that have a maximum capacity.
pub fn sys_socket_create(
&self,
@ -20,9 +20,9 @@ impl Syscall<'_> {
Ok(())
}
/// Write data to a socket.
///
/// Attempts to write `count: usize` bytes to the socket specified by `handle_value`.
/// Write data to a socket.
///
/// Attempts to write `count: usize` bytes to the socket specified by `handle_value`.
pub fn sys_socket_write(
&self,
handle_value: HandleValue,
@ -35,21 +35,20 @@ impl Syscall<'_> {
"socket.write: socket={:#x?}, options={:#x?}, buffer={:#x?}, size={:#x?}",
handle_value, options, user_bytes, count,
);
if count > 0 && user_bytes.is_null() {
return Err(ZxError::INVALID_ARGS);
if (count == 0 || !user_bytes.is_null()) && options == 0 {
let actual_count = self
.thread
.proc()
.get_object_with_rights::<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(
&self,
handle_value: HandleValue,
@ -79,7 +78,7 @@ impl Syscall<'_> {
Ok(())
}
/// Prevent future reading or writing on a socket.
/// Prevent future reading or writing on a socket.
pub fn sys_socket_shutdown(&self, socket: HandleValue, options: u32) -> ZxResult {
let options = SocketFlags::from_bits_truncate(options);
info!(

View File

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