use core::{
fmt::Display,
num::TryFromIntError,
sync::atomic::{AtomicU16, AtomicU64, Ordering},
time::Duration,
};
use crate::{
kso::KsoHdr,
syscall::{
sys_thread_sync, ThreadSync, ThreadSyncFlags, ThreadSyncOp, ThreadSyncReference,
ThreadSyncSleep, ThreadSyncWake,
},
};
pub mod bus;
pub const NUM_DEVICE_INTERRUPTS: usize = 32;
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug)]
#[repr(u32)]
pub enum DeviceType {
Unknown = 0,
Bus = 1,
Device = 2,
}
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug)]
#[repr(u32)]
pub enum BusType {
Unknown = 0,
System = 1,
Pcie = 2,
}
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug)]
#[repr(u32)]
pub enum SubObjectType {
Info = 0,
Mmio = 1,
}
impl From<SubObjectType> for u8 {
fn from(x: SubObjectType) -> Self {
match x {
SubObjectType::Info => 0,
SubObjectType::Mmio => 1,
}
}
}
impl TryFrom<u8> for SubObjectType {
type Error = ();
fn try_from(x: u8) -> Result<Self, ()> {
Ok(match x {
0 => SubObjectType::Info,
1 => SubObjectType::Mmio,
_ => return Err(()),
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u32)]
pub enum CacheType {
WriteBack = 0,
WriteCombining = 1,
WriteThrough = 2,
Uncacheable = 3,
MemoryMappedIO = 4,
}
#[derive(Debug)]
#[repr(C)]
pub struct MmioInfo {
pub length: u64,
pub cache_type: CacheType,
pub info: u64,
}
impl crate::marker::BaseType for MmioInfo {
fn init<T>(_t: T) -> Self {
todo!()
}
fn tags() -> &'static [(crate::marker::BaseVersion, crate::marker::BaseTag)] {
todo!()
}
}
pub const MMIO_OFFSET: usize = 0x2000;
bitflags::bitflags! {
pub struct DeviceInterruptFlags: u16 {}
}
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug)]
#[repr(transparent)]
pub struct InterruptVector(u32);
impl TryFrom<u64> for InterruptVector {
type Error = TryFromIntError;
fn try_from(value: u64) -> Result<Self, Self::Error> {
let u: u32 = value.try_into()?;
Ok(InterruptVector(u))
}
}
impl From<InterruptVector> for u32 {
fn from(iv: InterruptVector) -> Self {
iv.0
}
}
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug)]
#[repr(transparent)]
pub struct DeviceId(u32);
impl DeviceId {
pub fn new(v: u32) -> Self {
Self(v)
}
}
#[repr(C)]
pub struct DeviceInterrupt {
pub sync: AtomicU64,
pub vec: InterruptVector,
pub flags: DeviceInterruptFlags,
pub taken: AtomicU16,
}
#[derive(Clone, Copy, Debug)]
pub enum MailboxPriority {
Idle,
Low,
High,
Num,
}
impl TryFrom<usize> for MailboxPriority {
type Error = ();
fn try_from(value: usize) -> Result<Self, Self::Error> {
Ok(match value {
0 => MailboxPriority::Idle,
1 => MailboxPriority::Low,
2 => MailboxPriority::High,
3 => MailboxPriority::Num,
_ => return Err(()),
})
}
}
#[repr(C)]
pub struct DeviceRepr {
kso_hdr: KsoHdr,
pub device_type: DeviceType,
pub bus_type: BusType,
pub device_id: DeviceId,
pub interrupts: [DeviceInterrupt; NUM_DEVICE_INTERRUPTS],
pub mailboxes: [AtomicU64; MailboxPriority::Num as usize],
}
impl crate::marker::BaseType for DeviceRepr {
fn init<T>(_t: T) -> Self {
todo!()
}
fn tags() -> &'static [(crate::marker::BaseVersion, crate::marker::BaseTag)] {
todo!()
}
}
impl Display for DeviceRepr {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"Device::{{{:?}, {:?}, {:?}}}({})",
self.device_type, self.bus_type, self.device_id, self.kso_hdr
)
}
}
impl DeviceRepr {
pub fn new(
kso_hdr: KsoHdr,
device_type: DeviceType,
bus_type: BusType,
device_id: DeviceId,
) -> Self {
#[allow(clippy::declare_interior_mutable_const)]
const V: DeviceInterrupt = DeviceInterrupt {
sync: AtomicU64::new(0),
vec: InterruptVector(0),
flags: DeviceInterruptFlags::empty(),
taken: AtomicU16::new(0),
};
#[allow(clippy::declare_interior_mutable_const)]
const M: AtomicU64 = AtomicU64::new(0);
Self {
kso_hdr,
device_type,
bus_type,
device_id,
interrupts: [V; NUM_DEVICE_INTERRUPTS],
mailboxes: [M; MailboxPriority::Num as usize],
}
}
pub fn wait_for_interrupt(&self, inum: usize, timeout: Option<Duration>) -> u64 {
loop {
let val = self.interrupts[inum].sync.swap(0, Ordering::SeqCst);
if val != 0 {
return val;
}
for _ in 0..100 {
let val = self.interrupts[inum].sync.load(Ordering::SeqCst);
if val != 0 {
return self.interrupts[inum].sync.swap(0, Ordering::SeqCst);
}
}
let op = ThreadSync::new_sleep(ThreadSyncSleep::new(
ThreadSyncReference::Virtual(&self.interrupts[inum].sync as *const AtomicU64),
0,
ThreadSyncOp::Equal,
ThreadSyncFlags::empty(),
));
let res = crate::syscall::sys_thread_sync(&mut [op], timeout);
if res.is_err() {
return 0;
}
}
}
pub fn setup_interrupt_sleep(&self, inum: usize) -> ThreadSyncSleep {
ThreadSyncSleep {
reference: ThreadSyncReference::Virtual(&self.interrupts[inum].sync),
value: 0,
op: ThreadSyncOp::Equal,
flags: ThreadSyncFlags::empty(),
}
}
pub fn submit_mailbox_msg(&self, mb: MailboxPriority, msg: u64) {
while self.mailboxes[mb as usize]
.compare_exchange(0, msg, Ordering::SeqCst, Ordering::SeqCst)
.is_err()
{
core::hint::spin_loop()
}
let _ = sys_thread_sync(
&mut [ThreadSync::new_wake(ThreadSyncWake::new(
ThreadSyncReference::Virtual(&self.mailboxes[mb as usize]),
usize::MAX,
))],
None,
);
}
pub fn check_for_interrupt(&self, inum: usize) -> Option<u64> {
let val = self.interrupts[inum].sync.swap(0, Ordering::SeqCst);
if val == 0 {
None
} else {
Some(val)
}
}
pub fn check_for_mailbox(&self, inum: usize) -> Option<u64> {
let val = self.mailboxes[inum].swap(0, Ordering::SeqCst);
if val == 0 {
None
} else {
Some(val)
}
}
pub fn register_interrupt(
&mut self,
inum: usize,
vec: InterruptVector,
flags: DeviceInterruptFlags,
) {
self.interrupts[inum].vec = vec;
self.interrupts[inum].flags = flags;
self.interrupts[inum].sync = AtomicU64::new(0);
}
}