forked from rcore-os/zCore
Merge master
This commit is contained in:
commit
8497aeea23
|
@ -175,3 +175,56 @@ jobs:
|
|||
- name: Run full tests
|
||||
if: github.event_name == 'schedule'
|
||||
run: cd tests && python3 linux_libc_test.py --arch ${{ matrix.arch }}
|
||||
|
||||
linux-other-test-baremetal:
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: [x86_64, riscv64]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- name: Pull prebuilt images
|
||||
run: git lfs pull -I prebuilt/linux/libc-libos.so
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly-2022-01-20
|
||||
components: rust-src, llvm-tools-preview
|
||||
- if: matrix.arch == 'riscv64'
|
||||
uses: actions-rs/install@v0.1
|
||||
with:
|
||||
crate: cargo-binutils
|
||||
version: latest
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install musl-tools musl-dev ninja-build -y
|
||||
pip3 install -r tests/requirements.txt
|
||||
- name: Cache QEMU
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: qemu-6.1.0
|
||||
key: qemu-6.1.0-${{ matrix.arch }}
|
||||
- name: Install QEMU
|
||||
run: |
|
||||
[ ! -d qemu-6.1.0 ] && wget https://download.qemu.org/qemu-6.1.0.tar.xz \
|
||||
&& tar xJf qemu-6.1.0.tar.xz > /dev/null \
|
||||
&& cd qemu-6.1.0 && ./configure --target-list=${{ matrix.arch }}-softmmu && cd ..
|
||||
cd qemu-6.1.0 && sudo make install -j
|
||||
qemu-system-${{ matrix.arch }} --version
|
||||
- name: Prepare rootfs
|
||||
run: |
|
||||
if [ "${{ matrix.arch }}" = "x86_64" ]; then
|
||||
make rootfs && make image
|
||||
elif [ "${{ matrix.arch }}" = "riscv64" ]; then
|
||||
make riscv-image
|
||||
fi
|
||||
- name: Run fast tests
|
||||
if: github.event_name != 'schedule'
|
||||
run: cd tests && python3 linux_other_test.py --arch ${{ matrix.arch }} --fast
|
||||
- name: Run full tests
|
||||
if: github.event_name == 'schedule'
|
||||
run: cd tests && python3 linux_other_test.py --arch ${{ matrix.arch }}
|
||||
|
|
51
Makefile
51
Makefile
|
@ -1,8 +1,26 @@
|
|||
# Makefile for top level of zCore
|
||||
|
||||
# Possible things to $(MAKE):
|
||||
#
|
||||
# rootfs-x64 : contains alpine-rootfs for x86_64, and compiled binary of linux-syscall/test/*.c
|
||||
# riscv-rootfs : prebuilt binary for riscv64, contains busybox, libc-test and oscomp
|
||||
# libc-test : build binary of libc-test for x86_64
|
||||
# rcore-fs-fuse : install a tool called rcore-fs-fuse
|
||||
# image : make a normal x86_64 image from alpine-rootfs
|
||||
# riscv-image : make a riscv64 image from riscv-rootfs for testing
|
||||
# clean : delete all files generated by compilation
|
||||
# doc : cargo doc --open
|
||||
# baremetal-test-img : make a x86_64 image for testing
|
||||
|
||||
ROOTFS_TAR := alpine-minirootfs-3.12.0-x86_64.tar.gz
|
||||
ROOTFS_URL := http://dl-cdn.alpinelinux.org/alpine/v3.12/releases/x86_64/$(ROOTFS_TAR)
|
||||
|
||||
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
|
||||
|
||||
CROSS_TOOLCHAIN := http://musl.cc/riscv64-linux-musl-cross.tgz
|
||||
PATH := $(PATH):$(PWD)/toolchain/riscv64-linux-musl-cross/bin
|
||||
|
||||
ARCH ?= x86_64
|
||||
rcore_fs_fuse_revision := 7f5eeac
|
||||
|
@ -25,6 +43,11 @@ prebuilt/linux/$(ROOTFS_TAR):
|
|||
prebuilt/linux/riscv64/$(RISCV64_ROOTFS_TAR):
|
||||
@wget $(RISCV64_ROOTFS_URL) -O $@
|
||||
|
||||
toolchain:
|
||||
@mkdir -p toolchain
|
||||
@cd toolchain && wget $(CROSS_TOOLCHAIN)
|
||||
@cd toolchain && tar xzf riscv64-linux-musl-cross.tgz
|
||||
|
||||
rootfs: prebuilt/linux/$(ROOTFS_TAR)
|
||||
rm -rf rootfs && mkdir -p rootfs
|
||||
tar xf $< -C rootfs
|
||||
|
@ -38,9 +61,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
|
||||
|
@ -63,8 +91,12 @@ image: $(OUT_IMG)
|
|||
@qemu-img resize $(OUT_IMG) +5M
|
||||
|
||||
|
||||
riscv-image: rcore-fs-fuse riscv-rootfs
|
||||
riscv-image: rcore-fs-fuse riscv-rootfs toolchain
|
||||
@echo building riscv.img
|
||||
@cd riscv_rootfs && mv libc-test libc-test-prebuild
|
||||
@cd riscv_rootfs && git clone $(LIBC_TEST_URL) --depth 1
|
||||
@cd riscv_rootfs/libc-test && cp config.mak.def config.mak && make ARCH=riscv64 CROSS_COMPILE=riscv64-linux-musl- -j
|
||||
@cd riscv_rootfs && cp libc-test-prebuild/functional/tls_align-static.exe libc-test/src/functional/
|
||||
@rcore-fs-fuse zCore/riscv64.img riscv_rootfs zip
|
||||
@qemu-img resize -f raw zCore/riscv64.img +5M
|
||||
|
||||
|
@ -90,7 +122,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
|
||||
|
@ -98,3 +130,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
|
||||
|
|
|
@ -19,11 +19,12 @@ cfg-if = "1.0"
|
|||
bitflags = "1.3"
|
||||
lazy_static = "1.4"
|
||||
numeric-enum-macro = "0.2"
|
||||
device_tree = { git = "https://github.91chi.fun//https://github.com/rcore-os/device_tree-rs.git", rev = "2f2e55f" }
|
||||
bitmap-allocator = { git = "https://github.91chi.fun//https://github.com/rcore-os/bitmap-allocator.git", rev = "b3f9f51" }
|
||||
virtio-drivers = { git = "https://github.91chi.fun//https://github.com/rcore-os/virtio-drivers", rev = "2aaf7d6", optional = true }
|
||||
rcore-console = { git = "https://github.91chi.fun//https://github.com/rcore-os/rcore-console", default-features = false, rev = "ca5b1bc", optional = true }
|
||||
# smoltcp = { git = "https://github.91chi.fun//https://github.com/smoltcp-rs/smoltcp", rev = "35e833e3", default-features = false, features = ["log", "alloc", "verbose", "proto-ipv4", "proto-ipv6", "proto-igmp", "medium-ip", "medium-ethernet", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp"] }
|
||||
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 }
|
||||
# smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev = "35e833e3", default-features = false, features = ["log", "alloc", "verbose", "proto-ipv4", "proto-ipv6", "proto-igmp", "medium-ip", "medium-ethernet", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp"] }
|
||||
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"] }
|
||||
|
||||
[target.'cfg(not(target_os = "none"))'.dependencies]
|
||||
|
@ -33,6 +34,7 @@ sdl2 = { version = "0.34", optional = true }
|
|||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||
acpi = "4.0"
|
||||
x2apic = "0.4"
|
||||
x86_64 = "0.14"
|
||||
|
||||
[target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies]
|
||||
riscv = { git = "https://github.91chi.fun//https://github.com/rust-embedded/riscv", rev = "cd31989", features = ["inline-asm"] }
|
||||
|
|
|
@ -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;
|
|
@ -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 in:AllDeviceList
|
|
@ -1,3 +1,5 @@
|
|||
//! Only UEFI Display currently.
|
||||
|
||||
mod uefi;
|
||||
|
||||
pub use uefi::UefiDisplay;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! Only Mouse currently.
|
||||
|
||||
mod mouse;
|
||||
|
||||
pub mod input_event_codes;
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
|
@ -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;
|
||||
|
|
|
@ -38,8 +38,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 {
|
||||
|
@ -54,8 +53,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
|
||||
|
@ -69,8 +67,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 _);
|
||||
}
|
||||
|
||||
|
@ -84,8 +81,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 _);
|
||||
}
|
||||
|
||||
|
|
|
@ -66,9 +66,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,
|
||||
|
|
|
@ -18,6 +18,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>>,
|
||||
|
@ -25,6 +26,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),
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! Mock devices, including display, input, uart and graphic.
|
||||
|
||||
pub mod display;
|
||||
pub mod input;
|
||||
pub mod uart;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! LAN driver, only for Realtek currently.
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_arch = "riscv64")] {
|
||||
mod realtek;
|
||||
|
|
|
@ -235,7 +235,7 @@ where
|
|||
mac[i] = u8::from_str_radix(s, 16).unwrap();
|
||||
}
|
||||
} else {
|
||||
mac = mac_addr.clone();
|
||||
mac = *mac_addr;
|
||||
}
|
||||
|
||||
info!(
|
||||
|
@ -1144,11 +1144,11 @@ 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 {
|
||||
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) {
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
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 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;
|
||||
|
@ -18,6 +18,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};
|
||||
|
||||
|
@ -48,13 +49,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);
|
||||
|
@ -81,11 +82,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) => {
|
||||
|
@ -192,14 +193,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,
|
||||
|
@ -211,7 +218,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![]));
|
||||
// }
|
||||
|
|
|
@ -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};
|
||||
}
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -106,6 +106,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// MMIO driver for UART 16550
|
||||
pub struct Uart16550Mmio<V: 'static>
|
||||
where
|
||||
V: Copy + BitAnd<Output = V> + BitOr<Output = V> + Not<Output = V>,
|
||||
|
@ -200,20 +201,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) {
|
||||
|
@ -221,7 +223,7 @@ mod pio {
|
|||
}
|
||||
}
|
||||
|
||||
impl UartScheme for Uart16550Pio {
|
||||
impl UartScheme for Uart16550Pmio {
|
||||
fn try_recv(&self) -> DeviceResult<Option<u8>> {
|
||||
self.inner.lock().try_recv()
|
||||
}
|
||||
|
@ -235,16 +237,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 {
|
||||
|
@ -256,4 +259,4 @@ mod pio {
|
|||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use pio::Uart16550Pio;
|
||||
pub use pmio::Uart16550Pmio;
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -1,24 +1,34 @@
|
|||
use alloc::{boxed::Box, vec::Vec};
|
||||
|
||||
use spin::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);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! Event handler and device tree.
|
||||
|
||||
#![allow(unused_imports)]
|
||||
|
||||
mod event_listener;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! Packaging of [`virtio-drivers` library](https://github.com/rcore-os/virtio-drivers).
|
||||
|
||||
mod blk;
|
||||
mod console;
|
||||
mod gpu;
|
||||
|
|
|
@ -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"
|
||||
|
@ -25,7 +27,6 @@ lazy_static = { version = "1.4", features = ["spin_no_std"] }
|
|||
zcore-drivers = { path = "../drivers", features = ["virtio"] }
|
||||
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 }
|
||||
|
|
|
@ -87,5 +87,11 @@ pub(super) fn init() -> DeviceResult {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "loopback")]
|
||||
{
|
||||
use crate::net;
|
||||
net::init();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
)?;
|
||||
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(crate::timer::timer_tick))?;
|
||||
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(())
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// May need move to drivers
|
||||
use smoltcp::{
|
||||
iface::{InterfaceBuilder, NeighborCache, Route, Routes},
|
||||
phy::{Loopback, Medium},
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
// 如果指针为空,返回 `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.ptr as usize) % core::mem::align_of::<T>() != 0 {
|
||||
return Err(Error::InvalidPointer);
|
||||
}
|
||||
if !self.0.is_null() && (self.0 as usize) % core::mem::align_of::<T>() == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::InvalidPointer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.ptr, len);
|
||||
ret.as_mut_ptr().copy_from_nonoverlapping(self.0, 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(())
|
||||
}
|
||||
}
|
||||
|
||||
// 写入 `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(());
|
||||
}
|
||||
if !values.is_empty() {
|
||||
self.check()?;
|
||||
unsafe {
|
||||
self.ptr
|
||||
.copy_from_nonoverlapping(values.as_ptr(), values.len());
|
||||
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);
|
||||
}
|
||||
let slice = unsafe { core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) };
|
||||
Ok(slice)
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,4 +45,10 @@ pub(super) fn init() {
|
|||
|
||||
crate::console::init_graphic_console(display);
|
||||
}
|
||||
|
||||
#[cfg(feature = "loopback")]
|
||||
{
|
||||
use crate::net;
|
||||
net::init();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// May need move to drivers
|
||||
use smoltcp::{
|
||||
iface::{InterfaceBuilder, NeighborCache, Route, Routes},
|
||||
phy::{Loopback, Medium},
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -19,11 +19,22 @@ 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.91chi.fun//https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
|
||||
rcore-fs-sfs = { git = "https://github.91chi.fun//https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
|
||||
rcore-fs-ramfs = { git = "https://github.91chi.fun//https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
|
||||
rcore-fs-mountfs = { git = "https://github.91chi.fun//https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
|
||||
rcore-fs-devfs = { git = "https://github.91chi.fun//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"] }
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
@ -130,7 +133,7 @@ pub fn create_root_fs(rootfs: Arc<dyn FileSystem>) -> Arc<dyn INode> {
|
|||
.add("shm", Arc::new(RandomINode::new(true)))
|
||||
.expect("failed to mknod /dev/shm");
|
||||
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()))) {
|
||||
|
@ -158,6 +161,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)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
/// missing documentation
|
||||
pub mod socket_address;
|
||||
use smoltcp::wire::IpEndpoint;
|
||||
pub use socket_address::*;
|
||||
|
||||
/// missing documentation
|
||||
|
@ -111,24 +112,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() {
|
||||
|
@ -141,67 +126,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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,57 +96,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 Ok(size)");
|
||||
Poll::Ready((
|
||||
Err(LxError::ENOTCONN),
|
||||
Endpoint::Ip(IpEndpoint::UNSPECIFIED),
|
||||
))
|
||||
}
|
||||
} else {
|
||||
error!("can not recv");
|
||||
s.register_recv_waker(cx.waker());
|
||||
s.register_send_waker(cx.waker());
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
})
|
||||
.await
|
||||
// let net_sockets = get_net_sockets();
|
||||
// let mut sockets = net_sockets.lock();
|
||||
// let mut socket = sockets.get::<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");
|
||||
|
@ -241,194 +190,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 {
|
||||
|
@ -511,54 +272,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> {
|
||||
|
|
|
@ -121,34 +121,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 {
|
||||
|
|
|
@ -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,14 +14,11 @@ 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 kernel_hal::VirtAddr;
|
||||
use zircon_object::{
|
||||
object::{KernelObject, KoID, Signal},
|
||||
signal::Futex,
|
||||
|
@ -22,10 +26,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 {
|
||||
|
@ -506,9 +507,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;
|
||||
|
|
|
@ -6,7 +6,6 @@ use crate::signal::{Signal, SignalStack, SignalUserContext, Sigset};
|
|||
use alloc::sync::Arc;
|
||||
use kernel_hal::context::{UserContext, UserContextField};
|
||||
use kernel_hal::user::{Out, UserInPtr, UserOutPtr, UserPtr};
|
||||
use kernel_hal::VirtAddr;
|
||||
use spin::{Mutex, MutexGuard};
|
||||
use zircon_object::task::{CurrentThread, Process, Thread};
|
||||
use zircon_object::ZxResult;
|
||||
|
@ -66,7 +65,7 @@ impl ThreadExt for Thread {
|
|||
mut _head_ptr: UserOutPtr<UserOutPtr<RobustList>>,
|
||||
mut _len_ptr: UserOutPtr<usize>,
|
||||
) -> SysResult {
|
||||
_head_ptr = (self.lock_linux().robust_list.as_ptr() as *mut RobustList as usize).into();
|
||||
_head_ptr = (self.lock_linux().robust_list.as_addr() as *mut RobustList as usize).into();
|
||||
_len_ptr = (&self.lock_linux().robust_list_len as *const usize as usize).into();
|
||||
Ok(0)
|
||||
}
|
||||
|
@ -87,7 +86,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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.91chi.fun//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"] }
|
||||
futures = { version = "0.3", default-features = false, features = ["alloc", "async-await"] }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//! Directory operations
|
||||
//! Directory operations
|
||||
//!
|
||||
//! - getcwd
|
||||
//! - chdir
|
||||
|
@ -11,7 +11,6 @@
|
|||
//! - readlink(at)
|
||||
|
||||
use super::*;
|
||||
use alloc::string::String;
|
||||
use bitflags::bitflags;
|
||||
use kernel_hal::user::UserOutPtr;
|
||||
use linux_object::fs::vfs::FileType;
|
||||
|
@ -29,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)
|
||||
}
|
||||
|
||||
|
@ -57,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() {
|
||||
|
@ -76,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)?;
|
||||
|
@ -142,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={:?}",
|
||||
|
@ -151,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)
|
||||
|
@ -169,10 +168,10 @@ 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()?;
|
||||
// hard code special path
|
||||
let path = if path == "/dev/shm/testshm" {
|
||||
String::from("/testshm")
|
||||
"/testshm"
|
||||
} else {
|
||||
path
|
||||
};
|
||||
|
@ -183,7 +182,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 {
|
||||
|
@ -206,16 +205,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)?;
|
||||
|
@ -237,14 +236,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);
|
||||
}
|
||||
|
|
|
@ -23,10 +23,10 @@ impl Syscall<'_> {
|
|||
mode: usize,
|
||||
) -> SysResult {
|
||||
let proc = self.linux_process();
|
||||
let path = path.read_cstring()?;
|
||||
let path = path.as_c_str()?;
|
||||
// hard code special path
|
||||
let path = if path == "/dev/shm/testshm" {
|
||||
String::from("/testshm")
|
||||
"/testshm"
|
||||
} else {
|
||||
path
|
||||
};
|
||||
|
@ -37,7 +37,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) {
|
||||
|
@ -53,9 +53,9 @@ 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())
|
||||
}
|
||||
|
|
|
@ -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,12 +21,24 @@ 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();
|
||||
|
||||
// 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,
|
||||
/// you must first obtain a file descriptor using the open syscall. Returns bytes written successfully.
|
||||
|
@ -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,12 +104,24 @@ 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();
|
||||
|
||||
// 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.
|
||||
/// writes iov_count buffers of data described
|
||||
|
@ -119,10 +139,19 @@ impl Syscall<'_> {
|
|||
let iovs = iov_ptr.read_iovecs(iov_count)?;
|
||||
let buf = iovs.read_to_vec()?;
|
||||
let proc = self.linux_process();
|
||||
|
||||
// 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
|
||||
/// to the argument offset according to the directive whence
|
||||
|
@ -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,9 +319,18 @@ impl Syscall<'_> {
|
|||
fd, request, arg1, arg2, arg3
|
||||
);
|
||||
let proc = self.linux_process();
|
||||
|
||||
// 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.
|
||||
/// - cmd – cmd flag
|
||||
|
@ -301,6 +338,14 @@ 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();
|
||||
|
||||
// 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 {
|
||||
let file_like = proc.get_file_like(fd)?;
|
||||
|
||||
if let Ok(cmd) = FcntlCmd::try_from(cmd) {
|
||||
|
@ -340,6 +385,7 @@ impl Syscall<'_> {
|
|||
Err(LxError::EINVAL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether the calling process can access the file pathname
|
||||
pub fn sys_access(&self, path: UserInPtr<u8>, mode: usize) -> SysResult {
|
||||
|
@ -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;
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
@ -390,12 +397,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"))]
|
||||
|
|
|
@ -81,11 +81,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
|
||||
|
@ -102,8 +117,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 {
|
||||
|
@ -111,8 +124,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)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,27 +1,62 @@
|
|||
//! Syscalls for process
|
||||
//!
|
||||
//! - fork
|
||||
//! - vfork
|
||||
//! - clone
|
||||
//! - wait4
|
||||
//! - execve
|
||||
//! - gettid
|
||||
//! - getpid
|
||||
//! - getppid
|
||||
|
||||
use super::*;
|
||||
use core::fmt::Debug;
|
||||
use core::mem::size_of;
|
||||
|
||||
use alloc::string::ToString;
|
||||
use bitflags::bitflags;
|
||||
|
||||
use kernel_hal::context::UserContextField;
|
||||
use linux_object::thread::{CurrentThreadExt, RobustList, ThreadExt};
|
||||
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
|
||||
|
@ -35,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)?;
|
||||
|
@ -55,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,
|
||||
|
@ -100,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,
|
||||
|
@ -146,15 +226,24 @@ 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
|
||||
/// > **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.
|
||||
|
@ -164,7 +253,7 @@ impl Syscall<'_> {
|
|||
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!(
|
||||
|
@ -180,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
|
||||
|
@ -212,14 +305,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();
|
||||
|
@ -227,7 +324,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();
|
||||
|
@ -235,14 +335,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();
|
||||
|
@ -252,6 +361,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();
|
||||
|
@ -259,15 +378,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);
|
||||
|
|
|
@ -87,4 +87,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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
/// 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.
|
||||
/// - `fd` - mapping file descriptor
|
||||
/// - `offset` - offset in the 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();
|
||||
|
|
|
@ -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."
|
||||
|
||||
|
@ -26,7 +29,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.91chi.fun//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"
|
||||
|
|
|
@ -36,30 +36,40 @@ 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"] }
|
||||
bitmap-allocator = { git = "https://github.91chi.fun//https://github.com/rcore-os/bitmap-allocator.git", rev = "b3f9f51" }
|
||||
kernel-hal = { path = "../kernel-hal", default-features = false, features = ["smp"] }
|
||||
bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev = "b3f9f51" }
|
||||
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.91chi.fun//https://github.com/rcore-os/rcore-fs", rev = "7c232ec", optional = true }
|
||||
rcore-fs-sfs = { git = "https://github.91chi.fun//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 }
|
||||
|
||||
# LibOS mode
|
||||
[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.91chi.fun//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]
|
||||
|
@ -68,5 +78,5 @@ executor = { git = "https://github.91chi.fun//https://github.com/rcore-os/execut
|
|||
|
||||
# Bare-metal mode on x86_64
|
||||
[target.'cfg(all(target_os = "none", target_arch = "x86_64"))'.dependencies]
|
||||
rboot = { git = "https://github.91chi.fun//https://github.com/rcore-os/rboot.git", rev = "39d6e24", default-features = false }
|
||||
# rvm = { git = "https://github.91chi.fun//https://github.com/rcore-os/RVM", rev = "e91d625", optional = true }
|
||||
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 }
|
||||
|
|
|
@ -18,6 +18,8 @@ ZBI ?= bringup
|
|||
SMP ?= 1
|
||||
ACCEL ?=
|
||||
|
||||
NET ?=
|
||||
|
||||
OBJDUMP ?= rust-objdump --print-imm-hex --x86-asm-syntax=intel
|
||||
OBJCOPY ?= rust-objcopy --binary-architecture=$(ARCH)
|
||||
|
||||
|
@ -98,6 +100,7 @@ endif
|
|||
|
||||
ifeq ($(TEST), 1)
|
||||
features += baremetal-test
|
||||
NET := loopback
|
||||
endif
|
||||
|
||||
ifeq ($(GRAPHIC), on)
|
||||
|
@ -111,6 +114,10 @@ ifeq ($(HYPERVISOR), 1)
|
|||
ACCEL := 1
|
||||
endif
|
||||
|
||||
ifeq ($(NET), loopback)
|
||||
features += loopback
|
||||
endif
|
||||
|
||||
################ Cargo build args ################
|
||||
|
||||
build_args := --features "$(features)"
|
||||
|
@ -137,6 +144,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
|
||||
|
@ -147,6 +155,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)"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
|
@ -447,9 +447,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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -12,7 +12,7 @@ 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 kernel_hal::x86_64::{Io, Pmio};
|
||||
use spin::Mutex;
|
||||
|
||||
static PIO_LOCK: Mutex<()> = Mutex::new(());
|
||||
|
@ -20,9 +20,9 @@ if #[cfg(all(target_arch = "x86_64", target_os = "none"))] {
|
|||
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;
|
||||
|
@ -33,9 +33,9 @@ if #[cfg(all(target_arch = "x86_64", target_os = "none"))] {
|
|||
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;
|
||||
|
@ -54,17 +54,17 @@ if #[cfg(all(target_arch = "x86_64", target_os = "none"))] {
|
|||
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(
|
||||
|
@ -75,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)
|
||||
}
|
|
@ -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")?;
|
||||
}
|
||||
|
|
|
@ -96,9 +96,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);
|
||||
}
|
||||
|
@ -161,8 +161,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);
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
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)?;
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
/// Read data from a fifo.
|
||||
|
|
|
@ -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();
|
||||
|
@ -84,10 +84,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);
|
||||
|
@ -97,10 +97,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(())
|
||||
|
|
|
@ -55,12 +55,10 @@ 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(())
|
||||
}
|
||||
|
|
|
@ -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 _);
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(())
|
||||
|
|
|
@ -35,18 +35,17 @@ 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 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)?;
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
/// Read data from a socket.
|
||||
|
|
|
@ -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,17 +357,19 @@ impl Syscall<'_> {
|
|||
mut actual: UserOutPtr<usize>,
|
||||
) -> ZxResult {
|
||||
if buffer.is_null() || buffer_size == 0 || buffer_size > MAX_BLOCK {
|
||||
return Err(ZxError::INVALID_ARGS);
|
||||
}
|
||||
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)?;
|
||||
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(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const JOB_POL_BASE_V1: u32 = 0;
|
||||
const JOB_POL_BASE_V2: u32 = 0x0100_0000;
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue