1use core::{
4 fmt::Display,
5 sync::atomic::{AtomicU16, AtomicU64, Ordering},
6 time::Duration,
7};
8
9use twizzler_rt_abi::error::TwzError;
10
11use crate::{
12 kso::KsoHdr,
13 syscall::{
14 sys_thread_sync, ThreadSync, ThreadSyncFlags, ThreadSyncOp, ThreadSyncReference,
15 ThreadSyncSleep, ThreadSyncWake,
16 },
17};
18
19pub mod bus;
20
21pub const NUM_DEVICE_INTERRUPTS: usize = 32;
22
23#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug)]
25#[repr(u32)]
26pub enum DeviceType {
27 Unknown = 0,
29 Bus = 1,
31 Device = 2,
33}
34
35#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug)]
37#[repr(u32)]
38pub enum BusType {
39 Unknown = 0,
41 System = 1,
43 Pcie = 2,
45}
46
47#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug)]
50#[repr(u32)]
51pub enum SubObjectType {
52 Info = 0,
55 Mmio = 1,
57}
58
59impl From<SubObjectType> for u8 {
60 fn from(x: SubObjectType) -> Self {
61 match x {
62 SubObjectType::Info => 0,
63 SubObjectType::Mmio => 1,
64 }
65 }
66}
67
68impl TryFrom<u8> for SubObjectType {
69 type Error = ();
70 fn try_from(x: u8) -> Result<Self, ()> {
71 Ok(match x {
72 0 => SubObjectType::Info,
73 1 => SubObjectType::Mmio,
74 _ => return Err(()),
75 })
76 }
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
81#[repr(u32)]
82pub enum CacheType {
83 WriteBack = 0,
84 WriteCombining = 1,
85 WriteThrough = 2,
86 Uncacheable = 3,
87 MemoryMappedIO = 4,
88}
89
90#[derive(Debug)]
92#[repr(C)]
93pub struct MmioInfo {
94 pub length: u64,
96 pub cache_type: CacheType,
98 pub info: u64,
100}
101
102pub const MMIO_OFFSET: usize = 0x2000;
105
106bitflags::bitflags! {
107 pub struct DeviceInterruptFlags: u16 {}
109}
110
111#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug)]
113#[repr(transparent)]
114pub struct InterruptVector(u32);
115
116impl TryFrom<u64> for InterruptVector {
117 type Error = TwzError;
118
119 fn try_from(value: u64) -> Result<Self, Self::Error> {
120 let u: u32 = value.try_into().map_err(|_| TwzError::INVALID_ARGUMENT)?;
121 Ok(InterruptVector(u))
122 }
123}
124
125impl From<InterruptVector> for u32 {
126 fn from(iv: InterruptVector) -> Self {
127 iv.0
128 }
129}
130
131#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug)]
133#[repr(transparent)]
134pub struct DeviceId(u32);
135
136impl DeviceId {
137 pub fn new(v: u32) -> Self {
138 Self(v)
139 }
140}
141
142#[repr(C)]
143pub struct DeviceInterrupt {
144 pub sync: AtomicU64,
145 pub vec: InterruptVector,
146 pub flags: DeviceInterruptFlags,
147 pub taken: AtomicU16,
148}
149
150#[derive(Clone, Copy, Debug)]
151pub enum MailboxPriority {
152 Idle,
153 Low,
154 High,
155 Num,
156}
157
158impl TryFrom<usize> for MailboxPriority {
159 type Error = ();
160
161 fn try_from(value: usize) -> Result<Self, Self::Error> {
162 Ok(match value {
163 0 => MailboxPriority::Idle,
164 1 => MailboxPriority::Low,
165 2 => MailboxPriority::High,
166 3 => MailboxPriority::Num,
167 _ => return Err(()),
168 })
169 }
170}
171#[repr(C)]
173pub struct DeviceRepr {
174 kso_hdr: KsoHdr,
175 pub device_type: DeviceType,
176 pub bus_type: BusType,
177 pub device_id: DeviceId,
178 pub interrupts: [DeviceInterrupt; NUM_DEVICE_INTERRUPTS],
179 pub mailboxes: [AtomicU64; MailboxPriority::Num as usize],
180}
181
182impl Display for DeviceRepr {
183 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
184 write!(
185 f,
186 "Device::{{{:?}, {:?}, {:?}}}({})",
187 self.device_type, self.bus_type, self.device_id, self.kso_hdr
188 )
189 }
190}
191
192impl DeviceRepr {
193 pub fn new(
195 kso_hdr: KsoHdr,
196 device_type: DeviceType,
197 bus_type: BusType,
198 device_id: DeviceId,
199 ) -> Self {
200 #[allow(clippy::declare_interior_mutable_const)]
204 const V: DeviceInterrupt = DeviceInterrupt {
205 sync: AtomicU64::new(0),
206 vec: InterruptVector(0),
207 flags: DeviceInterruptFlags::empty(),
208 taken: AtomicU16::new(0),
209 };
210
211 #[allow(clippy::declare_interior_mutable_const)]
212 const M: AtomicU64 = AtomicU64::new(0);
213 Self {
214 kso_hdr,
215 device_type,
216 bus_type,
217 device_id,
218 interrupts: [V; NUM_DEVICE_INTERRUPTS],
219 mailboxes: [M; MailboxPriority::Num as usize],
220 }
221 }
222
223 pub fn wait_for_interrupt(&self, inum: usize, timeout: Option<Duration>) -> u64 {
225 loop {
226 let val = self.interrupts[inum].sync.swap(0, Ordering::SeqCst);
227 if val != 0 {
228 return val;
229 }
230 for _ in 0..100 {
232 let val = self.interrupts[inum].sync.load(Ordering::SeqCst);
233 if val != 0 {
234 return self.interrupts[inum].sync.swap(0, Ordering::SeqCst);
235 }
236 }
237 let op = ThreadSync::new_sleep(ThreadSyncSleep::new(
238 ThreadSyncReference::Virtual(&self.interrupts[inum].sync as *const AtomicU64),
239 0,
240 ThreadSyncOp::Equal,
241 ThreadSyncFlags::empty(),
242 ));
243 let res = crate::syscall::sys_thread_sync(&mut [op], timeout);
244 if res.is_err() {
245 return 0;
246 }
247 }
248 }
249
250 pub fn setup_interrupt_sleep(&self, inum: usize) -> ThreadSyncSleep {
251 ThreadSyncSleep {
252 reference: ThreadSyncReference::Virtual(&self.interrupts[inum].sync),
253 value: 0,
254 op: ThreadSyncOp::Equal,
255 flags: ThreadSyncFlags::empty(),
256 }
257 }
258
259 pub fn submit_mailbox_msg(&self, mb: MailboxPriority, msg: u64) {
260 while self.mailboxes[mb as usize]
261 .compare_exchange(0, msg, Ordering::SeqCst, Ordering::SeqCst)
262 .is_err()
263 {
264 core::hint::spin_loop()
265 }
266 let _ = sys_thread_sync(
267 &mut [ThreadSync::new_wake(ThreadSyncWake::new(
268 ThreadSyncReference::Virtual(&self.mailboxes[mb as usize]),
269 usize::MAX,
270 ))],
271 None,
272 );
273 }
274
275 pub fn check_for_interrupt(&self, inum: usize) -> Option<u64> {
277 let val = self.interrupts[inum].sync.swap(0, Ordering::SeqCst);
278 if val == 0 {
279 None
280 } else {
281 Some(val)
282 }
283 }
284
285 pub fn check_for_mailbox(&self, inum: usize) -> Option<u64> {
287 let val = self.mailboxes[inum].swap(0, Ordering::SeqCst);
288 if val == 0 {
289 None
290 } else {
291 Some(val)
292 }
293 }
294
295 pub fn register_interrupt(
297 &mut self,
298 inum: usize,
299 vec: InterruptVector,
300 flags: DeviceInterruptFlags,
301 ) {
302 self.interrupts[inum].vec = vec;
303 self.interrupts[inum].flags = flags;
304 self.interrupts[inum].sync = AtomicU64::new(0);
305 }
306}