Skip to content

Commit

Permalink
refac: use enum_from_bits! where appropriate
Browse files Browse the repository at this point in the history
Depends on #450.

This branch replaces some boilerplate implementations of `FromBits` for
enum types with the `enum_from_bits!` macro added to `mycelium-bitfield`
in #450.

I didn't touch a couple manual `FromBits` implementations. Some parts of
`mycelium-pci` manually implement `FromBits` in order to return a custom
error type, so I left those alone. A few places in `maitake` use manual
implementations for enums that cover all possible 2-bit bit patterns, so
that the error arm can be `unreachable_unchecked!`. I didn't touch those
either, since the perf delta may actually matter in those cases.
  • Loading branch information
hawkw committed Jul 22, 2023
1 parent 81f7e49 commit 5807e98
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 395 deletions.
105 changes: 11 additions & 94 deletions hal-x86_64/src/interrupt/apic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pub mod local;
pub use io::IoApic;
pub use local::LocalApic;

use mycelium_util::bits::FromBits;
use mycelium_util::bits::enum_from_bits;
use raw_cpuid::CpuId;

pub fn is_supported() -> bool {
Expand All @@ -14,101 +14,18 @@ pub fn is_supported() -> bool {
.unwrap_or(false)
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum PinPolarity {
High = 0,
Low = 1,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum TriggerMode {
Edge = 0,
Level = 1,
}

// === impl PinPolarity ===

impl PinPolarity {
#[inline(always)]
#[must_use]
fn from_u8(bits: u8) -> Self {
match bits {
0 => Self::High,
1 => Self::Low,
bits => unreachable!(
"APIC PinPolarity should be a single bit, but got {:#b}",
bits
),
}
enum_from_bits! {
#[derive(Debug, PartialEq, Eq)]
pub enum PinPolarity<u8> {
High = 0,
Low = 1,
}
}

impl FromBits<u64> for PinPolarity {
const BITS: u32 = 1;
type Error = core::convert::Infallible;

fn into_bits(self) -> u64 {
self as u8 as u64
}

fn try_from_bits(bits: u64) -> Result<Self, Self::Error> {
Ok(Self::from_u8(bits as u8))
}
}

impl FromBits<u32> for PinPolarity {
const BITS: u32 = 1;
type Error = core::convert::Infallible;

fn into_bits(self) -> u32 {
self as u8 as u32
}

fn try_from_bits(bits: u32) -> Result<Self, Self::Error> {
Ok(Self::from_u8(bits as u8))
}
}
// === impl TriggerMode ===

impl TriggerMode {
#[inline(always)]
#[must_use]
fn from_u8(bits: u8) -> Self {
match bits {
0 => Self::Edge,
1 => Self::Level,
_ => unreachable!(
"APIC TriggerMode should be a single bit, but got {:#b}",
bits
),
}
}
}

impl FromBits<u64> for TriggerMode {
const BITS: u32 = 1;
type Error = core::convert::Infallible;

fn into_bits(self) -> u64 {
self as u8 as u64
}

fn try_from_bits(bits: u64) -> Result<Self, Self::Error> {
Ok(Self::from_u8(bits as u8))
}
}

impl FromBits<u32> for TriggerMode {
const BITS: u32 = 1;
type Error = core::convert::Infallible;

fn into_bits(self) -> u32 {
self as u8 as u32
}

fn try_from_bits(bits: u32) -> Result<Self, Self::Error> {
Ok(Self::from_u8(bits as u8))
enum_from_bits! {
#[derive(Debug, PartialEq, Eq)]
pub enum TriggerMode<u8> {
Edge = 0,
Level = 1,
}
}
87 changes: 23 additions & 64 deletions hal-x86_64/src/interrupt/apic/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
mm::{self, page, size::Size4Kb, PhysPage, VirtPage},
};
use hal_core::PAddr;
use mycelium_util::bits::{bitfield, FromBits};
use mycelium_util::bits::{bitfield, enum_from_bits};
use volatile::Volatile;

#[derive(Debug)]
Expand Down Expand Up @@ -44,28 +44,30 @@ bitfield! {
}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum DestinationMode {
Physical = 0,
Logical = 1,
enum_from_bits! {
#[derive(Debug, PartialEq, Eq)]
pub enum DestinationMode<u8> {
Physical = 0,
Logical = 1,
}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum DeliveryMode {
/// Normal interrupt delivery.
Normal = 0b000,
/// Lowest priority.
LowPriority = 0b001,
/// System Management Interrupt (SMI).
SystemManagement = 0b010,
/// Non-Maskable Interrupt (NMI).
NonMaskable = 0b100,
/// "INIT" (what does this mean? i don't know!)
Init = 0b101,
/// External interrupt.
External = 0b111,
enum_from_bits! {
#[derive(Debug, PartialEq, Eq)]
pub enum DeliveryMode<u8> {
/// Normal interrupt delivery.
Normal = 0b000,
/// Lowest priority.
LowPriority = 0b001,
/// System Management Interrupt (SMI).
SystemManagement = 0b010,
/// Non-Maskable Interrupt (NMI).
NonMaskable = 0b100,
/// "INIT" (what does this mean? i don't know!)
Init = 0b101,
/// External interrupt.
External = 0b111,
}
}

/// Memory-mapped IOAPIC registers
Expand Down Expand Up @@ -278,49 +280,6 @@ impl Default for DeliveryMode {
}
}

impl FromBits<u64> for DeliveryMode {
const BITS: u32 = 3;
type Error = &'static str;

fn into_bits(self) -> u64 {
self as u8 as u64
}

fn try_from_bits(bits: u64) -> Result<Self, Self::Error> {
match bits {
bits if bits as u8 == Self::Normal as u8 => Ok(Self::Normal),
bits if bits as u8 == Self::LowPriority as u8 => Ok(Self::LowPriority),
bits if bits as u8 == Self::SystemManagement as u8 => Ok(Self::SystemManagement),
bits if bits as u8 == Self::NonMaskable as u8 => Ok(Self::NonMaskable),
bits if bits as u8 == Self::Init as u8 => Ok(Self::Init),
bits if bits as u8 == Self::External as u8 => Ok(Self::External),
_ => Err(
"IOAPIC delivery mode must be one of 0b000, 0b001, 0b010, 0b100, 0b101, or 0b111",
),
}
}
}

// === impl DestinationMode ===

impl FromBits<u64> for DestinationMode {
const BITS: u32 = 1;
type Error = core::convert::Infallible;

fn into_bits(self) -> u64 {
self as u8 as u64
}

fn try_from_bits(bits: u64) -> Result<Self, Self::Error> {
Ok(match bits {
0 => Self::Physical,
1 => Self::Logical,
_ => unreachable!(),
})
}
}

#[cfg(test)]
mod test {
use super::*;

Check warning on line 284 in hal-x86_64/src/interrupt/apic/io.rs

View workflow job for this annotation

GitHub Actions / cargo check (host)

warning: unused import: `super::*` --> hal-x86_64/src/interrupt/apic/io.rs:284:9 | 284 | use super::*; | ^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default

Check warning on line 284 in hal-x86_64/src/interrupt/apic/io.rs

View workflow job for this annotation

GitHub Actions / clippy

warning: unused import: `super::*` --> hal-x86_64/src/interrupt/apic/io.rs:284:9 | 284 | use super::*; | ^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default

Check warning on line 284 in hal-x86_64/src/interrupt/apic/io.rs

View workflow job for this annotation

GitHub Actions / docs

warning: unused import: `super::*` --> hal-x86_64/src/interrupt/apic/io.rs:284:9 | 284 | use super::*; | ^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default

Expand Down
37 changes: 10 additions & 27 deletions hal-x86_64/src/interrupt/apic/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ impl LocalApic {

pub mod register {
use super::*;
use mycelium_util::bits::{bitfield, FromBits};
use mycelium_util::bits::{bitfield, enum_from_bits};
use volatile::access::*;

impl<T> RegisterAccess for LocalApicRegister<T, ReadOnly> {
Expand Down Expand Up @@ -453,32 +453,15 @@ pub mod register {
}
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum TimerMode {
/// One-shot mode, program count-down value in an initial-count register.
OneShot = 0b00,
/// Periodic mode, program interval value in an initial-count register.
Periodic = 0b01,
/// TSC-Deadline mode, program target value in IA32_TSC_DEADLINE MSR.
TscDeadline = 0b10,
}

impl FromBits<u32> for TimerMode {
const BITS: u32 = 2;
type Error = &'static str;

fn try_from_bits(bits: u32) -> Result<Self, Self::Error> {
match bits {
bits if bits as u8 == Self::OneShot as u8 => Ok(Self::OneShot),
bits if bits as u8 == Self::Periodic as u8 => Ok(Self::Periodic),
bits if bits as u8 == Self::TscDeadline as u8 => Ok(Self::TscDeadline),
_ => Err("0b11 is not a valid local APIC timer mode"),
}
}

fn into_bits(self) -> u32 {
self as u8 as u32
enum_from_bits! {
#[derive(Debug, Eq, PartialEq)]
pub enum TimerMode<u8> {
/// One-shot mode, program count-down value in an initial-count register.
OneShot = 0b00,
/// Periodic mode, program interval value in an initial-count register.
Periodic = 0b01,
/// TSC-Deadline mode, program target value in IA32_TSC_DEADLINE MSR.
TscDeadline = 0b10,
}
}
}
Expand Down
Loading

0 comments on commit 5807e98

Please sign in to comment.