diff --git a/framework/jinux-frame/src/vm/frame.rs b/framework/jinux-frame/src/vm/frame.rs index 29cd18028..94155d43a 100644 --- a/framework/jinux-frame/src/vm/frame.rs +++ b/framework/jinux-frame/src/vm/frame.rs @@ -35,9 +35,6 @@ impl VmFrameVec { let page_size = options.page_size; let mut frame_list = Vec::new(); if options.is_contiguous { - if options.paddr.is_some() { - panic!("not support contiguous paddr"); - } let frames = frame_allocator::alloc_continuous(options.page_size); if frames.is_none() { return Err(Error::NoMemory); @@ -45,15 +42,7 @@ impl VmFrameVec { return Ok(Self(frames.unwrap())); } for i in 0..page_size { - let vm_frame = if let Some(paddr) = options.paddr { - frame_allocator::alloc_with_paddr(paddr + i * PAGE_SIZE) - } else { - frame_allocator::alloc() - }; - if vm_frame.is_none() { - return Err(Error::NoMemory); - } - frame_list.push(vm_frame.unwrap()); + frame_list.push(frame_allocator::alloc().unwrap()); } Ok(Self(frame_list)) } @@ -211,7 +200,6 @@ impl<'a> Iterator for VmFrameVecIter<'a> { /// See `VmFrameVec::alloc`. pub struct VmAllocOptions { page_size: usize, - paddr: Option, is_contiguous: bool, } @@ -220,22 +208,10 @@ impl VmAllocOptions { pub fn new(len: usize) -> Self { Self { page_size: len, - paddr: None, is_contiguous: false, } } - /// Sets the physical address of the first frame. - /// - /// If the physical address is given, then the allocated frames will be - /// contiguous. - /// - /// The default value is `None`. - pub fn paddr(&mut self, paddr: Option) -> &mut Self { - self.paddr = paddr; - self - } - /// Sets whether the allocated frames should be contiguous. /// /// If the physical address is set, then the frames must be contiguous. @@ -366,14 +342,13 @@ impl VmIo for VmFrame { /// Read a value of a specified type at a specified offset. fn read_val(&self, offset: usize) -> Result { let paddr = self.start_paddr() + offset; - let val = unsafe { &mut *(super::paddr_to_vaddr(paddr) as *mut T) }; - Ok(*val) + Ok(unsafe { core::ptr::read(super::paddr_to_vaddr(paddr) as *const T) }) } /// Write a value of a specified type at a specified offset. fn write_val(&self, offset: usize, new_val: &T) -> Result<()> { let paddr = self.start_paddr() + offset; - unsafe { (super::paddr_to_vaddr(paddr) as *mut T).write(*new_val) }; + unsafe { core::ptr::write(super::paddr_to_vaddr(paddr) as *mut T, *new_val) }; Ok(()) } } diff --git a/framework/jinux-frame/src/vm/frame_allocator.rs b/framework/jinux-frame/src/vm/frame_allocator.rs index 43213bada..386d8b3a0 100644 --- a/framework/jinux-frame/src/vm/frame_allocator.rs +++ b/framework/jinux-frame/src/vm/frame_allocator.rs @@ -41,43 +41,6 @@ pub fn alloc_continuous(frame_count: usize) -> Option> { }) } -pub fn alloc_with_paddr(paddr: Paddr) -> Option { - if !is_paddr_valid(paddr..paddr + PAGE_SIZE) { - debug!("not a valid paddr:{:x}", paddr); - return None; - } - unsafe { - Some(VmFrame::new( - paddr.align_down(PAGE_SIZE), - VmFrameFlags::empty(), - )) - } -} - -/// Check if the physical address in range is valid -fn is_paddr_valid(range: Range) -> bool { - // special area in x86 - #[cfg(target_arch = "x86_64")] - if range.start >= 0xFE00_0000 && range.end <= 0xFFFF_FFFF { - return true; - } - - for i in super::MEMORY_REGIONS.get().unwrap().iter() { - match i.typ { - MemoryRegionsType::Usable => {} - MemoryRegionsType::Reserved => {} - MemoryRegionsType::Framebuffer => {} - _ => { - continue; - } - } - if range.start as u64 >= i.base && (range.end as u64) <= i.base + i.len { - return true; - } - } - false -} - pub(crate) fn alloc_zero() -> Option { let frame = alloc()?; frame.zero(); diff --git a/services/comps/framebuffer/src/lib.rs b/services/comps/framebuffer/src/lib.rs index 79506e0d3..2949dc85f 100644 --- a/services/comps/framebuffer/src/lib.rs +++ b/services/comps/framebuffer/src/lib.rs @@ -12,11 +12,7 @@ use core::{ ops::{Index, IndexMut}, }; use font8x8::UnicodeFonts; -use jinux_frame::{ - config::PAGE_SIZE, - vm::{VmAllocOptions, VmFrameVec, VmIo}, - LimineFramebufferRequest, -}; +use jinux_frame::{config::PAGE_SIZE, mmio::Mmio, vm::VmIo, LimineFramebufferRequest}; use spin::{Mutex, Once}; #[init_component] @@ -43,10 +39,10 @@ pub(crate) fn init() { for i in response.framebuffers() { let page_size = size / PAGE_SIZE; - let frame_vec = VmFrameVec::allocate(VmAllocOptions::new(page_size).paddr( - jinux_frame::vm::vaddr_to_paddr(i.address.as_ptr().unwrap().addr()), - )) - .unwrap(); + let start_paddr = i.address.as_ptr().unwrap().addr(); + let mmio = + Mmio::new(start_paddr..(start_paddr + jinux_frame::config::PAGE_SIZE * page_size)) + .unwrap(); let mut buffer: Vec = Vec::with_capacity(size); for _ in 0..size { @@ -55,7 +51,7 @@ pub(crate) fn init() { log::debug!("Found framebuffer:{:?}", *i); writer = Some(Writer { - frame_vec, + mmio, x_pos: 0, y_pos: 0, bytes_per_pixel: (i.bpp / 8) as usize, @@ -72,7 +68,7 @@ pub(crate) fn init() { } pub(crate) struct Writer { - frame_vec: VmFrameVec, + mmio: Mmio, /// FIXME: remove buffer. The meaning of buffer is to facilitate the various operations of framebuffer buffer: &'static mut [u8], @@ -99,14 +95,14 @@ impl Writer { self.x_pos = 0; self.y_pos = 0; self.buffer.fill(0); - self.frame_vec.write_bytes(0, self.buffer).unwrap(); + self.mmio.write_bytes(0, self.buffer).unwrap(); } /// Everything moves up one letter in size fn shift_lines_up(&mut self) { let offset = self.bytes_per_pixel * 8; self.buffer.copy_within(offset.., 0); - self.frame_vec.write_bytes(0, self.buffer).unwrap(); + self.mmio.write_bytes(0, self.buffer).unwrap(); self.y_pos -= 8; } @@ -159,7 +155,7 @@ impl Writer { self.buffer .index_mut(byte_offset..(byte_offset + bytes_per_pixel)) .copy_from_slice(&color[..bytes_per_pixel]); - self.frame_vec + self.mmio .write_bytes( byte_offset, self.buffer diff --git a/services/comps/pci/src/msix.rs b/services/comps/pci/src/msix.rs index 0a0b304c3..ecc0bb03e 100644 --- a/services/comps/pci/src/msix.rs +++ b/services/comps/pci/src/msix.rs @@ -83,21 +83,22 @@ 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); - for i in 0..table_size { - let value: InFramePtr = - InFramePtr::new(table_base_address as usize + 16 * i as usize) - .expect("can not get in frame ptr for msix"); + let mut table_iter: InFramePtr = + InFramePtr::new(table_base_address as usize) + .expect("can not get in frame ptr for msix"); + for _ in 0..table_size { // local APIC address: 0xFEE0_0000 - value.write_at(offset_of!(MSIXTableEntry, msg_addr), 0xFEE0_0000 as u32); - value.write_at(offset_of!(MSIXTableEntry, msg_upper_addr), 0 as u32); + 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); // allocate irq number let handle = jinux_frame::trap::allocate_irq().expect("not enough irq"); - value.write_at(offset_of!(MSIXTableEntry, msg_data), handle.num() as u32); - value.write_at(offset_of!(MSIXTableEntry, vector_control), 0 as u32); + 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); cap.table.push(MSIXEntry { - table_entry: value, + table_entry: table_iter.clone(), irq_handle: handle, }); + table_iter = table_iter.add(1); } cap } diff --git a/services/comps/virtio/src/lib.rs b/services/comps/virtio/src/lib.rs index 067a685f5..29c5d6030 100644 --- a/services/comps/virtio/src/lib.rs +++ b/services/comps/virtio/src/lib.rs @@ -267,6 +267,10 @@ impl PCIVirtioDevice { let mut msix_vector_list: Vec = (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; + + // Reset device + common_cfg_frame_ptr.write_at(offset_of!(VitrioPciCommonCfg, device_status), 0 as u8); + let num_queues: u16 = common_cfg_frame_ptr.read_at(offset_of!(VitrioPciCommonCfg, num_queues)); debug!("num_queues:{:x}", num_queues); diff --git a/services/comps/virtio/src/queue.rs b/services/comps/virtio/src/queue.rs index 6cf1bb06a..7073bc5ba 100644 --- a/services/comps/virtio/src/queue.rs +++ b/services/comps/virtio/src/queue.rs @@ -6,7 +6,7 @@ use bitflags::bitflags; use core::sync::atomic::{fence, Ordering}; use jinux_frame::{ offset_of, - vm::{VmAllocOptions, VmFrame, VmFrameVec}, + vm::{VmAllocOptions, VmFrameVec}, }; use jinux_util::frame_ptr::InFramePtr; use log::debug; @@ -45,13 +45,11 @@ pub struct VirtQueue { /// The number of used queues. num_used: u16, /// The head desc index of the free list. - pub free_head: u16, + free_head: u16, /// the index of the next avail ring index avail_idx: u16, /// last service used index last_used_idx: u16, - - physical_frame_store: Vec, } impl VirtQueue { @@ -69,9 +67,7 @@ impl VirtQueue { cfg.read_at(offset_of!(VitrioPciCommonCfg, queue_select)), idx as u16 ); - // info!("actual queue_size:{}",cfg.read_at(offset_of!(VitrioPciCommonCfg, queue_size))); - if !size.is_power_of_two() || cfg.read_at(offset_of!(VitrioPciCommonCfg, queue_size)) < size - { + if !size.is_power_of_two() { return Err(QueueError::InvalidArgs); } @@ -85,63 +81,54 @@ impl VirtQueue { msix_vector ); - let mut descs = Vec::new(); - //allocate page - let mut frame_vec = Vec::new(); - let vm_allocate_option = VmAllocOptions::new(1); - if cfg.read_at(offset_of!(VitrioPciCommonCfg, queue_desc)) == 0 as u64 { - let frame = VmFrameVec::allocate(&vm_allocate_option) - .expect("cannot allocate physical frame for virtqueue") - .remove(0); - cfg.write_at( - offset_of!(VitrioPciCommonCfg, queue_desc), - frame.start_paddr() as u64, - ); - debug!("queue_desc vm frame:{:x?}", frame); - frame_vec.push(frame); + + let desc_frame_ptr: InFramePtr = InFramePtr::new_with_vm_frame( + VmFrameVec::allocate(&VmAllocOptions::new(1)) + .unwrap() + .pop() + .unwrap(), + ) + .unwrap(); + let avail_frame_ptr: InFramePtr = InFramePtr::new_with_vm_frame( + VmFrameVec::allocate(&VmAllocOptions::new(1)) + .unwrap() + .pop() + .unwrap(), + ) + .unwrap(); + let used_frame_ptr: InFramePtr = InFramePtr::new_with_vm_frame( + VmFrameVec::allocate(&VmAllocOptions::new(1)) + .unwrap() + .pop() + .unwrap(), + ) + .unwrap(); + 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!(VitrioPciCommonCfg, queue_desc), + desc_frame_ptr.paddr() as u64, + ); + + cfg.write_at( + offset_of!(VitrioPciCommonCfg, queue_driver), + avail_frame_ptr.paddr() as u64, + ); + + cfg.write_at( + offset_of!(VitrioPciCommonCfg, queue_device), + used_frame_ptr.paddr() as u64, + ); + + 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)) } - if cfg.read_at(offset_of!(VitrioPciCommonCfg, queue_driver)) == 0 as u64 { - let frame = VmFrameVec::allocate(&vm_allocate_option) - .expect("cannot allocate physical frame for virtqueue") - .remove(0); - cfg.write_at( - offset_of!(VitrioPciCommonCfg, queue_driver), - frame.start_paddr() as u64, - ); - debug!("queue_driver vm frame:{:x?}", frame); - frame_vec.push(frame); - } - - if cfg.read_at(offset_of!(VitrioPciCommonCfg, queue_device)) == 0 as u64 { - let frame = VmFrameVec::allocate(&vm_allocate_option) - .expect("cannot allocate physical frame for virtqueue") - .remove(0); - cfg.write_at( - offset_of!(VitrioPciCommonCfg, queue_device), - frame.start_paddr() as u64, - ); - debug!("queue_device vm frame:{:x?}", frame); - frame_vec.push(frame); - } - - for i in 0..size { - descs.push( - InFramePtr::new( - cfg.read_at(offset_of!(VitrioPciCommonCfg, queue_desc)) as usize - + i as usize * 16, - ) - .expect("can not get Inframeptr for virtio queue Descriptor"), - ) - } - - let avail = - InFramePtr::new(cfg.read_at(offset_of!(VitrioPciCommonCfg, queue_driver)) as usize) - .expect("can not get Inframeptr for virtio queue available ring"); - let used = - InFramePtr::new(cfg.read_at(offset_of!(VitrioPciCommonCfg, queue_device)) as usize) - .expect("can not get Inframeptr for virtio queue used ring"); let notify = InFramePtr::new(notify_base_address + notify_off_multiplier as usize * idx) .expect("can not get Inframeptr for virtio queue notify"); // Link descriptors together. @@ -149,12 +136,12 @@ impl VirtQueue { let temp = descs.get(i as usize).unwrap(); temp.write_at(offset_of!(Descriptor, next), i + 1); } - avail.write_at(offset_of!(AvailRing, flags), 0 as u16); + avail_frame_ptr.write_at(offset_of!(AvailRing, flags), 0 as u16); cfg.write_at(offset_of!(VitrioPciCommonCfg, queue_enable), 1 as u16); Ok(VirtQueue { descs, - avail, - used, + avail: avail_frame_ptr, + used: used_frame_ptr, notify, queue_size: size, queue_idx: idx as u32, @@ -162,7 +149,6 @@ impl VirtQueue { free_head: 0, avail_idx: 0, last_used_idx: 0, - physical_frame_store: frame_vec, }) } @@ -346,8 +332,6 @@ impl Descriptor { fn set_buf(inframe_ptr: &InFramePtr, buf: &[u8]) { let va = buf.as_ptr() as usize; let pa = jinux_frame::vm::vaddr_to_paddr(va).unwrap(); - debug!("set buf write virt address:{:x}", va); - debug!("set buf write phys address:{:x}", pa); inframe_ptr.write_at(offset_of!(Descriptor, addr), pa as u64); inframe_ptr.write_at(offset_of!(Descriptor, len), buf.len() as u32); } diff --git a/services/libs/jinux-std/src/vm/vmo/mod.rs b/services/libs/jinux-std/src/vm/vmo/mod.rs index 9717d80fe..311868de2 100644 --- a/services/libs/jinux-std/src/vm/vmo/mod.rs +++ b/services/libs/jinux-std/src/vm/vmo/mod.rs @@ -4,7 +4,7 @@ use core::ops::Range; use crate::rights::Rights; use align_ext::AlignExt; -use jinux_frame::vm::{Paddr, VmAllocOptions, VmFrameVec, VmIo}; +use jinux_frame::vm::{VmAllocOptions, VmFrameVec, VmIo}; use crate::prelude::*; @@ -142,8 +142,6 @@ pub(super) struct Vmo_ { inner: Mutex, /// Parent Vmo parent: Weak, - /// paddr - paddr: Option, /// vmo type vmo_type: VmoType, } @@ -419,10 +417,6 @@ impl Vmo_ { Ok(()) } - pub fn paddr(&self) -> Option { - self.paddr - } - pub fn flags(&self) -> VmoFlags { self.flags.clone() } @@ -434,12 +428,6 @@ impl Vmo { self.0.size() } - /// Returns the starting physical address of a VMO, if it is contiguous. - /// Otherwise, returns none. - pub fn paddr(&self) -> Option { - self.0.paddr() - } - /// Returns the flags of a VMO. pub fn flags(&self) -> VmoFlags { self.0.flags() diff --git a/services/libs/jinux-std/src/vm/vmo/options.rs b/services/libs/jinux-std/src/vm/vmo/options.rs index d003400ee..e9d2c1dc1 100644 --- a/services/libs/jinux-std/src/vm/vmo/options.rs +++ b/services/libs/jinux-std/src/vm/vmo/options.rs @@ -4,7 +4,7 @@ use core::marker::PhantomData; use core::ops::Range; use align_ext::AlignExt; -use jinux_frame::vm::{Paddr, VmAllocOptions, VmFrameVec}; +use jinux_frame::vm::{VmAllocOptions, VmFrameVec}; use jinux_rights_proc::require; use typeflags_util::{SetExtend, SetExtendOp}; @@ -54,7 +54,6 @@ use super::{Pager, Vmo, VmoFlags}; /// ``` pub struct VmoOptions { size: usize, - paddr: Option, flags: VmoFlags, rights: Option, pager: Option>, @@ -68,25 +67,12 @@ impl VmoOptions { pub fn new(size: usize) -> Self { Self { size, - paddr: None, flags: VmoFlags::empty(), rights: None, pager: None, } } - /// Sets the starting physical address of the VMO. - /// - /// By default, this option is not set. - /// - /// If this option is set, then the underlying pages of VMO must be contiguous. - /// So `VmoFlags::IS_CONTIGUOUS` will be set automatically. - pub fn paddr(mut self, paddr: Paddr) -> Self { - self.paddr = Some(paddr); - self.flags |= VmoFlags::CONTIGUOUS; - self - } - /// Sets the VMO flags. /// /// The default value is `VmoFlags::empty()`. @@ -112,13 +98,9 @@ impl VmoOptions { /// The VMO is initially assigned full access rights. pub fn alloc(self) -> Result> { let VmoOptions { - size, - paddr, - flags, - pager, - .. + size, flags, pager, .. } = self; - let vmo_ = alloc_vmo_(size, paddr, flags, pager)?; + let vmo_ = alloc_vmo_(size, flags, pager)?; Ok(Vmo(Arc::new(vmo_), Rights::all())) } } @@ -133,24 +115,18 @@ impl VmoOptions { pub fn alloc(self) -> Result> { let VmoOptions { size, - paddr, flags, rights, pager, } = self; - let vmo_ = alloc_vmo_(size, paddr, flags, pager)?; + let vmo_ = alloc_vmo_(size, flags, pager)?; Ok(Vmo(Arc::new(vmo_), R::new())) } } -fn alloc_vmo_( - size: usize, - paddr: Option, - flags: VmoFlags, - pager: Option>, -) -> Result { +fn alloc_vmo_(size: usize, flags: VmoFlags, pager: Option>) -> Result { let size = size.align_up(PAGE_SIZE); - let committed_pages = committed_pages_if_continuous(flags, size, paddr)?; + let committed_pages = committed_pages_if_continuous(flags, size)?; let vmo_inner = VmoInner { pager, size, @@ -161,7 +137,6 @@ fn alloc_vmo_( flags, inner: Mutex::new(vmo_inner), parent: Weak::new(), - paddr, vmo_type: VmoType::NotChild, }) } @@ -169,14 +144,12 @@ fn alloc_vmo_( fn committed_pages_if_continuous( flags: VmoFlags, size: usize, - paddr: Option, ) -> Result> { if flags.contains(VmoFlags::CONTIGUOUS) { // if the vmo is continuous, we need to allocate frames for the vmo let frames_num = size / PAGE_SIZE; let mut vm_alloc_option = VmAllocOptions::new(frames_num); vm_alloc_option.is_contiguous(true); - vm_alloc_option.paddr(paddr); let frames = VmFrameVec::allocate(&vm_alloc_option)?; let mut committed_pages = BTreeMap::new(); for (idx, frame) in frames.into_iter().enumerate() { @@ -500,9 +473,6 @@ fn alloc_child_vmo_( committed_pages: BTreeMap::new(), inherited_pages, }; - let child_paddr = parent_vmo_ - .paddr() - .map(|parent_paddr| parent_paddr + child_vmo_start); let vmo_type = match child_type { ChildType::Cow => VmoType::CopyOnWriteChild, ChildType::Slice => VmoType::SliceChild, @@ -511,7 +481,6 @@ fn alloc_child_vmo_( flags: child_flags, inner: Mutex::new(vmo_inner), parent: Arc::downgrade(&parent_vmo_), - paddr: child_paddr, vmo_type, }) } diff --git a/services/libs/jinux-util/src/frame_ptr.rs b/services/libs/jinux-util/src/frame_ptr.rs index 925b148d6..8437e3c9d 100644 --- a/services/libs/jinux-util/src/frame_ptr.rs +++ b/services/libs/jinux-util/src/frame_ptr.rs @@ -1,47 +1,74 @@ +extern crate alloc; + use core::marker::PhantomData; +use alloc::sync::Arc; use jinux_frame::{ - config::PAGE_SIZE, - vm::{Paddr, VmAllocOptions, VmFrame, VmFrameVec, VmIo}, + mmio::Mmio, + vm::{Paddr, VmFrame, VmIo}, Result, }; use pod::Pod; +#[derive(Debug, Clone)] +enum InFramePtrAccessMethod { + Mmio(Mmio), + VmFrame(Arc), +} + /// An in-frame pointer to a POD value, enabling safe access /// to a POD value given its physical memory address. #[derive(Debug)] pub struct InFramePtr { - frame: VmFrame, + access_method: InFramePtrAccessMethod, offset: usize, marker: PhantomData<&'static mut T>, } impl InFramePtr { + /// This function only allow the physical address in the MMIO region. + /// + /// Panic if the physical address is not in MMIO region. pub fn new(paddr: Paddr) -> Result { - let frame = { - let page_paddr = paddr & !(PAGE_SIZE - 1); - let mut options = VmAllocOptions::new(1); - options.paddr(Some(page_paddr)); - VmFrameVec::allocate(&options)?.remove(0) - }; - let offset = paddr - frame.start_paddr(); + let limit = core::mem::size_of::(); Ok(Self { - frame, - offset, + access_method: InFramePtrAccessMethod::Mmio( + jinux_frame::mmio::Mmio::new(paddr..paddr + limit).unwrap(), + ), + offset: 0, + marker: PhantomData, + }) + } + + /// Creating a pointer to the inside of VmFrame. + pub fn new_with_vm_frame(vm_frame_vec: VmFrame) -> Result { + Ok(Self { + access_method: InFramePtrAccessMethod::VmFrame(Arc::new(vm_frame_vec)), + offset: 0, marker: PhantomData, }) } pub fn read_at(&self, offset: *const F) -> F { - self.frame - .read_val::(self.offset + offset as usize) - .expect("read data from frame failed") + match &self.access_method { + InFramePtrAccessMethod::Mmio(mmio) => mmio + .read_val::(self.offset + offset as usize) + .expect("write data from frame failed"), + InFramePtrAccessMethod::VmFrame(vm_frame) => vm_frame + .read_val::(self.offset + offset as usize) + .expect("write data from frame failed"), + } } pub fn write_at(&self, offset: *const F, new_val: F) { - self.frame - .write_val::(self.offset + offset as usize, &new_val) - .expect("write data from frame failed"); + match &self.access_method { + InFramePtrAccessMethod::Mmio(mmio) => mmio + .write_val::(self.offset + offset as usize, &new_val) + .expect("write data from frame failed"), + InFramePtrAccessMethod::VmFrame(vm_frame) => vm_frame + .write_val::(self.offset + offset as usize, &new_val) + .expect("write data from frame failed"), + } } pub fn offset(&self) -> usize { @@ -49,6 +76,59 @@ impl InFramePtr { } pub fn paddr(&self) -> usize { - self.offset + self.frame.start_paddr() + match &self.access_method { + InFramePtrAccessMethod::Mmio(mmio) => self.offset + mmio.paddr(), + InFramePtrAccessMethod::VmFrame(vm_frame) => self.offset + vm_frame.start_paddr(), + } + } + + /// Clone self and then change the offset to the next `count` one. + /// + /// User can use this function to easily visit POD array. For example: + /// + /// ```rust + /// use pod::Pod + /// + /// #[derive(Pod)] + /// struct Foo{ + /// value1: usize, + /// value2: usize, + /// } + /// + /// fn visit(){ + /// // visit array [Foo1, Foo2, Foo3] + /// let Foo1 : InFramePtr = InFramePtr::alloc().unwrap(); + /// let Foo2 = Foo1.add(1); + /// let Foo3 = Foo2.add(1); + /// } + /// + /// ``` + /// + pub fn add(&self, count: usize) -> Self { + let mut next: InFramePtr = self.clone(); + next.access_method = match next.access_method { + InFramePtrAccessMethod::Mmio(mmio) => InFramePtrAccessMethod::Mmio( + jinux_frame::mmio::Mmio::new( + mmio.paddr() + count * core::mem::size_of::() + ..mmio.paddr() + (count + 1) * core::mem::size_of::(), + ) + .unwrap(), + ), + InFramePtrAccessMethod::VmFrame(_) => { + next.offset += core::mem::size_of::() * count; + next.access_method + } + }; + next + } +} + +impl Clone for InFramePtr { + fn clone(&self) -> Self { + Self { + access_method: self.access_method.clone(), + offset: self.offset, + marker: self.marker, + } } }