diff --git a/common/src/dma.rs b/common/src/dma.rs index c2ecbc37fc..3a092f1024 100644 --- a/common/src/dma.rs +++ b/common/src/dma.rs @@ -86,6 +86,16 @@ impl Dma<[T]> { Ok(Dma { phys, aligned_len, virt: ptr::slice_from_raw_parts_mut(virt.cast(), count) }) } + pub unsafe fn cast_slice(self) -> Dma<[U]> { + let Dma { phys, virt, aligned_len } = self; + core::mem::forget(self); + + Dma { + phys, + virt: virt as *mut [U], + aligned_len, + } + } } impl Dma<[MaybeUninit]> { pub unsafe fn assume_init(self) -> Dma<[T]> { diff --git a/ihdad/src/hda/cmdbuff.rs b/ihdad/src/hda/cmdbuff.rs index a401a1053a..a4af7820d7 100644 --- a/ihdad/src/hda/cmdbuff.rs +++ b/ihdad/src/hda/cmdbuff.rs @@ -1,3 +1,4 @@ +use common::dma::Dma; use syscall::io::{Io, Mmio}; use super::common::*; @@ -345,31 +346,33 @@ pub struct CommandBuffer { corb_rirb_base_phys: usize, use_immediate_cmd: bool, + mem: Dma<[u8; 0x1000]>, } impl CommandBuffer { pub fn new( regs_addr: usize, - cmd_buff_frame_phys: usize, - cmd_buff_frame: usize, + cmd_buff: Dma<[u8; 0x1000]>, ) -> CommandBuffer { - let corb = Corb::new(regs_addr + CORB_OFFSET, cmd_buff_frame_phys, cmd_buff_frame); + let corb = Corb::new(regs_addr + CORB_OFFSET, cmd_buff.physical(), cmd_buff.as_ptr() as usize); let rirb = Rirb::new( regs_addr + RIRB_OFFSET, - cmd_buff_frame_phys + CORB_BUFF_MAX_SIZE, - cmd_buff_frame + CORB_BUFF_MAX_SIZE, + cmd_buff.as_ptr() as usize + CORB_BUFF_MAX_SIZE, + cmd_buff.physical() + CORB_BUFF_MAX_SIZE, ); let icmd = ImmediateCommand::new(regs_addr + ICMD_OFFSET); let cmdbuff = CommandBuffer { - corb: corb, - rirb: rirb, - icmd: icmd, + corb, + rirb, + icmd, - corb_rirb_base_phys: cmd_buff_frame_phys, + corb_rirb_base_phys: cmd_buff.physical(), use_immediate_cmd: false, + + mem: cmd_buff, }; cmdbuff diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index 718ab6ed73..09d2c56bfb 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -7,6 +7,7 @@ use std::str; use std::collections::BTreeMap; use std::sync::atomic::{AtomicUsize, Ordering}; +use common::dma::Dma; use syscall::error::{Error, EACCES, EBADF, Result, EINVAL}; use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; use syscall::io::{Mmio, Io}; @@ -137,8 +138,7 @@ pub struct IntelHDA { beep_addr: WidgetAddr, - buff_desc: &'static mut [BufferDescriptorListEntry; 256], - buff_desc_phys: usize, + buff_desc: Dma<[BufferDescriptorListEntry; 256]>, output_streams: Vec, @@ -153,31 +153,23 @@ impl IntelHDA { pub unsafe fn new(base: usize, vend_prod:u32) -> Result { let regs = &mut *(base as *mut Regs); - let buff_desc_phys = - syscall::physalloc(0x1000) - .expect("Could not allocate physical memory for buffer descriptor list."); + let buff_desc = Dma::<[BufferDescriptorListEntry; 256]>::zeroed() + .expect("Could not allocate physical memory for buffer descriptor list.") + .assume_init(); - let buff_desc_virt = - common::physmap(buff_desc_phys, 0x1000, common::Prot::RW, common::MemoryType::Uncacheable) - .expect("ihdad: failed to map address for buffer descriptor list.") as usize; + log::debug!("Virt: {:016X}, Phys: {:016X}", buff_desc.as_ptr() as usize, buff_desc.physical()); - log::debug!("Virt: {:016X}, Phys: {:016X}", buff_desc_virt, buff_desc_phys); + let cmd_buff = Dma::<[u8; 0x1000]>::zeroed() + .expect("Could not allocate physical memory for CORB and RIRB.") + .assume_init(); - let buff_desc = &mut *(buff_desc_virt as *mut [BufferDescriptorListEntry;256]); - - let cmd_buff_address = - syscall::physalloc(0x1000) - .expect("Could not allocate physical memory for CORB and RIRB."); - - let cmd_buff_virt = common::physmap(cmd_buff_address, 0x1000, common::Prot::RW, common::MemoryType::Uncacheable).expect("ihdad: failed to map address for CORB/RIRB buff") as usize; - - log::debug!("Virt: {:016X}, Phys: {:016X}", cmd_buff_virt, cmd_buff_address); + log::debug!("Virt: {:016X}, Phys: {:016X}", cmd_buff.as_ptr() as usize, cmd_buff.physical()); let mut module = IntelHDA { - vend_prod: vend_prod, - base: base, - regs: regs, + vend_prod, + base, + regs, - cmd: CommandBuffer::new(base + COMMAND_BUFFER_OFFSET, cmd_buff_address, cmd_buff_virt), + cmd: CommandBuffer::new(base + COMMAND_BUFFER_OFFSET, cmd_buff), beep_addr: (0,0), @@ -191,8 +183,7 @@ impl IntelHDA { output_pins: Vec::::new(), input_pins: Vec::::new(), - buff_desc: buff_desc, - buff_desc_phys: buff_desc_phys, + buff_desc, output_streams: Vec::::new(), @@ -498,7 +489,7 @@ impl IntelHDA { // Create output stream let output = self.get_output_stream_descriptor(0).unwrap(); - output.set_address(self.buff_desc_phys); + output.set_address(self.buff_desc.physical()); output.set_pcm_format(&super::SR_44_1, BitsPerSample::Bits16, 2); output.set_cyclic_buffer_length((NUM_SUB_BUFFS * SUB_BUFF_SIZE) as u32); // number of bytes output.set_stream_number(1); diff --git a/ihdad/src/hda/stream.rs b/ihdad/src/hda/stream.rs index 62acd2c6d5..afad58a609 100644 --- a/ihdad/src/hda/stream.rs +++ b/ihdad/src/hda/stream.rs @@ -1,3 +1,4 @@ +use common::dma::Dma; use syscall::PAGE_SIZE; use syscall::error::{Error, EIO, Result}; use syscall::io::{Mmio, Io}; @@ -281,8 +282,7 @@ impl BufferDescriptorListEntry { } pub struct StreamBuffer { - phys: usize, - addr: usize, + mem: Dma<[u8]>, block_cnt: usize, block_len: usize, @@ -293,36 +293,10 @@ pub struct StreamBuffer { impl StreamBuffer { pub fn new(block_length: usize, block_count: usize) -> result::Result { let page_aligned_size = (block_length * block_count).next_multiple_of(PAGE_SIZE); - - let phys = match unsafe { - syscall::physalloc(page_aligned_size) - } { - Ok(phys) => phys, - Err(_err) => { - return Err("Could not allocate physical memory for buffer."); - } - }; - - let addr = match unsafe { - common::physmap(phys, page_aligned_size, common::Prot::RW, common::MemoryType::Uncacheable) - } { - Ok(ptr) => ptr as usize, - Err(_err) => { - unsafe { - syscall::physfree(phys, page_aligned_size); - } - return Err("Could not map physical memory for buffer."); - } - }; - - // TODO: Already zeroed by kernel? - unsafe { - ptr::write_bytes(addr as *mut u8, 0, block_length * block_count); - } + let mem = unsafe { Dma::zeroed_slice(page_aligned_size).map_err(|_| "Could not allocate physical memory for buffer.")?.assume_init() }; Ok(StreamBuffer { - phys: phys, - addr: addr, + mem, block_len: block_length, block_cnt: block_count, cur_pos: 0, @@ -334,11 +308,11 @@ impl StreamBuffer { } pub fn addr(&self) -> usize { - self.addr + self.mem.as_ptr() as usize } pub fn phys(&self) -> usize { - self.phys + self.mem.physical() } pub fn block_size(&self) -> usize { @@ -374,13 +348,6 @@ impl StreamBuffer { } impl Drop for StreamBuffer { fn drop(&mut self) { - unsafe { - log::debug!("IHDA: Deallocating buffer."); - let page_aligned_size = (self.block_len * self.block_cnt).next_multiple_of(PAGE_SIZE); - - if syscall::funmap(self.addr, page_aligned_size).is_ok() { - let _ = syscall::physfree(self.phys, page_aligned_size); - } - } + log::debug!("IHDA: Deallocating buffer."); } } diff --git a/virtio-core/src/legacy_transport.rs b/virtio-core/src/legacy_transport.rs index f2d7535ad0..e0a98e784f 100644 --- a/virtio-core/src/legacy_transport.rs +++ b/virtio-core/src/legacy_transport.rs @@ -3,7 +3,7 @@ use std::{sync::{Weak, atomic::{AtomicU16, Ordering}, Arc}, mem::size_of, fs::Fi use common::dma::Dma; use syscall::{Pio, Io}; -use crate::{transport::{NotifyBell, Transport, Queue, Error, Available, Used, queue_part_sizes, spawn_irq_thread}, spec::{Descriptor, DeviceStatusFlags}}; +use crate::{transport::{NotifyBell, Transport, Queue, Error, Available, Used, queue_part_sizes, spawn_irq_thread, Mem, Borrowed}, spec::{Descriptor, DeviceStatusFlags}}; pub enum LegacyRegister { @@ -123,10 +123,12 @@ impl Transport for LegacyTransport { }; let avail_addr = descriptor.physical() + desc_size; - let avail = unsafe { Available::from_raw(avail_addr, avail_size, queue_size)? }; + let avail_virt = (descriptor.as_ptr() as usize) + desc_size; + let avail = unsafe { Available::from_raw(Mem::Borrowed(Borrowed::new(avail_addr, avail_virt, avail_size)), queue_size)? }; let used_addr = avail_addr + avail_size; - let used = unsafe { Used::from_raw(used_addr, used_size, queue_size)? }; + let used_virt = avail_virt + desc_size; + let used = unsafe { Used::from_raw(Mem::Borrowed(Borrowed::new(used_addr, used_virt, used_size)), queue_size)? }; self.write::(LegacyRegister::QueueMsixVector, vector); self.write::(LegacyRegister::QueueAddress, (descriptor.physical() as u32) >> 12); diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index 7a2c662d10..a324a288cc 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -263,33 +263,68 @@ unsafe impl Sync for Queue<'_> {} unsafe impl Send for Queue<'_> {} pub struct Available<'a> { - addr: usize, - size: usize, - + mem: Mem<'a>, queue_size: usize, - - ring: &'a mut AvailableRing, +} +pub struct Borrowed<'a> { + phys: usize, + virt: usize, + size: usize, + _unused: &'a (), +} +pub enum Mem<'a> { + Owned(Dma<[u8]>), + Borrowed(Borrowed<'a>), +} +impl Borrowed<'_> { + pub unsafe fn new(phys: usize, virt: usize, size: usize) -> Self { + Self { + phys, + virt, + size, + _unused: &(), + } + } +} +impl<'a> Mem<'a> { + pub fn as_ptr(&self) -> *const T { + match *self { + Self::Owned(ref dma) => dma.as_ptr().cast(), + Self::Borrowed(Borrowed { phys, virt, size, _unused }) => virt as *const T, + } + } + pub fn as_mut_ptr(&mut self) -> *mut T { + match *self { + Self::Owned(ref mut dma) => dma.as_mut_ptr().cast(), + Self::Borrowed(Borrowed { phys, virt, size, _unused }) => virt as *mut T, + } + } + pub fn physical(&self) -> usize { + match self { + Self::Owned(dma) => dma.physical(), + Self::Borrowed(borrowed) => borrowed.phys, + } + } } impl<'a> Available<'a> { + pub fn ring(&self) -> &AvailableRing { + unsafe { &*self.mem.as_ptr() } + } + pub fn ring_mut(&mut self) -> &mut AvailableRing { + unsafe { &mut *self.mem.as_mut_ptr() } + } pub fn new(queue_size: usize) -> Result { let (_, _, size) = queue_part_sizes(queue_size); - let addr = unsafe { syscall::physalloc(size) }.map_err(Error::SyscallError)?; + let mem = unsafe { Dma::zeroed_slice(size).map_err(Error::SyscallError)?.assume_init() }; - unsafe { Self::from_raw(addr, size, queue_size) } + unsafe { Self::from_raw(Mem::Owned(mem), queue_size) } } /// `addr` is the physical address of the ring. - pub unsafe fn from_raw(addr: usize, size: usize, queue_size: usize) -> Result { - let virt = unsafe { - common::physmap(addr, size, common::Prot::RW, common::MemoryType::default()) - }?; - - let ring = unsafe { &mut *(virt as *mut AvailableRing) }; + pub unsafe fn from_raw(mem: Mem<'a>, queue_size: usize) -> Result { let ring = Self { - addr, - size, - ring, + mem, queue_size, }; @@ -310,7 +345,7 @@ impl<'a> Available<'a> { // SAFETY: We have exclusive access to the elements and the number of elements // is correct; same as the queue size. unsafe { - self.ring + self.ring() .elements .as_slice(self.queue_size) .get(index % self.queue_size) @@ -319,58 +354,51 @@ impl<'a> Available<'a> { } pub fn head_index(&self) -> u16 { - self.ring.head_index.load(Ordering::SeqCst) + self.ring().head_index.load(Ordering::SeqCst) } pub fn set_head_idx(&self, index: u16) { - self.ring.head_index.store(index, Ordering::SeqCst); + self.ring().head_index.store(index, Ordering::SeqCst); } pub fn phys_addr(&self) -> usize { - self.addr + self.mem.physical() } } -impl Drop for Available<'_> { +impl<'a> Drop for Available<'a> { fn drop(&mut self) { - log::warn!("virtio-core: dropping 'available' ring at {:#x}", self.addr); - - unsafe { - syscall::funmap(self.addr, self.size).unwrap(); - syscall::physfree(self.addr, self.size).unwrap(); - } + log::warn!("virtio-core: dropping 'available' ring at {:#x}", self.phys_addr()); } } pub struct Used<'a> { - addr: usize, - size: usize, - + mem: Mem<'a>, queue_size: usize, - - ring: &'a mut UsedRing, + _unused: &'a (), } impl<'a> Used<'a> { + fn ring(&self) -> &UsedRing { + unsafe { &*self.mem.as_ptr() } + } + fn ring_mut(&mut self) -> &mut UsedRing { + unsafe { &mut *self.mem.as_mut_ptr() } + } + pub fn new(queue_size: usize) -> Result { let (_, _, size) = queue_part_sizes(queue_size); - let addr = unsafe { syscall::physalloc(size) }.map_err(Error::SyscallError)?; + let mem = unsafe { Dma::zeroed_slice(size).map_err(Error::SyscallError)?.assume_init() }; - unsafe { Self::from_raw(addr, size, queue_size) } + unsafe { Self::from_raw(Mem::Owned(mem), queue_size) } } /// `addr` is the physical address of the ring. - pub unsafe fn from_raw(addr: usize, size: usize, queue_size: usize) -> Result { - let virt = unsafe { - common::physmap(addr, size, common::Prot::RW, common::MemoryType::default()) - }?; - - let ring = unsafe { &mut *(virt as *mut UsedRing) }; + pub unsafe fn from_raw(mem: Mem<'a>, queue_size: usize) -> Result { let mut ring = Self { - addr, - size, - ring, + mem, queue_size, + _unused: &(), }; for i in 0..queue_size { @@ -388,7 +416,7 @@ impl<'a> Used<'a> { // SAFETY: We have exclusive access to the elements and the number of elements // is correct; same as the queue size. unsafe { - self.ring + self.ring() .elements .as_slice(self.queue_size) .get(index % self.queue_size) @@ -401,36 +429,32 @@ impl<'a> Used<'a> { pub fn get_mut_element_at(&mut self, index: usize) -> &mut UsedRingElement { // SAFETY: We have exclusive access to the elements and the number of elements // is correct; same as the queue size. + let queue_size = self.queue_size; unsafe { - self.ring + self.ring_mut() .elements - .as_mut_slice(self.queue_size) + .as_mut_slice(queue_size) .get_mut(index % 256) .expect("virtio-core::used: index out of bounds") } } pub fn flags(&self) -> u16 { - self.ring.flags.get() + self.ring().flags.get() } pub fn head_index(&self) -> u16 { - self.ring.head_index.get() + self.ring().head_index.get() } pub fn phys_addr(&self) -> usize { - self.addr + self.mem.physical() } } impl Drop for Used<'_> { fn drop(&mut self) { - log::warn!("virtio-core: dropping 'used' ring at {:#x}", self.addr); - - unsafe { - syscall::funmap(self.addr, self.size).unwrap(); - syscall::physfree(self.addr, self.size).unwrap(); - } + log::warn!("virtio-core: dropping 'used' ring at {:#x}", self.phys_addr()); } } diff --git a/virtio-gpud/src/scheme.rs b/virtio-gpud/src/scheme.rs index 30dded638f..51cd14a76a 100644 --- a/virtio-gpud/src/scheme.rs +++ b/virtio-gpud/src/scheme.rs @@ -130,21 +130,18 @@ impl<'a> Display<'a> { let bpp = 32; let fb_size = (self.width as usize * self.height as usize * bpp / 8) .next_multiple_of(syscall::PAGE_SIZE); - let address = unsafe { syscall::physalloc(fb_size) }?; - let mapped = unsafe { - common::physmap( - address as usize, - fb_size, - common::Prot::RW, - common::MemoryType::default(), - ) - }? as usize; + let mut mapped = unsafe { Dma::zeroed_slice(fb_size)?.assume_init() }; unsafe { - core::ptr::write_bytes(mapped as *mut u8, 255, fb_size); + core::ptr::write_bytes(mapped.as_mut_ptr() as *mut u8, 255, fb_size); } - self.map_screen_with(offset, address, fb_size, mapped).await + let virt = mapped.as_mut_ptr() as usize; + let phys = mapped.physical(); + core::mem::forget(mapped); + // TODO: Keep Dma + + self.map_screen_with(offset, phys, fb_size, virt).await } async fn map_screen_with( diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index 4656a826fb..3779218c28 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; use log::debug; +use syscall::PAGE_SIZE; use syscall::error::Result; use syscall::io::{Io, Mmio}; @@ -178,18 +179,18 @@ impl ScratchpadBufferEntry { pub struct ScratchpadBufferArray { pub entries: Dma<[ScratchpadBufferEntry]>, - pub pages: Vec, + pub pages: Vec>, } impl ScratchpadBufferArray { - pub fn new(ac64: bool, page_size: usize, entries: u16) -> Result { + pub fn new(ac64: bool, entries: u16) -> Result { let mut entries = unsafe { Xhci::alloc_dma_zeroed_unsized_raw(ac64, entries as usize)? }; - let pages = entries.iter_mut().map(|entry: &mut ScratchpadBufferEntry| -> Result { - let pointer = unsafe { syscall::physalloc(page_size)? }; - assert_eq!((pointer as u64) & 0xFFFF_FFFF_FFFF_F000, pointer as u64, "physically allocated pointer (physalloc) wasn't 4k page-aligned"); - entry.set_addr(pointer as u64); - Ok(pointer) - }).collect::, _>>()?; + let pages = entries.iter_mut().map(|entry: &mut ScratchpadBufferEntry| { + let dma = unsafe { Dma::<[u8; PAGE_SIZE]>::zeroed()?.assume_init() }; + assert_eq!(dma.physical() % PAGE_SIZE, 0); + entry.set_addr(dma.physical() as u64); + Ok(dma) + }).collect::, _>>()?; Ok(Self { entries, diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index afe56101b8..aaf8b453c1 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -9,6 +9,7 @@ use std::sync::atomic::{AtomicBool, AtomicUsize}; use std::{mem, process, slice, sync::atomic, task, thread}; +use syscall::PAGE_SIZE; use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT, EIO}; use syscall::flag::{O_RDONLY, PhysallocFlags}; use syscall::io::Io; @@ -176,7 +177,7 @@ impl Xhci { pub struct Xhci { // immutable cap: &'static CapabilityRegs, - page_size: usize, + //page_size: usize, // XXX: It would be really useful to be able to mutably access individual elements of a slice, // without having to wrap every element in a lock (which wouldn't work since they're packed). @@ -248,12 +249,12 @@ impl Xhci { let cap = unsafe { &mut *(address as *mut CapabilityRegs) }; debug!("CAP REGS BASE {:X}", address); - let page_size = { + /*let page_size = { let memory_fd = syscall::open("memory:", O_RDONLY)?; let mut stat = syscall::data::StatVfs::default(); syscall::fstatvfs(memory_fd, &mut stat)?; stat.f_bsize as usize - }; + };*/ let op_base = address + cap.len.read() as usize; let op = unsafe { &mut *(op_base as *mut OperationalRegs) }; @@ -306,7 +307,7 @@ impl Xhci { // Create the command ring with 4096 / 16 (TRB size) entries, so that it uses all of the // DMA allocation (which is at least a 4k page). - let entries_per_page = page_size / mem::size_of::(); + let entries_per_page = PAGE_SIZE / mem::size_of::(); let cmd = Ring::new(cap.ac64(), entries_per_page, true)?; let (irq_reactor_sender, irq_reactor_receiver) = crossbeam_channel::unbounded(); @@ -315,7 +316,7 @@ impl Xhci { base: address as *const u8, cap, - page_size, + //page_size, op: Mutex::new(op), ports: Mutex::new(ports), @@ -459,7 +460,7 @@ impl Xhci { if buf_count == 0 { return Ok(()); } - let scratchpad_buf_arr = ScratchpadBufferArray::new(self.cap.ac64(), self.page_size,buf_count)?; + let scratchpad_buf_arr = ScratchpadBufferArray::new(self.cap.ac64(), buf_count)?; self.dev_ctx.dcbaa[0] = scratchpad_buf_arr.register() as u64; debug!("Setting up {} scratchpads, at {:#0x}", buf_count, scratchpad_buf_arr.register()); self.scratchpad_buf_arr = Some(scratchpad_buf_arr);