Skip to content

Commit ebf2e50

Browse files
committed
rust: cpu: Introduce CpuId abstraction
This adds abstraction for representing a CPU identifier. Suggested-by: Boqun Feng <[email protected]> Signed-off-by: Viresh Kumar <[email protected]> Reviewed-by: Boqun Feng <[email protected]>
1 parent 4823a58 commit ebf2e50

File tree

1 file changed

+110
-0
lines changed

1 file changed

+110
-0
lines changed

rust/kernel/cpu.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,116 @@
66
77
use crate::{bindings, device::Device, error::Result, prelude::ENODEV};
88

9+
/// Returns the maximum number of possible CPUs in the current system configuration.
10+
#[inline]
11+
pub fn nr_cpu_ids() -> u32 {
12+
#[cfg(any(NR_CPUS_1, CONFIG_FORCE_NR_CPUS))]
13+
{
14+
bindings::NR_CPUS
15+
}
16+
17+
#[cfg(not(any(NR_CPUS_1, CONFIG_FORCE_NR_CPUS)))]
18+
// SAFETY: `nr_cpu_ids` is a valid global provided by the kernel.
19+
unsafe {
20+
bindings::nr_cpu_ids
21+
}
22+
}
23+
24+
/// The CPU ID.
25+
///
26+
/// Represents a CPU identifier as a wrapper around an [`u32`].
27+
///
28+
/// # Invariants
29+
///
30+
/// The CPU ID lies within the range `[0, nr_cpu_ids())`.
31+
///
32+
/// # Examples
33+
///
34+
/// ```
35+
/// use kernel::cpu::CpuId;
36+
///
37+
/// let cpu = 0;
38+
///
39+
/// // SAFETY: 0 is always a valid CPU number.
40+
/// let id = unsafe { CpuId::from_u32_unchecked(cpu) };
41+
///
42+
/// assert_eq!(id.as_u32(), cpu);
43+
/// assert!(CpuId::from_i32(0).is_some());
44+
/// assert!(CpuId::from_i32(-1).is_none());
45+
/// ```
46+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
47+
pub struct CpuId(u32);
48+
49+
impl CpuId {
50+
/// Creates a new [`CpuId`] from the given `id` without checking bounds.
51+
///
52+
/// # Safety
53+
///
54+
/// The caller must ensure that `id` is a valid CPU ID (i.e., `0 <= id < nr_cpu_ids()`).
55+
#[inline]
56+
pub unsafe fn from_i32_unchecked(id: i32) -> Self {
57+
debug_assert!(id >= 0);
58+
debug_assert!((id as u32) < nr_cpu_ids());
59+
60+
// INVARIANT: The function safety guarantees `id` is a valid CPU id.
61+
Self(id as u32)
62+
}
63+
64+
/// Creates a new [`CpuId`] from the given `id`, checking that it is valid.
65+
pub fn from_i32(id: i32) -> Option<Self> {
66+
if id < 0 || id as u32 >= nr_cpu_ids() {
67+
None
68+
} else {
69+
// INVARIANT: `id` has just been checked as a valid CPU ID.
70+
Some(Self(id as u32))
71+
}
72+
}
73+
74+
/// Creates a new [`CpuId`] from the given `id` without checking bounds.
75+
///
76+
/// # Safety
77+
///
78+
/// The caller must ensure that `id` is a valid CPU ID (i.e., `0 <= id < nr_cpu_ids()`).
79+
#[inline]
80+
pub unsafe fn from_u32_unchecked(id: u32) -> Self {
81+
debug_assert!(id < nr_cpu_ids());
82+
83+
// Ensure the `id` fits in an [`i32`] as it's also representable that way.
84+
debug_assert!(id <= i32::MAX as u32);
85+
86+
// INVARIANT: The function safety guarantees `id` is a valid CPU id.
87+
Self(id)
88+
}
89+
90+
/// Creates a new [`CpuId`] from the given `id`, checking that it is valid.
91+
pub fn from_u32(id: u32) -> Option<Self> {
92+
if id >= nr_cpu_ids() {
93+
None
94+
} else {
95+
// INVARIANT: `id` has just been checked as a valid CPU ID.
96+
Some(Self(id))
97+
}
98+
}
99+
100+
/// Returns CPU number.
101+
#[inline]
102+
pub fn as_u32(&self) -> u32 {
103+
self.0
104+
}
105+
}
106+
107+
impl From<CpuId> for u32 {
108+
fn from(id: CpuId) -> Self {
109+
id.as_u32()
110+
}
111+
}
112+
113+
impl From<CpuId> for i32 {
114+
fn from(id: CpuId) -> Self {
115+
id.as_u32() as i32
116+
}
117+
}
118+
9119
/// Creates a new instance of CPU's device.
10120
///
11121
/// # Safety

0 commit comments

Comments
 (0)