use core::fmt::Debug;
use core::mem::size_of;
use core::ops::Range;
use core::sync::atomic::{AtomicU32, Ordering};
use memoffset::offset_of;
use static_assertions::const_assert;
pub unsafe fn make_atomic_u32<'a>(ptr: *mut u32) -> &'a AtomicU32 {
&*(ptr as *const AtomicU32)
}
#[derive(Copy, Clone, Debug, Default)]
pub struct Host;
#[derive(Copy, Clone, Debug, Default)]
pub struct Client;
#[repr(C)]
pub struct ClientInfo {
pub reserved_start: u64,
pub reserved_end: u64,
}
#[repr(C)]
pub struct ControlFrameData {
pub next: AtomicU32,
_next_padding: [u8; 60],
pub current: AtomicU32,
_current_padding: [u8; 60],
pub num_command_frames: u32,
pub next_control_frame: u32,
_info_padding: [u8; 56],
pub client_info: ClientInfo,
pub xsave_layout: Layout,
}
const_assert!(size_of::<ControlFrameData>() == 256);
pub struct ControlFrame<'a, K> {
data: &'a ControlFrameData,
_kind: K,
}
impl<K> Debug for ControlFrame<'_, K> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ControlFrame")
.field("next", &self.data.next.load(Ordering::Acquire))
.field("current", &self.data.current.load(Ordering::Acquire))
.field("num_control_frames", &self.data.num_command_frames)
.finish()
}
}
impl<'a, K: Default> ControlFrame<'a, K> {
pub const NEXT_OFFSET: usize = offset_of!(ControlFrameData, next);
pub const CURRENT_OFFSET: usize = offset_of!(ControlFrameData, current);
pub const NUM_CONTROL_FRAMES_OFFSET: usize = offset_of!(ControlFrameData, num_command_frames);
pub unsafe fn new(ptr: *mut u8) -> ControlFrame<'a, K> {
ControlFrame {
data: &*(ptr as *const ControlFrameData),
_kind: K::default(),
}
}
#[inline]
pub fn reserved_range(&self) -> Range<u64> {
self.data.client_info.reserved_start..self.data.client_info.reserved_end
}
#[inline]
pub fn xsave_layout(&self) -> &Layout {
&self.data.xsave_layout
}
#[inline]
pub fn num_command_frames(&self) -> u32 {
self.data.num_command_frames
}
}
impl ControlFrame<'_, Host> {
#[inline]
pub fn current(&self) -> u32 {
self.data.current.load(Ordering::Acquire) % self.data.num_command_frames
}
#[inline]
pub fn update_next(&self, index: u32) {
self.data.next.store(index, Ordering::Release)
}
}
impl ControlFrame<'_, Client> {
#[inline]
pub fn next(&self) -> u32 {
self.data.next.load(Ordering::Acquire) % self.data.num_command_frames
}
#[inline]
pub fn update_current(&self, index: u32) {
self.data.current.store(index, Ordering::Release)
}
}
#[repr(C)]
#[derive(Clone, Debug)]
pub struct Layout {
pub x87: LayoutEntry,
pub avx256: LayoutEntry,
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct LayoutEntry {
pub available: bool,
pub offset: u64,
pub size: u64,
}
#[cfg(test)]
mod tests {
use memoffset::offset_of;
use crate::frame::control::ControlFrameData;
#[test]
pub fn verify_control_frame_alignment() {
assert!(offset_of!(ControlFrameData, current) - offset_of!(ControlFrameData, next) >= 64);
}
}