Skip to content

Commit

Permalink
Add macros to read and write config space in a type-safe way.
Browse files Browse the repository at this point in the history
  • Loading branch information
qwandor committed Nov 27, 2024
1 parent f4ead6f commit d34d941
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 52 deletions.
11 changes: 3 additions & 8 deletions src/device/blk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@
use crate::hal::Hal;
use crate::queue::VirtQueue;
use crate::transport::Transport;
use crate::transport::{read_config, Transport};
use crate::volatile::Volatile;
use crate::{Error, Result};
use bitflags::bitflags;
use core::mem::offset_of;
use log::info;
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};

Expand Down Expand Up @@ -57,12 +56,8 @@ impl<H: Hal, T: Transport> VirtIOBlk<H, T> {

// Read configuration space.
let capacity = transport.read_consistent(|| {
Ok(
transport.read_config_space::<u32>(offset_of!(BlkConfig, capacity_low))? as u64
| (transport.read_config_space::<u32>(offset_of!(BlkConfig, capacity_high))?
as u64)
<< 32,
)
Ok(read_config!(transport, BlkConfig, capacity_low)? as u64
| (read_config!(transport, BlkConfig, capacity_high)? as u64) << 32)
})?;
info!("found a block device of size {}KB", capacity / 2);

Expand Down
10 changes: 4 additions & 6 deletions src/device/console.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ mod embedded_io;

use crate::hal::Hal;
use crate::queue::VirtQueue;
use crate::transport::Transport;
use crate::transport::{read_config, write_config, Transport};
use crate::volatile::{ReadOnly, WriteOnly};
use crate::{Error, Result, PAGE_SIZE};
use alloc::boxed::Box;
use bitflags::bitflags;
use core::fmt::{self, Display, Formatter, Write};
use core::mem::offset_of;
use log::error;

const QUEUE_RECEIVEQ_PORT_0: u16 = 0;
Expand Down Expand Up @@ -129,8 +128,8 @@ impl<H: Hal, T: Transport> VirtIOConsole<H, T> {
if self.negotiated_features.contains(Features::SIZE) {
self.transport.read_consistent(|| {
Ok(Some(Size {
columns: self.transport.read_config_space(offset_of!(Config, cols))?,
rows: self.transport.read_config_space(offset_of!(Config, rows))?,
columns: read_config!(self.transport, Config, cols)?,
rows: read_config!(self.transport, Config, rows)?,
}))
})
} else {
Expand Down Expand Up @@ -240,8 +239,7 @@ impl<H: Hal, T: Transport> VirtIOConsole<H, T> {
/// Returns an error if the device doesn't support emergency write.
pub fn emergency_write(&mut self, chr: u8) -> Result<()> {
if self.negotiated_features.contains(Features::EMERG_WRITE) {
self.transport
.write_config_space::<u32>(offset_of!(Config, emerg_wr), chr.into())?;
write_config!(self.transport, Config, emerg_wr, chr.into())?;
Ok(())
} else {
Err(Error::Unsupported)
Expand Down
7 changes: 3 additions & 4 deletions src/device/gpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@
use crate::hal::{BufferDirection, Dma, Hal};
use crate::queue::VirtQueue;
use crate::transport::Transport;
use crate::transport::{read_config, Transport};
use crate::volatile::{ReadOnly, Volatile, WriteOnly};
use crate::{pages, Error, Result, PAGE_SIZE};
use alloc::boxed::Box;
use bitflags::bitflags;
use core::mem::offset_of;
use log::info;
use zerocopy::{FromBytes, FromZeros, Immutable, IntoBytes, KnownLayout};

Expand Down Expand Up @@ -44,8 +43,8 @@ impl<H: Hal, T: Transport> VirtIOGpu<H, T> {
let negotiated_features = transport.begin_init(SUPPORTED_FEATURES);

// read configuration space
let events_read = transport.read_config_space::<u32>(offset_of!(Config, events_read))?;
let num_scanouts = transport.read_config_space::<u32>(offset_of!(Config, num_scanouts))?;
let events_read = read_config!(transport, Config, events_read)?;
let num_scanouts = read_config!(transport, Config, num_scanouts)?;
info!(
"events_read: {:#x}, num_scanouts: {:#x}",
events_read, num_scanouts
Expand Down
21 changes: 7 additions & 14 deletions src/device/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use super::common::Feature;
use crate::hal::Hal;
use crate::queue::VirtQueue;
use crate::transport::Transport;
use crate::transport::{read_config, write_config, Transport};
use crate::volatile::{ReadOnly, WriteOnly};
use crate::Error;
use alloc::{boxed::Box, string::String};
Expand Down Expand Up @@ -103,11 +103,9 @@ impl<H: Hal, T: Transport> VirtIOInput<H, T> {
subsel: u8,
out: &mut [u8],
) -> Result<u8, Error> {
self.transport
.write_config_space(offset_of!(Config, select), select as u8)?;
self.transport
.write_config_space(offset_of!(Config, subsel), subsel)?;
let size: u8 = self.transport.read_config_space(offset_of!(Config, size))?;
write_config!(self.transport, Config, select, select as u8)?;
write_config!(self.transport, Config, subsel, subsel)?;
let size: u8 = read_config!(self.transport, Config, size)?;
// Safe because config points to a valid MMIO region for the config space.
let size_to_copy = min(usize::from(size), out.len());
for (i, out_item) in out.iter_mut().take(size_to_copy).enumerate() {
Expand All @@ -126,14 +124,9 @@ impl<H: Hal, T: Transport> VirtIOInput<H, T> {
select: InputConfigSelect,
subsel: u8,
) -> Result<Box<[u8]>, Error> {
self.transport
.write_config_space(offset_of!(Config, select), select as u8)?;
self.transport
.write_config_space(offset_of!(Config, subsel), subsel)?;
let size = usize::from(
self.transport
.read_config_space::<u8>(offset_of!(Config, size))?,
);
write_config!(self.transport, Config, select, select as u8)?;
write_config!(self.transport, Config, subsel, subsel)?;
let size = usize::from(read_config!(self.transport, Config, size)?);
if size > CONFIG_DATA_MAX_LENGTH {
return Err(Error::IoError);
}
Expand Down
9 changes: 3 additions & 6 deletions src/device/net/dev_raw.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
use super::{Config, EthernetAddress, Features, VirtioNetHdr};
use super::{MIN_BUFFER_LEN, NET_HDR_SIZE, QUEUE_RECEIVE, QUEUE_TRANSMIT, SUPPORTED_FEATURES};
use crate::device::net::Status;
use crate::hal::Hal;
use crate::queue::VirtQueue;
use crate::transport::Transport;
use crate::transport::{read_config, Transport};
use crate::{Error, Result};
use core::mem::offset_of;
use log::{debug, info, warn};
use zerocopy::IntoBytes;

Expand All @@ -31,9 +29,8 @@ impl<H: Hal, T: Transport, const QUEUE_SIZE: usize> VirtIONetRaw<H, T, QUEUE_SIZ
info!("negotiated_features {:?}", negotiated_features);

// Read configuration space.
let mac =
transport.read_consistent(|| transport.read_config_space(offset_of!(Config, mac)))?;
let status = transport.read_config_space::<Status>(offset_of!(Config, status))?;
let mac = transport.read_consistent(|| read_config!(transport, Config, mac))?;
let status = read_config!(transport, Config, status)?;
debug!("Got MAC={:02x?}, status={:?}", mac, status);

let send_queue = VirtQueue::new(
Expand Down
12 changes: 4 additions & 8 deletions src/device/socket/vsock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ use super::protocol::{
use super::DEFAULT_RX_BUFFER_SIZE;
use crate::hal::Hal;
use crate::queue::{owning::OwningQueue, VirtQueue};
use crate::transport::Transport;
use crate::transport::{read_config, Transport};
use crate::Result;
use core::mem::{offset_of, size_of};
use core::mem::size_of;
use log::debug;
use zerocopy::{FromBytes, IntoBytes};

Expand Down Expand Up @@ -249,12 +249,8 @@ impl<H: Hal, T: Transport, const RX_BUFFER_SIZE: usize> VirtIOSocket<H, T, RX_BU

let guest_cid = transport.read_consistent(|| {
Ok(
transport.read_config_space::<u32>(offset_of!(VirtioVsockConfig, guest_cid_low))?
as u64
| (transport
.read_config_space::<u32>(offset_of!(VirtioVsockConfig, guest_cid_high))?
as u64)
<< 32,
read_config!(transport, VirtioVsockConfig, guest_cid_low)? as u64
| (read_config!(transport, VirtioVsockConfig, guest_cid_high)? as u64) << 32,
)
})?;
debug!("guest cid: {guest_cid:?}");
Expand Down
10 changes: 5 additions & 5 deletions src/device/sound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ mod fake;
use super::common::Feature;
use crate::{
queue::{owning::OwningQueue, VirtQueue},
transport::Transport,
transport::{read_config, Transport},
volatile::ReadOnly,
Error, Hal, Result, PAGE_SIZE,
};
Expand All @@ -16,7 +16,7 @@ use core::{
array,
fmt::{self, Debug, Display, Formatter},
hint::spin_loop,
mem::{offset_of, size_of},
mem::size_of,
ops::RangeInclusive,
};
use enumn::N;
Expand Down Expand Up @@ -96,9 +96,9 @@ impl<H: Hal, T: Transport> VirtIOSound<H, T> {
)?;

// read configuration space
let jacks = transport.read_config_space(offset_of!(VirtIOSoundConfig, jacks))?;
let streams = transport.read_config_space(offset_of!(VirtIOSoundConfig, streams))?;
let chmaps = transport.read_config_space(offset_of!(VirtIOSoundConfig, chmaps))?;
let jacks = read_config!(transport, VirtIOSoundConfig, jacks)?;
let streams = read_config!(transport, VirtIOSoundConfig, streams)?;
let chmaps = read_config!(transport, VirtIOSoundConfig, chmaps)?;
info!(
"[sound device] config: jacks: {}, streams: {}, chmaps: {}",
jacks, streams, chmaps
Expand Down
43 changes: 43 additions & 0 deletions src/transport/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,3 +231,46 @@ impl From<u8> for DeviceType {
u32::from(virtio_device_id).into()
}
}

#[inline(always)]
pub(crate) fn read_help<T: Transport, V: FromBytes>(
transport: &T,
offset: usize,
_dummy_v: Option<V>,
) -> Result<V> {
transport.read_config_space(offset)
}

#[inline(always)]
pub(crate) fn write_help<T: Transport, V: Immutable + IntoBytes>(
transport: &mut T,
offset: usize,
value: V,
_dummy_v: Option<V>,
) -> Result<()> {
transport.write_config_space(offset, value)
}

macro_rules! read_config {
($transport:expr, $struct:ty, $field:ident) => {{
let dummy_struct: Option<$struct> = None;
let dummy_v = dummy_struct.map(|s| s.$field.0);
crate::transport::read_help(&$transport, core::mem::offset_of!($struct, $field), dummy_v)
}};
}

macro_rules! write_config {
($transport:expr, $struct:ty, $field:ident, $value:expr) => {{
let dummy_struct: Option<$struct> = None;
let dummy_v = dummy_struct.map(|s| s.$field.0);
crate::transport::write_help(
&mut $transport,
core::mem::offset_of!($struct, $field),
$value,
dummy_v,
)
}};
}

pub(crate) use read_config;
pub(crate) use write_config;
2 changes: 1 addition & 1 deletion src/volatile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub struct WriteOnly<T: Copy>(pub(crate) T);
/// An MMIO register which may be both read and written.
#[derive(Default)]
#[repr(transparent)]
pub struct Volatile<T: Copy>(T);
pub struct Volatile<T: Copy>(pub(crate) T);

impl<T: Copy> Volatile<T> {
/// Construct a new instance for testing.
Expand Down

0 comments on commit d34d941

Please sign in to comment.