Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/rust/kernel/cpu.rs
29266 views
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
#[inline]
113
pub fn current() -> Self {
114
// SAFETY: raw_smp_processor_id() always returns a valid CPU ID.
115
unsafe { Self::from_u32_unchecked(bindings::raw_smp_processor_id()) }
116
}
117
}
118
119
impl From<CpuId> for u32 {
120
fn from(id: CpuId) -> Self {
121
id.as_u32()
122
}
123
}
124
125
impl From<CpuId> for i32 {
126
fn from(id: CpuId) -> Self {
127
id.as_u32() as i32
128
}
129
}
130
131
/// Creates a new instance of CPU's device.
132
///
133
/// # Safety
134
///
135
/// Reference counting is not implemented for the CPU device in the C code. When a CPU is
136
/// hot-unplugged, the corresponding CPU device is unregistered, but its associated memory
137
/// is not freed.
138
///
139
/// Callers must ensure that the CPU device is not used after it has been unregistered.
140
/// This can be achieved, for example, by registering a CPU hotplug notifier and removing
141
/// any references to the CPU device within the notifier's callback.
142
pub unsafe fn from_cpu(cpu: CpuId) -> Result<&'static Device> {
143
// SAFETY: It is safe to call `get_cpu_device()` for any CPU.
144
let ptr = unsafe { bindings::get_cpu_device(u32::from(cpu)) };
145
if ptr.is_null() {
146
return Err(ENODEV);
147
}
148
149
// SAFETY: The pointer returned by `get_cpu_device()`, if not `NULL`, is a valid pointer to
150
// a `struct device` and is never freed by the C code.
151
Ok(unsafe { Device::from_raw(ptr) })
152
}
153
154