Replace all physalloc usages with Dma.

This commit is contained in:
4lDO2
2023-11-17 19:36:28 +01:00
parent 0d99333c3f
commit ea73da92bf
9 changed files with 153 additions and 157 deletions
+10
View File
@@ -86,6 +86,16 @@ impl<T> Dma<[T]> {
Ok(Dma { phys, aligned_len, virt: ptr::slice_from_raw_parts_mut(virt.cast(), count) })
}
pub unsafe fn cast_slice<U>(self) -> Dma<[U]> {
let Dma { phys, virt, aligned_len } = self;
core::mem::forget(self);
Dma {
phys,
virt: virt as *mut [U],
aligned_len,
}
}
}
impl<T> Dma<[MaybeUninit<T>]> {
pub unsafe fn assume_init(self) -> Dma<[T]> {
+12 -9
View File
@@ -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
+16 -25
View File
@@ -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<OutputStream>,
@@ -153,31 +153,23 @@ impl IntelHDA {
pub unsafe fn new(base: usize, vend_prod:u32) -> Result<Self> {
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::<WidgetAddr>::new(),
input_pins: Vec::<WidgetAddr>::new(),
buff_desc: buff_desc,
buff_desc_phys: buff_desc_phys,
buff_desc,
output_streams: Vec::<OutputStream>::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);
+7 -40
View File
@@ -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<StreamBuffer, &'static str> {
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.");
}
}
+5 -3
View File
@@ -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::<u16>(LegacyRegister::QueueMsixVector, vector);
self.write::<u32>(LegacyRegister::QueueAddress, (descriptor.physical() as u32) >> 12);
+79 -55
View File
@@ -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<T>(&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<T>(&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<Self, Error> {
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<Self, Error> {
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<Self, Error> {
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<Self, Error> {
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<Self, Error> {
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<Self, Error> {
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());
}
}
+8 -11
View File
@@ -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(
+9 -8
View File
@@ -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<usize>,
pub pages: Vec<Dma<[u8; PAGE_SIZE]>>,
}
impl ScratchpadBufferArray {
pub fn new(ac64: bool, page_size: usize, entries: u16) -> Result<Self> {
pub fn new(ac64: bool, entries: u16) -> Result<Self> {
let mut entries = unsafe { Xhci::alloc_dma_zeroed_unsized_raw(ac64, entries as usize)? };
let pages = entries.iter_mut().map(|entry: &mut ScratchpadBufferEntry| -> Result<usize> {
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::<Result<Vec<usize>, _>>()?;
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::<Result<Vec<_>, _>>()?;
Ok(Self {
entries,
+7 -6
View File
@@ -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::<Trb>();
let entries_per_page = PAGE_SIZE / mem::size_of::<Trb>();
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);