diff --git a/.gitattributes b/.gitattributes index 112cce3c..07ef07a5 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,3 +8,7 @@ regression/apps/signal_c/signal_test filter=lfs diff=lfs merge=lfs -text regression/apps/busybox/busybox filter=lfs diff=lfs merge=lfs -text regression/apps/pthread/pthread_test filter=lfs diff=lfs merge=lfs -text regression/apps/hello_pie/hello filter=lfs diff=lfs merge=lfs -text +regression/apps/network/tcp/client filter=lfs diff=lfs merge=lfs -text +regression/apps/network/tcp/server filter=lfs diff=lfs merge=lfs -text +regression/apps/network/udp/client filter=lfs diff=lfs merge=lfs -text +regression/apps/network/udp/server filter=lfs diff=lfs merge=lfs -text \ No newline at end of file diff --git a/.gitignore b/.gitignore index 19881b37..0c876925 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,6 @@ regression/ramdisk/build/ # qemu log file qemu.log + +# packet dump file +virtio-net.pcap diff --git a/Cargo.lock b/Cargo.lock index 870d0cd4..693a9ec5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -59,6 +59,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" +[[package]] +name = "atomic-polyfill" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28" +dependencies = [ + "critical-section", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -145,6 +154,12 @@ dependencies = [ name = "cpio-decoder" version = "0.1.0" +[[package]] +name = "critical-section" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6548a0ad5d2549e111e1f6a11a6c2e2d00ce6a3dafe22948d67c2b443f775e52" + [[package]] name = "crossbeam-utils" version = "0.8.15" @@ -198,6 +213,38 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "defmt" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956673bd3cb347512bf988d1e8d89ac9a82b64f6eec54d3c01c3529dac019882" +dependencies = [ + "bitflags", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4abc4821bd84d3d8f49945ddb24d029be9385ed9b77c99bf2f6296847a6a9f0" +dependencies = [ + "defmt-parser", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "defmt-parser" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "269924c02afd7f94bc4cecbfa5c379f6ffcf9766b3408fe63d22c728654eccd0" +dependencies = [ + "thiserror", +] + [[package]] name = "either" version = "1.8.0" @@ -233,6 +280,15 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -248,6 +304,19 @@ dependencies = [ "ahash", ] +[[package]] +name = "heapless" +version = "0.7.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743" +dependencies = [ + "atomic-polyfill", + "hash32", + "rustc_version", + "spin 0.9.4", + "stable_deref_trait", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -461,6 +530,7 @@ dependencies = [ "lru", "pod", "ringbuf", + "smoltcp", "spin 0.9.4", "time", "typeflags", @@ -495,6 +565,7 @@ dependencies = [ name = "jinux-virtio" version = "0.1.0" dependencies = [ + "align_ext", "bitflags", "component", "int-to-c-enum", @@ -568,6 +639,12 @@ dependencies = [ "hashbrown 0.13.1", ] +[[package]] +name = "managed" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" + [[package]] name = "memchr" version = "2.5.0" @@ -607,6 +684,30 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.56" @@ -668,6 +769,15 @@ dependencies = [ "wait-timeout", ] +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "rustversion" version = "1.0.9" @@ -680,6 +790,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + [[package]] name = "serde" version = "1.0.152" @@ -695,6 +811,21 @@ dependencies = [ "serde", ] +[[package]] +name = "smoltcp" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e9786ac45091b96f946693e05bfa4d8ca93e2d3341237d97a380107a6b38dea" +dependencies = [ + "bitflags", + "byteorder", + "cfg-if", + "defmt", + "heapless", + "log", + "managed", +] + [[package]] name = "spin" version = "0.5.2" @@ -719,6 +850,12 @@ dependencies = [ "lock_api", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "strsim" version = "0.10.0" diff --git a/Components.toml b/Components.toml index cb2b6c26..2f247f91 100644 --- a/Components.toml +++ b/Components.toml @@ -7,6 +7,7 @@ input = { name = "jinux-input" } block = { name = "jinux-block" } time = { name = "jinux-time" } framebuffer = { name = "jinux-framebuffer" } +network = { name = "jinux-network" } main = { name = "jinux" } [whitelist] diff --git a/framework/jinux-frame/src/arch/x86/timer/mod.rs b/framework/jinux-frame/src/arch/x86/timer/mod.rs index 992c3263..a7c22022 100644 --- a/framework/jinux-frame/src/arch/x86/timer/mod.rs +++ b/framework/jinux-frame/src/arch/x86/timer/mod.rs @@ -3,6 +3,7 @@ pub mod hpet; pub mod pit; use core::any::Any; +use core::sync::atomic::{AtomicU64, Ordering}; use alloc::{boxed::Box, collections::BinaryHeap, sync::Arc, vec::Vec}; use spin::{Mutex, Once}; @@ -12,7 +13,7 @@ use crate::arch::x86::kernel; use crate::trap::IrqAllocateHandle; pub const TIMER_IRQ_NUM: u8 = 32; -pub static mut TICK: u64 = 0; +pub static TICK: AtomicU64 = AtomicU64::new(0); static TIMER_IRQ: Once = Once::new(); @@ -30,11 +31,7 @@ pub fn init() { } fn timer_callback(trap_frame: &TrapFrame) { - let current_ms; - unsafe { - current_ms = TICK; - TICK += 1; - } + let current_ms = TICK.fetch_add(1, Ordering::SeqCst); let mut timeout_list = TIMEOUT_LIST.get().unwrap().lock(); let mut callbacks: Vec> = Vec::new(); while let Some(t) = timeout_list.peek() { @@ -121,10 +118,18 @@ where F: Fn(&TimerCallback) + Send + Sync + 'static, T: Any + Send + Sync, { - unsafe { - let timer_callback = TimerCallback::new(TICK + timeout, Arc::new(data), Box::new(callback)); - let arc = Arc::new(timer_callback); - TIMEOUT_LIST.get().unwrap().lock().push(arc.clone()); - arc - } + let timer_callback = TimerCallback::new( + TICK.load(Ordering::SeqCst) + timeout, + Arc::new(data), + Box::new(callback), + ); + let arc = Arc::new(timer_callback); + TIMEOUT_LIST.get().unwrap().lock().push(arc.clone()); + arc +} + +/// The time since the system boots up. +/// The currently returned results are in milliseconds. +pub fn read_monotonic_milli_seconds() -> u64 { + TICK.load(Ordering::SeqCst) } diff --git a/framework/jinux-frame/src/config.rs b/framework/jinux-frame/src/config.rs index a4d13d33..6975a892 100644 --- a/framework/jinux-frame/src/config.rs +++ b/framework/jinux-frame/src/config.rs @@ -18,4 +18,4 @@ pub const KVA_START: usize = (usize::MAX) << PAGE_SIZE_BITS; pub const DEFAULT_LOG_LEVEL: Level = Level::Error; /// This value represent the base timer frequency in Hz -pub const TIMER_FREQ: u64 = 100; +pub const TIMER_FREQ: u64 = 1000; diff --git a/framework/jinux-frame/src/timer.rs b/framework/jinux-frame/src/timer.rs index c7f76f96..a02b9bcb 100644 --- a/framework/jinux-frame/src/timer.rs +++ b/framework/jinux-frame/src/timer.rs @@ -3,9 +3,12 @@ #[cfg(target_arch = "x86_64")] use crate::arch::x86::timer::{add_timeout_list, TimerCallback, TICK}; use crate::{config::TIMER_FREQ, prelude::*}; -use core::time::Duration; +use core::{sync::atomic::Ordering, time::Duration}; use spin::Mutex; +#[cfg(target_arch = "x86_64")] +pub use crate::arch::x86::timer::read_monotonic_milli_seconds; + /// A timer invokes a callback function after a specified span of time elapsed. /// /// A new timer is initially inactive. Only after a timeout value is set with @@ -63,10 +66,9 @@ impl Timer { } let tick_count = timeout.as_secs() * TIMER_FREQ + timeout.subsec_nanos() as u64 / NANOS_DIVIDE; - unsafe { - lock.start_tick = TICK; - lock.timeout_tick = TICK + tick_count; - } + let tick = TICK.load(Ordering::SeqCst); + lock.start_tick = tick; + lock.timeout_tick = tick + tick_count; lock.timer_callback = Some(add_timeout_list(tick_count, self.clone(), timer_callback)); } @@ -75,10 +77,10 @@ impl Timer { /// If the timer is not set, then the remaining timeout value is zero. pub fn remain(&self) -> Duration { let lock = self.inner.lock(); - let tick_remain; - unsafe { - tick_remain = lock.timeout_tick as i64 - TICK as i64; - } + let tick_remain = { + let tick = TICK.load(Ordering::SeqCst) as i64; + lock.timeout_tick as i64 - tick + }; if tick_remain <= 0 { Duration::new(0, 0) } else { diff --git a/regression/ramdisk/Makefile b/regression/ramdisk/Makefile index aa31091f..1c8f4653 100644 --- a/regression/ramdisk/Makefile +++ b/regression/ramdisk/Makefile @@ -16,7 +16,7 @@ ifneq (, $(wildcard $(INITRAMFS)/. )) endif -.PHONY: all clean prepare_libs +.PHONY: all clean prepare_libs copy_special_files all: $(RAMDISK) diff --git a/services/comps/block/src/virtio.rs b/services/comps/block/src/virtio.rs index d92b318b..45f1cdb1 100644 --- a/services/comps/block/src/virtio.rs +++ b/services/comps/block/src/virtio.rs @@ -3,7 +3,7 @@ use jinux_frame::trap::TrapFrame; use jinux_pci::msix::MSIX; use jinux_util::frame_ptr::InFramePtr; -use jinux_virtio::{device::block::device::BLKDevice, PCIVirtioDevice, VitrioPciCommonCfg}; +use jinux_virtio::{device::block::device::BLKDevice, PCIVirtioDevice, VirtioPciCommonCfg}; use log::debug; use spin::Mutex; @@ -11,7 +11,7 @@ use crate::{BlockDevice, BLK_COMPONENT}; pub struct VirtioBlockDevice { blk_device: Mutex, - pub common_cfg: InFramePtr, + pub common_cfg: InFramePtr, msix: MSIX, } diff --git a/services/comps/input/src/virtio.rs b/services/comps/input/src/virtio.rs index c895082a..b2aa908f 100644 --- a/services/comps/input/src/virtio.rs +++ b/services/comps/input/src/virtio.rs @@ -6,7 +6,7 @@ use jinux_frame::trap::TrapFrame; use jinux_pci::msix::MSIX; use jinux_util::frame_ptr::InFramePtr; use jinux_virtio::device::input::device::InputProp; -use jinux_virtio::VitrioPciCommonCfg; +use jinux_virtio::VirtioPciCommonCfg; use jinux_virtio::{ device::input::{device::InputDevice, InputConfigSelect}, PCIVirtioDevice, @@ -18,7 +18,7 @@ use virtio_input_decoder::{DecodeType, Decoder}; use crate::INPUTDevice; pub struct VirtioInputDevice { input_device: InputDevice, - common_cfg: InFramePtr, + common_cfg: InFramePtr, msix: Mutex, name: String, callbacks: Mutex>>, @@ -57,7 +57,7 @@ impl VirtioInputDevice { let mut msix = virtio_device.msix; let config_msix_vector = - common_cfg.read_at(offset_of!(VitrioPciCommonCfg, config_msix_vector)) as usize; + common_cfg.read_at(offset_of!(VirtioPciCommonCfg, config_msix_vector)) as usize; let mut event_irq_number = 0; for i in 0..msix.table_size as usize { diff --git a/services/comps/virtio/Cargo.toml b/services/comps/virtio/Cargo.toml index 67d76fb8..0dd5ccc1 100644 --- a/services/comps/virtio/Cargo.toml +++ b/services/comps/virtio/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] bitflags = "1.3" spin = "0.9.4" +align_ext = { path = "../../../framework/libs/align_ext" } jinux-frame = { path = "../../../framework/jinux-frame" } jinux-pci = { path = "../pci" } jinux-util = { path = "../../libs/jinux-util" } diff --git a/services/comps/virtio/src/device/block/device.rs b/services/comps/virtio/src/device/block/device.rs index 64648436..c721a19b 100644 --- a/services/comps/virtio/src/device/block/device.rs +++ b/services/comps/virtio/src/device/block/device.rs @@ -10,7 +10,7 @@ use crate::{ device::block::{BlkReq, BlkResp, ReqType, RespStatus, BLK_SIZE}, device::VirtioDeviceError, queue::{QueueError, VirtQueue}, - VitrioPciCommonCfg, + VirtioPciCommonCfg, }; use super::{BLKFeatures, VirtioBLKConfig}; @@ -27,13 +27,13 @@ impl BLKDevice { pub(crate) fn new( cap: &CapabilityVirtioData, bars: [Option; 6], - common_cfg: &InFramePtr, + common_cfg: &InFramePtr, notify_base_address: usize, notify_off_multiplier: u32, mut msix_vector_left: Vec, ) -> Result { let config = VirtioBLKConfig::new(cap, bars); - let num_queues = common_cfg.read_at(offset_of!(VitrioPciCommonCfg, num_queues)) as u16; + let num_queues = common_cfg.read_at(offset_of!(VirtioPciCommonCfg, num_queues)) as u16; if num_queues != 1 { return Err(VirtioDeviceError::QueuesAmountDoNotMatch(num_queues, 1)); } diff --git a/services/comps/virtio/src/device/input/device.rs b/services/comps/virtio/src/device/input/device.rs index 2f870653..b78663b3 100644 --- a/services/comps/virtio/src/device/input/device.rs +++ b/services/comps/virtio/src/device/input/device.rs @@ -1,4 +1,4 @@ -use crate::{device::VirtioDeviceError, queue::VirtQueue, VitrioPciCommonCfg}; +use crate::{device::VirtioDeviceError, queue::VirtQueue, VirtioPciCommonCfg}; use alloc::{boxed::Box, vec::Vec}; use bitflags::bitflags; use jinux_frame::offset_of; @@ -56,7 +56,7 @@ impl InputDevice { pub fn new( cap: &CapabilityVirtioData, bars: [Option; 6], - common_cfg: &InFramePtr, + common_cfg: &InFramePtr, notify_base_address: usize, notify_off_multiplier: u32, mut msix_vector_left: Vec, diff --git a/services/comps/virtio/src/device/mod.rs b/services/comps/virtio/src/device/mod.rs index 8a09a470..385fd41c 100644 --- a/services/comps/virtio/src/device/mod.rs +++ b/services/comps/virtio/src/device/mod.rs @@ -1,4 +1,7 @@ -use crate::{device::block::device::BLKDevice, Feature, VirtioDeviceType, VitrioPciCommonCfg}; +use crate::{ + device::block::device::BLKDevice, queue::QueueError, Feature, VirtioDeviceType, + VirtioPciCommonCfg, +}; use alloc::vec::Vec; use jinux_pci::{ capability::{vendor::virtio::CapabilityVirtioData, Capability}, @@ -43,11 +46,17 @@ pub enum VirtioDeviceError { CapabilityListError, } +impl From for VirtioDeviceError { + fn from(_: QueueError) -> Self { + VirtioDeviceError::QueueUnknownError + } +} + pub struct VirtioInfo { pub device_type: VirtioDeviceType, pub notify_base_address: u64, pub notify_off_multiplier: u32, - pub common_cfg_frame_ptr: InFramePtr, + pub common_cfg_frame_ptr: InFramePtr, pub device_cap_cfg: CapabilityVirtioData, } @@ -68,7 +77,7 @@ impl VirtioInfo { match cap_data.cfg_type { PCI_VIRTIO_CAP_COMMON_CFG => { common_cfg_frame_ptr_some = - Some(VitrioPciCommonCfg::new(&cap_data, bars)); + Some(VirtioPciCommonCfg::new(&cap_data, bars)); } PCI_VIRTIO_CAP_NOTIFY_CFG => { notify_off_multiplier = cap_data.option.unwrap(); @@ -140,7 +149,8 @@ impl VirtioDevice { } pub(crate) fn negotiate_features(features: u64, device_type: VirtioDeviceType) -> u64 { - let device_specified_features = features & ((1 << 24) - 1); + let mask = ((1u64 << 24) - 1) | (((1u64 << 24) - 1) << 50); + let device_specified_features = features & mask; let device_support_features = match device_type { VirtioDeviceType::Network => todo!(), VirtioDeviceType::Block => BLKDevice::negotiate_features(device_specified_features), diff --git a/services/comps/virtio/src/lib.rs b/services/comps/virtio/src/lib.rs index 29c5d603..f94a6b92 100644 --- a/services/comps/virtio/src/lib.rs +++ b/services/comps/virtio/src/lib.rs @@ -119,7 +119,7 @@ bitflags! { } bitflags! { - /// all device features, bits 0~23 are sepecified by device + /// all device features, bits 0~23 and 50~63 are sepecified by device. /// if using this struct to translate u64, use from_bits_truncate function instead of from_bits /// struct Feature: u64 { @@ -144,7 +144,7 @@ bitflags! { #[derive(Debug, Default, Copy, Clone, Pod)] #[repr(C)] -pub struct VitrioPciCommonCfg { +pub struct VirtioPciCommonCfg { device_feature_select: u32, device_feature: u32, driver_feature_select: u32, @@ -164,7 +164,7 @@ pub struct VitrioPciCommonCfg { queue_device: u64, } -impl VitrioPciCommonCfg { +impl VirtioPciCommonCfg { pub(crate) fn new(cap: &CapabilityVirtioData, bars: [Option; 6]) -> InFramePtr { let bar = cap.bar; let offset = cap.offset; @@ -219,7 +219,7 @@ impl VirtioDeviceType { pub struct PCIVirtioDevice { /// common config of one device - pub common_cfg: InFramePtr, + pub common_cfg: InFramePtr, pub device: VirtioDevice, pub msix: MSIX, } @@ -269,35 +269,35 @@ impl PCIVirtioDevice { let common_cfg_frame_ptr = &virtio_info.common_cfg_frame_ptr; // Reset device - common_cfg_frame_ptr.write_at(offset_of!(VitrioPciCommonCfg, device_status), 0 as u8); + common_cfg_frame_ptr.write_at(offset_of!(VirtioPciCommonCfg, device_status), 0 as u8); let num_queues: u16 = - common_cfg_frame_ptr.read_at(offset_of!(VitrioPciCommonCfg, num_queues)); + common_cfg_frame_ptr.read_at(offset_of!(VirtioPciCommonCfg, num_queues)); debug!("num_queues:{:x}", num_queues); // the table size of msix should be equal to n+1 or 2 where n is the virtqueue amount assert!(msix.table_size == 2 || msix.table_size == (num_queues + 1)); common_cfg_frame_ptr.write_at( - offset_of!(VitrioPciCommonCfg, config_msix_vector), + offset_of!(VirtioPciCommonCfg, config_msix_vector), config_msix_vector, ); common_cfg_frame_ptr.write_at( - offset_of!(VitrioPciCommonCfg, device_status), + offset_of!(VirtioPciCommonCfg, device_status), (DeviceStatus::ACKNOWLEDGE | DeviceStatus::DRIVER).bits(), ); // negotiate features // get the value of device features common_cfg_frame_ptr.write_at( - offset_of!(VitrioPciCommonCfg, device_feature_select), + offset_of!(VirtioPciCommonCfg, device_feature_select), 0 as u32, ); let mut low: u32 = - common_cfg_frame_ptr.read_at(offset_of!(VitrioPciCommonCfg, device_feature)); + common_cfg_frame_ptr.read_at(offset_of!(VirtioPciCommonCfg, device_feature)); common_cfg_frame_ptr.write_at( - offset_of!(VitrioPciCommonCfg, device_feature_select), + offset_of!(VirtioPciCommonCfg, device_feature_select), 1 as u32, ); let mut high: u32 = - common_cfg_frame_ptr.read_at(offset_of!(VitrioPciCommonCfg, device_feature)); + common_cfg_frame_ptr.read_at(offset_of!(VirtioPciCommonCfg, device_feature)); let mut feature = (high as u64) << 32; feature |= low as u64; // let the device to negotiate Features @@ -307,26 +307,26 @@ impl PCIVirtioDevice { low = driver_features as u32; high = (driver_features >> 32) as u32; common_cfg_frame_ptr.write_at( - offset_of!(VitrioPciCommonCfg, driver_feature_select), + offset_of!(VirtioPciCommonCfg, driver_feature_select), 0 as u32, ); - common_cfg_frame_ptr.write_at(offset_of!(VitrioPciCommonCfg, driver_feature), low); + common_cfg_frame_ptr.write_at(offset_of!(VirtioPciCommonCfg, driver_feature), low); common_cfg_frame_ptr.write_at( - offset_of!(VitrioPciCommonCfg, driver_feature_select), + offset_of!(VirtioPciCommonCfg, driver_feature_select), 1 as u32, ); - common_cfg_frame_ptr.write_at(offset_of!(VitrioPciCommonCfg, driver_feature), high); + common_cfg_frame_ptr.write_at(offset_of!(VirtioPciCommonCfg, driver_feature), high); // change to features ok status common_cfg_frame_ptr.write_at( - offset_of!(VitrioPciCommonCfg, device_status), + offset_of!(VirtioPciCommonCfg, device_status), (DeviceStatus::ACKNOWLEDGE | DeviceStatus::DRIVER | DeviceStatus::FEATURES_OK).bits(), ); let device = VirtioDevice::new(&virtio_info, bars, msix_vector_list).unwrap(); // change to driver ok status common_cfg_frame_ptr.write_at( - offset_of!(VitrioPciCommonCfg, device_status), + offset_of!(VirtioPciCommonCfg, device_status), (DeviceStatus::ACKNOWLEDGE | DeviceStatus::DRIVER | DeviceStatus::FEATURES_OK @@ -351,7 +351,7 @@ impl PCIVirtioDevice { { let config_msix_vector = self.common_cfg - .read_at(offset_of!(VitrioPciCommonCfg, config_msix_vector)) as usize; + .read_at(offset_of!(VirtioPciCommonCfg, config_msix_vector)) as usize; for i in 0..self.msix.table_size as usize { let msix = self.msix.table.get_mut(i).unwrap(); if !msix.irq_handle.is_empty() { diff --git a/services/comps/virtio/src/queue.rs b/services/comps/virtio/src/queue.rs index 7073bc5b..083e0c05 100644 --- a/services/comps/virtio/src/queue.rs +++ b/services/comps/virtio/src/queue.rs @@ -1,6 +1,6 @@ //! Virtqueue -use super::VitrioPciCommonCfg; +use super::VirtioPciCommonCfg; use alloc::vec::Vec; use bitflags::bitflags; use core::sync::atomic::{fence, Ordering}; @@ -55,29 +55,29 @@ pub struct VirtQueue { impl VirtQueue { /// Create a new VirtQueue. pub(crate) fn new( - cfg: &InFramePtr, + cfg: &InFramePtr, idx: usize, size: u16, notify_base_address: usize, notify_off_multiplier: u32, msix_vector: u16, ) -> Result { - cfg.write_at(offset_of!(VitrioPciCommonCfg, queue_select), idx as u16); + cfg.write_at(offset_of!(VirtioPciCommonCfg, queue_select), idx as u16); assert_eq!( - cfg.read_at(offset_of!(VitrioPciCommonCfg, queue_select)), + cfg.read_at(offset_of!(VirtioPciCommonCfg, queue_select)), idx as u16 ); if !size.is_power_of_two() { return Err(QueueError::InvalidArgs); } - cfg.write_at(offset_of!(VitrioPciCommonCfg, queue_size), size); + cfg.write_at(offset_of!(VirtioPciCommonCfg, queue_size), size); cfg.write_at( - offset_of!(VitrioPciCommonCfg, queue_msix_vector), + offset_of!(VirtioPciCommonCfg, queue_msix_vector), msix_vector, ); assert_eq!( - cfg.read_at(offset_of!(VitrioPciCommonCfg, queue_msix_vector)), + cfg.read_at(offset_of!(VirtioPciCommonCfg, queue_msix_vector)), msix_vector ); @@ -109,17 +109,17 @@ impl VirtQueue { debug!("queue_device start paddr:{:x?}", used_frame_ptr.paddr()); cfg.write_at( - offset_of!(VitrioPciCommonCfg, queue_desc), + offset_of!(VirtioPciCommonCfg, queue_desc), desc_frame_ptr.paddr() as u64, ); cfg.write_at( - offset_of!(VitrioPciCommonCfg, queue_driver), + offset_of!(VirtioPciCommonCfg, queue_driver), avail_frame_ptr.paddr() as u64, ); cfg.write_at( - offset_of!(VitrioPciCommonCfg, queue_device), + offset_of!(VirtioPciCommonCfg, queue_device), used_frame_ptr.paddr() as u64, ); @@ -137,7 +137,7 @@ impl VirtQueue { temp.write_at(offset_of!(Descriptor, next), i + 1); } avail_frame_ptr.write_at(offset_of!(AvailRing, flags), 0 as u16); - cfg.write_at(offset_of!(VitrioPciCommonCfg, queue_enable), 1 as u16); + cfg.write_at(offset_of!(VirtioPciCommonCfg, queue_enable), 1 as u16); Ok(VirtQueue { descs, avail: avail_frame_ptr, @@ -305,6 +305,14 @@ impl VirtQueue { self.queue_size } + /// whether the driver should notify the device + pub fn should_notify(&self) -> bool { + // read barrier + fence(Ordering::SeqCst); + let flags = self.used.read_at(offset_of!(UsedRing, flags)); + flags & 0x0001u16 == 0u16 + } + /// notify that there are available rings pub fn notify(&mut self) { self.notify diff --git a/services/libs/comp-sys/component/src/lib.rs b/services/libs/comp-sys/component/src/lib.rs index 73306caa..da311c49 100644 --- a/services/libs/comp-sys/component/src/lib.rs +++ b/services/libs/comp-sys/component/src/lib.rs @@ -163,6 +163,7 @@ fn match_and_call( } infos.sort(); + debug!("component infos: {infos:?}"); info!("Components initializing..."); for i in infos { diff --git a/services/libs/jinux-std/Cargo.toml b/services/libs/jinux-std/Cargo.toml index 7c81c9e1..8d94b029 100644 --- a/services/libs/jinux-std/Cargo.toml +++ b/services/libs/jinux-std/Cargo.toml @@ -24,6 +24,7 @@ virtio-input-decoder = "0.1.4" ascii = { version = "1.1", default-features = false, features = ["alloc"] } intrusive-collections = "0.9.5" time = { version = "0.3", default-features = false, features = ["alloc"] } +smoltcp = { version = "0.9.1", default-features = false, features = ["alloc", "log", "medium-ethernet", "medium-ip", "proto-dhcpv4", "proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw", "socket-dhcpv4"] } # parse elf file xmas-elf = "0.8.0" diff --git a/services/libs/jinux-std/src/fs/file_handle.rs b/services/libs/jinux-std/src/fs/file_handle.rs index 2596c39c..a6dd1a30 100644 --- a/services/libs/jinux-std/src/fs/file_handle.rs +++ b/services/libs/jinux-std/src/fs/file_handle.rs @@ -2,6 +2,7 @@ use crate::events::Observer; use crate::fs::utils::{AccessMode, IoEvents, IoctlCmd, Metadata, Poller, SeekFrom, StatusFlags}; +use crate::net::socket::Socket; use crate::prelude::*; use core::any::Any; @@ -67,6 +68,10 @@ pub trait FileLike: Send + Sync + Any { ) -> Result>> { return_errno_with_message!(Errno::EINVAL, "unregister_observer is not supported") } + + fn as_socket(&self) -> Option<&dyn Socket> { + None + } } impl dyn FileLike { diff --git a/services/libs/jinux-std/src/fs/file_table.rs b/services/libs/jinux-std/src/fs/file_table.rs index 8964cfb5..8c63d4e7 100644 --- a/services/libs/jinux-std/src/fs/file_table.rs +++ b/services/libs/jinux-std/src/fs/file_table.rs @@ -1,4 +1,5 @@ use crate::events::{Events, Observer, Subject}; +use crate::net::socket::Socket; use crate::prelude::*; use core::cell::Cell; @@ -101,6 +102,12 @@ impl FileTable { .ok_or(Error::with_message(Errno::EBADF, "fd not exits")) } + pub fn get_socket(&self, sockfd: FileDescripter) -> Result<&dyn Socket> { + self.get_file(sockfd)? + .as_socket() + .ok_or_else(|| Error::with_message(Errno::ENOTSOCK, "the fd is not a socket")) + } + pub fn get_entry(&self, fd: FileDescripter) -> Result<&FileTableEntry> { self.table .get(fd as usize) diff --git a/services/libs/jinux-std/src/fs/utils/poll.rs b/services/libs/jinux-std/src/fs/utils/poll.rs index 9a1a37f2..da32a5b3 100644 --- a/services/libs/jinux-std/src/fs/utils/poll.rs +++ b/services/libs/jinux-std/src/fs/utils/poll.rs @@ -8,6 +8,7 @@ use keyable_arc::KeyableWeak; /// A pollee maintains a set of active events, which can be polled with /// pollers or be monitored with observers. +#[derive(Clone)] pub struct Pollee { inner: Arc, } diff --git a/services/libs/jinux-std/src/lib.rs b/services/libs/jinux-std/src/lib.rs index 7f2c51b4..bacac88e 100644 --- a/services/libs/jinux-std/src/lib.rs +++ b/services/libs/jinux-std/src/lib.rs @@ -16,14 +16,17 @@ #![feature(specialization)] #![feature(fn_traits)] #![feature(linked_list_remove)] +#![feature(trait_alias)] #![feature(register_tool)] #![feature(trait_upcasting)] #![register_tool(component_access_control)] use crate::{ prelude::*, + process::status::ProcessStatus, thread::{kernel_thread::KernelThreadExt, Thread}, }; +use jinux_frame::exit_qemu; use process::Process; extern crate alloc; @@ -36,6 +39,7 @@ pub mod driver; pub mod error; pub mod events; pub mod fs; +pub mod net; pub mod prelude; mod process; pub mod syscall; @@ -46,6 +50,7 @@ pub mod vm; pub fn init(ramdisk: &[u8]) { driver::init(); + net::init(); process::fifo_scheduler::init(); fs::initramfs::init(ramdisk).unwrap(); device::init().unwrap(); @@ -56,6 +61,7 @@ fn init_thread() { "[kernel] Spawn init thread, tid = {}", current_thread!().tid() ); + net::lazy_init(); // driver::pci::virtio::block::block_device_test(); let thread = Thread::spawn_kernel_thread(|| { println!("[kernel] Hello world from kernel!"); @@ -70,9 +76,14 @@ fn init_thread() { ); print_banner(); - run_busybox().expect("run busybox fails"); + let busybox = run_busybox().expect("run busybox fails"); loop { + // If busybox becomes zombie, then exit qemu. + if *busybox.status().lock() == ProcessStatus::Zombie { + println!("Exit jinux."); + exit_qemu(jinux_frame::QemuExitCode::Success); + } // We don't have preemptive scheduler now. // The long running init thread should yield its own execution to allow other tasks to go on. Thread::yield_now(); diff --git a/services/libs/jinux-std/src/prelude.rs b/services/libs/jinux-std/src/prelude.rs index aa3851c8..c3a7871b 100644 --- a/services/libs/jinux-std/src/prelude.rs +++ b/services/libs/jinux-std/src/prelude.rs @@ -17,12 +17,13 @@ pub(crate) use core::any::Any; pub(crate) use core::ffi::CStr; pub(crate) use int_to_c_enum::TryFromInt; pub(crate) use jinux_frame::config::PAGE_SIZE; -pub(crate) use jinux_frame::sync::{Mutex, MutexGuard}; +// pub(crate) use jinux_frame::sync::{Mutex, MutexGuard}; pub(crate) use jinux_frame::vm::Vaddr; pub(crate) use jinux_frame::{print, println}; pub(crate) use log::{debug, error, info, trace, warn}; pub(crate) use pod::Pod; pub(crate) use spin::RwLock; +pub(crate) use spin::{Mutex, MutexGuard}; /// return current process #[macro_export] diff --git a/services/libs/jinux-std/src/syscall/mod.rs b/services/libs/jinux-std/src/syscall/mod.rs index fc195103..ed8f17b5 100644 --- a/services/libs/jinux-std/src/syscall/mod.rs +++ b/services/libs/jinux-std/src/syscall/mod.rs @@ -69,16 +69,30 @@ use crate::syscall::write::sys_write; use crate::syscall::writev::sys_writev; use jinux_frame::cpu::UserContext; +use self::accept::sys_accept; +use self::bind::sys_bind; +use self::connect::sys_connect; +use self::getpeername::sys_getpeername; +use self::getsockname::sys_getsockname; +use self::listen::sys_listen; use self::pread64::sys_pread64; +use self::recvfrom::sys_recvfrom; +use self::sendto::sys_sendto; +use self::setsockopt::sys_setsockopt; +use self::shutdown::sys_shutdown; +use self::socket::sys_socket; +mod accept; mod access; mod arch_prctl; +mod bind; mod brk; mod chdir; mod clock_gettime; mod clock_nanosleep; mod clone; mod close; +mod connect; mod constants; mod dup; mod epoll; @@ -93,15 +107,18 @@ mod getdents64; mod getegid; mod geteuid; mod getgid; +mod getpeername; mod getpgrp; mod getpid; mod getppid; +mod getsockname; mod gettid; mod gettimeofday; mod getuid; mod ioctl; mod kill; mod link; +mod listen; mod lseek; mod madvise; mod mkdir; @@ -117,6 +134,7 @@ mod pread64; mod prlimit64; mod read; mod readlink; +mod recvfrom; mod rename; mod rmdir; mod rt_sigaction; @@ -124,9 +142,13 @@ mod rt_sigprocmask; mod rt_sigreturn; mod sched_yield; mod select; +mod sendto; mod set_robust_list; mod set_tid_address; mod setpgid; +mod setsockopt; +mod shutdown; +mod socket; mod stat; mod symlink; mod tgkill; @@ -199,6 +221,17 @@ define_syscall_nums!( SYS_DUP2 = 33, SYS_PAUSE = 34, SYS_GETPID = 39, + SYS_SOCKET = 41, + SYS_CONNECT = 42, + SYS_ACCEPT = 43, + SYS_SENDTO = 44, + SYS_RECVFROM = 45, + SYS_SHUTDOWN = 48, + SYS_BIND = 49, + SYS_LISTEN = 50, + SYS_GETSOCKNAME = 51, + SYS_GETPEERNAME = 52, + SYS_SETSOCKOPT = 54, SYS_CLONE = 56, SYS_FORK = 57, SYS_EXECVE = 59, @@ -340,6 +373,17 @@ pub fn syscall_dispatch( SYS_DUP2 => syscall_handler!(2, sys_dup2, args), SYS_PAUSE => syscall_handler!(0, sys_pause), SYS_GETPID => syscall_handler!(0, sys_getpid), + SYS_SOCKET => syscall_handler!(3, sys_socket, args), + SYS_CONNECT => syscall_handler!(3, sys_connect, args), + SYS_ACCEPT => syscall_handler!(3, sys_accept, args), + SYS_SENDTO => syscall_handler!(6, sys_sendto, args), + SYS_RECVFROM => syscall_handler!(6, sys_recvfrom, args), + SYS_SHUTDOWN => syscall_handler!(2, sys_shutdown, args), + SYS_BIND => syscall_handler!(3, sys_bind, args), + SYS_LISTEN => syscall_handler!(2, sys_listen, args), + SYS_GETSOCKNAME => syscall_handler!(3, sys_getsockname, args), + SYS_GETPEERNAME => syscall_handler!(3, sys_getpeername, args), + SYS_SETSOCKOPT => syscall_handler!(5, sys_setsockopt, args), SYS_CLONE => syscall_handler!(5, sys_clone, args, context.clone()), SYS_FORK => syscall_handler!(0, sys_fork, context.clone()), SYS_EXECVE => syscall_handler!(3, sys_execve, args, context), diff --git a/services/libs/jinux-std/src/util/mod.rs b/services/libs/jinux-std/src/util/mod.rs index 0bcbd953..cbb1e2e8 100644 --- a/services/libs/jinux-std/src/util/mod.rs +++ b/services/libs/jinux-std/src/util/mod.rs @@ -1,5 +1,10 @@ -use crate::prelude::*; +use crate::{ + net::socket::SocketAddr, + prelude::*, + util::net::{InAddr, SaFamily, SockAddr, SockAddrIn, SockAddrIn6, SockAddrUn}, +}; use jinux_frame::vm::VmIo; +pub mod net; /// copy bytes from user space of current process. The bytes len is the len of dest. pub fn read_bytes_from_user(src: Vaddr, dest: &mut [u8]) -> Result<()> { @@ -35,3 +40,51 @@ pub fn read_cstring_from_user(addr: Vaddr, max_len: usize) -> Result { read_bytes_from_user(addr, &mut buffer)?; Ok(CString::from(CStr::from_bytes_until_nul(&buffer)?)) } + +pub fn read_socket_addr_from_user(addr: Vaddr, addr_len: usize) -> Result { + debug_assert!(addr_len >= core::mem::size_of::()); + let sockaddr: SockAddr = read_val_from_user(addr)?; + let socket_addr = match sockaddr.sa_family()? { + SaFamily::AF_UNSPEC => { + return_errno_with_message!(Errno::EINVAL, "the socket addr family is unspecified") + } + SaFamily::AF_UNIX => { + debug_assert!(addr_len >= core::mem::size_of::()); + let sock_addr_un: SockAddrUn = read_val_from_user(addr)?; + todo!() + } + SaFamily::AF_INET => { + debug_assert!(addr_len >= core::mem::size_of::()); + let sock_addr_in: SockAddrIn = read_val_from_user(addr)?; + SocketAddr::from(sock_addr_in) + } + SaFamily::AF_INET6 => { + debug_assert!(addr_len >= core::mem::size_of::()); + let sock_addr_in6: SockAddrIn6 = read_val_from_user(addr)?; + todo!() + } + _ => { + return_errno_with_message!(Errno::EAFNOSUPPORT, "cannot support address for the family") + } + }; + Ok(socket_addr) +} + +pub fn write_socket_addr_to_user( + socket_addr: &SocketAddr, + dest: Vaddr, + max_len: usize, +) -> Result { + match socket_addr { + SocketAddr::Unix => todo!(), + SocketAddr::IPv4(addr, port) => { + let in_addr = InAddr::from(*addr); + let sock_addr_in = SockAddrIn::new(*port, in_addr); + let write_size = core::mem::size_of::(); + debug_assert!(max_len >= write_size); + write_val_to_user(dest, &sock_addr_in)?; + Ok(write_size) + } + SocketAddr::IPv6 => todo!(), + } +} diff --git a/services/libs/jinux-util/src/frame_ptr.rs b/services/libs/jinux-util/src/frame_ptr.rs index 8437e3c9..c1713522 100644 --- a/services/libs/jinux-util/src/frame_ptr.rs +++ b/services/libs/jinux-util/src/frame_ptr.rs @@ -1,5 +1,6 @@ extern crate alloc; +use core::fmt::Debug; use core::marker::PhantomData; use alloc::sync::Arc; @@ -16,15 +17,30 @@ enum InFramePtrAccessMethod { VmFrame(Arc), } +impl InFramePtrAccessMethod { + fn read_val(&self, offset: usize) -> Result { + match self { + InFramePtrAccessMethod::Mmio(mmio) => mmio.read_val(offset), + InFramePtrAccessMethod::VmFrame(frame) => frame.read_val(offset), + } + } +} + /// An in-frame pointer to a POD value, enabling safe access /// to a POD value given its physical memory address. -#[derive(Debug)] pub struct InFramePtr { access_method: InFramePtrAccessMethod, offset: usize, marker: PhantomData<&'static mut T>, } +impl Debug for InFramePtr { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let inner = self.access_method.read_val::(self.offset).unwrap(); + f.write_fmt(format_args!("{:?}", inner)) + } +} + impl InFramePtr { /// This function only allow the physical address in the MMIO region. /// @@ -49,6 +65,12 @@ impl InFramePtr { }) } + pub fn read(&self) -> T { + self.access_method + .read_val::(self.offset) + .expect("read inner from frame failed") + } + pub fn read_at(&self, offset: *const F) -> F { match &self.access_method { InFramePtrAccessMethod::Mmio(mmio) => mmio