Replace InFramePtr with SafePtr

This commit is contained in:
Yuke Peng 2023-08-08 21:12:28 +08:00 committed by Tate, Hongliang Tian
parent ab4b1b47dc
commit c38e4f0800
24 changed files with 427 additions and 308 deletions

5
Cargo.lock generated
View File

@ -702,6 +702,7 @@ dependencies = [
"component",
"jinux-frame",
"jinux-pci",
"jinux-rights",
"jinux-util",
"jinux-virtio",
"lazy_static",
@ -717,6 +718,7 @@ dependencies = [
"component",
"jinux-frame",
"jinux-pci",
"jinux-rights",
"jinux-util",
"jinux-virtio",
"log",
@ -732,6 +734,7 @@ dependencies = [
"bitflags 1.3.2",
"component",
"jinux-frame",
"jinux-rights",
"jinux-util",
"lazy_static",
"log",
@ -830,10 +833,12 @@ dependencies = [
"int-to-c-enum",
"jinux-frame",
"jinux-pci",
"jinux-rights",
"jinux-util",
"log",
"pod",
"spin 0.9.8",
"typeflags-util",
]
[[package]]

View File

@ -3,7 +3,7 @@ use pod::Pod;
use spin::Once;
use crate::{
vm::{Paddr, Vaddr, VmIo},
vm::{HasPaddr, Paddr, Vaddr, VmIo},
Error,
};
@ -60,6 +60,12 @@ impl VmIo for IoMem {
}
}
impl HasPaddr for IoMem {
fn paddr(&self) -> Paddr {
crate::vm::vaddr_to_paddr(self.virtual_address).unwrap()
}
}
impl IoMem {
pub fn new(range: Range<Paddr>) -> Option<IoMem> {
if CHECKER.get().unwrap().check(&range) {
@ -72,10 +78,6 @@ impl IoMem {
}
}
pub fn paddr(&self) -> Paddr {
crate::vm::vaddr_to_paddr(self.virtual_address).unwrap()
}
fn check_range(&self, offset: usize, len: usize) -> crate::Result<()> {
let sum = offset.checked_add(len).ok_or(Error::InvalidArgs)?;
if sum > self.limit {

View File

@ -6,7 +6,7 @@ use core::{
use crate::{arch::iommu, config::PAGE_SIZE, prelude::*, Error};
use super::frame_allocator;
use super::{frame_allocator, HasPaddr};
use super::{Paddr, VmIo};
use pod::Pod;
@ -304,6 +304,12 @@ impl Clone for VmFrame {
}
}
impl HasPaddr for VmFrame {
fn paddr(&self) -> Paddr {
self.start_paddr()
}
}
impl VmFrame {
/// Creates a new VmFrame.
///

View File

@ -32,9 +32,9 @@ use spin::Once;
use crate::boot::memory_region::{MemoryRegion, MemoryRegionType};
/// Convert physical address to virtual address using offset, only available inside jinux-frame
pub(crate) fn paddr_to_vaddr(pa: usize) -> usize {
pa + PHYS_OFFSET
/// Get physical address trait
pub trait HasPaddr {
fn paddr(&self) -> Paddr;
}
pub fn vaddr_to_paddr(va: Vaddr) -> Option<Paddr> {
@ -50,6 +50,11 @@ pub const fn is_page_aligned(p: usize) -> bool {
(p & (PAGE_SIZE - 1)) == 0
}
/// Convert physical address to virtual address using offset, only available inside jinux-frame
pub(crate) fn paddr_to_vaddr(pa: usize) -> usize {
pa + PHYS_OFFSET
}
/// Only available inside jinux-frame
pub(crate) static MEMORY_REGIONS: Once<Vec<MemoryRegion>> = Once::new();

View File

@ -1,8 +1,8 @@
//! Block device based on Virtio
use jinux_frame::trap::TrapFrame;
use jinux_frame::{io_mem::IoMem, trap::TrapFrame};
use jinux_pci::msix::MSIX;
use jinux_util::frame_ptr::InFramePtr;
use jinux_util::safe_ptr::SafePtr;
use jinux_virtio::{device::block::device::BLKDevice, PCIVirtioDevice, VirtioPciCommonCfg};
use log::debug;
use spin::Mutex;
@ -11,8 +11,8 @@ use crate::{BlockDevice, BLK_COMPONENT};
pub struct VirtioBlockDevice {
blk_device: Mutex<BLKDevice>,
pub common_cfg: InFramePtr<VirtioPciCommonCfg>,
msix: MSIX,
pub common_cfg: SafePtr<VirtioPciCommonCfg, IoMem>,
_msix: MSIX,
}
impl BlockDevice for VirtioBlockDevice {
@ -48,7 +48,7 @@ impl VirtioBlockDevice {
Self {
blk_device,
common_cfg: virtio_device.common_cfg,
msix: virtio_device.msix,
_msix: virtio_device.msix,
}
}
}

View File

@ -12,6 +12,7 @@ jinux-frame = { path = "../../../framework/jinux-frame" }
jinux-pci = { path = "../pci" }
jinux-virtio = { path = "../virtio" }
jinux-util = { path = "../../libs/jinux-util" }
jinux-rights = { path = "../../libs/jinux-rights" }
component = { path = "../../libs/comp-sys/component" }
virtio-input-decoder = "0.1.4"
log = "0.4"

View File

@ -83,6 +83,7 @@ impl INPUTComponent {
}
}
#[allow(dead_code)]
#[derive(Debug)]
enum InputDeviceHandleError {
DeviceNotExists,

View File

@ -1,10 +1,12 @@
//! Input device based on Virtio
use alloc::{string::String, sync::Arc, vec::Vec};
use jinux_frame::io_mem::IoMem;
use jinux_frame::offset_of;
use jinux_frame::trap::TrapFrame;
use jinux_pci::msix::MSIX;
use jinux_util::frame_ptr::InFramePtr;
use jinux_util::field_ptr;
use jinux_util::safe_ptr::SafePtr;
use jinux_virtio::device::input::device::InputProp;
use jinux_virtio::VirtioPciCommonCfg;
use jinux_virtio::{
@ -18,8 +20,8 @@ use virtio_input_decoder::{DecodeType, Decoder};
use crate::INPUTDevice;
pub struct VirtioInputDevice {
input_device: InputDevice,
common_cfg: InFramePtr<VirtioPciCommonCfg>,
msix: Mutex<MSIX>,
_common_cfg: SafePtr<VirtioPciCommonCfg, IoMem>,
_msix: Mutex<MSIX>,
name: String,
callbacks: Mutex<Vec<Arc<dyn Fn(DecodeType) + Send + Sync + 'static>>>,
}
@ -47,7 +49,7 @@ impl VirtioInputDevice {
fn handle_input(frame: &TrapFrame) {
debug!("in handle input");
let input_component = crate::INPUT_COMPONENT.get().unwrap();
input_component.call(frame.trap_num as u8);
input_component.call(frame.trap_num as u8).unwrap();
}
fn config_space_change(_: &TrapFrame) {
debug!("input device config space change");
@ -56,8 +58,9 @@ impl VirtioInputDevice {
let common_cfg = virtio_device.common_cfg;
let mut msix = virtio_device.msix;
let config_msix_vector =
common_cfg.read_at(offset_of!(VirtioPciCommonCfg, config_msix_vector)) as usize;
let config_msix_vector = field_ptr!(&common_cfg, VirtioPciCommonCfg, config_msix_vector)
.read()
.unwrap() as usize;
let mut event_irq_number = 0;
for i in 0..msix.table_size as usize {
@ -76,8 +79,8 @@ impl VirtioInputDevice {
(
Self {
input_device,
common_cfg,
msix: Mutex::new(msix),
_common_cfg: common_cfg,
_msix: Mutex::new(msix),
name,
callbacks: Mutex::new(Vec::new()),
},

View File

@ -11,6 +11,7 @@ jinux-frame = { path = "../../../framework/jinux-frame" }
jinux-virtio = { path = "../virtio" }
jinux-util = { path = "../../libs/jinux-util" }
jinux-pci = { path = "../pci" }
jinux-rights = { path = "../../libs/jinux-rights" }
spin = "0.9.4"
ringbuf = { version = "0.3.2", default-features = false, features = ["alloc"] }
log = "0.4"

View File

@ -1,8 +1,10 @@
use jinux_frame::io_mem::IoMem;
use jinux_frame::offset_of;
use jinux_frame::sync::SpinLock;
use jinux_frame::trap::TrapFrame;
use jinux_pci::msix::MSIX;
use jinux_util::frame_ptr::InFramePtr;
use jinux_util::field_ptr;
use jinux_util::safe_ptr::SafePtr;
use jinux_virtio::device::network::device::{self, EthernetAddr};
use jinux_virtio::PCIVirtioDevice;
use jinux_virtio::VirtioPciCommonCfg;
@ -14,7 +16,7 @@ pub struct VirtioNet {
/// Network Device
device: device::NetworkDevice,
/// Own common cfg to avoid other devices access this frame
_common_cfg: InFramePtr<VirtioPciCommonCfg>,
_common_cfg: SafePtr<VirtioPciCommonCfg, IoMem>,
_msix: SpinLock<MSIX>,
irq_number: u8,
}
@ -45,8 +47,9 @@ impl VirtioNet {
let common_cfg = virtio_device.common_cfg;
let mut msix = virtio_device.msix;
let config_msix_vector =
common_cfg.read_at(offset_of!(VirtioPciCommonCfg, config_msix_vector)) as usize;
let config_msix_vector = field_ptr!(&common_cfg, VirtioPciCommonCfg, config_msix_vector)
.read()
.unwrap() as usize;
let mut network_irq_num = 0;
for i in 0..msix.table_size as usize {

View File

@ -10,6 +10,7 @@ bitflags = "1.3"
spin = "0.9.4"
jinux-frame = { path = "../../../framework/jinux-frame" }
jinux-util = { path = "../../libs/jinux-util" }
jinux-rights = { path = "../../libs/jinux-rights" }
pod = { git = "https://github.com/jinzhao-dev/pod", rev = "71e59ec" }
component = { path = "../../libs/comp-sys/component" }
log = "0.4"

View File

@ -1,3 +1,5 @@
use core::mem::size_of;
use alloc::vec::Vec;
use log::debug;
use pod::Pod;
@ -6,8 +8,8 @@ use crate::util::{CSpaceAccessMethod, BAR};
use super::capability::msix::CapabilityMSIXData;
use jinux_frame::{bus::pci::PciDeviceLocation, offset_of, trap::IrqAllocateHandle};
use jinux_util::frame_ptr::InFramePtr;
use jinux_frame::{bus::pci::PciDeviceLocation, io_mem::IoMem, offset_of, trap::IrqAllocateHandle};
use jinux_util::{field_ptr, safe_ptr::SafePtr};
#[derive(Debug, Default)]
pub struct MSIX {
@ -19,7 +21,7 @@ pub struct MSIX {
#[derive(Debug)]
pub struct MSIXEntry {
pub table_entry: InFramePtr<MSIXTableEntry>,
pub table_entry: SafePtr<MSIXTableEntry, IoMem>,
pub irq_handle: IrqAllocateHandle,
}
@ -83,22 +85,36 @@ impl MSIX {
debug!("command after:{:x}", am.read16(loc, crate::PCI_COMMAND));
let message_control = am.read16(loc, cap_ptr + 2) | 0x8000;
am.write16(loc, cap_ptr + 2, message_control);
let mut table_iter: InFramePtr<MSIXTableEntry> =
InFramePtr::new(table_base_address as usize)
.expect("can not get in frame ptr for msix");
let mut table_iter: SafePtr<MSIXTableEntry, IoMem> = SafePtr::new(
IoMem::new(
table_base_address as usize
..table_base_address as usize
+ (size_of::<MSIXTableEntry>() * table_size as usize),
)
.unwrap(),
0,
);
for _ in 0..table_size {
// local APIC address: 0xFEE0_0000
table_iter.write_at(offset_of!(MSIXTableEntry, msg_addr), 0xFEE0_0000 as u32);
table_iter.write_at(offset_of!(MSIXTableEntry, msg_upper_addr), 0 as u32);
field_ptr!(&table_iter, MSIXTableEntry, msg_addr)
.write(&0xFEE0_0000u32)
.unwrap();
field_ptr!(&table_iter, MSIXTableEntry, msg_upper_addr)
.write(&0u32)
.unwrap();
// allocate irq number
let handle = jinux_frame::trap::allocate_irq().expect("not enough irq");
table_iter.write_at(offset_of!(MSIXTableEntry, msg_data), handle.num() as u32);
table_iter.write_at(offset_of!(MSIXTableEntry, vector_control), 0 as u32);
field_ptr!(&table_iter, MSIXTableEntry, msg_data)
.write(&(handle.num() as u32))
.unwrap();
field_ptr!(&table_iter, MSIXTableEntry, vector_control)
.write(&0u32)
.unwrap();
cap.table.push(MSIXEntry {
table_entry: table_iter.clone(),
irq_handle: handle,
});
table_iter = table_iter.add(1);
table_iter.add(1);
}
cap
}

View File

@ -13,6 +13,8 @@ align_ext = { path = "../../../framework/libs/align_ext" }
jinux-frame = { path = "../../../framework/jinux-frame" }
jinux-pci = { path = "../pci" }
jinux-util = { path = "../../libs/jinux-util" }
jinux-rights = { path = "../../libs/jinux-rights" }
typeflags-util = { path = "../../libs/typeflags-util" }
pod = { git = "https://github.com/jinzhao-dev/pod", rev = "71e59ec" }
component = { path = "../../libs/comp-sys/component" }
log = "0.4"

View File

@ -1,9 +1,9 @@
use core::hint::spin_loop;
use alloc::vec::Vec;
use jinux_frame::offset_of;
use jinux_frame::{io_mem::IoMem, offset_of};
use jinux_pci::{capability::vendor::virtio::CapabilityVirtioData, util::BAR};
use jinux_util::frame_ptr::InFramePtr;
use jinux_util::{field_ptr, safe_ptr::SafePtr};
use pod::Pod;
use crate::{
@ -17,7 +17,7 @@ use super::{BLKFeatures, VirtioBLKConfig};
#[derive(Debug)]
pub struct BLKDevice {
config: InFramePtr<VirtioBLKConfig>,
config: SafePtr<VirtioBLKConfig, IoMem>,
queue: VirtQueue,
}
@ -27,13 +27,15 @@ impl BLKDevice {
pub(crate) fn new(
cap: &CapabilityVirtioData,
bars: [Option<BAR>; 6],
common_cfg: &InFramePtr<VirtioPciCommonCfg>,
common_cfg: &SafePtr<VirtioPciCommonCfg, IoMem>,
notify_base_address: usize,
notify_off_multiplier: u32,
mut msix_vector_left: Vec<u16>,
) -> Result<Self, VirtioDeviceError> {
let config = VirtioBLKConfig::new(cap, bars);
let num_queues = common_cfg.read_at(offset_of!(VirtioPciCommonCfg, num_queues)) as u16;
let num_queues = field_ptr!(common_cfg, VirtioPciCommonCfg, num_queues)
.read()
.unwrap();
if num_queues != 1 {
return Err(VirtioDeviceError::QueuesAmountDoNotMatch(num_queues, 1));
}

View File

@ -1,10 +1,13 @@
pub mod device;
use core::mem::size_of;
use bitflags::bitflags;
use int_to_c_enum::TryFromInt;
use jinux_frame::io_mem::IoMem;
use jinux_pci::capability::vendor::virtio::CapabilityVirtioData;
use jinux_pci::util::BAR;
use jinux_util::frame_ptr::InFramePtr;
use jinux_util::safe_ptr::SafePtr;
use pod::Pod;
pub const BLK_SIZE: usize = 512;
@ -110,15 +113,19 @@ pub struct VirtioBLKTopology {
}
impl VirtioBLKConfig {
pub(crate) fn new(cap: &CapabilityVirtioData, bars: [Option<BAR>; 6]) -> InFramePtr<Self> {
pub(crate) fn new(cap: &CapabilityVirtioData, bars: [Option<BAR>; 6]) -> SafePtr<Self, IoMem> {
let bar = cap.bar;
let offset = cap.offset;
match bars[bar as usize].expect("Virtio pci block cfg:bar is none") {
BAR::Memory(address, _, _, _) => InFramePtr::new(address as usize + offset as usize)
.expect("can not get in frame ptr for virtio block config"),
BAR::IO(_, _) => {
panic!("Virtio pci block cfg:bar is IO type")
}
BAR::Memory(address, _, _, _) => SafePtr::new(
IoMem::new(
(address as usize + offset as usize)
..(address as usize + offset as usize + size_of::<Self>()),
)
.unwrap(),
0,
),
BAR::IO(_, _) => panic!("Virtio pci block cfg:bar is IO type"),
}
}
}

View File

@ -1,9 +1,9 @@
use crate::{device::VirtioDeviceError, queue::VirtQueue, VirtioPciCommonCfg};
use alloc::{boxed::Box, vec::Vec};
use bitflags::bitflags;
use jinux_frame::offset_of;
use jinux_frame::{io_mem::IoMem, offset_of};
use jinux_pci::{capability::vendor::virtio::CapabilityVirtioData, util::BAR};
use jinux_util::frame_ptr::InFramePtr;
use jinux_util::{field_ptr, safe_ptr::SafePtr};
use pod::Pod;
use spin::Mutex;
@ -43,7 +43,7 @@ pub const FF_STATUS: u8 = 0x17;
/// making pass-through implementations on top of evdev easy.
#[derive(Debug)]
pub struct InputDevice {
config: InFramePtr<VirtioInputConfig>,
config: SafePtr<VirtioInputConfig, IoMem>,
event_queue: Mutex<VirtQueue>,
status_queue: VirtQueue,
pub event_buf: Mutex<Box<[InputEvent; QUEUE_SIZE]>>,
@ -55,7 +55,7 @@ impl InputDevice {
pub fn new(
cap: &CapabilityVirtioData,
bars: [Option<BAR>; 6],
common_cfg: &InFramePtr<VirtioPciCommonCfg>,
common_cfg: &SafePtr<VirtioPciCommonCfg, IoMem>,
notify_base_address: usize,
notify_off_multiplier: u32,
mut msix_vector_left: Vec<u16>,
@ -135,12 +135,18 @@ impl InputDevice {
/// Query a specific piece of information by `select` and `subsel`, and write
/// result to `out`, return the result size.
pub fn query_config_select(&self, select: InputConfigSelect, subsel: u8, out: &mut [u8]) -> u8 {
self.config
.write_at(offset_of!(VirtioInputConfig, select), select as u8);
self.config
.write_at(offset_of!(VirtioInputConfig, subsel), subsel as u8);
let size = self.config.read_at(offset_of!(VirtioInputConfig, size));
let data: [u8; 128] = self.config.read_at(offset_of!(VirtioInputConfig, data));
field_ptr!(&self.config, VirtioInputConfig, select)
.write(&(select as u8))
.unwrap();
field_ptr!(&self.config, VirtioInputConfig, subsel)
.write(&(subsel as u8))
.unwrap();
let size = field_ptr!(&self.config, VirtioInputConfig, size)
.read()
.unwrap();
let data: [u8; 128] = field_ptr!(&self.config, VirtioInputConfig, data)
.read()
.unwrap();
out[..size as usize].copy_from_slice(&data[..size as usize]);
size
}

View File

@ -25,8 +25,11 @@
//
pub mod device;
use core::mem::size_of;
use jinux_frame::io_mem::IoMem;
use jinux_pci::{capability::vendor::virtio::CapabilityVirtioData, util::BAR};
use jinux_util::frame_ptr::InFramePtr;
use jinux_util::safe_ptr::SafePtr;
use pod::Pod;
/// Select value used for [`VirtIOInput::query_config_select()`].
@ -69,15 +72,19 @@ pub struct VirtioInputConfig {
}
impl VirtioInputConfig {
pub(crate) fn new(cap: &CapabilityVirtioData, bars: [Option<BAR>; 6]) -> InFramePtr<Self> {
pub(crate) fn new(cap: &CapabilityVirtioData, bars: [Option<BAR>; 6]) -> SafePtr<Self, IoMem> {
let bar = cap.bar;
let offset = cap.offset;
match bars[bar as usize].expect("Virtio pci block cfg:bar is none") {
BAR::Memory(address, _, _, _) => InFramePtr::new(address as usize + offset as usize)
.expect("can not get in frame ptr for virtio block config"),
BAR::IO(_, _) => {
panic!("Virtio pci block cfg:bar is IO type")
}
BAR::Memory(address, _, _, _) => SafePtr::new(
IoMem::new(
(address as usize + offset as usize)
..(address as usize + offset as usize + size_of::<Self>()),
)
.unwrap(),
0,
),
BAR::IO(_, _) => panic!("Virtio pci block cfg:bar is IO type"),
}
}
}

View File

@ -3,11 +3,12 @@ use crate::{
VirtioPciCommonCfg,
};
use alloc::vec::Vec;
use jinux_frame::io_mem::IoMem;
use jinux_pci::{
capability::{vendor::virtio::CapabilityVirtioData, Capability},
util::BAR,
};
use jinux_util::frame_ptr::InFramePtr;
use jinux_util::safe_ptr::SafePtr;
use self::{input::device::InputDevice, network::device::NetworkDevice};
@ -56,7 +57,7 @@ pub struct VirtioInfo {
pub device_type: VirtioDeviceType,
pub notify_base_address: u64,
pub notify_off_multiplier: u32,
pub common_cfg_frame_ptr: InFramePtr<VirtioPciCommonCfg>,
pub common_cfg_frame_ptr: SafePtr<VirtioPciCommonCfg, IoMem>,
pub device_cap_cfg: CapabilityVirtioData,
}

View File

@ -1,6 +1,9 @@
use core::mem::size_of;
use bitflags::bitflags;
use jinux_frame::io_mem::IoMem;
use jinux_pci::{capability::vendor::virtio::CapabilityVirtioData, util::BAR};
use jinux_util::frame_ptr::InFramePtr;
use jinux_util::safe_ptr::SafePtr;
use pod::Pod;
use super::device::EthernetAddr;
@ -70,12 +73,18 @@ pub struct VirtioNetConfig {
}
impl VirtioNetConfig {
pub(crate) fn new(cap: &CapabilityVirtioData, bars: [Option<BAR>; 6]) -> InFramePtr<Self> {
pub(crate) fn new(cap: &CapabilityVirtioData, bars: [Option<BAR>; 6]) -> SafePtr<Self, IoMem> {
let bar = cap.bar;
let offset = cap.offset;
match bars[bar as usize].expect("Virtio pci net cfg:bar is none") {
BAR::Memory(address, _, _, _) => InFramePtr::new(address as usize + offset as usize)
.expect("can not get in frame ptr for virtio net config"),
BAR::Memory(address, _, _, _) => SafePtr::new(
IoMem::new(
(address as usize + offset as usize)
..(address as usize + offset as usize + size_of::<Self>()),
)
.unwrap(),
0,
),
BAR::IO(_, _) => panic!("Virtio pci net cfg:bar is IO type"),
}
}

View File

@ -1,9 +1,9 @@
use core::hint::spin_loop;
use alloc::vec::Vec;
use jinux_frame::offset_of;
use jinux_frame::{io_mem::IoMem, offset_of};
use jinux_pci::{capability::vendor::virtio::CapabilityVirtioData, util::BAR};
use jinux_util::{frame_ptr::InFramePtr, slot_vec::SlotVec};
use jinux_util::{field_ptr, safe_ptr::SafePtr, slot_vec::SlotVec};
use log::debug;
use pod::Pod;
@ -60,7 +60,7 @@ impl NetworkDevice {
pub fn new(
cap: &CapabilityVirtioData,
bars: [Option<BAR>; 6],
common_cfg: &InFramePtr<VirtioPciCommonCfg>,
common_cfg: &SafePtr<VirtioPciCommonCfg, IoMem>,
notify_base_address: usize,
notify_off_multiplier: u32,
mut msix_vector_left: Vec<u16>,
@ -68,26 +68,30 @@ impl NetworkDevice {
let virtio_net_config = VirtioNetConfig::new(cap, bars);
let features = {
// select low
common_cfg.write_at(
offset_of!(VirtioPciCommonCfg, device_feature_select),
0 as u32,
);
let device_feature_low =
common_cfg.read_at(offset_of!(VirtioPciCommonCfg, device_feature)) as u64;
field_ptr!(common_cfg, VirtioPciCommonCfg, device_feature_select)
.write(&0u32)
.unwrap();
let device_feature_low = field_ptr!(common_cfg, VirtioPciCommonCfg, device_feature)
.read()
.unwrap() as u64;
// select high
common_cfg.write_at(
offset_of!(VirtioPciCommonCfg, device_feature_select),
1 as u32,
);
let device_feature_high =
common_cfg.read_at(offset_of!(VirtioPciCommonCfg, device_feature)) as u64;
field_ptr!(common_cfg, VirtioPciCommonCfg, device_feature_select)
.write(&1u32)
.unwrap();
let device_feature_high = field_ptr!(common_cfg, VirtioPciCommonCfg, device_feature)
.read()
.unwrap() as u64;
let device_feature = device_feature_high << 32 | device_feature_low;
NetworkFeatures::from_bits_truncate(Self::negotiate_features(device_feature))
};
debug!("virtio_net_config = {:?}", virtio_net_config);
debug!("features = {:?}", features);
let mac_addr = virtio_net_config.read_at(offset_of!(VirtioNetConfig, mac));
let status = virtio_net_config.read_at(offset_of!(VirtioNetConfig, status));
let mac_addr = field_ptr!(&virtio_net_config, VirtioNetConfig, mac)
.read()
.unwrap();
let status = field_ptr!(&virtio_net_config, VirtioNetConfig, status)
.read()
.unwrap();
debug!("mac addr = {:x?}, status = {:?}", mac_addr, status);
let (recv_msix_vec, send_msix_vec) = {
if msix_vector_left.len() >= 2 {
@ -132,7 +136,7 @@ impl NetworkDevice {
}
Ok(Self {
config: virtio_net_config.read(),
config: virtio_net_config.read().unwrap(),
mac_addr,
send_queue,
recv_queue,

View File

@ -6,15 +6,15 @@
extern crate alloc;
use component::init_component;
use core::str::FromStr;
use core::{mem::size_of, str::FromStr};
use alloc::{collections::VecDeque, string::String, sync::Arc, vec::Vec};
use bitflags::bitflags;
use component::ComponentInitError;
use device::VirtioDevice;
use jinux_frame::{offset_of, trap::TrapFrame};
use jinux_frame::{io_mem::IoMem, offset_of, trap::TrapFrame};
use jinux_pci::{util::BAR, PciDevice};
use jinux_util::frame_ptr::InFramePtr;
use jinux_util::{field_ptr, safe_ptr::SafePtr};
use log::{debug, info};
use pod::Pod;
use spin::{Mutex, Once};
@ -76,7 +76,7 @@ impl VIRTIOComponent {
let mut devices = Vec::new();
let mut lock = self.virtio_devices.lock();
let len = lock.len();
for i in 0..len {
for _ in 0..len {
let device = lock.pop_front().unwrap();
let d_type = VirtioDeviceType::from_virtio_device(&device.device);
if d_type == device_type {
@ -165,14 +165,20 @@ pub struct VirtioPciCommonCfg {
}
impl VirtioPciCommonCfg {
pub(crate) fn new(cap: &CapabilityVirtioData, bars: [Option<BAR>; 6]) -> InFramePtr<Self> {
pub(crate) fn new(cap: &CapabilityVirtioData, bars: [Option<BAR>; 6]) -> SafePtr<Self, IoMem> {
let bar = cap.bar;
let offset = cap.offset;
match bars[bar as usize].expect("Virtio pci common cfg:bar is none") {
BAR::Memory(address, _, _, _) => {
debug!("common_cfg addr:{:x}", (address as usize + offset as usize));
InFramePtr::new(address as usize + offset as usize)
.expect("cannot get InFramePtr in VitioPciCommonCfg")
SafePtr::new(
IoMem::new(
(address as usize + offset as usize)
..(address as usize + offset as usize + size_of::<Self>()),
)
.unwrap(),
0,
)
}
BAR::IO(first, second) => {
panic!(
@ -219,7 +225,7 @@ impl VirtioDeviceType {
pub struct PCIVirtioDevice {
/// common config of one device
pub common_cfg: InFramePtr<VirtioPciCommonCfg>,
pub common_cfg: SafePtr<VirtioPciCommonCfg, IoMem>,
pub device: VirtioDevice,
pub msix: MSIX,
}
@ -266,73 +272,70 @@ impl PCIVirtioDevice {
let virtio_info = VirtioInfo::new(device_type, bars, virtio_cap_list).unwrap();
let mut msix_vector_list: Vec<u16> = (0..msix.table_size).collect();
let config_msix_vector = msix_vector_list.pop().unwrap();
let common_cfg_frame_ptr = &virtio_info.common_cfg_frame_ptr;
let common_cfg = &virtio_info.common_cfg_frame_ptr;
// Reset device
common_cfg_frame_ptr.write_at(offset_of!(VirtioPciCommonCfg, device_status), 0 as u8);
field_ptr!(common_cfg, VirtioPciCommonCfg, device_status)
.write(&0u8)
.unwrap();
let num_queues: u16 =
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!(VirtioPciCommonCfg, config_msix_vector),
config_msix_vector,
);
common_cfg_frame_ptr.write_at(
offset_of!(VirtioPciCommonCfg, device_status),
(DeviceStatus::ACKNOWLEDGE | DeviceStatus::DRIVER).bits(),
);
field_ptr!(common_cfg, VirtioPciCommonCfg, config_msix_vector)
.write(&config_msix_vector)
.unwrap();
field_ptr!(common_cfg, VirtioPciCommonCfg, device_status)
.write(&(DeviceStatus::ACKNOWLEDGE | DeviceStatus::DRIVER).bits())
.unwrap();
// negotiate features
// get the value of device features
common_cfg_frame_ptr.write_at(
offset_of!(VirtioPciCommonCfg, device_feature_select),
0 as u32,
);
let mut low: u32 =
common_cfg_frame_ptr.read_at(offset_of!(VirtioPciCommonCfg, device_feature));
common_cfg_frame_ptr.write_at(
offset_of!(VirtioPciCommonCfg, device_feature_select),
1 as u32,
);
let mut high: u32 =
common_cfg_frame_ptr.read_at(offset_of!(VirtioPciCommonCfg, device_feature));
field_ptr!(common_cfg, VirtioPciCommonCfg, device_feature_select)
.write(&0u32)
.unwrap();
let mut low: u32 = field_ptr!(common_cfg, VirtioPciCommonCfg, device_feature)
.read()
.unwrap();
field_ptr!(common_cfg, VirtioPciCommonCfg, device_feature_select)
.write(&1u32)
.unwrap();
let mut high: u32 = field_ptr!(common_cfg, VirtioPciCommonCfg, device_feature)
.read()
.unwrap();
let mut feature = (high as u64) << 32;
feature |= low as u64;
// let the device to negotiate Features
let driver_features = VirtioDevice::negotiate_features(feature, device_type);
debug!("support_features:{:x}", driver_features);
// write features back
low = driver_features as u32;
high = (driver_features >> 32) as u32;
common_cfg_frame_ptr.write_at(
offset_of!(VirtioPciCommonCfg, driver_feature_select),
0 as u32,
);
common_cfg_frame_ptr.write_at(offset_of!(VirtioPciCommonCfg, driver_feature), low);
common_cfg_frame_ptr.write_at(
offset_of!(VirtioPciCommonCfg, driver_feature_select),
1 as u32,
);
common_cfg_frame_ptr.write_at(offset_of!(VirtioPciCommonCfg, driver_feature), high);
field_ptr!(common_cfg, VirtioPciCommonCfg, driver_feature_select)
.write(&0u32)
.unwrap();
field_ptr!(common_cfg, VirtioPciCommonCfg, driver_feature)
.write(&low)
.unwrap();
field_ptr!(common_cfg, VirtioPciCommonCfg, driver_feature_select)
.write(&1u32)
.unwrap();
field_ptr!(common_cfg, VirtioPciCommonCfg, driver_feature)
.write(&high)
.unwrap();
// change to features ok status
common_cfg_frame_ptr.write_at(
offset_of!(VirtioPciCommonCfg, device_status),
(DeviceStatus::ACKNOWLEDGE | DeviceStatus::DRIVER | DeviceStatus::FEATURES_OK).bits(),
);
field_ptr!(common_cfg, VirtioPciCommonCfg, device_status)
.write(
&(DeviceStatus::ACKNOWLEDGE | DeviceStatus::DRIVER | DeviceStatus::FEATURES_OK)
.bits(),
)
.unwrap();
let device = VirtioDevice::new(&virtio_info, bars, msix_vector_list).unwrap();
// change to driver ok status
common_cfg_frame_ptr.write_at(
offset_of!(VirtioPciCommonCfg, device_status),
(DeviceStatus::ACKNOWLEDGE
| DeviceStatus::DRIVER
| DeviceStatus::FEATURES_OK
| DeviceStatus::DRIVER_OK)
.bits(),
);
field_ptr!(common_cfg, VirtioPciCommonCfg, device_status)
.write(
&(DeviceStatus::ACKNOWLEDGE
| DeviceStatus::DRIVER
| DeviceStatus::FEATURES_OK
| DeviceStatus::DRIVER_OK)
.bits(),
)
.unwrap();
Self {
common_cfg: virtio_info.common_cfg_frame_ptr,
device,
@ -350,8 +353,9 @@ impl PCIVirtioDevice {
T: Fn(&TrapFrame) + Send + Sync + 'static,
{
let config_msix_vector =
self.common_cfg
.read_at(offset_of!(VirtioPciCommonCfg, config_msix_vector)) as usize;
field_ptr!(&self.common_cfg, VirtioPciCommonCfg, config_msix_vector)
.read()
.unwrap() 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() {

View File

@ -3,12 +3,17 @@
use super::VirtioPciCommonCfg;
use alloc::vec::Vec;
use bitflags::bitflags;
use core::sync::atomic::{fence, Ordering};
use jinux_frame::{
offset_of,
vm::{VmAllocOptions, VmFrameVec},
use core::{
mem::size_of,
sync::atomic::{fence, Ordering},
};
use jinux_util::frame_ptr::InFramePtr;
use jinux_frame::{
io_mem::IoMem,
offset_of,
vm::{VmAllocOptions, VmFrame, VmFrameVec},
};
use jinux_rights::{Dup, TRightSet, TRights, Write};
use jinux_util::{field_ptr, safe_ptr::SafePtr};
use log::debug;
use pod::Pod;
@ -27,13 +32,13 @@ pub enum QueueError {
#[derive(Debug)]
pub struct VirtQueue {
/// Descriptor table
descs: Vec<InFramePtr<Descriptor>>,
descs: Vec<SafePtr<Descriptor, VmFrame>>,
/// Available ring
avail: InFramePtr<AvailRing>,
avail: SafePtr<AvailRing, VmFrame>,
/// Used ring
used: InFramePtr<UsedRing>,
used: SafePtr<UsedRing, VmFrame>,
/// point to notify address
notify: InFramePtr<u32>,
notify: SafePtr<u32, IoMem>,
/// The index of queue
queue_idx: u32,
@ -55,89 +60,97 @@ pub struct VirtQueue {
impl VirtQueue {
/// Create a new VirtQueue.
pub(crate) fn new(
cfg: &InFramePtr<VirtioPciCommonCfg>,
cfg: &SafePtr<VirtioPciCommonCfg, IoMem>,
idx: usize,
size: u16,
notify_base_address: usize,
notify_off_multiplier: u32,
msix_vector: u16,
) -> Result<Self, QueueError> {
cfg.write_at(offset_of!(VirtioPciCommonCfg, queue_select), idx as u16);
field_ptr!(cfg, VirtioPciCommonCfg, queue_select)
.write(&(idx as u16))
.unwrap();
assert_eq!(
cfg.read_at(offset_of!(VirtioPciCommonCfg, queue_select)),
field_ptr!(cfg, VirtioPciCommonCfg, queue_select)
.read()
.unwrap(),
idx as u16
);
if !size.is_power_of_two() {
return Err(QueueError::InvalidArgs);
}
cfg.write_at(offset_of!(VirtioPciCommonCfg, queue_size), size);
cfg.write_at(
offset_of!(VirtioPciCommonCfg, queue_msix_vector),
msix_vector,
);
field_ptr!(cfg, VirtioPciCommonCfg, queue_size)
.write(&size)
.unwrap();
field_ptr!(cfg, VirtioPciCommonCfg, queue_msix_vector)
.write(&msix_vector)
.unwrap();
assert_eq!(
cfg.read_at(offset_of!(VirtioPciCommonCfg, queue_msix_vector)),
field_ptr!(cfg, VirtioPciCommonCfg, queue_msix_vector)
.read()
.unwrap(),
msix_vector
);
//allocate page
let desc_frame_ptr: InFramePtr<Descriptor> = InFramePtr::new_with_vm_frame(
let desc_frame_ptr: SafePtr<Descriptor, VmFrame> = SafePtr::new(
VmFrameVec::allocate(&VmAllocOptions::new(1).uninit(false).can_dma(true))
.unwrap()
.pop()
.unwrap(),
)
.unwrap();
let avail_frame_ptr: InFramePtr<AvailRing> = InFramePtr::new_with_vm_frame(
0,
);
let avail_frame_ptr: SafePtr<AvailRing, VmFrame> = SafePtr::new(
VmFrameVec::allocate(&VmAllocOptions::new(1).uninit(false).can_dma(true))
.unwrap()
.pop()
.unwrap(),
)
.unwrap();
let used_frame_ptr: InFramePtr<UsedRing> = InFramePtr::new_with_vm_frame(
0,
);
let used_frame_ptr: SafePtr<UsedRing, VmFrame> = SafePtr::new(
VmFrameVec::allocate(&VmAllocOptions::new(1).uninit(false).can_dma(true))
.unwrap()
.pop()
.unwrap(),
)
.unwrap();
0,
);
debug!("queue_desc start paddr:{:x?}", desc_frame_ptr.paddr());
debug!("queue_driver start paddr:{:x?}", avail_frame_ptr.paddr());
debug!("queue_device start paddr:{:x?}", used_frame_ptr.paddr());
cfg.write_at(
offset_of!(VirtioPciCommonCfg, queue_desc),
desc_frame_ptr.paddr() as u64,
);
cfg.write_at(
offset_of!(VirtioPciCommonCfg, queue_driver),
avail_frame_ptr.paddr() as u64,
);
cfg.write_at(
offset_of!(VirtioPciCommonCfg, queue_device),
used_frame_ptr.paddr() as u64,
);
field_ptr!(cfg, VirtioPciCommonCfg, queue_desc)
.write(&(desc_frame_ptr.paddr() as u64))
.unwrap();
field_ptr!(cfg, VirtioPciCommonCfg, queue_driver)
.write(&(avail_frame_ptr.paddr() as u64))
.unwrap();
field_ptr!(cfg, VirtioPciCommonCfg, queue_device)
.write(&(used_frame_ptr.paddr() as u64))
.unwrap();
let mut descs = Vec::with_capacity(size as usize);
descs.push(desc_frame_ptr);
for i in 0..size as usize {
descs.push(descs.get(i).unwrap().add(1))
let mut desc = descs.get(i).unwrap().clone();
desc.offset(1);
descs.push(desc);
}
let notify = InFramePtr::new(notify_base_address + notify_off_multiplier as usize * idx)
.expect("can not get Inframeptr for virtio queue notify");
let notify_address = notify_base_address + notify_off_multiplier as usize * idx;
let notify = SafePtr::new(
IoMem::new(notify_address..notify_address + size_of::<u32>()).unwrap(),
0,
);
// Link descriptors together.
for i in 0..(size - 1) {
let temp = descs.get(i as usize).unwrap();
temp.write_at(offset_of!(Descriptor, next), i + 1);
field_ptr!(temp, Descriptor, next)
.write(&(i + 1))
.map_err(|_err| QueueError::InvalidArgs)?;
}
avail_frame_ptr.write_at(offset_of!(AvailRing, flags), 0 as u16);
cfg.write_at(offset_of!(VirtioPciCommonCfg, queue_enable), 1 as u16);
field_ptr!(&avail_frame_ptr, AvailRing, flags)
.write(&(0u16))
.map_err(|_err| QueueError::InvalidArgs)?;
field_ptr!(cfg, VirtioPciCommonCfg, queue_enable)
.write(&1u16)
.unwrap();
Ok(VirtQueue {
descs,
avail: avail_frame_ptr,
@ -168,44 +181,46 @@ impl VirtQueue {
let mut last = self.free_head;
for input in inputs.iter() {
let desc = &self.descs[self.free_head as usize];
set_buf(desc, input);
desc.write_at(offset_of!(Descriptor, flags), DescFlags::NEXT);
set_buf(&desc.borrow_vm().restrict::<TRights![Write, Dup]>(), input);
field_ptr!(desc, Descriptor, flags)
.write(&DescFlags::NEXT)
.unwrap();
last = self.free_head;
self.free_head = desc.read_at(offset_of!(Descriptor, next));
self.free_head = field_ptr!(desc, Descriptor, next).read().unwrap();
}
for output in outputs.iter() {
let desc = &mut self.descs[self.free_head as usize];
set_buf(desc, output);
desc.write_at(
offset_of!(Descriptor, flags),
DescFlags::NEXT | DescFlags::WRITE,
);
set_buf(&desc.borrow_vm().restrict::<TRights![Write, Dup]>(), output);
field_ptr!(desc, Descriptor, flags)
.write(&(DescFlags::NEXT | DescFlags::WRITE))
.unwrap();
last = self.free_head;
self.free_head = desc.read_at(offset_of!(Descriptor, next));
self.free_head = field_ptr!(desc, Descriptor, next).read().unwrap();
}
// set last_elem.next = NULL
{
let desc = &mut self.descs[last as usize];
let mut flags: DescFlags = desc.read_at(offset_of!(Descriptor, flags));
let mut flags: DescFlags = field_ptr!(desc, Descriptor, flags).read().unwrap();
flags.remove(DescFlags::NEXT);
desc.write_at(offset_of!(Descriptor, flags), flags);
field_ptr!(desc, Descriptor, flags).write(&flags).unwrap();
}
self.num_used += (inputs.len() + outputs.len()) as u16;
let avail_slot = self.avail_idx & (self.queue_size - 1);
self.avail.write_at(
(offset_of!(AvailRing, ring) as usize + avail_slot as usize * 2) as *const u16,
head,
);
{
let mut ring_ptr = field_ptr!(&self.avail, AvailRing, ring);
ring_ptr.byte_add(offset_of!(AvailRing, ring) as usize + avail_slot as usize * 2);
ring_ptr.cast::<u16>().write(&self.avail_idx).unwrap();
}
// write barrier
fence(Ordering::SeqCst);
// increase head of avail ring
self.avail_idx = self.avail_idx.wrapping_add(1);
self.avail
.write_at(offset_of!(AvailRing, idx), self.avail_idx);
field_ptr!(&self.avail, AvailRing, idx)
.write(&self.avail_idx)
.unwrap();
fence(Ordering::SeqCst);
Ok(head)
@ -213,7 +228,7 @@ impl VirtQueue {
/// Whether there is a used element that can pop.
pub fn can_pop(&self) -> bool {
self.last_used_idx != self.used.read_at(offset_of!(UsedRing, idx))
self.last_used_idx != field_ptr!(&self.used, UsedRing, idx).read().unwrap()
}
/// The number of free descriptors.
@ -233,15 +248,19 @@ impl VirtQueue {
head - 1
};
let temp_desc = &mut self.descs[last_free_head as usize];
temp_desc.write_at(offset_of!(Descriptor, next), head);
field_ptr!(temp_desc, Descriptor, next)
.write(&head)
.unwrap();
loop {
let desc = &mut self.descs[head as usize];
let flags: DescFlags = desc.read_at(offset_of!(Descriptor, flags));
let flags: DescFlags = field_ptr!(desc, Descriptor, flags).read().unwrap();
self.num_used -= 1;
if flags.contains(DescFlags::NEXT) {
head = desc.read_at(offset_of!(Descriptor, next));
head = field_ptr!(desc, Descriptor, next).read().unwrap();
} else {
desc.write_at(offset_of!(Descriptor, next), origin_free_head);
field_ptr!(desc, Descriptor, next)
.write(&origin_free_head)
.unwrap();
return;
}
}
@ -258,17 +277,18 @@ impl VirtQueue {
fence(Ordering::SeqCst);
let last_used_slot = self.last_used_idx & (self.queue_size - 1);
let index = self.used.read_at(
(offset_of!(UsedRing, ring) as usize + last_used_slot as usize * 8) as *const u32,
) as u16;
let len = self.used.read_at(
(offset_of!(UsedRing, ring) as usize + last_used_slot as usize * 8 + 4) as *const u32,
);
let element_ptr = {
let mut ptr = self.used.borrow_vm();
ptr.byte_add(offset_of!(UsedRing, ring) as usize + last_used_slot as usize * 8);
ptr.cast::<UsedElem>()
};
let index = field_ptr!(&element_ptr, UsedElem, id).read().unwrap();
let len = field_ptr!(&element_ptr, UsedElem, len).read().unwrap();
self.recycle_descriptors(index);
self.recycle_descriptors(index as u16);
self.last_used_idx = self.last_used_idx.wrapping_add(1);
Ok((index, len))
Ok((index as u16, len))
}
/// If the given token is next on the device used queue, pops it and returns the total buffer
@ -283,18 +303,19 @@ impl VirtQueue {
fence(Ordering::SeqCst);
let last_used_slot = self.last_used_idx & (self.queue_size - 1);
let index = self.used.read_at(
(offset_of!(UsedRing, ring) as usize + last_used_slot as usize * 8) as *const u32,
) as u16;
let len = self.used.read_at(
(offset_of!(UsedRing, ring) as usize + last_used_slot as usize * 8 + 4) as *const u32,
);
let element_ptr = {
let mut ptr = self.used.borrow_vm();
ptr.byte_add(offset_of!(UsedRing, ring) as usize + last_used_slot as usize * 8);
ptr.cast::<UsedElem>()
};
let index = field_ptr!(&element_ptr, UsedElem, id).read().unwrap();
let len = field_ptr!(&element_ptr, UsedElem, len).read().unwrap();
if index != token {
if index as u16 != token {
return Err(QueueError::WrongToken);
}
self.recycle_descriptors(index);
self.recycle_descriptors(index as u16);
self.last_used_idx = self.last_used_idx.wrapping_add(1);
Ok(len)
@ -309,14 +330,13 @@ impl VirtQueue {
pub fn should_notify(&self) -> bool {
// read barrier
fence(Ordering::SeqCst);
let flags = self.used.read_at(offset_of!(UsedRing, flags));
let flags = field_ptr!(&self.used, UsedRing, flags).read().unwrap();
flags & 0x0001u16 == 0u16
}
/// notify that there are available rings
pub fn notify(&mut self) {
self.notify
.write_at(0 as usize as *const u32, self.queue_idx);
self.notify.write(&self.queue_idx).unwrap();
}
}
@ -329,19 +349,16 @@ struct Descriptor {
next: u16,
}
impl Descriptor {
fn set_buf(&mut self, buf: &[u8]) {
self.addr = jinux_frame::vm::vaddr_to_paddr(buf.as_ptr() as usize).unwrap() as u64;
self.len = buf.len() as u32;
}
}
fn set_buf(inframe_ptr: &InFramePtr<Descriptor>, buf: &[u8]) {
#[inline]
fn set_buf(ptr: &SafePtr<Descriptor, &VmFrame, TRightSet<TRights![Dup, Write]>>, buf: &[u8]) {
let va = buf.as_ptr() as usize;
let pa = jinux_frame::vm::vaddr_to_paddr(va).unwrap();
inframe_ptr.write_at(offset_of!(Descriptor, addr), pa as u64);
inframe_ptr.write_at(offset_of!(Descriptor, len), buf.len() as u32);
field_ptr!(ptr, Descriptor, addr)
.write(&(pa as u64))
.unwrap();
field_ptr!(ptr, Descriptor, len)
.write(&(buf.len() as u32))
.unwrap();
}
bitflags! {
/// Descriptor flags

View File

@ -6,7 +6,7 @@ use core::marker::PhantomData;
use alloc::sync::Arc;
use jinux_frame::{
io_mem::IoMem,
vm::{Paddr, VmFrame, VmIo},
vm::{HasPaddr, Paddr, VmFrame, VmIo},
Result,
};
use pod::Pod;

View File

@ -1,9 +1,12 @@
use core::fmt::Debug;
use core::marker::PhantomData;
use jinux_frame::vm::VmIo;
use jinux_frame::vm::Paddr;
use jinux_frame::vm::{HasPaddr, VmIo};
use jinux_frame::Result;
use jinux_rights::{Dup, Exec, Full, Read, Signal, TRightSet, TRights, Write};
use jinux_rights_proc::require;
use pod::Pod;
pub use pod::Pod;
pub use typeflags_util::SetContain;
/// Safe pointers.
///
@ -48,10 +51,10 @@ use pod::Pod;
/// ```
///
/// The generic parameter `M` of `SafePtr<_, M, _>` must implement the `VmIo`
/// trait. The most important `VmIo` types are `Vmar`, `Vmo`, `Mmio`, and
/// trait. The most important `VmIo` types are `Vmar`, `Vmo`, `IoMem`, and
/// `VmFrame`. The blanket implementations of `VmIo` also include pointer-like
/// types that refer to a `VmIo` type. Some examples are `&Vmo`, `Box<Vmar>`,
/// and `Arc<Mmio>`.
/// and `Arc<IoMem>`.
///
/// The safe pointer itself does not and cannot guarantee that its address is valid.
/// This is because different VM objects may interpret addresses differently
@ -144,7 +147,7 @@ use pod::Pod;
/// A safe pointer may have a combination of three access rights:
/// Read, Write, and Dup.
pub struct SafePtr<T, M, R = Full> {
addr: usize,
offset: usize,
vm_obj: M,
rights: R,
phantom: PhantomData<T>,
@ -157,17 +160,23 @@ impl<T: Pod, M: VmIo> SafePtr<T, M> {
///
/// The default access rights of a new instance are `Read`, `Write`, and
/// `Dup`.
pub fn new(vm_obj: M, addr: usize) -> Self {
pub fn new(vm_obj: M, offset: usize) -> Self {
Self {
vm_obj,
addr,
offset,
rights: TRightSet(<TRights![Dup, Read, Write, Exec, Signal]>::new()),
phantom: PhantomData,
}
}
}
impl<T: Pod, M: VmIo, R: TRights> SafePtr<T, M, R> {
impl<T: Pod, M: VmIo + HasPaddr> SafePtr<T, M> {
pub fn paddr(&self) -> Paddr {
self.vm_obj.paddr() + self.offset
}
}
impl<T: Pod, M: VmIo, R: TRights> SafePtr<T, M, TRightSet<R>> {
// =============== Read and write methods ==============
/// Read the value from the pointer.
@ -177,7 +186,7 @@ impl<T: Pod, M: VmIo, R: TRights> SafePtr<T, M, R> {
/// This method requires the Read right.
#[require(R > Read)]
pub fn read(&self) -> Result<T> {
self.vm_obj.read_val(self.addr)
self.vm_obj.read_val(self.offset)
}
/// Read a slice of values from the pointer.
@ -197,7 +206,7 @@ impl<T: Pod, M: VmIo, R: TRights> SafePtr<T, M, R> {
/// This method requires the Write right.
#[require(R > Write)]
pub fn write(&self, val: &T) -> Result<()> {
self.vm_obj.write_val(self.addr, val)
self.vm_obj.write_val(self.offset, val)
}
/// Overwrite a slice of values at the pointer.
@ -212,45 +221,37 @@ impl<T: Pod, M: VmIo, R: TRights> SafePtr<T, M, R> {
// =============== Address-related methods ==============
pub const fn addr(&self) -> usize {
self.addr
}
pub fn set_addr(&mut self, addr: usize) {
self.addr = addr;
}
pub const fn is_aligned(&self) -> bool {
self.addr % core::mem::align_of::<T>() == 0
self.offset % core::mem::align_of::<T>() == 0
}
/// Increase the address in units of bytes occupied by the generic T.
pub fn add(&mut self, count: usize) {
let offset = count * core::mem::size_of::<T>();
self.addr += offset;
self.offset += offset;
}
/// Increase or decrease the address in units of bytes occupied by the generic T.
pub fn offset(&mut self, count: isize) {
let offset = count * core::mem::size_of::<T>() as isize;
if count >= 0 {
self.addr += offset as usize;
self.offset += offset as usize;
} else {
self.addr -= (-offset) as usize;
self.offset -= (-offset) as usize;
}
}
/// Increase the address in units of bytes.
pub fn byte_add(&mut self, bytes: usize) {
self.addr += bytes;
self.offset += bytes;
}
/// Increase or decrease the address in units of bytes.
pub fn byte_offset(&mut self, bytes: isize) {
if bytes >= 0 {
self.addr += bytes as usize;
self.offset += bytes as usize;
} else {
self.addr -= (-bytes) as usize;
self.offset -= (-bytes) as usize;
}
}
@ -265,15 +266,15 @@ impl<T: Pod, M: VmIo, R: TRights> SafePtr<T, M, R> {
}
/// Construct a new SafePtr which will point to the same address
pub const fn borrow_vm(&self) -> SafePtr<T, &M, R> {
pub fn borrow_vm(&self) -> SafePtr<T, &M, TRightSet<R>> {
let SafePtr {
addr,
offset: addr,
vm_obj,
rights,
..
} = self;
SafePtr {
addr: *addr,
offset: *addr,
vm_obj,
rights: *rights,
phantom: PhantomData,
@ -283,15 +284,15 @@ impl<T: Pod, M: VmIo, R: TRights> SafePtr<T, M, R> {
// =============== Type conversion methods ==============
/// Cast the accessed structure into a new one, which is usually used when accessing a field in a structure.
pub fn cast<U: Pod>(self) -> SafePtr<U, M, R> {
pub fn cast<U: Pod>(self) -> SafePtr<U, M, TRightSet<R>> {
let SafePtr {
addr,
offset: addr,
vm_obj,
rights,
..
} = self;
SafePtr {
addr,
offset: addr,
vm_obj,
rights,
phantom: PhantomData,
@ -304,22 +305,26 @@ impl<T: Pod, M: VmIo, R: TRights> SafePtr<T, M, R> {
///
/// This method requires the target rights to be a subset of the current rights.
#[require(R > R1)]
pub fn restrict<R1: TRights>(self) -> SafePtr<T, M, R1> {
let SafePtr { addr, vm_obj, .. } = self;
SafePtr {
addr,
pub fn restrict<R1: TRights>(self) -> SafePtr<T, M, TRightSet<R1>> {
let SafePtr {
offset: addr,
vm_obj,
rights: R1::new(),
..
} = self;
SafePtr {
offset: addr,
vm_obj,
rights: TRightSet(R1::new()),
phantom: PhantomData,
}
}
}
#[require(R > Dup)]
impl<T, M: Clone, R: TRights> Clone for SafePtr<T, M, R> {
impl<T, M: Clone, R: TRights> Clone for SafePtr<T, M, TRightSet<R>> {
fn clone(&self) -> Self {
Self {
addr: self.addr,
offset: self.offset,
vm_obj: self.vm_obj.clone(),
rights: self.rights,
phantom: PhantomData,
@ -328,10 +333,10 @@ impl<T, M: Clone, R: TRights> Clone for SafePtr<T, M, R> {
}
#[require(R > Dup)]
impl<T, M: crate::dup::Dup, R: TRights> crate::dup::Dup for SafePtr<T, M, R> {
impl<T, M: crate::dup::Dup, R: TRights> crate::dup::Dup for SafePtr<T, M, TRightSet<R>> {
fn dup(&self) -> Result<Self> {
let duplicated = Self {
addr: self.addr,
offset: self.offset,
vm_obj: self.vm_obj.dup()?,
rights: self.rights,
phantom: PhantomData,
@ -340,33 +345,44 @@ impl<T, M: crate::dup::Dup, R: TRights> crate::dup::Dup for SafePtr<T, M, R> {
}
}
impl<T, M: Debug, R> Debug for SafePtr<T, M, R> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("SafePtr")
.field("offset", &self.offset)
.field("vm_obj", &self.vm_obj)
.finish()
}
}
/// Create a safe pointer for the field of a struct.
#[macro_export]
macro_rules! field_ptr {
($ptr:expr, $type:ty, $($field:tt)+) => {{
use jinux_frame::offset_of;
use jinux_frame::vm::VmIo;
// import more...
use jinux_rights::TRights;
use jinux_rights::TRightSet;
use jinux_rights::Dup;
use jinux_util::safe_ptr::SetContain;
use jinux_util::safe_ptr::Pod;
#[inline]
fn new_field_ptr<T, M, R, U>(
container_ptr: &SafePtr<T, M, R>,
container_ptr: &SafePtr<T, M, TRightSet<R>>,
field_offset: *const U
) -> SafePtr<U, &M, R>
) -> SafePtr<U, &M, TRightSet<R>>
where
T: Pod,
M: VmIo,
R: TRights,
U: Pod,
{
container_ptr
.borrow_vm()
.byte_add(offset as usize)
.cast()
let mut ptr = container_ptr.borrow_vm();
ptr.byte_add(field_offset as usize);
ptr.cast()
}
let ptr = $ptr;
let field_offset = offset_of!(ty, $($field)*);
new_field_ptr(ptr, field_offset)
let field_offset = offset_of!($type, $($field)*);
new_field_ptr($ptr,field_offset)
}}
}