[PATCH v3 1/2] rust: math: add div64_u64() and div64_u64_round_up()
FUJITA Tomonori
tomo at flapping.org
Thu Oct 29 19:02:08 PDT 2026
From: FUJITA Tomonori <fujita.tomonori at gmail.com>
On 32-bit architectures, dividing a u64 by a u64 with the `/` operator
makes the compiler emit a call to a compiler runtime function, such as
__aeabi_uldivmod() on arm. The kernel does not provide these functions,
so the build fails when Rust code that is also built for 32-bit
architectures uses `/` on u64.
C code uses the helpers in include/linux/math64.h instead. Add a math
module with Rust versions of two of them:
- div64_u64(), the same as div64_u64() in C.
- div64_u64_round_up(), the same as DIV64_U64_ROUND_UP() in C.
On 64-bit architectures, both use `/`. On 32-bit architectures,
div64_u64() calls the C function. Both panic if the divisor is zero,
as `/` does.
Assisted-by: LLM
Signed-off-by: FUJITA Tomonori <fujita.tomonori at gmail.com>
---
rust/kernel/lib.rs | 1 +
rust/kernel/math.rs | 71 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 72 insertions(+)
create mode 100644 rust/kernel/math.rs
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 1ab41129d557..482fef8be2e8 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -100,6 +100,7 @@
pub mod kunit;
pub mod list;
pub mod maple_tree;
+pub mod math;
pub mod mem;
pub mod miscdevice;
pub mod mm;
diff --git a/rust/kernel/math.rs b/rust/kernel/math.rs
new file mode 100644
index 000000000000..395816639af8
--- /dev/null
+++ b/rust/kernel/math.rs
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Integer arithmetic helpers.
+//!
+//! C header: [`include/linux/math64.h`](srctree/include/linux/math64.h).
+
+/// Divides a [`u64`] dividend by a [`u64`] divisor, rounding down.
+///
+/// On 32-bit architectures, `/` on [`u64`] needs a function that the kernel does
+/// not provide. Use this function in code that is also built for 32-bit
+/// architectures.
+///
+/// # Panics
+///
+/// Panics if `divisor` is zero.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::math::div64_u64;
+///
+/// assert_eq!(div64_u64(7, 2), 3);
+/// assert_eq!(div64_u64(u64::MAX, 1 << 32), u64::from(u32::MAX));
+/// ```
+#[inline]
+pub fn div64_u64(dividend: u64, divisor: u64) -> u64 {
+ if divisor == 0 {
+ panic!("attempt to divide by zero");
+ }
+
+ #[cfg(CONFIG_64BIT)]
+ {
+ dividend / divisor
+ }
+
+ #[cfg(not(CONFIG_64BIT))]
+ {
+ // SAFETY: `div64_u64()` requires a non-zero `divisor`, which is
+ // checked above.
+ unsafe { bindings::div64_u64(dividend, divisor) }
+ }
+}
+
+/// Divides a [`u64`] dividend by a [`u64`] divisor, rounding up.
+///
+/// # Panics
+///
+/// Panics if `divisor` is zero.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::math::div64_u64_round_up;
+///
+/// assert_eq!(div64_u64_round_up(7, 2), 4);
+/// assert_eq!(div64_u64_round_up(6, 2), 3);
+/// assert_eq!(div64_u64_round_up(u64::MAX, 2), 1 << 63);
+/// ```
+#[inline]
+pub fn div64_u64_round_up(dividend: u64, divisor: u64) -> u64 {
+ let quotient = div64_u64(dividend, divisor);
+
+ // `quotient * divisor` is not greater than `dividend`, so this does not
+ // overflow.
+ if dividend - quotient * divisor == 0 {
+ quotient
+ } else {
+ // A non-zero remainder means `divisor >= 2`, so this does not overflow.
+ quotient + 1
+ }
+}
--
2.43.0
More information about the linux-riscv
mailing list