Merge branch 'remove_physfree' into 'master'
Remove physfree See merge request redox-os/drivers!122
This commit is contained in:
@@ -74,8 +74,6 @@ This section cover the interfaces used by Redox drivers.
|
||||
### System Calls
|
||||
|
||||
- `iopl` - syscall that sets the I/O privilege level. x86 has four privilege rings (0/1/2/3), of which the kernel runs in ring 0 and userspace in ring 3. IOPL can only be changed by the kernel, for obvious security reasons, and therefore the Redox kernel needs root to set it. It is unique for each process. Processes with IOPL=3 can access I/O ports, and the kernel can access them as well.
|
||||
- `physalloc` - allocates physical memory frames.
|
||||
- `physfree` - frees memory frames.
|
||||
|
||||
### Schemes
|
||||
|
||||
|
||||
+3
-13
@@ -8,7 +8,7 @@ use syscall::error::{Error, EACCES, EBADF, Result, EINVAL, ENOENT};
|
||||
use syscall::io::{Mmio, Pio, Io};
|
||||
use syscall::scheme::SchemeBlockMut;
|
||||
|
||||
use common::dma::{Dma, PhysBox};
|
||||
use common::dma::Dma;
|
||||
use spin::Mutex;
|
||||
|
||||
const NUM_SUB_BUFFS: usize = 32;
|
||||
@@ -145,24 +145,14 @@ pub struct Ac97 {
|
||||
|
||||
impl Ac97 {
|
||||
pub unsafe fn new(bar0: u16, bar1: u16) -> Result<Self> {
|
||||
let round_page = |size: usize| -> usize {
|
||||
let page_size = 4096;
|
||||
let pages = (size + (page_size - 1)) / page_size;
|
||||
pages * page_size
|
||||
};
|
||||
let bdl_size = round_page(NUM_SUB_BUFFS * mem::size_of::<BufferDescriptor>());
|
||||
let buf_size = round_page(NUM_SUB_BUFFS * SUB_BUFF_SIZE);
|
||||
|
||||
let mut module = Ac97 {
|
||||
mixer: MixerRegs::new(bar0),
|
||||
bus: BusRegs::new(bar1),
|
||||
bdl: Dma::from_physbox_zeroed(
|
||||
bdl: Dma::zeroed(
|
||||
//TODO: PhysBox::new_in_32bit_space(bdl_size)?
|
||||
PhysBox::new(bdl_size)?
|
||||
)?.assume_init(),
|
||||
buf: Dma::from_physbox_zeroed(
|
||||
buf: Dma::zeroed(
|
||||
//TODO: PhysBox::new_in_32bit_space(buf_size)?
|
||||
PhysBox::new(buf_size)?
|
||||
)?.assume_init(),
|
||||
handles: Mutex::new(BTreeMap::new()),
|
||||
next_id: AtomicUsize::new(0),
|
||||
|
||||
+57
-140
@@ -1,196 +1,110 @@
|
||||
use std::mem::{self, MaybeUninit};
|
||||
use std::mem::{self, MaybeUninit, size_of};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::{ptr, slice};
|
||||
use std::ptr;
|
||||
|
||||
use syscall::PAGE_SIZE;
|
||||
|
||||
use syscall::Result;
|
||||
use syscall::{PartialAllocStrategy, PhysallocFlags};
|
||||
|
||||
use crate::MemoryType;
|
||||
|
||||
/// An RAII guard of a physical memory allocation. Currently all physically allocated memory are
|
||||
/// page-aligned and take up at least 4k of space (on x86_64).
|
||||
#[derive(Debug)]
|
||||
pub struct PhysBox {
|
||||
address: usize,
|
||||
size: usize
|
||||
}
|
||||
|
||||
fn assert_aligned(x: usize) {
|
||||
assert_eq!(x % PAGE_SIZE, 0);
|
||||
}
|
||||
|
||||
const DMA_MEMTY: MemoryType = {
|
||||
if cfg!(any(target_arch = "x86", target_arch = "x86_64")) {
|
||||
// aarch64 currently must map DMA memory without caching to ensure coherence
|
||||
// x86 ensures cache coherence with DMA memory
|
||||
MemoryType::Writeback
|
||||
} else if cfg!(target_arch = "aarch64") {
|
||||
// x86 ensures cache coherence with DMA memory
|
||||
// aarch64 currently must map DMA memory without caching to ensure coherence
|
||||
MemoryType::Uncacheable
|
||||
} else {
|
||||
panic!("invalid arch")
|
||||
}
|
||||
};
|
||||
|
||||
impl PhysBox {
|
||||
/// Construct a PhysBox from an address and a size. The address must be page-aligned, and the
|
||||
/// size must similarly be a multiple of the page size.
|
||||
///
|
||||
/// # Safety
|
||||
/// This function is unsafe because when dropping, Self has to a valid allocation.
|
||||
pub unsafe fn from_raw_parts(address: usize, size: usize) -> Self {
|
||||
assert_aligned(address);
|
||||
assert_aligned(size);
|
||||
|
||||
Self {
|
||||
address,
|
||||
size,
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve the byte address in physical memory, of this allocation.
|
||||
pub fn address(&self) -> usize {
|
||||
self.address
|
||||
}
|
||||
|
||||
/// Retrieve the size in bytes of the alloc.
|
||||
pub fn size(&self) -> usize {
|
||||
self.size
|
||||
}
|
||||
|
||||
/// Allocate physical memory that must reside in 32-bit space.
|
||||
pub fn new_in_32bit_space(size: usize) -> Result<Self> {
|
||||
Self::new_with_flags(size, PhysallocFlags::SPACE_32)
|
||||
}
|
||||
|
||||
pub fn new_with_flags(size: usize, flags: PhysallocFlags) -> Result<Self> {
|
||||
assert!(!flags.contains(PhysallocFlags::PARTIAL_ALLOC));
|
||||
assert_aligned(size);
|
||||
|
||||
let address = unsafe { syscall::physalloc2(size, flags.bits())? };
|
||||
Ok(unsafe { Self::from_raw_parts(address, size) })
|
||||
}
|
||||
|
||||
/// "Partially" allocate physical memory, in the sense that the allocation may be smaller than
|
||||
/// expected, but still with a minimum limit. This is particularly useful when the physical
|
||||
/// memory space is fragmented, and a device supports scatter-gather I/O. In that case, the
|
||||
/// driver can optimistically request e.g. 1 alloc of 1 MiB, with the minimum of 512 KiB. If
|
||||
/// that first allocation only returns half the size, the driver can do another allocation
|
||||
/// and then let the device use both buffers.
|
||||
pub fn new_partial_allocation(size: usize, flags: PhysallocFlags, strategy: Option<PartialAllocStrategy>, mut min: usize) -> Result<Self> {
|
||||
assert_aligned(size);
|
||||
debug_assert!(!(flags.contains(PhysallocFlags::PARTIAL_ALLOC) && strategy.is_none()));
|
||||
|
||||
let address = unsafe { syscall::physalloc3(size, flags.bits() | strategy.map_or(0, |s| s as usize), &mut min)? };
|
||||
Ok(unsafe { Self::from_raw_parts(address, size) })
|
||||
}
|
||||
|
||||
pub fn new(size: usize) -> Result<Self> {
|
||||
assert_aligned(size);
|
||||
|
||||
let address = unsafe { syscall::physalloc(size)? };
|
||||
Ok(unsafe { Self::from_raw_parts(address, size) })
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for PhysBox {
|
||||
fn drop(&mut self) {
|
||||
let _ = unsafe { syscall::physfree(self.address, self.size) };
|
||||
fn alloc_and_map(len: usize) -> Result<(usize, *mut ())> {
|
||||
assert_eq!(len % PAGE_SIZE, 0);
|
||||
unsafe {
|
||||
let fd = syscall::open(format!("memory:zeroed@{DMA_MEMTY}?phys_contiguous"), syscall::O_CLOEXEC)?;
|
||||
let virt = syscall::fmap(fd, &syscall::Map {
|
||||
offset: 0, // ignored
|
||||
address: 0, // ignored
|
||||
size: len,
|
||||
flags: syscall::MapFlags::MAP_PRIVATE | syscall::MapFlags::PROT_READ | syscall::MapFlags::PROT_WRITE,
|
||||
});
|
||||
let _ = syscall::close(fd);
|
||||
let virt = virt?;
|
||||
let phys = syscall::virttophys(virt)?;
|
||||
/*for i in 1..len.div_ceil(PAGE_SIZE) {
|
||||
assert_eq!(syscall::virttophys(virt + i * PAGE_SIZE), Ok(phys + i * PAGE_SIZE), "NOT CONTIGUOUS");
|
||||
}*/
|
||||
Ok((phys, virt as *mut ()))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Dma<T: ?Sized> {
|
||||
phys: PhysBox,
|
||||
phys: usize,
|
||||
aligned_len: usize,
|
||||
virt: *mut T,
|
||||
}
|
||||
|
||||
impl<T> Dma<T> {
|
||||
pub fn from_physbox_uninit(phys: PhysBox) -> Result<Dma<MaybeUninit<T>>> {
|
||||
Ok(Dma {
|
||||
virt: unsafe { crate::physmap(phys.address, phys.size, crate::Prot::RW, DMA_MEMTY)? } as *mut MaybeUninit<T>,
|
||||
phys,
|
||||
})
|
||||
}
|
||||
pub fn from_physbox_zeroed(phys: PhysBox) -> Result<Dma<MaybeUninit<T>>> {
|
||||
let this = Self::from_physbox_uninit(phys)?;
|
||||
unsafe { ptr::write_bytes(this.virt as *mut MaybeUninit<u8>, 0, this.phys.size) }
|
||||
Ok(this)
|
||||
}
|
||||
|
||||
pub fn from_physbox(phys: PhysBox, value: T) -> Result<Self> {
|
||||
let this = Self::from_physbox_uninit(phys)?;
|
||||
|
||||
Ok(unsafe {
|
||||
ptr::write(this.virt, MaybeUninit::new(value));
|
||||
this.assume_init()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new(value: T) -> Result<Self> {
|
||||
let phys = PhysBox::new(mem::size_of::<T>().next_multiple_of(PAGE_SIZE))?;
|
||||
Self::from_physbox(phys, value)
|
||||
unsafe {
|
||||
let mut zeroed = Self::zeroed()?;
|
||||
zeroed.as_mut_ptr().write(value);
|
||||
Ok(zeroed.assume_init())
|
||||
}
|
||||
}
|
||||
pub fn zeroed() -> Result<Dma<MaybeUninit<T>>> {
|
||||
let phys = PhysBox::new(mem::size_of::<T>().next_multiple_of(PAGE_SIZE))?;
|
||||
Self::from_physbox_zeroed(phys)
|
||||
let aligned_len = size_of::<T>().next_multiple_of(PAGE_SIZE);
|
||||
let (phys, virt) = alloc_and_map(aligned_len)?;
|
||||
Ok(Dma { phys, virt: virt.cast(), aligned_len })
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Dma<MaybeUninit<T>> {
|
||||
pub unsafe fn assume_init(self) -> Dma<T> {
|
||||
let &Dma { phys: PhysBox { address, size }, virt } = &self;
|
||||
let Dma { phys, aligned_len, virt } = self;
|
||||
mem::forget(self);
|
||||
|
||||
Dma {
|
||||
phys: PhysBox { address, size },
|
||||
virt: virt as *mut T,
|
||||
phys,
|
||||
aligned_len,
|
||||
virt: virt.cast(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: ?Sized> Dma<T> {
|
||||
pub fn physical(&self) -> usize {
|
||||
self.phys.address()
|
||||
}
|
||||
pub fn size(&self) -> usize {
|
||||
self.phys.size()
|
||||
}
|
||||
pub fn phys(&self) -> &PhysBox {
|
||||
&self.phys
|
||||
self.phys
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Dma<[T]> {
|
||||
pub fn from_physbox_uninit_unsized(phys: PhysBox, len: usize) -> Result<Dma<[MaybeUninit<T>]>> {
|
||||
let max_len = phys.size() / mem::size_of::<T>();
|
||||
assert!(len <= max_len);
|
||||
pub fn zeroed_slice(count: usize) -> Result<Dma<[MaybeUninit<T>]>> {
|
||||
let aligned_len = count.checked_mul(size_of::<T>()).unwrap().next_multiple_of(PAGE_SIZE);
|
||||
let (phys, virt) = alloc_and_map(aligned_len)?;
|
||||
|
||||
Ok(Dma {
|
||||
virt: unsafe { slice::from_raw_parts_mut(crate::physmap(phys.address, phys.size, crate::Prot::RW, DMA_MEMTY)? as *mut MaybeUninit<T>, len) } as *mut [MaybeUninit<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,
|
||||
})
|
||||
}
|
||||
pub fn from_physbox_zeroed_unsized(phys: PhysBox, len: usize) -> Result<Dma<[MaybeUninit<T>]>> {
|
||||
let this = Self::from_physbox_uninit_unsized(phys, len)?;
|
||||
unsafe { ptr::write_bytes(this.virt as *mut MaybeUninit<u8>, 0, this.phys.size()) }
|
||||
Ok(this)
|
||||
}
|
||||
/// Creates a new DMA buffer with a size only known at runtime.
|
||||
/// ## Safety
|
||||
/// * `T` must be properly aligned.
|
||||
/// * `T` must be valid as zeroed (i.e. no NonNull pointers).
|
||||
pub unsafe fn zeroed_unsized(count: usize) -> Result<Self> {
|
||||
let phys = PhysBox::new((mem::size_of::<T>() * count).next_multiple_of(PAGE_SIZE))?;
|
||||
Ok(Self::from_physbox_zeroed_unsized(phys, count)?.assume_init())
|
||||
virt: virt as *mut [U],
|
||||
aligned_len,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T> Dma<[MaybeUninit<T>]> {
|
||||
pub unsafe fn assume_init(self) -> Dma<[T]> {
|
||||
let &Dma { phys: PhysBox { address, size }, virt } = &self;
|
||||
let &Dma { phys, aligned_len, virt } = &self;
|
||||
mem::forget(self);
|
||||
|
||||
Dma {
|
||||
phys: PhysBox { address, size },
|
||||
phys,
|
||||
aligned_len,
|
||||
virt: virt as *mut [T],
|
||||
}
|
||||
}
|
||||
@@ -198,6 +112,7 @@ impl<T> Dma<[MaybeUninit<T>]> {
|
||||
|
||||
impl<T: ?Sized> Deref for Dma<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
unsafe { &*self.virt }
|
||||
}
|
||||
@@ -211,7 +126,9 @@ impl<T: ?Sized> DerefMut for Dma<T> {
|
||||
|
||||
impl<T: ?Sized> Drop for Dma<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { ptr::drop_in_place(self.virt) }
|
||||
let _ = unsafe { syscall::funmap(self.virt as *mut u8 as usize, self.phys.size) };
|
||||
unsafe {
|
||||
ptr::drop_in_place(self.virt);
|
||||
let _ = syscall::funmap(self.virt as *mut u8 as usize, self.aligned_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,3 +59,14 @@ pub unsafe fn physmap(base_phys: usize, len: usize, Prot { read, write }: Prot,
|
||||
|
||||
Ok(base? as *mut ())
|
||||
}
|
||||
|
||||
impl std::fmt::Display for MemoryType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", match self {
|
||||
Self::Writeback => "wb",
|
||||
Self::Uncacheable => "uc",
|
||||
Self::WriteCombining => "wc",
|
||||
Self::DeviceMemory => "dev",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+5
-9
@@ -10,7 +10,7 @@ use syscall::{
|
||||
io::{Io, Pio, ReadOnly, WriteOnly},
|
||||
};
|
||||
|
||||
use common::dma::{Dma, PhysBox};
|
||||
use common::dma::Dma;
|
||||
|
||||
static TIMEOUT: Duration = Duration::new(1, 0);
|
||||
|
||||
@@ -61,7 +61,7 @@ pub struct Channel {
|
||||
|
||||
impl Channel {
|
||||
pub fn new(base: u16, control_base: u16, busmaster_base: u16) -> Result<Self> {
|
||||
let mut chan = Self {
|
||||
Ok(Self {
|
||||
data8: Pio::new(base + 0),
|
||||
data32: Pio::new(base + 0),
|
||||
error: ReadOnly::new(Pio::new(base + 1)),
|
||||
@@ -79,20 +79,16 @@ impl Channel {
|
||||
busmaster_status: Pio::new(busmaster_base + 2),
|
||||
busmaster_prdt: Pio::new(busmaster_base + 4),
|
||||
prdt: unsafe {
|
||||
Dma::from_physbox_zeroed(
|
||||
Dma::zeroed(
|
||||
//TODO: PhysBox::new_in_32bit_space(4096)?
|
||||
PhysBox::new(4096 /* 128 * 8 page aligned */)?
|
||||
)?.assume_init()
|
||||
},
|
||||
buf: unsafe {
|
||||
Dma::from_physbox_zeroed(
|
||||
Dma::zeroed(
|
||||
//TODO: PhysBox::new_in_32bit_space(16 * 4096)?
|
||||
PhysBox::new(128 * 512)?
|
||||
)?.assume_init()
|
||||
},
|
||||
};
|
||||
|
||||
Ok(chan)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn primary_compat(busmaster_base: u16) -> Result<Self> {
|
||||
|
||||
+15
-16
@@ -1,3 +1,4 @@
|
||||
use common::dma::Dma;
|
||||
use syscall::io::{Io, Mmio};
|
||||
|
||||
use super::common::*;
|
||||
@@ -72,12 +73,12 @@ struct Corb {
|
||||
}
|
||||
|
||||
impl Corb {
|
||||
pub fn new(regs_addr: usize, corb_buff_phys: usize, corb_buff_virt: usize) -> Corb {
|
||||
pub fn new(regs_addr: usize, corb_buff_phys: usize, corb_buff_virt: *mut u32) -> Corb {
|
||||
println!("regs addr {:x}", regs_addr);
|
||||
unsafe {
|
||||
Corb {
|
||||
regs: &mut *(regs_addr as *mut CorbRegs),
|
||||
corb_base: (corb_buff_virt) as *mut u32,
|
||||
corb_base: corb_buff_virt,
|
||||
corb_base_phys: corb_buff_phys,
|
||||
corb_count: 0,
|
||||
}
|
||||
@@ -208,11 +209,11 @@ struct Rirb {
|
||||
}
|
||||
|
||||
impl Rirb {
|
||||
pub fn new(regs_addr: usize, rirb_buff_phys: usize, rirb_buff_virt: usize) -> Rirb {
|
||||
pub fn new(regs_addr: usize, rirb_buff_phys: usize, rirb_buff_virt: *mut u64) -> Rirb {
|
||||
unsafe {
|
||||
Rirb {
|
||||
regs: &mut *(regs_addr as *mut RirbRegs),
|
||||
rirb_base: (rirb_buff_virt) as *mut u64,
|
||||
rirb_base: rirb_buff_virt,
|
||||
rirb_rp: 0,
|
||||
rirb_base_phys: rirb_buff_phys,
|
||||
rirb_count: 0,
|
||||
@@ -342,34 +343,32 @@ pub struct CommandBuffer {
|
||||
rirb: Rirb,
|
||||
icmd: ImmediateCommand,
|
||||
|
||||
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,
|
||||
mut 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_mut_ptr().cast());
|
||||
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.physical() + CORB_BUFF_MAX_SIZE,
|
||||
cmd_buff.as_mut_ptr().cast::<u8>().wrapping_add(CORB_BUFF_MAX_SIZE).cast(),
|
||||
);
|
||||
|
||||
let icmd = ImmediateCommand::new(regs_addr + ICMD_OFFSET);
|
||||
|
||||
let cmdbuff = CommandBuffer {
|
||||
corb: corb,
|
||||
rirb: rirb,
|
||||
icmd: icmd,
|
||||
|
||||
corb_rirb_base_phys: cmd_buff_frame_phys,
|
||||
corb,
|
||||
rirb,
|
||||
icmd,
|
||||
|
||||
use_immediate_cmd: false,
|
||||
|
||||
mem: cmd_buff,
|
||||
};
|
||||
|
||||
cmdbuff
|
||||
|
||||
+16
-25
@@ -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
@@ -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.");
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> {
|
||||
let mut logger = RedoxLogger::new()
|
||||
.with_output(
|
||||
OutputBuilder::stderr()
|
||||
.with_filter(log::LevelFilter::Info) // limit global output to important info
|
||||
.with_filter(log::LevelFilter::Debug) // limit global output to important info
|
||||
.with_ansi_escape_codes()
|
||||
.flush_on_newline(true)
|
||||
.build()
|
||||
|
||||
+1
-1
@@ -516,7 +516,7 @@ pub fn main() {
|
||||
"vesa"
|
||||
} else {
|
||||
// TODO: What should we do when there are multiple display devices?
|
||||
device[0].split('/').nth(2).unwrap()
|
||||
device[0][2..].split('.').nth(1).unwrap()
|
||||
};
|
||||
|
||||
let mut handle =
|
||||
|
||||
@@ -57,7 +57,7 @@ pub struct NvmeCompQueue {
|
||||
impl NvmeCompQueue {
|
||||
pub fn new() -> Result<Self> {
|
||||
Ok(Self {
|
||||
data: unsafe { Dma::zeroed_unsized(256)? },
|
||||
data: unsafe { Dma::zeroed_slice(256)?.assume_init() },
|
||||
head: 0,
|
||||
phase: true,
|
||||
})
|
||||
@@ -110,7 +110,7 @@ pub struct NvmeCmdQueue {
|
||||
impl NvmeCmdQueue {
|
||||
pub fn new() -> Result<Self> {
|
||||
Ok(Self {
|
||||
data: unsafe { Dma::zeroed_unsized(64)? },
|
||||
data: unsafe { Dma::zeroed_slice(64)?.assume_init() },
|
||||
tail: 0,
|
||||
head: 0,
|
||||
})
|
||||
|
||||
@@ -8,7 +8,6 @@ use syscall::error::{Error, EACCES, EBADF, Result, EINVAL, ENODEV, ENOENT};
|
||||
use syscall::io::{Mmio, Pio, Io, ReadOnly, WriteOnly};
|
||||
use syscall::scheme::SchemeBlockMut;
|
||||
|
||||
use common::dma::{Dma, PhysBox};
|
||||
use spin::Mutex;
|
||||
|
||||
const NUM_SUB_BUFFS: usize = 32;
|
||||
|
||||
@@ -35,7 +35,7 @@ impl BlkExtension for Queue<'_> {
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let result = unsafe { Dma::<[u8]>::zeroed_unsized(target.len()) }.unwrap();
|
||||
let result = unsafe { Dma::<[u8]>::zeroed_slice(target.len()).unwrap().assume_init() };
|
||||
let status = Dma::new(u8::MAX).unwrap();
|
||||
|
||||
let chain = ChainBuilder::new()
|
||||
@@ -60,7 +60,7 @@ impl BlkExtension for Queue<'_> {
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let mut result = unsafe { Dma::<[u8]>::zeroed_unsized(target.len()) }.unwrap();
|
||||
let mut result = unsafe { Dma::<[u8]>::zeroed_slice(target.len()).unwrap().assume_init() };
|
||||
result.copy_from_slice(target.as_ref());
|
||||
|
||||
let status = Dma::new(u8::MAX).unwrap();
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use std::{sync::{Weak, atomic::{AtomicU16, Ordering}, Arc}, mem::size_of, fs::File};
|
||||
|
||||
use common::dma::{PhysBox, Dma};
|
||||
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 {
|
||||
@@ -118,24 +118,20 @@ impl Transport for LegacyTransport {
|
||||
let queue_size = self.read::<u16>(LegacyRegister::QueueSize) as usize;
|
||||
let (desc_size, avail_size, used_size) = queue_part_sizes(queue_size);
|
||||
|
||||
let size_bytes = desc_size + avail_size + used_size;
|
||||
let addr = unsafe { syscall::physalloc(size_bytes).map_err(Error::SyscallError)? };
|
||||
|
||||
let descriptor = unsafe {
|
||||
let physbox = PhysBox::from_raw_parts(addr, desc_size);
|
||||
let table = Dma::<[Descriptor]>::from_physbox_uninit_unsized(physbox, queue_size)?;
|
||||
|
||||
table.assume_init()
|
||||
Dma::<[Descriptor]>::zeroed_slice(queue_size)?.assume_init()
|
||||
};
|
||||
|
||||
let avail_addr = addr + desc_size;
|
||||
let avail = unsafe { Available::from_raw(avail_addr, avail_size, queue_size)? };
|
||||
let avail_addr = descriptor.physical() + desc_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, (addr as u32) >> 12);
|
||||
self.write::<u32>(LegacyRegister::QueueAddress, (descriptor.physical() as u32) >> 12);
|
||||
|
||||
log::info!("virtio-core: enabled queue #{queue_index} (size={queue_size})");
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,7 +612,7 @@ impl Transport for StandardTransport<'_> {
|
||||
|
||||
// Allocate memory for the queue structues.
|
||||
let descriptor = unsafe {
|
||||
Dma::<[Descriptor]>::zeroed_unsized(queue_size).map_err(Error::SyscallError)?
|
||||
Dma::<[Descriptor]>::zeroed_slice(queue_size).map_err(Error::SyscallError)?.assume_init()
|
||||
};
|
||||
|
||||
let avail = Available::new(queue_size)?;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -31,7 +31,7 @@ impl<'a> NetworkScheme<'a> {
|
||||
// Populate all of the `rx_queue` with buffers to maximize performence.
|
||||
let mut rx_buffers = vec![];
|
||||
for i in 0..(rx.descriptor_len() as usize) {
|
||||
rx_buffers.push(unsafe { Dma::<[u8]>::zeroed_unsized(MAX_BUFFER_LEN) }.unwrap());
|
||||
rx_buffers.push(unsafe { Dma::<[u8]>::zeroed_slice(MAX_BUFFER_LEN).unwrap().assume_init() });
|
||||
|
||||
let chain = ChainBuilder::new()
|
||||
.chain(Buffer::new_unsized(&rx_buffers[i]).flags(DescriptorFlags::WRITE_ONLY))
|
||||
@@ -123,7 +123,7 @@ impl<'a> SchemeBlockMut for NetworkScheme<'a> {
|
||||
|
||||
let header = unsafe { Dma::<VirtHeader>::zeroed()?.assume_init() };
|
||||
|
||||
let mut payload = unsafe { Dma::<[u8]>::zeroed_unsized(buffer.len())? };
|
||||
let mut payload = unsafe { Dma::<[u8]>::zeroed_slice(buffer.len())?.assume_init() };
|
||||
payload.copy_from_slice(buffer);
|
||||
|
||||
let chain = ChainBuilder::new()
|
||||
|
||||
@@ -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,
|
||||
|
||||
+14
-23
@@ -9,12 +9,13 @@ 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;
|
||||
|
||||
use chashmap::CHashMap;
|
||||
use common::dma::{Dma, PhysBox};
|
||||
use common::dma::Dma;
|
||||
use crossbeam_channel::{Receiver, Sender};
|
||||
use log::{debug, error, info, trace, warn};
|
||||
use serde::Deserialize;
|
||||
@@ -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);
|
||||
@@ -490,26 +491,16 @@ impl Xhci {
|
||||
pub fn slot_state(&self, slot: usize) -> u8 {
|
||||
self.dev_ctx.contexts[slot].slot.state()
|
||||
}
|
||||
pub unsafe fn alloc_phys(ac64: bool, byte_count: usize) -> Result<PhysBox> {
|
||||
let flags = if ac64 {
|
||||
PhysallocFlags::SPACE_64
|
||||
} else {
|
||||
PhysallocFlags::SPACE_32
|
||||
};
|
||||
PhysBox::new_with_flags(byte_count, flags)
|
||||
}
|
||||
fn page_align(size: usize) -> usize {
|
||||
// TODO: PAGE_SIZE
|
||||
(size+4095)/4096*4096
|
||||
}
|
||||
pub unsafe fn alloc_dma_zeroed_raw<T>(ac64: bool) -> Result<Dma<T>> {
|
||||
Ok(Dma::from_physbox_zeroed(Self::alloc_phys(ac64, Self::page_align(mem::size_of::<T>()))?)?.assume_init())
|
||||
pub unsafe fn alloc_dma_zeroed_raw<T>(_ac64: bool) -> Result<Dma<T>> {
|
||||
// TODO: ac64
|
||||
Ok(Dma::zeroed()?.assume_init())
|
||||
}
|
||||
pub unsafe fn alloc_dma_zeroed<T>(&self) -> Result<Dma<T>> {
|
||||
Self::alloc_dma_zeroed_raw(self.cap.ac64())
|
||||
}
|
||||
pub unsafe fn alloc_dma_zeroed_unsized_raw<T>(ac64: bool, count: usize) -> Result<Dma<[T]>> {
|
||||
Ok(Dma::from_physbox_zeroed_unsized(Self::alloc_phys(ac64, Self::page_align(mem::size_of::<T>() * count))?, count)?.assume_init())
|
||||
pub unsafe fn alloc_dma_zeroed_unsized_raw<T>(_ac64: bool, count: usize) -> Result<Dma<[T]>> {
|
||||
// TODO: ac64
|
||||
Ok(Dma::zeroed_slice(count)?.assume_init())
|
||||
}
|
||||
pub unsafe fn alloc_dma_zeroed_unsized<T>(&self, count: usize) -> Result<Dma<[T]>> {
|
||||
Self::alloc_dma_zeroed_unsized_raw(self.cap.ac64(), count)
|
||||
|
||||
Reference in New Issue
Block a user