mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-10 13:56:48 +00:00
Change physical address accees to MMIO
This commit is contained in:
parent
5656805520
commit
42ecbe1b04
@ -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<Paddr>,
|
||||
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<Paddr>) -> &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<T: Pod>(&self, offset: usize) -> Result<T> {
|
||||
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<T: Pod>(&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(())
|
||||
}
|
||||
}
|
||||
|
@ -41,43 +41,6 @@ pub fn alloc_continuous(frame_count: usize) -> Option<Vec<VmFrame>> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn alloc_with_paddr(paddr: Paddr) -> Option<VmFrame> {
|
||||
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<usize>) -> 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<VmFrame> {
|
||||
let frame = alloc()?;
|
||||
frame.zero();
|
||||
|
@ -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<u8> = 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
|
||||
|
@ -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<MSIXTableEntry> =
|
||||
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<MSIXTableEntry> =
|
||||
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
|
||||
}
|
||||
|
@ -267,6 +267,10 @@ impl PCIVirtioDevice {
|
||||
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;
|
||||
|
||||
// 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);
|
||||
|
@ -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<VmFrame>,
|
||||
}
|
||||
|
||||
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<Descriptor> = InFramePtr::new_with_vm_frame(
|
||||
VmFrameVec::allocate(&VmAllocOptions::new(1))
|
||||
.unwrap()
|
||||
.pop()
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
let avail_frame_ptr: InFramePtr<AvailRing> = InFramePtr::new_with_vm_frame(
|
||||
VmFrameVec::allocate(&VmAllocOptions::new(1))
|
||||
.unwrap()
|
||||
.pop()
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
let used_frame_ptr: InFramePtr<UsedRing> = 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<Descriptor>, 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);
|
||||
}
|
||||
|
@ -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<VmoInner>,
|
||||
/// Parent Vmo
|
||||
parent: Weak<Vmo_>,
|
||||
/// paddr
|
||||
paddr: Option<Paddr>,
|
||||
/// vmo type
|
||||
vmo_type: VmoType,
|
||||
}
|
||||
@ -419,10 +417,6 @@ impl Vmo_ {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn paddr(&self) -> Option<Paddr> {
|
||||
self.paddr
|
||||
}
|
||||
|
||||
pub fn flags(&self) -> VmoFlags {
|
||||
self.flags.clone()
|
||||
}
|
||||
@ -434,12 +428,6 @@ impl<R> Vmo<R> {
|
||||
self.0.size()
|
||||
}
|
||||
|
||||
/// Returns the starting physical address of a VMO, if it is contiguous.
|
||||
/// Otherwise, returns none.
|
||||
pub fn paddr(&self) -> Option<Paddr> {
|
||||
self.0.paddr()
|
||||
}
|
||||
|
||||
/// Returns the flags of a VMO.
|
||||
pub fn flags(&self) -> VmoFlags {
|
||||
self.0.flags()
|
||||
|
@ -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<R = Rights> {
|
||||
size: usize,
|
||||
paddr: Option<Paddr>,
|
||||
flags: VmoFlags,
|
||||
rights: Option<R>,
|
||||
pager: Option<Arc<dyn Pager>>,
|
||||
@ -68,25 +67,12 @@ impl<R> VmoOptions<R> {
|
||||
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<Rights> {
|
||||
/// The VMO is initially assigned full access rights.
|
||||
pub fn alloc(self) -> Result<Vmo<Rights>> {
|
||||
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<R: TRights> VmoOptions<R> {
|
||||
pub fn alloc(self) -> Result<Vmo<R>> {
|
||||
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<Paddr>,
|
||||
flags: VmoFlags,
|
||||
pager: Option<Arc<dyn Pager>>,
|
||||
) -> Result<Vmo_> {
|
||||
fn alloc_vmo_(size: usize, flags: VmoFlags, pager: Option<Arc<dyn Pager>>) -> Result<Vmo_> {
|
||||
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<Paddr>,
|
||||
) -> Result<BTreeMap<usize, VmFrameVec>> {
|
||||
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,
|
||||
})
|
||||
}
|
||||
|
@ -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<VmFrame>),
|
||||
}
|
||||
|
||||
/// 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<T: 'static> {
|
||||
frame: VmFrame,
|
||||
access_method: InFramePtrAccessMethod,
|
||||
offset: usize,
|
||||
marker: PhantomData<&'static mut T>,
|
||||
}
|
||||
|
||||
impl<T: Pod> InFramePtr<T> {
|
||||
/// 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<Self> {
|
||||
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::<T>();
|
||||
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<Self> {
|
||||
Ok(Self {
|
||||
access_method: InFramePtrAccessMethod::VmFrame(Arc::new(vm_frame_vec)),
|
||||
offset: 0,
|
||||
marker: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn read_at<F: Pod>(&self, offset: *const F) -> F {
|
||||
self.frame
|
||||
.read_val::<F>(self.offset + offset as usize)
|
||||
.expect("read data from frame failed")
|
||||
match &self.access_method {
|
||||
InFramePtrAccessMethod::Mmio(mmio) => mmio
|
||||
.read_val::<F>(self.offset + offset as usize)
|
||||
.expect("write data from frame failed"),
|
||||
InFramePtrAccessMethod::VmFrame(vm_frame) => vm_frame
|
||||
.read_val::<F>(self.offset + offset as usize)
|
||||
.expect("write data from frame failed"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_at<F: Pod>(&self, offset: *const F, new_val: F) {
|
||||
self.frame
|
||||
.write_val::<F>(self.offset + offset as usize, &new_val)
|
||||
.expect("write data from frame failed");
|
||||
match &self.access_method {
|
||||
InFramePtrAccessMethod::Mmio(mmio) => mmio
|
||||
.write_val::<F>(self.offset + offset as usize, &new_val)
|
||||
.expect("write data from frame failed"),
|
||||
InFramePtrAccessMethod::VmFrame(vm_frame) => vm_frame
|
||||
.write_val::<F>(self.offset + offset as usize, &new_val)
|
||||
.expect("write data from frame failed"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn offset(&self) -> usize {
|
||||
@ -49,6 +76,59 @@ impl<T: Pod> InFramePtr<T> {
|
||||
}
|
||||
|
||||
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<Foo> = InFramePtr::alloc().unwrap();
|
||||
/// let Foo2 = Foo1.add(1);
|
||||
/// let Foo3 = Foo2.add(1);
|
||||
/// }
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
pub fn add(&self, count: usize) -> Self {
|
||||
let mut next: InFramePtr<T> = 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::<T>()
|
||||
..mmio.paddr() + (count + 1) * core::mem::size_of::<T>(),
|
||||
)
|
||||
.unwrap(),
|
||||
),
|
||||
InFramePtrAccessMethod::VmFrame(_) => {
|
||||
next.offset += core::mem::size_of::<T>() * count;
|
||||
next.access_method
|
||||
}
|
||||
};
|
||||
next
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Pod> Clone for InFramePtr<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
access_method: self.access_method.clone(),
|
||||
offset: self.offset,
|
||||
marker: self.marker,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user