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

View File

@ -3,7 +3,7 @@ use pod::Pod;
use spin::Once; use spin::Once;
use crate::{ use crate::{
vm::{Paddr, Vaddr, VmIo}, vm::{HasPaddr, Paddr, Vaddr, VmIo},
Error, 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 { impl IoMem {
pub fn new(range: Range<Paddr>) -> Option<IoMem> { pub fn new(range: Range<Paddr>) -> Option<IoMem> {
if CHECKER.get().unwrap().check(&range) { 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<()> { fn check_range(&self, offset: usize, len: usize) -> crate::Result<()> {
let sum = offset.checked_add(len).ok_or(Error::InvalidArgs)?; let sum = offset.checked_add(len).ok_or(Error::InvalidArgs)?;
if sum > self.limit { if sum > self.limit {

View File

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

View File

@ -32,9 +32,9 @@ use spin::Once;
use crate::boot::memory_region::{MemoryRegion, MemoryRegionType}; use crate::boot::memory_region::{MemoryRegion, MemoryRegionType};
/// Convert physical address to virtual address using offset, only available inside jinux-frame /// Get physical address trait
pub(crate) fn paddr_to_vaddr(pa: usize) -> usize { pub trait HasPaddr {
pa + PHYS_OFFSET fn paddr(&self) -> Paddr;
} }
pub fn vaddr_to_paddr(va: Vaddr) -> Option<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 (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 /// Only available inside jinux-frame
pub(crate) static MEMORY_REGIONS: Once<Vec<MemoryRegion>> = Once::new(); pub(crate) static MEMORY_REGIONS: Once<Vec<MemoryRegion>> = Once::new();

View File

@ -1,8 +1,8 @@
//! Block device based on Virtio //! 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_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 jinux_virtio::{device::block::device::BLKDevice, PCIVirtioDevice, VirtioPciCommonCfg};
use log::debug; use log::debug;
use spin::Mutex; use spin::Mutex;
@ -11,8 +11,8 @@ use crate::{BlockDevice, BLK_COMPONENT};
pub struct VirtioBlockDevice { pub struct VirtioBlockDevice {
blk_device: Mutex<BLKDevice>, blk_device: Mutex<BLKDevice>,
pub common_cfg: InFramePtr<VirtioPciCommonCfg>, pub common_cfg: SafePtr<VirtioPciCommonCfg, IoMem>,
msix: MSIX, _msix: MSIX,
} }
impl BlockDevice for VirtioBlockDevice { impl BlockDevice for VirtioBlockDevice {
@ -48,7 +48,7 @@ impl VirtioBlockDevice {
Self { Self {
blk_device, blk_device,
common_cfg: virtio_device.common_cfg, 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-pci = { path = "../pci" }
jinux-virtio = { path = "../virtio" } jinux-virtio = { path = "../virtio" }
jinux-util = { path = "../../libs/jinux-util" } jinux-util = { path = "../../libs/jinux-util" }
jinux-rights = { path = "../../libs/jinux-rights" }
component = { path = "../../libs/comp-sys/component" } component = { path = "../../libs/comp-sys/component" }
virtio-input-decoder = "0.1.4" virtio-input-decoder = "0.1.4"
log = "0.4" log = "0.4"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,9 +1,9 @@
use core::hint::spin_loop; use core::hint::spin_loop;
use alloc::vec::Vec; 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_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 pod::Pod;
use crate::{ use crate::{
@ -17,7 +17,7 @@ use super::{BLKFeatures, VirtioBLKConfig};
#[derive(Debug)] #[derive(Debug)]
pub struct BLKDevice { pub struct BLKDevice {
config: InFramePtr<VirtioBLKConfig>, config: SafePtr<VirtioBLKConfig, IoMem>,
queue: VirtQueue, queue: VirtQueue,
} }
@ -27,13 +27,15 @@ impl BLKDevice {
pub(crate) fn new( pub(crate) fn new(
cap: &CapabilityVirtioData, cap: &CapabilityVirtioData,
bars: [Option<BAR>; 6], bars: [Option<BAR>; 6],
common_cfg: &InFramePtr<VirtioPciCommonCfg>, common_cfg: &SafePtr<VirtioPciCommonCfg, IoMem>,
notify_base_address: usize, notify_base_address: usize,
notify_off_multiplier: u32, notify_off_multiplier: u32,
mut msix_vector_left: Vec<u16>, mut msix_vector_left: Vec<u16>,
) -> Result<Self, VirtioDeviceError> { ) -> Result<Self, VirtioDeviceError> {
let config = VirtioBLKConfig::new(cap, bars); 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 { if num_queues != 1 {
return Err(VirtioDeviceError::QueuesAmountDoNotMatch(num_queues, 1)); return Err(VirtioDeviceError::QueuesAmountDoNotMatch(num_queues, 1));
} }

View File

@ -1,10 +1,13 @@
pub mod device; pub mod device;
use core::mem::size_of;
use bitflags::bitflags; use bitflags::bitflags;
use int_to_c_enum::TryFromInt; use int_to_c_enum::TryFromInt;
use jinux_frame::io_mem::IoMem;
use jinux_pci::capability::vendor::virtio::CapabilityVirtioData; use jinux_pci::capability::vendor::virtio::CapabilityVirtioData;
use jinux_pci::util::BAR; use jinux_pci::util::BAR;
use jinux_util::frame_ptr::InFramePtr; use jinux_util::safe_ptr::SafePtr;
use pod::Pod; use pod::Pod;
pub const BLK_SIZE: usize = 512; pub const BLK_SIZE: usize = 512;
@ -110,15 +113,19 @@ pub struct VirtioBLKTopology {
} }
impl VirtioBLKConfig { 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 bar = cap.bar;
let offset = cap.offset; let offset = cap.offset;
match bars[bar as usize].expect("Virtio pci block cfg:bar is none") { match bars[bar as usize].expect("Virtio pci block cfg:bar is none") {
BAR::Memory(address, _, _, _) => InFramePtr::new(address as usize + offset as usize) BAR::Memory(address, _, _, _) => SafePtr::new(
.expect("can not get in frame ptr for virtio block config"), IoMem::new(
BAR::IO(_, _) => { (address as usize + offset as usize)
panic!("Virtio pci block cfg:bar is IO type") ..(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 crate::{device::VirtioDeviceError, queue::VirtQueue, VirtioPciCommonCfg};
use alloc::{boxed::Box, vec::Vec}; use alloc::{boxed::Box, vec::Vec};
use bitflags::bitflags; 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_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 pod::Pod;
use spin::Mutex; use spin::Mutex;
@ -43,7 +43,7 @@ pub const FF_STATUS: u8 = 0x17;
/// making pass-through implementations on top of evdev easy. /// making pass-through implementations on top of evdev easy.
#[derive(Debug)] #[derive(Debug)]
pub struct InputDevice { pub struct InputDevice {
config: InFramePtr<VirtioInputConfig>, config: SafePtr<VirtioInputConfig, IoMem>,
event_queue: Mutex<VirtQueue>, event_queue: Mutex<VirtQueue>,
status_queue: VirtQueue, status_queue: VirtQueue,
pub event_buf: Mutex<Box<[InputEvent; QUEUE_SIZE]>>, pub event_buf: Mutex<Box<[InputEvent; QUEUE_SIZE]>>,
@ -55,7 +55,7 @@ impl InputDevice {
pub fn new( pub fn new(
cap: &CapabilityVirtioData, cap: &CapabilityVirtioData,
bars: [Option<BAR>; 6], bars: [Option<BAR>; 6],
common_cfg: &InFramePtr<VirtioPciCommonCfg>, common_cfg: &SafePtr<VirtioPciCommonCfg, IoMem>,
notify_base_address: usize, notify_base_address: usize,
notify_off_multiplier: u32, notify_off_multiplier: u32,
mut msix_vector_left: Vec<u16>, mut msix_vector_left: Vec<u16>,
@ -135,12 +135,18 @@ impl InputDevice {
/// Query a specific piece of information by `select` and `subsel`, and write /// Query a specific piece of information by `select` and `subsel`, and write
/// result to `out`, return the result size. /// result to `out`, return the result size.
pub fn query_config_select(&self, select: InputConfigSelect, subsel: u8, out: &mut [u8]) -> u8 { pub fn query_config_select(&self, select: InputConfigSelect, subsel: u8, out: &mut [u8]) -> u8 {
self.config field_ptr!(&self.config, VirtioInputConfig, select)
.write_at(offset_of!(VirtioInputConfig, select), select as u8); .write(&(select as u8))
self.config .unwrap();
.write_at(offset_of!(VirtioInputConfig, subsel), subsel as u8); field_ptr!(&self.config, VirtioInputConfig, subsel)
let size = self.config.read_at(offset_of!(VirtioInputConfig, size)); .write(&(subsel as u8))
let data: [u8; 128] = self.config.read_at(offset_of!(VirtioInputConfig, data)); .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]); out[..size as usize].copy_from_slice(&data[..size as usize]);
size size
} }

View File

@ -25,8 +25,11 @@
// //
pub mod device; 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_pci::{capability::vendor::virtio::CapabilityVirtioData, util::BAR};
use jinux_util::frame_ptr::InFramePtr; use jinux_util::safe_ptr::SafePtr;
use pod::Pod; use pod::Pod;
/// Select value used for [`VirtIOInput::query_config_select()`]. /// Select value used for [`VirtIOInput::query_config_select()`].
@ -69,15 +72,19 @@ pub struct VirtioInputConfig {
} }
impl 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 bar = cap.bar;
let offset = cap.offset; let offset = cap.offset;
match bars[bar as usize].expect("Virtio pci block cfg:bar is none") { match bars[bar as usize].expect("Virtio pci block cfg:bar is none") {
BAR::Memory(address, _, _, _) => InFramePtr::new(address as usize + offset as usize) BAR::Memory(address, _, _, _) => SafePtr::new(
.expect("can not get in frame ptr for virtio block config"), IoMem::new(
BAR::IO(_, _) => { (address as usize + offset as usize)
panic!("Virtio pci block cfg:bar is IO type") ..(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, VirtioPciCommonCfg,
}; };
use alloc::vec::Vec; use alloc::vec::Vec;
use jinux_frame::io_mem::IoMem;
use jinux_pci::{ use jinux_pci::{
capability::{vendor::virtio::CapabilityVirtioData, Capability}, capability::{vendor::virtio::CapabilityVirtioData, Capability},
util::BAR, util::BAR,
}; };
use jinux_util::frame_ptr::InFramePtr; use jinux_util::safe_ptr::SafePtr;
use self::{input::device::InputDevice, network::device::NetworkDevice}; use self::{input::device::InputDevice, network::device::NetworkDevice};
@ -56,7 +57,7 @@ pub struct VirtioInfo {
pub device_type: VirtioDeviceType, pub device_type: VirtioDeviceType,
pub notify_base_address: u64, pub notify_base_address: u64,
pub notify_off_multiplier: u32, 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, pub device_cap_cfg: CapabilityVirtioData,
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,9 +1,12 @@
use core::fmt::Debug;
use core::marker::PhantomData; 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_frame::Result;
use jinux_rights::{Dup, Exec, Full, Read, Signal, TRightSet, TRights, Write}; use jinux_rights::{Dup, Exec, Full, Read, Signal, TRightSet, TRights, Write};
use jinux_rights_proc::require; use jinux_rights_proc::require;
use pod::Pod; pub use pod::Pod;
pub use typeflags_util::SetContain;
/// Safe pointers. /// Safe pointers.
/// ///
@ -48,10 +51,10 @@ use pod::Pod;
/// ``` /// ```
/// ///
/// The generic parameter `M` of `SafePtr<_, M, _>` must implement the `VmIo` /// 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 /// `VmFrame`. The blanket implementations of `VmIo` also include pointer-like
/// types that refer to a `VmIo` type. Some examples are `&Vmo`, `Box<Vmar>`, /// 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. /// The safe pointer itself does not and cannot guarantee that its address is valid.
/// This is because different VM objects may interpret addresses differently /// 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: /// A safe pointer may have a combination of three access rights:
/// Read, Write, and Dup. /// Read, Write, and Dup.
pub struct SafePtr<T, M, R = Full> { pub struct SafePtr<T, M, R = Full> {
addr: usize, offset: usize,
vm_obj: M, vm_obj: M,
rights: R, rights: R,
phantom: PhantomData<T>, 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 /// The default access rights of a new instance are `Read`, `Write`, and
/// `Dup`. /// `Dup`.
pub fn new(vm_obj: M, addr: usize) -> Self { pub fn new(vm_obj: M, offset: usize) -> Self {
Self { Self {
vm_obj, vm_obj,
addr, offset,
rights: TRightSet(<TRights![Dup, Read, Write, Exec, Signal]>::new()), rights: TRightSet(<TRights![Dup, Read, Write, Exec, Signal]>::new()),
phantom: PhantomData, 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 and write methods ==============
/// Read the value from the pointer. /// 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. /// This method requires the Read right.
#[require(R > Read)] #[require(R > Read)]
pub fn read(&self) -> Result<T> { 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. /// 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. /// This method requires the Write right.
#[require(R > Write)] #[require(R > Write)]
pub fn write(&self, val: &T) -> Result<()> { 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. /// 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 ============== // =============== 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 { 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. /// Increase the address in units of bytes occupied by the generic T.
pub fn add(&mut self, count: usize) { pub fn add(&mut self, count: usize) {
let offset = count * core::mem::size_of::<T>(); 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. /// Increase or decrease the address in units of bytes occupied by the generic T.
pub fn offset(&mut self, count: isize) { pub fn offset(&mut self, count: isize) {
let offset = count * core::mem::size_of::<T>() as isize; let offset = count * core::mem::size_of::<T>() as isize;
if count >= 0 { if count >= 0 {
self.addr += offset as usize; self.offset += offset as usize;
} else { } else {
self.addr -= (-offset) as usize; self.offset -= (-offset) as usize;
} }
} }
/// Increase the address in units of bytes. /// Increase the address in units of bytes.
pub fn byte_add(&mut self, bytes: usize) { pub fn byte_add(&mut self, bytes: usize) {
self.addr += bytes; self.offset += bytes;
} }
/// Increase or decrease the address in units of bytes. /// Increase or decrease the address in units of bytes.
pub fn byte_offset(&mut self, bytes: isize) { pub fn byte_offset(&mut self, bytes: isize) {
if bytes >= 0 { if bytes >= 0 {
self.addr += bytes as usize; self.offset += bytes as usize;
} else { } 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 /// 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 { let SafePtr {
addr, offset: addr,
vm_obj, vm_obj,
rights, rights,
.. ..
} = self; } = self;
SafePtr { SafePtr {
addr: *addr, offset: *addr,
vm_obj, vm_obj,
rights: *rights, rights: *rights,
phantom: PhantomData, phantom: PhantomData,
@ -283,15 +284,15 @@ impl<T: Pod, M: VmIo, R: TRights> SafePtr<T, M, R> {
// =============== Type conversion methods ============== // =============== Type conversion methods ==============
/// Cast the accessed structure into a new one, which is usually used when accessing a field in a structure. /// 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 { let SafePtr {
addr, offset: addr,
vm_obj, vm_obj,
rights, rights,
.. ..
} = self; } = self;
SafePtr { SafePtr {
addr, offset: addr,
vm_obj, vm_obj,
rights, rights,
phantom: PhantomData, 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. /// This method requires the target rights to be a subset of the current rights.
#[require(R > R1)] #[require(R > R1)]
pub fn restrict<R1: TRights>(self) -> SafePtr<T, M, R1> { pub fn restrict<R1: TRights>(self) -> SafePtr<T, M, TRightSet<R1>> {
let SafePtr { addr, vm_obj, .. } = self; let SafePtr {
SafePtr { offset: addr,
addr,
vm_obj, vm_obj,
rights: R1::new(), ..
} = self;
SafePtr {
offset: addr,
vm_obj,
rights: TRightSet(R1::new()),
phantom: PhantomData, phantom: PhantomData,
} }
} }
} }
#[require(R > Dup)] #[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 { fn clone(&self) -> Self {
Self { Self {
addr: self.addr, offset: self.offset,
vm_obj: self.vm_obj.clone(), vm_obj: self.vm_obj.clone(),
rights: self.rights, rights: self.rights,
phantom: PhantomData, phantom: PhantomData,
@ -328,10 +333,10 @@ impl<T, M: Clone, R: TRights> Clone for SafePtr<T, M, R> {
} }
#[require(R > Dup)] #[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> { fn dup(&self) -> Result<Self> {
let duplicated = Self { let duplicated = Self {
addr: self.addr, offset: self.offset,
vm_obj: self.vm_obj.dup()?, vm_obj: self.vm_obj.dup()?,
rights: self.rights, rights: self.rights,
phantom: PhantomData, 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. /// Create a safe pointer for the field of a struct.
#[macro_export] #[macro_export]
macro_rules! field_ptr { macro_rules! field_ptr {
($ptr:expr, $type:ty, $($field:tt)+) => {{ ($ptr:expr, $type:ty, $($field:tt)+) => {{
use jinux_frame::offset_of; use jinux_frame::offset_of;
use jinux_frame::vm::VmIo; 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] #[inline]
fn new_field_ptr<T, M, R, U>( 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 field_offset: *const U
) -> SafePtr<U, &M, R> ) -> SafePtr<U, &M, TRightSet<R>>
where where
T: Pod, T: Pod,
M: VmIo, M: VmIo,
R: TRights, R: TRights,
U: Pod, U: Pod,
{ {
container_ptr let mut ptr = container_ptr.borrow_vm();
.borrow_vm() ptr.byte_add(field_offset as usize);
.byte_add(offset as usize) ptr.cast()
.cast()
} }
let ptr = $ptr; let field_offset = offset_of!($type, $($field)*);
let field_offset = offset_of!(ty, $($field)*); new_field_ptr($ptr,field_offset)
new_field_ptr(ptr, field_offset)
}} }}
} }