1 // SPDX-License-Identifier: GPL-2.0 2 3 //! Generic CPU definitions. 4 //! 5 //! C header: [`include/linux/cpu.h`](srctree/include/linux/cpu.h) 6 7 use crate::{bindings, device::Device, error::Result, prelude::ENODEV}; 8 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 130 /// Creates a new instance of CPU's device. 131 /// 132 /// # Safety 133 /// 134 /// Reference counting is not implemented for the CPU device in the C code. When a CPU is 135 /// hot-unplugged, the corresponding CPU device is unregistered, but its associated memory 136 /// is not freed. 137 /// 138 /// Callers must ensure that the CPU device is not used after it has been unregistered. 139 /// This can be achieved, for example, by registering a CPU hotplug notifier and removing 140 /// any references to the CPU device within the notifier's callback. 141 pub unsafe fn from_cpu(cpu: CpuId) -> Result<&'static Device> { 142 // SAFETY: It is safe to call `get_cpu_device()` for any CPU. 143 let ptr = unsafe { bindings::get_cpu_device(u32::from(cpu)) }; 144 if ptr.is_null() { 145 return Err(ENODEV); 146 } 147 148 // SAFETY: The pointer returned by `get_cpu_device()`, if not `NULL`, is a valid pointer to 149 // a `struct device` and is never freed by the C code. 150 Ok(unsafe { Device::as_ref(ptr) }) 151 } 152