Skip to content

Commit

Permalink
Add ERST entry
Browse files Browse the repository at this point in the history
  • Loading branch information
paulsohn committed Dec 8, 2023
1 parent 77ace61 commit 18ac2ae
Show file tree
Hide file tree
Showing 2 changed files with 233 additions and 0 deletions.
132 changes: 132 additions & 0 deletions src/ring/erst.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
//! Event Ring Segment Table Entry.

use super::trb::event::TRB;
use bit_field::BitField;
use core::ops::{Index, IndexMut};

/// The Event Ring Segment Table entry.
/// This plays the same role as an array pointer, and require special care to guarantee memory safety.
///
/// For example, the entry do not implement `Drop` trait, so the user should manually free its memory.
#[repr(transparent)]
#[derive(Clone, Copy, Debug)]
pub struct EventRingSegmentTableEntry([u32; 4]);

impl EventRingSegmentTableEntry {
/// Create new segment table entry from base address `base` and entry count `len`.
/// `len` should be the entry count, not the size in bytes.
///
/// # Panics
///
/// This method will panic if `len >= 4096`.
pub unsafe fn new(base: *const Block, len: usize) -> Self {
let size_in_bytes = len * core::mem::size_of::<Block>();
assert!(size_in_bytes <= u16::MAX as usize);

let mut entry = Self([0; 4]);
entry
.set_ring_segment_base_address(base as usize as u64)
.set_ring_segment_size((len * core::mem::size_of::<Block>()) as u16);
entry
}

/// Create new segment table entry from a block buffer.
pub unsafe fn from_buf(buf: &[Block]) -> Self {
Self::new(buf.as_ptr(), buf.len())
}

/// Returns the entry count of the segment.
pub fn len(&self) -> usize {
return self.ring_segment_size() as usize / core::mem::size_of::<Block>();
}

/// Returns the slice that this entry is representing.
pub fn as_slice(&self) -> &[Block] {
unsafe {
let base = self.ring_segment_base_address() as *const _;
let len = self.len();

core::slice::from_raw_parts(base, len)
}
}

/// Returns the mutable slice that this entry is representing.
pub fn as_mut_slice(&mut self) -> &mut [Block] {
unsafe {
let base = self.ring_segment_base_address() as *mut _;
let len = self.len();

core::slice::from_raw_parts_mut(base, len)
}
}
}

impl EventRingSegmentTableEntry {
/// Returns the value of the Ring Segment Base Address field.
pub(crate) unsafe fn ring_segment_base_address(&self) -> u64 {
let l: u64 = self.0[0].into();
let u: u64 = self.0[1].into();

(u << 32) | l
}

/// Sets the value of the Ring Segment Base Address field.
///
/// # Panics
///
/// This method panics if `p` is not 64-byte aligned.
pub(crate) unsafe fn set_ring_segment_base_address(&mut self, p: u64) -> &mut Self {
assert_eq!(
p % 64,
0,
"The Ring Segment Base Address must be 64-byte aligned."
);

let l = p.get_bits(0..32);
let u = p.get_bits(32..64);

self.0[0] = l.try_into().unwrap();
self.0[1] = u.try_into().unwrap();
self
}

/// Returns the value of the Ring Segment Size field.
///
/// This field represents size in bytes.
pub(crate) fn ring_segment_size(&self) -> u16 {
self.0[2].get_bits(0..16) as _
}
/// Sets the value of the Ring Segment Size field.
///
/// The value should be size in bytes.
pub(crate) unsafe fn set_ring_segment_size(&mut self, v: u16) -> &mut Self {
self.0[2].set_bits(0..16, v.into());
self
}
// rw_field!([2](0..16), ring_segment_size, "Ring Segment Size", u16);

/// Returns the value of the ring segment end address.
pub(crate) unsafe fn ring_segment_bound_address(&self) -> u64 {
self.ring_segment_base_address() + (self.ring_segment_size() as u64)
}
}

impl Index<usize> for EventRingSegmentTableEntry {
type Output = Block;

fn index(&self, index: usize) -> &Self::Output {
let slice = self.as_slice();
assert!(index < slice.len());

&slice[index]
}
}

impl IndexMut<usize> for EventRingSegmentTableEntry {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
let slice = self.as_mut_slice();
assert!(index < slice.len());

&mut slice[index]
}
}
101 changes: 101 additions & 0 deletions src/ring/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,104 @@
//! TRB Ring.

pub mod trb;

use trb::event;
use core::ops::{Index, IndexMut};

/// The Event Ring Segment Table entry.
/// This plays the same role as an array pointer, and require special care to guarantee memory safety.
///
/// For example, the entry do not implement `Drop` trait, so the user should manually free its memory.
#[repr(transparent)]
#[derive(Clone, Copy, Debug)]
pub struct EventRingSegmentTableEntry([u32; 4]);

impl EventRingSegmentTableEntry {
/// Create new segment table entry from base address `base` and entry count `len`.
/// `len` should be the entry count, not the size in bytes.
///
/// # Panics
///
/// This method will panic if `len >= 4096`.
pub unsafe fn new(base: *const event::TRB, len: usize) -> Self {
let size_in_bytes = len * trb::BYTES;
assert!(size_in_bytes <= u16::MAX as usize);

let mut entry = Self([0; 4]);
entry
.set_ring_segment_base_address(base as usize as u64)
.set_ring_segment_size((len * trb::BYTES) as u16);
entry
}

/// Create new segment table entry from a event::TRB buffer.
pub unsafe fn from_buf(buf: &[event::TRB]) -> Self {
Self::new(buf.as_ptr(), buf.len())
}

/// Returns the entry count of the segment.
pub fn len(&self) -> usize {
return self.ring_segment_size() as usize / trb::BYTES;
}

/// Returns the slice that this entry is representing.
pub fn as_slice(&self) -> &[event::TRB] {
unsafe {
let base = self.ring_segment_base_address() as usize as *const _;
let len = self.len();

core::slice::from_raw_parts(base, len)
}
}

/// Returns the mutable slice that this entry is representing.
pub fn as_mut_slice(&mut self) -> &mut [event::TRB] {
unsafe {
let base = self.ring_segment_base_address() as usize as *mut _;
let len = self.len();

core::slice::from_raw_parts_mut(base, len)
}
}
}

impl EventRingSegmentTableEntry {
rw_double_zero_trailing!(
pub, self,
self.0; [0, 1]; 6~; "64-byte aligned",
ring_segment_base_address,
"Ring Segment Base Address",
32, u64
);

rw_field!(
pub, self,
self.0[2]; 0..=15,
ring_segment_size,
"Ring Segment Size (in bytes)",
u16
);

/// Returns the value of the ring segment end address.
pub fn ring_segment_bound_address(&self) -> u64 {
self.ring_segment_base_address() + (self.ring_segment_size() as u64)
}
}

impl Index<usize> for EventRingSegmentTableEntry {
type Output = event::TRB;

fn index(&self, index: usize) -> &Self::Output {
let slice = self.as_slice();

&slice[index]
}
}

impl IndexMut<usize> for EventRingSegmentTableEntry {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
let slice = self.as_mut_slice();

&mut slice[index]
}
}

0 comments on commit 18ac2ae

Please sign in to comment.