Skip to main content

axdevice_base/
device.rs

1//! Device address and access width definitions.
2
3use core::fmt::{Debug, LowerHex, UpperHex};
4
5use ax_memory_addr::AddrRange;
6use axvm_types::GuestPhysAddr;
7
8/// The width of an access.
9///
10/// Note that the term "word" here refers to 16-bit data, as in the x86 architecture.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
12pub enum AccessWidth {
13    /// 8-bit access.
14    Byte,
15    /// 16-bit access.
16    Word,
17    /// 32-bit access.
18    Dword,
19    /// 64-bit access.
20    Qword,
21}
22
23impl TryFrom<usize> for AccessWidth {
24    type Error = ();
25
26    fn try_from(value: usize) -> Result<Self, Self::Error> {
27        match value {
28            1 => Ok(Self::Byte),
29            2 => Ok(Self::Word),
30            4 => Ok(Self::Dword),
31            8 => Ok(Self::Qword),
32            _ => Err(()),
33        }
34    }
35}
36
37impl From<AccessWidth> for usize {
38    fn from(width: AccessWidth) -> usize {
39        match width {
40            AccessWidth::Byte => 1,
41            AccessWidth::Word => 2,
42            AccessWidth::Dword => 4,
43            AccessWidth::Qword => 8,
44        }
45    }
46}
47
48impl AccessWidth {
49    /// Returns the size of the access in bytes.
50    pub fn size(&self) -> usize {
51        (*self).into()
52    }
53
54    /// Returns the range of bits that the access covers.
55    pub fn bits_range(&self) -> core::ops::Range<usize> {
56        match self {
57            AccessWidth::Byte => 0..8,
58            AccessWidth::Word => 0..16,
59            AccessWidth::Dword => 0..32,
60            AccessWidth::Qword => 0..64,
61        }
62    }
63}
64
65/// The port number of an I/O operation.
66#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
67pub struct Port(pub u16);
68
69impl Port {
70    /// Creates a new `Port` instance.
71    pub fn new(port: u16) -> Self {
72        Self(port)
73    }
74
75    /// Returns the port number.
76    pub fn number(&self) -> u16 {
77        self.0
78    }
79}
80
81impl LowerHex for Port {
82    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
83        write!(f, "Port({:#x})", self.0)
84    }
85}
86
87impl UpperHex for Port {
88    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
89        write!(f, "Port({:#X})", self.0)
90    }
91}
92
93impl Debug for Port {
94    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
95        write!(f, "Port({})", self.0)
96    }
97}
98
99/// A system register address.
100#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
101pub struct SysRegAddr(pub usize);
102
103impl SysRegAddr {
104    /// Creates a new `SysRegAddr` instance.
105    pub const fn new(addr: usize) -> Self {
106        Self(addr)
107    }
108
109    /// Returns the address.
110    pub const fn addr(&self) -> usize {
111        self.0
112    }
113}
114
115impl LowerHex for SysRegAddr {
116    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
117        write!(f, "SysRegAddr({:#x})", self.0)
118    }
119}
120
121impl UpperHex for SysRegAddr {
122    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
123        write!(f, "SysRegAddr({:#X})", self.0)
124    }
125}
126
127impl Debug for SysRegAddr {
128    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
129        write!(f, "SysRegAddr({})", self.0)
130    }
131}
132
133/// An address-like type that can be used to access devices.
134pub trait DeviceAddr: Copy + Eq + Ord + core::fmt::Debug {}
135
136/// A range of device addresses. It may be contiguous or not.
137pub trait DeviceAddrRange {
138    /// The address type of the range.
139    type Addr: DeviceAddr;
140
141    /// Returns whether the address range contains the given address.
142    fn contains(&self, addr: Self::Addr) -> bool;
143}
144
145impl DeviceAddr for GuestPhysAddr {}
146
147impl DeviceAddrRange for AddrRange<GuestPhysAddr> {
148    type Addr = GuestPhysAddr;
149
150    fn contains(&self, addr: Self::Addr) -> bool {
151        Self::contains(*self, addr)
152    }
153}
154
155impl DeviceAddr for SysRegAddr {}
156
157/// A inclusive range of system register addresses.
158///
159/// Unlike [`AddrRange`], this type is inclusive on both ends.
160#[derive(Copy, Clone, Eq, PartialEq, Debug)]
161pub struct SysRegAddrRange {
162    /// The start address of the range.
163    pub start: SysRegAddr,
164    /// The end address of the range.
165    pub end: SysRegAddr,
166}
167
168impl SysRegAddrRange {
169    /// Creates a new [`SysRegAddrRange`] instance.
170    pub fn new(start: SysRegAddr, end: SysRegAddr) -> Self {
171        Self { start, end }
172    }
173}
174
175impl DeviceAddrRange for SysRegAddrRange {
176    type Addr = SysRegAddr;
177
178    fn contains(&self, addr: Self::Addr) -> bool {
179        addr.0 >= self.start.0 && addr.0 <= self.end.0
180    }
181}
182
183impl LowerHex for SysRegAddrRange {
184    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
185        write!(f, "{:#x}..={:#x}", self.start.0, self.end.0)
186    }
187}
188
189impl DeviceAddr for Port {}
190
191/// A inclusive range of port numbers.
192///
193/// Unlike [`AddrRange`], this type is inclusive on both ends.
194#[derive(Copy, Clone, Eq, PartialEq, Debug)]
195pub struct PortRange {
196    /// The start port number of the range.
197    pub start: Port,
198    /// The end port number of the range.
199    pub end: Port,
200}
201
202impl PortRange {
203    /// Creates a new [`PortRange`] instance.
204    pub fn new(start: Port, end: Port) -> Self {
205        Self { start, end }
206    }
207}
208
209impl DeviceAddrRange for PortRange {
210    type Addr = Port;
211
212    fn contains(&self, addr: Self::Addr) -> bool {
213        addr.0 >= self.start.0 && addr.0 <= self.end.0
214    }
215}
216
217impl LowerHex for PortRange {
218    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
219        write!(f, "{:#x}..={:#x}", self.start.0, self.end.0)
220    }
221}