refactor: ByteOffset newtype for window/register/ring offsets; named virtio-gpu cmd fields

This commit is contained in:
2026-10-27 21:52:33 +01:00
parent 842d14987c
commit 7b8258b231
13 changed files with 145 additions and 93 deletions

View File

@@ -5,7 +5,7 @@
//! Every access is volatile and bounds-checked; out of range panics.
use core::sync::atomic::AtomicUsize;
use types::address::VirtualAddress;
use types::address::{ByteOffset, VirtualAddress};
use types::bounded::{CapSlot, PageCount};
use types::mapping::PagePerms;
@@ -76,7 +76,8 @@ impl Window {
}
/// The address of `size` bytes at `offset`, aligned for them.
fn at(&self, offset: usize, size: usize, align: usize) -> usize {
fn at(&self, offset: ByteOffset, size: usize, align: usize) -> usize {
let offset = offset.raw();
let end = offset.checked_add(size);
assert!(end.is_some_and(|e| e <= self.len), "window access out of range");
let addr = self.base.raw() + offset;
@@ -84,33 +85,33 @@ impl Window {
addr
}
pub fn read<T: Scalar>(&self, offset: usize) -> T {
pub fn read<T: Scalar>(&self, offset: ByteOffset) -> T {
let addr = self.at(offset, size_of::<T>(), align_of::<T>());
// SAFETY: in range of memory mapped for this process, aligned for
// T; T is a plain integer, valid for any bits.
unsafe { core::ptr::read_volatile(addr as *const T) }
}
pub fn write<T: Scalar>(&self, offset: usize, value: T) {
pub fn write<T: Scalar>(&self, offset: ByteOffset, value: T) {
let addr = self.at(offset, size_of::<T>(), align_of::<T>());
// SAFETY: as in `read`; the window hands out no references to it.
unsafe { core::ptr::write_volatile(addr as *mut T, value) }
}
/// The `len` bytes at `offset`, as a window of their own.
pub fn sub(&self, offset: usize, len: usize) -> Window {
pub fn sub(&self, offset: ByteOffset, len: usize) -> Window {
let base = VirtualAddress::from_raw(self.at(offset, len, 1));
Window { base, len }
}
pub fn copy_from(&self, offset: usize, src: &[u8]) {
pub fn copy_from(&self, offset: ByteOffset, src: &[u8]) {
self.at(offset, src.len(), 1);
for (i, b) in src.iter().enumerate() {
self.write(offset + i, *b);
}
}
pub fn copy_to(&self, offset: usize, dst: &mut [u8]) {
pub fn copy_to(&self, offset: ByteOffset, dst: &mut [u8]) {
self.at(offset, dst.len(), 1);
for (i, b) in dst.iter_mut().enumerate() {
*b = self.read(offset + i);
@@ -118,7 +119,7 @@ impl Window {
}
/// `count` u32s from `offset` set to `value`.
pub fn fill_u32(&self, offset: usize, count: usize, value: u32) {
pub fn fill_u32(&self, offset: ByteOffset, count: usize, value: u32) {
let bytes = count.checked_mul(4).expect("window fill too large");
self.at(offset, bytes, 4);
for i in 0..count {
@@ -128,7 +129,7 @@ impl Window {
/// `count` words from `offset` as atomics, for memory shared with
/// threads or processes that only ever touch it atomically.
pub fn atomics(&self, offset: usize, count: usize) -> &'static [AtomicUsize] {
pub fn atomics(&self, offset: ByteOffset, count: usize) -> &'static [AtomicUsize] {
let bytes = count.checked_mul(size_of::<AtomicUsize>()).expect("too many atomics");
let addr = self.at(offset, bytes, align_of::<AtomicUsize>());
// SAFETY: mapped and aligned; AtomicUsize may be shared and is