66
77use 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+ /// Returns the ID of the CPU the code is currently running on.
107+ ///
108+ /// The returned value is considered unstable because it may change
109+ /// unexpectedly due to preemption or CPU migration. It should only be
110+ /// used when the context ensures that the task remains on the same CPU
111+ /// or the users could use a stale (yet valid) CPU ID.
112+ pub fn current ( ) -> Self {
113+ // SAFETY: raw_smp_processor_id() always returns a valid CPU ID.
114+ unsafe { Self :: from_u32_unchecked ( bindings:: raw_smp_processor_id ( ) ) }
115+ }
116+ }
117+
118+ impl From < CpuId > for u32 {
119+ fn from ( id : CpuId ) -> Self {
120+ id. as_u32 ( )
121+ }
122+ }
123+
124+ impl From < CpuId > for i32 {
125+ fn from ( id : CpuId ) -> Self {
126+ id. as_u32 ( ) as i32
127+ }
128+ }
129+
9130/// Creates a new instance of CPU's device.
10131///
11132/// # Safety
@@ -17,9 +138,9 @@ use crate::{bindings, device::Device, error::Result, prelude::ENODEV};
17138/// Callers must ensure that the CPU device is not used after it has been unregistered.
18139/// This can be achieved, for example, by registering a CPU hotplug notifier and removing
19140/// any references to the CPU device within the notifier's callback.
20- pub unsafe fn from_cpu ( cpu : u32 ) -> Result < & ' static Device > {
141+ pub unsafe fn from_cpu ( cpu : CpuId ) -> Result < & ' static Device > {
21142 // SAFETY: It is safe to call `get_cpu_device()` for any CPU.
22- let ptr = unsafe { bindings:: get_cpu_device ( cpu) } ;
143+ let ptr = unsafe { bindings:: get_cpu_device ( u32 :: from ( cpu) ) } ;
23144 if ptr. is_null ( ) {
24145 return Err ( ENODEV ) ;
25146 }
0 commit comments