use bitflags::bitflags;
use zerocopy::{Immutable, IntoBytes};
use crate::{
net::{BROADCAST_MAC_ADDR, UHYVE_NET_MTU},
pci::PciConfigurationOffset,
virtio::{
VirtqueueNotification,
pci::{HeaderConf, get_offset},
},
};
#[derive(Debug, Clone, Copy, IntoBytes, PartialEq, Eq, Immutable)]
#[repr(u8)]
#[allow(non_camel_case_types, unused)]
pub enum CfgType {
INVALID_CFG = 0x00,
COMMON_CFG = 0x01,
NOTIFY_CFG = 0x02,
ISR_CFG = 0x03,
DEVICE_CFG = 0x04,
PCI_CFG = 0x05,
_SHARED_MEMORY_CFG = 0x08,
VENDOR_CFG = 0x09,
}
#[repr(u32)]
#[derive(Clone, Copy, Debug, IntoBytes, Immutable)]
pub enum FeatureSelector {
Low = 0,
High = 1,
}
impl From<u32> for FeatureSelector {
fn from(value: u32) -> Self {
match value {
0 => Self::Low,
1 => Self::High,
_ => Self::Low, }
}
}
#[derive(IntoBytes, Clone, Copy, Debug, Immutable)]
#[repr(C)]
pub struct PciCap {
pub cap_vndr: u8,
pub cap_next: u8,
pub cap_len: u8,
pub cfg_type: CfgType,
pub bar_index: u8,
pub id: u8,
pub _padding: [u8; 2],
pub offset: u32,
pub length: u32,
}
impl Default for PciCap {
fn default() -> Self {
Self {
cap_vndr: 0x09, cap_next: 0,
cap_len: std::mem::size_of::<PciCap>() as u8,
cfg_type: CfgType::INVALID_CFG,
bar_index: 0,
id: 0,
_padding: [0u8; 2],
offset: 0,
length: 0,
}
}
}
#[derive(Copy, Clone, Debug, IntoBytes, PartialEq, Eq, Immutable)]
#[repr(C)]
pub struct NetDevStatus(u16);
bitflags! {
impl NetDevStatus: u16 {
const UNINITIALIZED = 0;
const VIRTIO_NET_S_LINK_UP = 1;
const VIRTIO_NET_S_ANNOUNCE = 2;
}
}
#[derive(IntoBytes, Clone, Debug, Immutable)]
#[repr(C)]
pub struct NetDevCfg {
pub mac: [u8; 6],
pub status: NetDevStatus,
_max_virtqueue_pairs: u16,
pub mtu: u16,
_speed: u32,
_duplex: u8,
_rss_max_key_size: u8,
_rss_max_indirection_table_length: u16,
_supported_hash_types: u32,
}
impl NetDevCfg {
pub const MAC_ADDRESS: u8 = get_offset!(HeaderConf::DEVICE_CFG_START, NetDevCfg, mac).0;
pub const MAC_ADDRESS_END: u8 = get_offset!(HeaderConf::DEVICE_CFG_START, NetDevCfg, mac).0 + 6;
pub const NET_STATUS: u8 = get_offset!(HeaderConf::DEVICE_CFG_START, NetDevCfg, status).0;
pub const MTU: u8 = get_offset!(HeaderConf::DEVICE_CFG_START, NetDevCfg, mtu).0;
}
impl Default for NetDevCfg {
fn default() -> Self {
Self {
mac: BROADCAST_MAC_ADDR,
status: NetDevStatus::UNINITIALIZED,
_max_virtqueue_pairs: 0,
mtu: UHYVE_NET_MTU as u16,
_speed: 0u32,
_duplex: 0u8,
_rss_max_key_size: 0u8,
_rss_max_indirection_table_length: 0u16,
_supported_hash_types: 0u32,
}
}
}
#[derive(Copy, Clone, Debug, IntoBytes, PartialEq, Eq, Default, Immutable)]
#[repr(C)]
pub struct IsrStatus(u8);
bitflags! {
impl IsrStatus: u8 {
const NOTIFY_USED_BUFFER = 0b01;
const NOTIFY_CONFIGURUTION_CHANGED = 0b10;
}
}
impl IsrStatus {
pub const ISR_FLAGS: u8 = PciConfigurationOffset(HeaderConf::ISR_CFG_START).0;
}
#[derive(IntoBytes, Clone, Debug, Immutable)]
#[repr(C)]
pub struct NotifyCap {
pub cap: PciCap,
pub notify_off_multiplier: u32,
}
impl Default for NotifyCap {
fn default() -> Self {
Self {
cap: PciCap {
cap_len: std::mem::size_of::<NotifyCap>() as u8,
cfg_type: CfgType::NOTIFY_CFG,
offset: 0,
length: std::mem::size_of::<VirtqueueNotification>() as u32 * 2,
..Default::default()
},
notify_off_multiplier: 0,
}
}
}
#[derive(IntoBytes, Clone, Copy, Debug, Immutable)]
#[repr(C)]
#[allow(dead_code, reason = "Not all PCI structures are used in Uhyve")]
pub struct ComCfg {
pub device_feature_select: FeatureSelector,
pub device_feature: u32,
pub driver_feature_select: FeatureSelector,
pub driver_feature: u32,
pub config_msix_vector: u16,
pub num_queues: u16,
pub device_status: u8,
pub config_generation: u8,
pub queue_select: u16,
pub queue_size: u16,
pub queue_msix_vector: u16,
pub queue_enable: u16,
pub queue_notify_off: u16,
pub queue_desc: u64,
pub queue_driver: u64,
pub queue_device: u64,
pub queue_notify_data: u16,
pub queue_reset: u16,
_padding: [u8; 4],
}
#[allow(dead_code)]
impl ComCfg {
pub const DEVICE_FEATURE_SELECT: u8 =
get_offset!(HeaderConf::COMMON_CFG_START, Self, device_feature_select).0;
pub const DEVICE_FEATURE: u8 =
get_offset!(HeaderConf::COMMON_CFG_START, Self, device_feature).0;
pub const DRIVER_FEATURE_SELECT: u8 =
get_offset!(HeaderConf::COMMON_CFG_START, Self, driver_feature_select).0;
pub const DRIVER_FEATURE: u8 =
get_offset!(HeaderConf::COMMON_CFG_START, Self, driver_feature).0;
pub const NUM_QUEUES: u8 = get_offset!(HeaderConf::COMMON_CFG_START, Self, num_queues).0;
pub const CONFIG_MSIX_VECTOR: u8 =
get_offset!(HeaderConf::COMMON_CFG_START, Self, config_msix_vector).0;
pub const DEVICE_STATUS: u8 = get_offset!(HeaderConf::COMMON_CFG_START, Self, device_status).0;
pub const CONFIG_GENERATION: u8 =
get_offset!(HeaderConf::COMMON_CFG_START, Self, config_generation).0;
pub const QUEUE_SELECT: u8 = get_offset!(HeaderConf::COMMON_CFG_START, Self, queue_select).0;
pub const QUEUE_SIZE: u8 = get_offset!(HeaderConf::COMMON_CFG_START, Self, queue_size).0;
pub const QUEUE_MSIX_VECTOR: u8 =
get_offset!(HeaderConf::COMMON_CFG_START, Self, queue_msix_vector).0;
pub const QUEUE_ENABLE: u8 = get_offset!(HeaderConf::COMMON_CFG_START, Self, queue_enable).0;
pub const QUEUE_NOTIFY_OFFSET: u8 =
get_offset!(HeaderConf::COMMON_CFG_START, Self, queue_notify_off).0;
pub const QUEUE_DESC_LOW: u8 = get_offset!(HeaderConf::COMMON_CFG_START, Self, queue_desc).0;
pub const QUEUE_DESC_HIGH: u8 =
get_offset!(HeaderConf::COMMON_CFG_START, Self, queue_desc).0 + 4;
pub const QUEUE_DRIVER_LOW: u8 =
get_offset!(HeaderConf::COMMON_CFG_START, Self, queue_driver).0;
pub const QUEUE_DRIVER_HIGH: u8 =
get_offset!(HeaderConf::COMMON_CFG_START, Self, queue_driver).0 + 4;
pub const QUEUE_DEVICE_LOW: u8 =
get_offset!(HeaderConf::COMMON_CFG_START, Self, queue_device).0;
pub const QUEUE_DEVICE_HIGH: u8 =
get_offset!(HeaderConf::COMMON_CFG_START, Self, queue_device).0 + 4;
pub const QUEUE_NOTIFY_DATA: u8 =
get_offset!(HeaderConf::COMMON_CFG_START, Self, queue_notify_data).0;
pub const QUEUE_RESET: u8 = get_offset!(HeaderConf::COMMON_CFG_START, Self, queue_reset).0;
}
impl Default for ComCfg {
fn default() -> Self {
Self {
device_feature_select: FeatureSelector::Low,
device_feature: 0,
driver_feature_select: FeatureSelector::Low,
driver_feature: 0,
config_msix_vector: super::VIRTIO_MSI_NO_VECTOR,
num_queues: 0,
device_status: 0,
config_generation: 0,
queue_select: 0,
queue_size: 0,
queue_msix_vector: 0,
queue_enable: 0,
queue_notify_off: 0,
queue_desc: 0,
queue_driver: 0,
queue_device: 0,
queue_notify_data: 0,
queue_reset: 0,
_padding: Default::default(),
}
}
}