Rust changes for v6.18
Toolchain and infrastructure:
- Derive 'Zeroable' for all structs and unions generated by 'bindgen'
where possible and corresponding cleanups. To do so, add the
'pin-init' crate as a dependency to 'bindings' and 'uapi'.
It also includes its first use in the 'cpufreq' module, with more to
come in the next cycle.
- Add warning to the 'rustdoc' target to detect broken 'srctree/' links
and fix existing cases.
- Remove support for unused (since v6.16) host '#[test]'s, simplifying
the 'rusttest' target. Tests should generally run within KUnit.
'kernel' crate:
- Add 'ptr' module with a new 'Alignment' type, which is always a power
of two and is used to validate that a given value is a valid
alignment and to perform masking and alignment operations:
// Checked at build time.
assert_eq!(Alignment:🆕:<16>().as_usize(), 16);
// Checked at runtime.
assert_eq!(Alignment::new_checked(15), None);
assert_eq!(Alignment::of::<u8>().log2(), 0);
assert_eq!(0x25u8.align_down(Alignment:🆕:<0x10>()), 0x20);
assert_eq!(0x5u8.align_up(Alignment:🆕:<0x10>()), Some(0x10));
assert_eq!(u8::MAX.align_up(Alignment:🆕:<0x10>()), None);
It also includes its first use in Nova.
- Add 'core::mem::{align,size}_of{,_val}' to the prelude, matching
Rust 1.80.0.
- Keep going with the steps on our migration to the standard library
'core::ffi::CStr' type (use 'kernel::{fmt, prelude::fmt!}' and use
upstream method names).
- 'error' module: improve 'Error::from_errno' and 'to_result'
documentation, including examples/tests.
- 'sync' module: extend 'aref' submodule documentation now that it
exists, and more updates to complete the ongoing move of 'ARef' and
'AlwaysRefCounted' to 'sync::aref'.
- 'list' module: add an example/test for 'ListLinksSelfPtr' usage.
- 'alloc' module:
- Implement 'Box::pin_slice()', which constructs a pinned slice of
elements.
- Provide information about the minimum alignment guarantees of
'Kmalloc', 'Vmalloc' and 'KVmalloc'.
- Take minimum alignment guarantees of allocators for
'ForeignOwnable' into account.
- Remove the 'allocator_test' (including 'Cmalloc').
- Add doctest for 'Vec::as_slice()'.
- Constify various methods.
- 'time' module:
- Add methods on 'HrTimer' that can only be called with exclusive
access to an unarmed timer, or from timer callback context.
- Add arithmetic operations to 'Instant' and 'Delta'.
- Add a few convenience and access methods to 'HrTimer' and
'Instant'.
'macros' crate:
- Reduce collections in 'quote!' macro.
And a few other cleanups and improvements.
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEPjU5OPd5QIZ9jqqOGXyLc2htIW0FAmjZb3kACgkQGXyLc2ht
IW2+PA//T23FOYFjN2M+N2qBFocL4qBK0nSjp1UnnTsJ7ohlLU3orApY/Nl2DJTq
oO7SrWrdw6OVapvJN9IC2Jk0SfgFEiGu4L/eDg/xzkRmw89GGOOv+gp8gzz190mH
vZS5Nbbvs1GOlALA0BxwJG0vXtAu1de284/v0CCzXms6tCxSaUSes0vB7JNNzBSW
u73StEM5WlU3giGvnREl2lyX+jUFwG3mtfwpOuNavSYi3yO9Kg1pIIeP7ie/qrKF
30D8X3VacO2JcGC1qpQPsFCSfIlNl0yjkVPpFi8mIQO/XEqcej3tlojXq9oyP9Tj
tXcQL37ayBYnFSMPbelbOyTsgIyU9WwIJF+4V8u1H2C89k3f7/zqj+RMvW4y90Dc
/43z0OwW/N5PzUQ/EyTY0JYfMeNcsOyVcGXYawD/0pZuHgOz39WHPJSdq+wMpZUy
XESd6tr7ZHZudDsX+oq0hO1AI3pwkMvievFKG7ZtUiIcR9slv246M+WroOJcZUJ3
6I9v/f/z9rxsIYExQA2rTHiJ0+GAuXZ5lH5x/owZEZmzN3WLCHwuMoaIp/oL6387
y17yBpDtp6ar4B1KJILjuyjTF/kehazCNy7uiG1P8KTiCRUUTueIDYs257NMghg2
VKkyfdABAwgnsdrGLQXgRmI09RHg0xqslgT11DiPmLVVxJYCeLI=
=+VG2
-----END PGP SIGNATURE-----
Merge tag 'rust-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux
Pull rust updates from Miguel Ojeda:
"Toolchain and infrastructure:
- Derive 'Zeroable' for all structs and unions generated by 'bindgen'
where possible and corresponding cleanups. To do so, add the
'pin-init' crate as a dependency to 'bindings' and 'uapi'.
It also includes its first use in the 'cpufreq' module, with more
to come in the next cycle.
- Add warning to the 'rustdoc' target to detect broken 'srctree/'
links and fix existing cases.
- Remove support for unused (since v6.16) host '#[test]'s,
simplifying the 'rusttest' target. Tests should generally run
within KUnit.
'kernel' crate:
- Add 'ptr' module with a new 'Alignment' type, which is always a
power of two and is used to validate that a given value is a valid
alignment and to perform masking and alignment operations:
// Checked at build time.
assert_eq!(Alignment:🆕:<16>().as_usize(), 16);
// Checked at runtime.
assert_eq!(Alignment::new_checked(15), None);
assert_eq!(Alignment::of::<u8>().log2(), 0);
assert_eq!(0x25u8.align_down(Alignment:🆕:<0x10>()), 0x20);
assert_eq!(0x5u8.align_up(Alignment:🆕:<0x10>()), Some(0x10));
assert_eq!(u8::MAX.align_up(Alignment:🆕:<0x10>()), None);
It also includes its first use in Nova.
- Add 'core::mem::{align,size}_of{,_val}' to the prelude, matching
Rust 1.80.0.
- Keep going with the steps on our migration to the standard library
'core::ffi::CStr' type (use 'kernel::{fmt, prelude::fmt!}' and use
upstream method names).
- 'error' module: improve 'Error::from_errno' and 'to_result'
documentation, including examples/tests.
- 'sync' module: extend 'aref' submodule documentation now that it
exists, and more updates to complete the ongoing move of 'ARef' and
'AlwaysRefCounted' to 'sync::aref'.
- 'list' module: add an example/test for 'ListLinksSelfPtr' usage.
- 'alloc' module:
- Implement 'Box::pin_slice()', which constructs a pinned slice of
elements.
- Provide information about the minimum alignment guarantees of
'Kmalloc', 'Vmalloc' and 'KVmalloc'.
- Take minimum alignment guarantees of allocators for
'ForeignOwnable' into account.
- Remove the 'allocator_test' (including 'Cmalloc').
- Add doctest for 'Vec::as_slice()'.
- Constify various methods.
- 'time' module:
- Add methods on 'HrTimer' that can only be called with exclusive
access to an unarmed timer, or from timer callback context.
- Add arithmetic operations to 'Instant' and 'Delta'.
- Add a few convenience and access methods to 'HrTimer' and
'Instant'.
'macros' crate:
- Reduce collections in 'quote!' macro.
And a few other cleanups and improvements"
* tag 'rust-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux: (58 commits)
gpu: nova-core: use Alignment for alignment-related operations
rust: add `Alignment` type
rust: macros: reduce collections in `quote!` macro
rust: acpi: use `core::ffi::CStr` method names
rust: of: use `core::ffi::CStr` method names
rust: net: use `core::ffi::CStr` method names
rust: miscdevice: use `core::ffi::CStr` method names
rust: kunit: use `core::ffi::CStr` method names
rust: firmware: use `core::ffi::CStr` method names
rust: drm: use `core::ffi::CStr` method names
rust: cpufreq: use `core::ffi::CStr` method names
rust: configfs: use `core::ffi::CStr` method names
rust: auxiliary: use `core::ffi::CStr` method names
drm/panic: use `core::ffi::CStr` method names
rust: device: use `kernel::{fmt,prelude::fmt!}`
rust: sync: use `kernel::{fmt,prelude::fmt!}`
rust: seq_file: use `kernel::{fmt,prelude::fmt!}`
rust: kunit: use `kernel::{fmt,prelude::fmt!}`
rust: file: use `kernel::{fmt,prelude::fmt!}`
rust: device: use `kernel::{fmt,prelude::fmt!}`
...
pull/1354/merge
commit
f4e0ff7e45
|
|
@ -147,7 +147,6 @@ Numerical operations [NUMM]
|
||||||
Nova uses integer operations that are not part of the standard library (or not
|
Nova uses integer operations that are not part of the standard library (or not
|
||||||
implemented in an optimized way for the kernel). These include:
|
implemented in an optimized way for the kernel). These include:
|
||||||
|
|
||||||
- Aligning up and down to a power of two,
|
|
||||||
- The "Find Last Set Bit" (`fls` function of the C part of the kernel)
|
- The "Find Last Set Bit" (`fls` function of the C part of the kernel)
|
||||||
operation.
|
operation.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ impl kernel::InPlaceModule for NullBlkModule {
|
||||||
.logical_block_size(4096)?
|
.logical_block_size(4096)?
|
||||||
.physical_block_size(4096)?
|
.physical_block_size(4096)?
|
||||||
.rotational(false)
|
.rotational(false)
|
||||||
.build(format_args!("rnullb{}", 0), tagset)
|
.build(fmt!("rnullb{}", 0), tagset)
|
||||||
})();
|
})();
|
||||||
|
|
||||||
try_pin_init!(Self {
|
try_pin_init!(Self {
|
||||||
|
|
|
||||||
|
|
@ -968,7 +968,7 @@ pub unsafe extern "C" fn drm_panic_qr_generate(
|
||||||
// nul-terminated string.
|
// nul-terminated string.
|
||||||
let url_cstr: &CStr = unsafe { CStr::from_char_ptr(url) };
|
let url_cstr: &CStr = unsafe { CStr::from_char_ptr(url) };
|
||||||
let segments = &[
|
let segments = &[
|
||||||
&Segment::Binary(url_cstr.as_bytes()),
|
&Segment::Binary(url_cstr.to_bytes()),
|
||||||
&Segment::Numeric(&data_slice[0..data_len]),
|
&Segment::Numeric(&data_slice[0..data_len]),
|
||||||
];
|
];
|
||||||
match EncodedMsg::new(segments, tmp_slice) {
|
match EncodedMsg::new(segments, tmp_slice) {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
use core::ops::Range;
|
use core::ops::Range;
|
||||||
|
|
||||||
use kernel::prelude::*;
|
use kernel::prelude::*;
|
||||||
|
use kernel::ptr::{Alignable, Alignment};
|
||||||
use kernel::sizes::*;
|
use kernel::sizes::*;
|
||||||
use kernel::types::ARef;
|
use kernel::types::ARef;
|
||||||
use kernel::{dev_warn, device};
|
use kernel::{dev_warn, device};
|
||||||
|
|
@ -130,10 +131,9 @@ impl FbLayout {
|
||||||
};
|
};
|
||||||
|
|
||||||
let frts = {
|
let frts = {
|
||||||
const FRTS_DOWN_ALIGN: u64 = SZ_128K as u64;
|
const FRTS_DOWN_ALIGN: Alignment = Alignment::new::<SZ_128K>();
|
||||||
const FRTS_SIZE: u64 = SZ_1M as u64;
|
const FRTS_SIZE: u64 = SZ_1M as u64;
|
||||||
// TODO[NUMM]: replace with `align_down` once it lands.
|
let frts_base = vga_workspace.start.align_down(FRTS_DOWN_ALIGN) - FRTS_SIZE;
|
||||||
let frts_base = (vga_workspace.start & !(FRTS_DOWN_ALIGN - 1)) - FRTS_SIZE;
|
|
||||||
|
|
||||||
frts_base..frts_base + FRTS_SIZE
|
frts_base..frts_base + FRTS_SIZE
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
use kernel::{device, devres::Devres, error::code::*, pci, prelude::*, sync::Arc};
|
use kernel::{device, devres::Devres, error::code::*, fmt, pci, prelude::*, sync::Arc};
|
||||||
|
|
||||||
use crate::driver::Bar0;
|
use crate::driver::Bar0;
|
||||||
use crate::falcon::{gsp::Gsp, sec2::Sec2, Falcon};
|
use crate::falcon::{gsp::Gsp, sec2::Sec2, Falcon};
|
||||||
|
|
@ -12,7 +12,6 @@ use crate::gfw;
|
||||||
use crate::regs;
|
use crate::regs;
|
||||||
use crate::util;
|
use crate::util;
|
||||||
use crate::vbios::Vbios;
|
use crate::vbios::Vbios;
|
||||||
use core::fmt;
|
|
||||||
|
|
||||||
macro_rules! define_chipset {
|
macro_rules! define_chipset {
|
||||||
({ $($variant:ident = $value:expr),* $(,)* }) =>
|
({ $($variant:ident = $value:expr),* $(,)* }) =>
|
||||||
|
|
|
||||||
|
|
@ -149,10 +149,10 @@ macro_rules! register {
|
||||||
|
|
||||||
// TODO[REGA]: display the raw hex value, then the value of all the fields. This requires
|
// TODO[REGA]: display the raw hex value, then the value of all the fields. This requires
|
||||||
// matching the fields, which will complexify the syntax considerably...
|
// matching the fields, which will complexify the syntax considerably...
|
||||||
impl ::core::fmt::Debug for $name {
|
impl ::kernel::fmt::Debug for $name {
|
||||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result {
|
||||||
f.debug_tuple(stringify!($name))
|
f.debug_tuple(stringify!($name))
|
||||||
.field(&format_args!("0x{0:x}", &self.0))
|
.field(&::kernel::prelude::fmt!("0x{0:x}", &self.0))
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ use kernel::device;
|
||||||
use kernel::error::Result;
|
use kernel::error::Result;
|
||||||
use kernel::pci;
|
use kernel::pci;
|
||||||
use kernel::prelude::*;
|
use kernel::prelude::*;
|
||||||
|
use kernel::ptr::{Alignable, Alignment};
|
||||||
|
|
||||||
/// The offset of the VBIOS ROM in the BAR0 space.
|
/// The offset of the VBIOS ROM in the BAR0 space.
|
||||||
const ROM_OFFSET: usize = 0x300000;
|
const ROM_OFFSET: usize = 0x300000;
|
||||||
|
|
@ -177,8 +178,7 @@ impl<'a> Iterator for VbiosIterator<'a> {
|
||||||
|
|
||||||
// Advance to next image (aligned to 512 bytes).
|
// Advance to next image (aligned to 512 bytes).
|
||||||
self.current_offset += image_size;
|
self.current_offset += image_size;
|
||||||
// TODO[NUMM]: replace with `align_up` once it lands.
|
self.current_offset = self.current_offset.align_up(Alignment::new::<512>())?;
|
||||||
self.current_offset = self.current_offset.next_multiple_of(512);
|
|
||||||
|
|
||||||
Some(Ok(full_image))
|
Some(Ok(full_image))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,12 @@ quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $<
|
||||||
# and then retouch the generated files.
|
# and then retouch the generated files.
|
||||||
rustdoc: rustdoc-core rustdoc-macros rustdoc-compiler_builtins \
|
rustdoc: rustdoc-core rustdoc-macros rustdoc-compiler_builtins \
|
||||||
rustdoc-kernel rustdoc-pin_init
|
rustdoc-kernel rustdoc-pin_init
|
||||||
|
$(Q)grep -Ehro '<a href="srctree/([^"]+)"' $(rustdoc_output) | \
|
||||||
|
cut -d'"' -f2 | cut -d/ -f2- | while read f; do \
|
||||||
|
if [ ! -e "$(srctree)/$$f" ]; then \
|
||||||
|
echo "warning: srctree/ link to $$f does not exist"; \
|
||||||
|
fi \
|
||||||
|
done
|
||||||
$(Q)cp $(srctree)/Documentation/images/logo.svg $(rustdoc_output)/static.files/
|
$(Q)cp $(srctree)/Documentation/images/logo.svg $(rustdoc_output)/static.files/
|
||||||
$(Q)cp $(srctree)/Documentation/images/COPYING-logo $(rustdoc_output)/static.files/
|
$(Q)cp $(srctree)/Documentation/images/COPYING-logo $(rustdoc_output)/static.files/
|
||||||
$(Q)find $(rustdoc_output) -name '*.html' -type f -print0 | xargs -0 sed -Ei \
|
$(Q)find $(rustdoc_output) -name '*.html' -type f -print0 | xargs -0 sed -Ei \
|
||||||
|
|
@ -193,12 +199,12 @@ rusttestlib-kernel: $(src)/kernel/lib.rs rusttestlib-bindings rusttestlib-uapi \
|
||||||
$(obj)/bindings.o FORCE
|
$(obj)/bindings.o FORCE
|
||||||
+$(call if_changed,rustc_test_library)
|
+$(call if_changed,rustc_test_library)
|
||||||
|
|
||||||
rusttestlib-bindings: private rustc_target_flags = --extern ffi
|
rusttestlib-bindings: private rustc_target_flags = --extern ffi --extern pin_init
|
||||||
rusttestlib-bindings: $(src)/bindings/lib.rs rusttestlib-ffi FORCE
|
rusttestlib-bindings: $(src)/bindings/lib.rs rusttestlib-ffi rusttestlib-pin_init FORCE
|
||||||
+$(call if_changed,rustc_test_library)
|
+$(call if_changed,rustc_test_library)
|
||||||
|
|
||||||
rusttestlib-uapi: private rustc_target_flags = --extern ffi
|
rusttestlib-uapi: private rustc_target_flags = --extern ffi --extern pin_init
|
||||||
rusttestlib-uapi: $(src)/uapi/lib.rs rusttestlib-ffi FORCE
|
rusttestlib-uapi: $(src)/uapi/lib.rs rusttestlib-ffi rusttestlib-pin_init FORCE
|
||||||
+$(call if_changed,rustc_test_library)
|
+$(call if_changed,rustc_test_library)
|
||||||
|
|
||||||
quiet_cmd_rustdoc_test = RUSTDOC T $<
|
quiet_cmd_rustdoc_test = RUSTDOC T $<
|
||||||
|
|
@ -248,7 +254,7 @@ quiet_cmd_rustc_test = $(RUSTC_OR_CLIPPY_QUIET) T $<
|
||||||
$(objtree)/$(obj)/test/$(subst rusttest-,,$@) $(rust_test_quiet) \
|
$(objtree)/$(obj)/test/$(subst rusttest-,,$@) $(rust_test_quiet) \
|
||||||
$(rustc_test_run_flags)
|
$(rustc_test_run_flags)
|
||||||
|
|
||||||
rusttest: rusttest-macros rusttest-kernel
|
rusttest: rusttest-macros
|
||||||
|
|
||||||
rusttest-macros: private rustc_target_flags = --extern proc_macro \
|
rusttest-macros: private rustc_target_flags = --extern proc_macro \
|
||||||
--extern macros --extern kernel --extern pin_init
|
--extern macros --extern kernel --extern pin_init
|
||||||
|
|
@ -258,13 +264,6 @@ rusttest-macros: $(src)/macros/lib.rs \
|
||||||
+$(call if_changed,rustc_test)
|
+$(call if_changed,rustc_test)
|
||||||
+$(call if_changed,rustdoc_test)
|
+$(call if_changed,rustdoc_test)
|
||||||
|
|
||||||
rusttest-kernel: private rustc_target_flags = --extern ffi --extern pin_init \
|
|
||||||
--extern build_error --extern macros --extern bindings --extern uapi
|
|
||||||
rusttest-kernel: $(src)/kernel/lib.rs rusttestlib-ffi rusttestlib-kernel \
|
|
||||||
rusttestlib-build_error rusttestlib-macros rusttestlib-bindings \
|
|
||||||
rusttestlib-uapi rusttestlib-pin_init FORCE
|
|
||||||
+$(call if_changed,rustc_test)
|
|
||||||
|
|
||||||
ifdef CONFIG_CC_IS_CLANG
|
ifdef CONFIG_CC_IS_CLANG
|
||||||
bindgen_c_flags = $(c_flags)
|
bindgen_c_flags = $(c_flags)
|
||||||
else
|
else
|
||||||
|
|
@ -531,17 +530,19 @@ $(obj)/ffi.o: private skip_gendwarfksyms = 1
|
||||||
$(obj)/ffi.o: $(src)/ffi.rs $(obj)/compiler_builtins.o FORCE
|
$(obj)/ffi.o: $(src)/ffi.rs $(obj)/compiler_builtins.o FORCE
|
||||||
+$(call if_changed_rule,rustc_library)
|
+$(call if_changed_rule,rustc_library)
|
||||||
|
|
||||||
$(obj)/bindings.o: private rustc_target_flags = --extern ffi
|
$(obj)/bindings.o: private rustc_target_flags = --extern ffi --extern pin_init
|
||||||
$(obj)/bindings.o: $(src)/bindings/lib.rs \
|
$(obj)/bindings.o: $(src)/bindings/lib.rs \
|
||||||
$(obj)/ffi.o \
|
$(obj)/ffi.o \
|
||||||
|
$(obj)/pin_init.o \
|
||||||
$(obj)/bindings/bindings_generated.rs \
|
$(obj)/bindings/bindings_generated.rs \
|
||||||
$(obj)/bindings/bindings_helpers_generated.rs FORCE
|
$(obj)/bindings/bindings_helpers_generated.rs FORCE
|
||||||
+$(call if_changed_rule,rustc_library)
|
+$(call if_changed_rule,rustc_library)
|
||||||
|
|
||||||
$(obj)/uapi.o: private rustc_target_flags = --extern ffi
|
$(obj)/uapi.o: private rustc_target_flags = --extern ffi --extern pin_init
|
||||||
$(obj)/uapi.o: private skip_gendwarfksyms = 1
|
$(obj)/uapi.o: private skip_gendwarfksyms = 1
|
||||||
$(obj)/uapi.o: $(src)/uapi/lib.rs \
|
$(obj)/uapi.o: $(src)/uapi/lib.rs \
|
||||||
$(obj)/ffi.o \
|
$(obj)/ffi.o \
|
||||||
|
$(obj)/pin_init.o \
|
||||||
$(obj)/uapi/uapi_generated.rs FORCE
|
$(obj)/uapi/uapi_generated.rs FORCE
|
||||||
+$(call if_changed_rule,rustc_library)
|
+$(call if_changed_rule,rustc_library)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,3 +34,8 @@
|
||||||
# We use const helpers to aid bindgen, to avoid conflicts when constants are
|
# We use const helpers to aid bindgen, to avoid conflicts when constants are
|
||||||
# recognized, block generation of the non-helper constants.
|
# recognized, block generation of the non-helper constants.
|
||||||
--blocklist-item ARCH_SLAB_MINALIGN
|
--blocklist-item ARCH_SLAB_MINALIGN
|
||||||
|
--blocklist-item ARCH_KMALLOC_MINALIGN
|
||||||
|
|
||||||
|
# Structs should implement `Zeroable` when all of their fields do.
|
||||||
|
--with-derive-custom-struct .*=MaybeZeroable
|
||||||
|
--with-derive-custom-union .*=MaybeZeroable
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,7 @@
|
||||||
|
|
||||||
/* `bindgen` gets confused at certain things. */
|
/* `bindgen` gets confused at certain things. */
|
||||||
const size_t RUST_CONST_HELPER_ARCH_SLAB_MINALIGN = ARCH_SLAB_MINALIGN;
|
const size_t RUST_CONST_HELPER_ARCH_SLAB_MINALIGN = ARCH_SLAB_MINALIGN;
|
||||||
|
const size_t RUST_CONST_HELPER_ARCH_KMALLOC_MINALIGN = ARCH_KMALLOC_MINALIGN;
|
||||||
const size_t RUST_CONST_HELPER_PAGE_SIZE = PAGE_SIZE;
|
const size_t RUST_CONST_HELPER_PAGE_SIZE = PAGE_SIZE;
|
||||||
const gfp_t RUST_CONST_HELPER_GFP_ATOMIC = GFP_ATOMIC;
|
const gfp_t RUST_CONST_HELPER_GFP_ATOMIC = GFP_ATOMIC;
|
||||||
const gfp_t RUST_CONST_HELPER_GFP_KERNEL = GFP_KERNEL;
|
const gfp_t RUST_CONST_HELPER_GFP_KERNEL = GFP_KERNEL;
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,19 @@
|
||||||
#[allow(clippy::undocumented_unsafe_blocks)]
|
#[allow(clippy::undocumented_unsafe_blocks)]
|
||||||
#[cfg_attr(CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES, allow(unnecessary_transmutes))]
|
#[cfg_attr(CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES, allow(unnecessary_transmutes))]
|
||||||
mod bindings_raw {
|
mod bindings_raw {
|
||||||
|
use pin_init::{MaybeZeroable, Zeroable};
|
||||||
|
|
||||||
// Manual definition for blocklisted types.
|
// Manual definition for blocklisted types.
|
||||||
type __kernel_size_t = usize;
|
type __kernel_size_t = usize;
|
||||||
type __kernel_ssize_t = isize;
|
type __kernel_ssize_t = isize;
|
||||||
type __kernel_ptrdiff_t = isize;
|
type __kernel_ptrdiff_t = isize;
|
||||||
|
|
||||||
|
// `bindgen` doesn't automatically do this, see
|
||||||
|
// <https://github.com/rust-lang/rust-bindgen/issues/3196>
|
||||||
|
//
|
||||||
|
// SAFETY: `__BindgenBitfieldUnit<Storage>` is a newtype around `Storage`.
|
||||||
|
unsafe impl<Storage> Zeroable for __BindgenBitfieldUnit<Storage> where Storage: Zeroable {}
|
||||||
|
|
||||||
// Use glob import here to expose all helpers.
|
// Use glob import here to expose all helpers.
|
||||||
// Symbols defined within the module will take precedence to the glob import.
|
// Symbols defined within the module will take precedence to the glob import.
|
||||||
pub use super::bindings_helper::*;
|
pub use super::bindings_helper::*;
|
||||||
|
|
|
||||||
|
|
@ -37,11 +37,8 @@ impl DeviceId {
|
||||||
/// Create a new device id from an ACPI 'id' string.
|
/// Create a new device id from an ACPI 'id' string.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub const fn new(id: &'static CStr) -> Self {
|
pub const fn new(id: &'static CStr) -> Self {
|
||||||
build_assert!(
|
let src = id.to_bytes_with_nul();
|
||||||
id.len_with_nul() <= Self::ACPI_ID_LEN,
|
build_assert!(src.len() <= Self::ACPI_ID_LEN, "ID exceeds 16 bytes");
|
||||||
"ID exceeds 16 bytes"
|
|
||||||
);
|
|
||||||
let src = id.as_bytes_with_nul();
|
|
||||||
// Replace with `bindings::acpi_device_id::default()` once stabilized for `const`.
|
// Replace with `bindings::acpi_device_id::default()` once stabilized for `const`.
|
||||||
// SAFETY: FFI type is valid to be zero-initialized.
|
// SAFETY: FFI type is valid to be zero-initialized.
|
||||||
let mut acpi: bindings::acpi_device_id = unsafe { core::mem::zeroed() };
|
let mut acpi: bindings::acpi_device_id = unsafe { core::mem::zeroed() };
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,11 @@
|
||||||
|
|
||||||
//! Implementation of the kernel's memory allocation infrastructure.
|
//! Implementation of the kernel's memory allocation infrastructure.
|
||||||
|
|
||||||
#[cfg(not(any(test, testlib)))]
|
|
||||||
pub mod allocator;
|
pub mod allocator;
|
||||||
pub mod kbox;
|
pub mod kbox;
|
||||||
pub mod kvec;
|
pub mod kvec;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
|
|
||||||
#[cfg(any(test, testlib))]
|
|
||||||
pub mod allocator_test;
|
|
||||||
|
|
||||||
#[cfg(any(test, testlib))]
|
|
||||||
pub use self::allocator_test as allocator;
|
|
||||||
|
|
||||||
pub use self::kbox::Box;
|
pub use self::kbox::Box;
|
||||||
pub use self::kbox::KBox;
|
pub use self::kbox::KBox;
|
||||||
pub use self::kbox::KVBox;
|
pub use self::kbox::KVBox;
|
||||||
|
|
@ -137,6 +130,14 @@ pub mod flags {
|
||||||
/// - Implementers must ensure that all trait functions abide by the guarantees documented in the
|
/// - Implementers must ensure that all trait functions abide by the guarantees documented in the
|
||||||
/// `# Guarantees` sections.
|
/// `# Guarantees` sections.
|
||||||
pub unsafe trait Allocator {
|
pub unsafe trait Allocator {
|
||||||
|
/// The minimum alignment satisfied by all allocations from this allocator.
|
||||||
|
///
|
||||||
|
/// # Guarantees
|
||||||
|
///
|
||||||
|
/// Any pointer allocated by this allocator is guaranteed to be aligned to `MIN_ALIGN` even if
|
||||||
|
/// the requested layout has a smaller alignment.
|
||||||
|
const MIN_ALIGN: usize;
|
||||||
|
|
||||||
/// Allocate memory based on `layout` and `flags`.
|
/// Allocate memory based on `layout` and `flags`.
|
||||||
///
|
///
|
||||||
/// On success, returns a buffer represented as `NonNull<[u8]>` that satisfies the layout
|
/// On success, returns a buffer represented as `NonNull<[u8]>` that satisfies the layout
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ use crate::alloc::{AllocError, Allocator};
|
||||||
use crate::bindings;
|
use crate::bindings;
|
||||||
use crate::pr_warn;
|
use crate::pr_warn;
|
||||||
|
|
||||||
|
const ARCH_KMALLOC_MINALIGN: usize = bindings::ARCH_KMALLOC_MINALIGN;
|
||||||
|
|
||||||
/// The contiguous kernel allocator.
|
/// The contiguous kernel allocator.
|
||||||
///
|
///
|
||||||
/// `Kmalloc` is typically used for physically contiguous allocations up to page size, but also
|
/// `Kmalloc` is typically used for physically contiguous allocations up to page size, but also
|
||||||
|
|
@ -128,6 +130,8 @@ impl Kmalloc {
|
||||||
// - passing a pointer to a valid memory allocation is OK,
|
// - passing a pointer to a valid memory allocation is OK,
|
||||||
// - `realloc` satisfies the guarantees, since `ReallocFunc::call` has the same.
|
// - `realloc` satisfies the guarantees, since `ReallocFunc::call` has the same.
|
||||||
unsafe impl Allocator for Kmalloc {
|
unsafe impl Allocator for Kmalloc {
|
||||||
|
const MIN_ALIGN: usize = ARCH_KMALLOC_MINALIGN;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn realloc(
|
unsafe fn realloc(
|
||||||
ptr: Option<NonNull<u8>>,
|
ptr: Option<NonNull<u8>>,
|
||||||
|
|
@ -147,6 +151,8 @@ unsafe impl Allocator for Kmalloc {
|
||||||
// - passing a pointer to a valid memory allocation is OK,
|
// - passing a pointer to a valid memory allocation is OK,
|
||||||
// - `realloc` satisfies the guarantees, since `ReallocFunc::call` has the same.
|
// - `realloc` satisfies the guarantees, since `ReallocFunc::call` has the same.
|
||||||
unsafe impl Allocator for Vmalloc {
|
unsafe impl Allocator for Vmalloc {
|
||||||
|
const MIN_ALIGN: usize = kernel::page::PAGE_SIZE;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn realloc(
|
unsafe fn realloc(
|
||||||
ptr: Option<NonNull<u8>>,
|
ptr: Option<NonNull<u8>>,
|
||||||
|
|
@ -171,6 +177,8 @@ unsafe impl Allocator for Vmalloc {
|
||||||
// - passing a pointer to a valid memory allocation is OK,
|
// - passing a pointer to a valid memory allocation is OK,
|
||||||
// - `realloc` satisfies the guarantees, since `ReallocFunc::call` has the same.
|
// - `realloc` satisfies the guarantees, since `ReallocFunc::call` has the same.
|
||||||
unsafe impl Allocator for KVmalloc {
|
unsafe impl Allocator for KVmalloc {
|
||||||
|
const MIN_ALIGN: usize = ARCH_KMALLOC_MINALIGN;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn realloc(
|
unsafe fn realloc(
|
||||||
ptr: Option<NonNull<u8>>,
|
ptr: Option<NonNull<u8>>,
|
||||||
|
|
|
||||||
|
|
@ -1,124 +0,0 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
|
||||||
|
|
||||||
//! So far the kernel's `Box` and `Vec` types can't be used by userspace test cases, since all users
|
|
||||||
//! of those types (e.g. `CString`) use kernel allocators for instantiation.
|
|
||||||
//!
|
|
||||||
//! In order to allow userspace test cases to make use of such types as well, implement the
|
|
||||||
//! `Cmalloc` allocator within the `allocator_test` module and type alias all kernel allocators to
|
|
||||||
//! `Cmalloc`. The `Cmalloc` allocator uses libc's `realloc()` function as allocator backend.
|
|
||||||
|
|
||||||
#![allow(missing_docs)]
|
|
||||||
|
|
||||||
use super::{flags::*, AllocError, Allocator, Flags};
|
|
||||||
use core::alloc::Layout;
|
|
||||||
use core::cmp;
|
|
||||||
use core::ptr;
|
|
||||||
use core::ptr::NonNull;
|
|
||||||
|
|
||||||
/// The userspace allocator based on libc.
|
|
||||||
pub struct Cmalloc;
|
|
||||||
|
|
||||||
pub type Kmalloc = Cmalloc;
|
|
||||||
pub type Vmalloc = Kmalloc;
|
|
||||||
pub type KVmalloc = Kmalloc;
|
|
||||||
|
|
||||||
impl Cmalloc {
|
|
||||||
/// Returns a [`Layout`] that makes [`Kmalloc`] fulfill the requested size and alignment of
|
|
||||||
/// `layout`.
|
|
||||||
pub fn aligned_layout(layout: Layout) -> Layout {
|
|
||||||
// Note that `layout.size()` (after padding) is guaranteed to be a multiple of
|
|
||||||
// `layout.align()` which together with the slab guarantees means that `Kmalloc` will return
|
|
||||||
// a properly aligned object (see comments in `kmalloc()` for more information).
|
|
||||||
layout.pad_to_align()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#[link_name = "aligned_alloc"]
|
|
||||||
fn libc_aligned_alloc(align: usize, size: usize) -> *mut crate::ffi::c_void;
|
|
||||||
|
|
||||||
#[link_name = "free"]
|
|
||||||
fn libc_free(ptr: *mut crate::ffi::c_void);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SAFETY:
|
|
||||||
// - memory remains valid until it is explicitly freed,
|
|
||||||
// - passing a pointer to a valid memory allocation created by this `Allocator` is always OK,
|
|
||||||
// - `realloc` provides the guarantees as provided in the `# Guarantees` section.
|
|
||||||
unsafe impl Allocator for Cmalloc {
|
|
||||||
unsafe fn realloc(
|
|
||||||
ptr: Option<NonNull<u8>>,
|
|
||||||
layout: Layout,
|
|
||||||
old_layout: Layout,
|
|
||||||
flags: Flags,
|
|
||||||
) -> Result<NonNull<[u8]>, AllocError> {
|
|
||||||
let src = match ptr {
|
|
||||||
Some(src) => {
|
|
||||||
if old_layout.size() == 0 {
|
|
||||||
ptr::null_mut()
|
|
||||||
} else {
|
|
||||||
src.as_ptr()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => ptr::null_mut(),
|
|
||||||
};
|
|
||||||
|
|
||||||
if layout.size() == 0 {
|
|
||||||
// SAFETY: `src` is either NULL or was previously allocated with this `Allocator`
|
|
||||||
unsafe { libc_free(src.cast()) };
|
|
||||||
|
|
||||||
return Ok(NonNull::slice_from_raw_parts(
|
|
||||||
crate::alloc::dangling_from_layout(layout),
|
|
||||||
0,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ISO C (ISO/IEC 9899:2011) defines `aligned_alloc`:
|
|
||||||
//
|
|
||||||
// > The value of alignment shall be a valid alignment supported by the implementation
|
|
||||||
// [...].
|
|
||||||
//
|
|
||||||
// As an example of the "supported by the implementation" requirement, POSIX.1-2001 (IEEE
|
|
||||||
// 1003.1-2001) defines `posix_memalign`:
|
|
||||||
//
|
|
||||||
// > The value of alignment shall be a power of two multiple of sizeof (void *).
|
|
||||||
//
|
|
||||||
// and POSIX-based implementations of `aligned_alloc` inherit this requirement. At the time
|
|
||||||
// of writing, this is known to be the case on macOS (but not in glibc).
|
|
||||||
//
|
|
||||||
// Satisfy the stricter requirement to avoid spurious test failures on some platforms.
|
|
||||||
let min_align = core::mem::size_of::<*const crate::ffi::c_void>();
|
|
||||||
let layout = layout.align_to(min_align).map_err(|_| AllocError)?;
|
|
||||||
let layout = layout.pad_to_align();
|
|
||||||
|
|
||||||
// SAFETY: Returns either NULL or a pointer to a memory allocation that satisfies or
|
|
||||||
// exceeds the given size and alignment requirements.
|
|
||||||
let dst = unsafe { libc_aligned_alloc(layout.align(), layout.size()) }.cast::<u8>();
|
|
||||||
let dst = NonNull::new(dst).ok_or(AllocError)?;
|
|
||||||
|
|
||||||
if flags.contains(__GFP_ZERO) {
|
|
||||||
// SAFETY: The preceding calls to `libc_aligned_alloc` and `NonNull::new`
|
|
||||||
// guarantee that `dst` points to memory of at least `layout.size()` bytes.
|
|
||||||
unsafe { dst.as_ptr().write_bytes(0, layout.size()) };
|
|
||||||
}
|
|
||||||
|
|
||||||
if !src.is_null() {
|
|
||||||
// SAFETY:
|
|
||||||
// - `src` has previously been allocated with this `Allocator`; `dst` has just been
|
|
||||||
// newly allocated, hence the memory regions do not overlap.
|
|
||||||
// - both` src` and `dst` are properly aligned and valid for reads and writes
|
|
||||||
unsafe {
|
|
||||||
ptr::copy_nonoverlapping(
|
|
||||||
src,
|
|
||||||
dst.as_ptr(),
|
|
||||||
cmp::min(layout.size(), old_layout.size()),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// SAFETY: `src` is either NULL or was previously allocated with this `Allocator`
|
|
||||||
unsafe { libc_free(src.cast()) };
|
|
||||||
|
|
||||||
Ok(NonNull::slice_from_raw_parts(dst, layout.size()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -7,7 +7,6 @@ use super::allocator::{KVmalloc, Kmalloc, Vmalloc};
|
||||||
use super::{AllocError, Allocator, Flags};
|
use super::{AllocError, Allocator, Flags};
|
||||||
use core::alloc::Layout;
|
use core::alloc::Layout;
|
||||||
use core::borrow::{Borrow, BorrowMut};
|
use core::borrow::{Borrow, BorrowMut};
|
||||||
use core::fmt;
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::mem::ManuallyDrop;
|
use core::mem::ManuallyDrop;
|
||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
|
|
@ -17,6 +16,7 @@ use core::ptr::NonNull;
|
||||||
use core::result::Result;
|
use core::result::Result;
|
||||||
|
|
||||||
use crate::ffi::c_void;
|
use crate::ffi::c_void;
|
||||||
|
use crate::fmt;
|
||||||
use crate::init::InPlaceInit;
|
use crate::init::InPlaceInit;
|
||||||
use crate::types::ForeignOwnable;
|
use crate::types::ForeignOwnable;
|
||||||
use pin_init::{InPlaceWrite, Init, PinInit, ZeroableOption};
|
use pin_init::{InPlaceWrite, Init, PinInit, ZeroableOption};
|
||||||
|
|
@ -290,6 +290,83 @@ where
|
||||||
Ok(Self::new(x, flags)?.into())
|
Ok(Self::new(x, flags)?.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Construct a pinned slice of elements `Pin<Box<[T], A>>`.
|
||||||
|
///
|
||||||
|
/// This is a convenient means for creation of e.g. slices of structrures containing spinlocks
|
||||||
|
/// or mutexes.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use kernel::sync::{new_spinlock, SpinLock};
|
||||||
|
///
|
||||||
|
/// struct Inner {
|
||||||
|
/// a: u32,
|
||||||
|
/// b: u32,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// #[pin_data]
|
||||||
|
/// struct Example {
|
||||||
|
/// c: u32,
|
||||||
|
/// #[pin]
|
||||||
|
/// d: SpinLock<Inner>,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl Example {
|
||||||
|
/// fn new() -> impl PinInit<Self, Error> {
|
||||||
|
/// try_pin_init!(Self {
|
||||||
|
/// c: 10,
|
||||||
|
/// d <- new_spinlock!(Inner { a: 20, b: 30 }),
|
||||||
|
/// })
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Allocate a boxed slice of 10 `Example`s.
|
||||||
|
/// let s = KBox::pin_slice(
|
||||||
|
/// | _i | Example::new(),
|
||||||
|
/// 10,
|
||||||
|
/// GFP_KERNEL
|
||||||
|
/// )?;
|
||||||
|
///
|
||||||
|
/// assert_eq!(s[5].c, 10);
|
||||||
|
/// assert_eq!(s[3].d.lock().a, 20);
|
||||||
|
/// # Ok::<(), Error>(())
|
||||||
|
/// ```
|
||||||
|
pub fn pin_slice<Func, Item, E>(
|
||||||
|
mut init: Func,
|
||||||
|
len: usize,
|
||||||
|
flags: Flags,
|
||||||
|
) -> Result<Pin<Box<[T], A>>, E>
|
||||||
|
where
|
||||||
|
Func: FnMut(usize) -> Item,
|
||||||
|
Item: PinInit<T, E>,
|
||||||
|
E: From<AllocError>,
|
||||||
|
{
|
||||||
|
let mut buffer = super::Vec::<T, A>::with_capacity(len, flags)?;
|
||||||
|
for i in 0..len {
|
||||||
|
let ptr = buffer.spare_capacity_mut().as_mut_ptr().cast();
|
||||||
|
// SAFETY:
|
||||||
|
// - `ptr` is a valid pointer to uninitialized memory.
|
||||||
|
// - `ptr` is not used if an error is returned.
|
||||||
|
// - `ptr` won't be moved until it is dropped, i.e. it is pinned.
|
||||||
|
unsafe { init(i).__pinned_init(ptr)? };
|
||||||
|
|
||||||
|
// SAFETY:
|
||||||
|
// - `i + 1 <= len`, hence we don't exceed the capacity, due to the call to
|
||||||
|
// `with_capacity()` above.
|
||||||
|
// - The new value at index buffer.len() + 1 is the only element being added here, and
|
||||||
|
// it has been initialized above by `init(i).__pinned_init(ptr)`.
|
||||||
|
unsafe { buffer.inc_len(1) };
|
||||||
|
}
|
||||||
|
|
||||||
|
let (ptr, _, _) = buffer.into_raw_parts();
|
||||||
|
let slice = core::ptr::slice_from_raw_parts_mut(ptr, len);
|
||||||
|
|
||||||
|
// SAFETY: `slice` points to an allocation allocated with `A` (`buffer`) and holds a valid
|
||||||
|
// `[T]`.
|
||||||
|
Ok(Pin::from(unsafe { Box::from_raw(slice) }))
|
||||||
|
}
|
||||||
|
|
||||||
/// Convert a [`Box<T,A>`] to a [`Pin<Box<T,A>>`]. If `T` does not implement
|
/// Convert a [`Box<T,A>`] to a [`Pin<Box<T,A>>`]. If `T` does not implement
|
||||||
/// [`Unpin`], then `x` will be pinned in memory and can't be moved.
|
/// [`Unpin`], then `x` will be pinned in memory and can't be moved.
|
||||||
pub fn into_pin(this: Self) -> Pin<Self> {
|
pub fn into_pin(this: Self) -> Pin<Self> {
|
||||||
|
|
@ -401,12 +478,17 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: The pointer returned by `into_foreign` comes from a well aligned
|
// SAFETY: The pointer returned by `into_foreign` comes from a well aligned
|
||||||
// pointer to `T`.
|
// pointer to `T` allocated by `A`.
|
||||||
unsafe impl<T: 'static, A> ForeignOwnable for Box<T, A>
|
unsafe impl<T: 'static, A> ForeignOwnable for Box<T, A>
|
||||||
where
|
where
|
||||||
A: Allocator,
|
A: Allocator,
|
||||||
{
|
{
|
||||||
const FOREIGN_ALIGN: usize = core::mem::align_of::<T>();
|
const FOREIGN_ALIGN: usize = if core::mem::align_of::<T>() < A::MIN_ALIGN {
|
||||||
|
A::MIN_ALIGN
|
||||||
|
} else {
|
||||||
|
core::mem::align_of::<T>()
|
||||||
|
};
|
||||||
|
|
||||||
type Borrowed<'a> = &'a T;
|
type Borrowed<'a> = &'a T;
|
||||||
type BorrowedMut<'a> = &'a mut T;
|
type BorrowedMut<'a> = &'a mut T;
|
||||||
|
|
||||||
|
|
@ -435,12 +517,12 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: The pointer returned by `into_foreign` comes from a well aligned
|
// SAFETY: The pointer returned by `into_foreign` comes from a well aligned
|
||||||
// pointer to `T`.
|
// pointer to `T` allocated by `A`.
|
||||||
unsafe impl<T: 'static, A> ForeignOwnable for Pin<Box<T, A>>
|
unsafe impl<T: 'static, A> ForeignOwnable for Pin<Box<T, A>>
|
||||||
where
|
where
|
||||||
A: Allocator,
|
A: Allocator,
|
||||||
{
|
{
|
||||||
const FOREIGN_ALIGN: usize = core::mem::align_of::<T>();
|
const FOREIGN_ALIGN: usize = <Box<T, A> as ForeignOwnable>::FOREIGN_ALIGN;
|
||||||
type Borrowed<'a> = Pin<&'a T>;
|
type Borrowed<'a> = Pin<&'a T>;
|
||||||
type BorrowedMut<'a> = Pin<&'a mut T>;
|
type BorrowedMut<'a> = Pin<&'a mut T>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ use super::{
|
||||||
layout::ArrayLayout,
|
layout::ArrayLayout,
|
||||||
AllocError, Allocator, Box, Flags,
|
AllocError, Allocator, Box, Flags,
|
||||||
};
|
};
|
||||||
|
use crate::fmt;
|
||||||
use core::{
|
use core::{
|
||||||
borrow::{Borrow, BorrowMut},
|
borrow::{Borrow, BorrowMut},
|
||||||
fmt,
|
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
mem::{ManuallyDrop, MaybeUninit},
|
mem::{ManuallyDrop, MaybeUninit},
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
|
|
@ -175,7 +175,7 @@ where
|
||||||
|
|
||||||
/// Returns the number of elements that can be stored within the vector without allocating
|
/// Returns the number of elements that can be stored within the vector without allocating
|
||||||
/// additional memory.
|
/// additional memory.
|
||||||
pub fn capacity(&self) -> usize {
|
pub const fn capacity(&self) -> usize {
|
||||||
if const { Self::is_zst() } {
|
if const { Self::is_zst() } {
|
||||||
usize::MAX
|
usize::MAX
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -185,7 +185,7 @@ where
|
||||||
|
|
||||||
/// Returns the number of elements stored within the vector.
|
/// Returns the number of elements stored within the vector.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn len(&self) -> usize {
|
pub const fn len(&self) -> usize {
|
||||||
self.len
|
self.len
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -196,7 +196,7 @@ where
|
||||||
/// - `additional` must be less than or equal to `self.capacity - self.len`.
|
/// - `additional` must be less than or equal to `self.capacity - self.len`.
|
||||||
/// - All elements within the interval [`self.len`,`self.len + additional`) must be initialized.
|
/// - All elements within the interval [`self.len`,`self.len + additional`) must be initialized.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn inc_len(&mut self, additional: usize) {
|
pub const unsafe fn inc_len(&mut self, additional: usize) {
|
||||||
// Guaranteed by the type invariant to never underflow.
|
// Guaranteed by the type invariant to never underflow.
|
||||||
debug_assert!(additional <= self.capacity() - self.len());
|
debug_assert!(additional <= self.capacity() - self.len());
|
||||||
// INVARIANT: By the safety requirements of this method this represents the exact number of
|
// INVARIANT: By the safety requirements of this method this represents the exact number of
|
||||||
|
|
@ -224,6 +224,16 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a slice of the entire vector.
|
/// Returns a slice of the entire vector.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let mut v = KVec::new();
|
||||||
|
/// v.push(1, GFP_KERNEL)?;
|
||||||
|
/// v.push(2, GFP_KERNEL)?;
|
||||||
|
/// assert_eq!(v.as_slice(), &[1, 2]);
|
||||||
|
/// # Ok::<(), Error>(())
|
||||||
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_slice(&self) -> &[T] {
|
pub fn as_slice(&self) -> &[T] {
|
||||||
self
|
self
|
||||||
|
|
@ -245,7 +255,7 @@ where
|
||||||
/// Returns a raw pointer to the vector's backing buffer, or, if `T` is a ZST, a dangling raw
|
/// Returns a raw pointer to the vector's backing buffer, or, if `T` is a ZST, a dangling raw
|
||||||
/// pointer.
|
/// pointer.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_ptr(&self) -> *const T {
|
pub const fn as_ptr(&self) -> *const T {
|
||||||
self.ptr.as_ptr()
|
self.ptr.as_ptr()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -261,7 +271,7 @@ where
|
||||||
/// assert!(!v.is_empty());
|
/// assert!(!v.is_empty());
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_empty(&self) -> bool {
|
pub const fn is_empty(&self) -> bool {
|
||||||
self.len() == 0
|
self.len() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1294,7 +1304,7 @@ impl<'vec, T> Drop for DrainAll<'vec, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macros::kunit_tests(rust_kvec_kunit)]
|
#[macros::kunit_tests(rust_kvec)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
//! Errors for the [`Vec`] type.
|
//! Errors for the [`Vec`] type.
|
||||||
|
|
||||||
use core::fmt::{self, Debug, Formatter};
|
use kernel::fmt::{self, Debug, Formatter};
|
||||||
use kernel::prelude::*;
|
use kernel::prelude::*;
|
||||||
|
|
||||||
/// Error type for [`Vec::push_within_capacity`].
|
/// Error type for [`Vec::push_within_capacity`].
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ impl<T> ArrayLayout<T> {
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// `len` must be a value, for which `len * size_of::<T>() <= isize::MAX` is true.
|
/// `len` must be a value, for which `len * size_of::<T>() <= isize::MAX` is true.
|
||||||
pub unsafe fn new_unchecked(len: usize) -> Self {
|
pub const unsafe fn new_unchecked(len: usize) -> Self {
|
||||||
// INVARIANT: By the safety requirements of this function
|
// INVARIANT: By the safety requirements of this function
|
||||||
// `len * size_of::<T>() <= isize::MAX`.
|
// `len * size_of::<T>() <= isize::MAX`.
|
||||||
Self {
|
Self {
|
||||||
|
|
|
||||||
|
|
@ -105,8 +105,8 @@ pub struct DeviceId(bindings::auxiliary_device_id);
|
||||||
impl DeviceId {
|
impl DeviceId {
|
||||||
/// Create a new [`DeviceId`] from name.
|
/// Create a new [`DeviceId`] from name.
|
||||||
pub const fn new(modname: &'static CStr, name: &'static CStr) -> Self {
|
pub const fn new(modname: &'static CStr, name: &'static CStr) -> Self {
|
||||||
let name = name.as_bytes_with_nul();
|
let name = name.to_bytes_with_nul();
|
||||||
let modname = modname.as_bytes_with_nul();
|
let modname = modname.to_bytes_with_nul();
|
||||||
|
|
||||||
// TODO: Replace with `bindings::auxiliary_device_id::default()` once stabilized for
|
// TODO: Replace with `bindings::auxiliary_device_id::default()` once stabilized for
|
||||||
// `const`.
|
// `const`.
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@
|
||||||
//! Arc::pin_init(TagSet::new(1, 256, 1), flags::GFP_KERNEL)?;
|
//! Arc::pin_init(TagSet::new(1, 256, 1), flags::GFP_KERNEL)?;
|
||||||
//! let mut disk = gen_disk::GenDiskBuilder::new()
|
//! let mut disk = gen_disk::GenDiskBuilder::new()
|
||||||
//! .capacity_sectors(4096)
|
//! .capacity_sectors(4096)
|
||||||
//! .build(format_args!("myblk"), tagset)?;
|
//! .build(fmt!("myblk"), tagset)?;
|
||||||
//!
|
//!
|
||||||
//! # Ok::<(), kernel::error::Error>(())
|
//! # Ok::<(), kernel::error::Error>(())
|
||||||
//! ```
|
//! ```
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,12 @@
|
||||||
//! Generic disk abstraction.
|
//! Generic disk abstraction.
|
||||||
//!
|
//!
|
||||||
//! C header: [`include/linux/blkdev.h`](srctree/include/linux/blkdev.h)
|
//! C header: [`include/linux/blkdev.h`](srctree/include/linux/blkdev.h)
|
||||||
//! C header: [`include/linux/blk_mq.h`](srctree/include/linux/blk_mq.h)
|
//! C header: [`include/linux/blk-mq.h`](srctree/include/linux/blk-mq.h)
|
||||||
|
|
||||||
use crate::block::mq::{raw_writer::RawWriter, Operations, TagSet};
|
use crate::block::mq::{raw_writer::RawWriter, Operations, TagSet};
|
||||||
|
use crate::fmt::{self, Write};
|
||||||
use crate::{bindings, error::from_err_ptr, error::Result, sync::Arc};
|
use crate::{bindings, error::from_err_ptr, error::Result, sync::Arc};
|
||||||
use crate::{error, static_lock_class};
|
use crate::{error, static_lock_class};
|
||||||
use core::fmt::{self, Write};
|
|
||||||
|
|
||||||
/// A builder for [`GenDisk`].
|
/// A builder for [`GenDisk`].
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
use core::fmt::{self, Write};
|
|
||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
|
use crate::fmt::{self, Write};
|
||||||
use crate::prelude::EINVAL;
|
use crate::prelude::EINVAL;
|
||||||
|
|
||||||
/// A mutable reference to a byte buffer where a string can be written into.
|
/// A mutable reference to a byte buffer where a string can be written into.
|
||||||
|
|
|
||||||
|
|
@ -263,7 +263,7 @@ impl<Data> Group<Data> {
|
||||||
try_pin_init!(Self {
|
try_pin_init!(Self {
|
||||||
group <- pin_init::init_zeroed().chain(|v: &mut Opaque<bindings::config_group>| {
|
group <- pin_init::init_zeroed().chain(|v: &mut Opaque<bindings::config_group>| {
|
||||||
let place = v.get();
|
let place = v.get();
|
||||||
let name = name.as_bytes_with_nul().as_ptr();
|
let name = name.to_bytes_with_nul().as_ptr();
|
||||||
// SAFETY: It is safe to initialize a group once it has been zeroed.
|
// SAFETY: It is safe to initialize a group once it has been zeroed.
|
||||||
unsafe {
|
unsafe {
|
||||||
bindings::config_group_init_type_name(place, name.cast(), item_type.as_ptr())
|
bindings::config_group_init_type_name(place, name.cast(), item_type.as_ptr())
|
||||||
|
|
@ -613,7 +613,7 @@ where
|
||||||
pub const fn new(name: &'static CStr) -> Self {
|
pub const fn new(name: &'static CStr) -> Self {
|
||||||
Self {
|
Self {
|
||||||
attribute: Opaque::new(bindings::configfs_attribute {
|
attribute: Opaque::new(bindings::configfs_attribute {
|
||||||
ca_name: name.as_char_ptr(),
|
ca_name: crate::str::as_char_ptr_in_const_context(name),
|
||||||
ca_owner: core::ptr::null_mut(),
|
ca_owner: core::ptr::null_mut(),
|
||||||
ca_mode: 0o660,
|
ca_mode: 0o660,
|
||||||
show: Some(Self::show),
|
show: Some(Self::show),
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,7 @@ impl CpuId {
|
||||||
/// unexpectedly due to preemption or CPU migration. It should only be
|
/// unexpectedly due to preemption or CPU migration. It should only be
|
||||||
/// used when the context ensures that the task remains on the same CPU
|
/// used when the context ensures that the task remains on the same CPU
|
||||||
/// or the users could use a stale (yet valid) CPU ID.
|
/// or the users could use a stale (yet valid) CPU ID.
|
||||||
|
#[inline]
|
||||||
pub fn current() -> Self {
|
pub fn current() -> Self {
|
||||||
// SAFETY: raw_smp_processor_id() always returns a valid CPU ID.
|
// SAFETY: raw_smp_processor_id() always returns a valid CPU ID.
|
||||||
unsafe { Self::from_u32_unchecked(bindings::raw_smp_processor_id()) }
|
unsafe { Self::from_u32_unchecked(bindings::raw_smp_processor_id()) }
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ use crate::clk::Clk;
|
||||||
use core::{
|
use core::{
|
||||||
cell::UnsafeCell,
|
cell::UnsafeCell,
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
mem::MaybeUninit,
|
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
ptr,
|
ptr,
|
||||||
|
|
@ -1013,12 +1012,11 @@ impl<T: Driver> Registration<T> {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
// SAFETY: All zeros is a valid value for `bindings::cpufreq_driver`.
|
..pin_init::zeroed()
|
||||||
..unsafe { MaybeUninit::zeroed().assume_init() }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const fn copy_name(name: &'static CStr) -> [c_char; CPUFREQ_NAME_LEN] {
|
const fn copy_name(name: &'static CStr) -> [c_char; CPUFREQ_NAME_LEN] {
|
||||||
let src = name.as_bytes_with_nul();
|
let src = name.to_bytes_with_nul();
|
||||||
let mut dst = [0; CPUFREQ_NAME_LEN];
|
let mut dst = [0; CPUFREQ_NAME_LEN];
|
||||||
|
|
||||||
build_assert!(src.len() <= CPUFREQ_NAME_LEN);
|
build_assert!(src.len() <= CPUFREQ_NAME_LEN);
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@
|
||||||
//! C header: [`include/linux/device.h`](srctree/include/linux/device.h)
|
//! C header: [`include/linux/device.h`](srctree/include/linux/device.h)
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bindings,
|
bindings, fmt,
|
||||||
types::{ARef, ForeignOwnable, Opaque},
|
types::{ARef, ForeignOwnable, Opaque},
|
||||||
};
|
};
|
||||||
use core::{fmt, marker::PhantomData, ptr};
|
use core::{marker::PhantomData, ptr};
|
||||||
|
|
||||||
#[cfg(CONFIG_PRINTK)]
|
#[cfg(CONFIG_PRINTK)]
|
||||||
use crate::c_str;
|
use crate::c_str;
|
||||||
|
|
@ -596,7 +596,7 @@ macro_rules! impl_device_context_into_aref {
|
||||||
macro_rules! dev_printk {
|
macro_rules! dev_printk {
|
||||||
($method:ident, $dev:expr, $($f:tt)*) => {
|
($method:ident, $dev:expr, $($f:tt)*) => {
|
||||||
{
|
{
|
||||||
($dev).$method(::core::format_args!($($f)*));
|
($dev).$method($crate::prelude::fmt!($($f)*));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ use crate::{
|
||||||
alloc::KVec,
|
alloc::KVec,
|
||||||
bindings,
|
bindings,
|
||||||
error::{to_result, Result},
|
error::{to_result, Result},
|
||||||
|
fmt,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
str::{CStr, CString},
|
str::{CStr, CString},
|
||||||
types::{ARef, Opaque},
|
types::{ARef, Opaque},
|
||||||
|
|
@ -68,16 +69,16 @@ impl FwNode {
|
||||||
unsafe { bindings::is_of_node(self.as_raw()) }
|
unsafe { bindings::is_of_node(self.as_raw()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an object that implements [`Display`](core::fmt::Display) for
|
/// Returns an object that implements [`Display`](fmt::Display) for
|
||||||
/// printing the name of a node.
|
/// printing the name of a node.
|
||||||
///
|
///
|
||||||
/// This is an alternative to the default `Display` implementation, which
|
/// This is an alternative to the default `Display` implementation, which
|
||||||
/// prints the full path.
|
/// prints the full path.
|
||||||
pub fn display_name(&self) -> impl core::fmt::Display + '_ {
|
pub fn display_name(&self) -> impl fmt::Display + '_ {
|
||||||
struct FwNodeDisplayName<'a>(&'a FwNode);
|
struct FwNodeDisplayName<'a>(&'a FwNode);
|
||||||
|
|
||||||
impl core::fmt::Display for FwNodeDisplayName<'_> {
|
impl fmt::Display for FwNodeDisplayName<'_> {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
// SAFETY: `self` is valid by its type invariant.
|
// SAFETY: `self` is valid by its type invariant.
|
||||||
let name = unsafe { bindings::fwnode_get_name(self.0.as_raw()) };
|
let name = unsafe { bindings::fwnode_get_name(self.0.as_raw()) };
|
||||||
if name.is_null() {
|
if name.is_null() {
|
||||||
|
|
@ -87,7 +88,7 @@ impl FwNode {
|
||||||
// - `fwnode_get_name` returns null or a valid C string.
|
// - `fwnode_get_name` returns null or a valid C string.
|
||||||
// - `name` was checked to be non-null.
|
// - `name` was checked to be non-null.
|
||||||
let name = unsafe { CStr::from_char_ptr(name) };
|
let name = unsafe { CStr::from_char_ptr(name) };
|
||||||
write!(f, "{name}")
|
fmt::Display::fmt(name, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -351,8 +352,8 @@ impl FwNodeReferenceArgs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl core::fmt::Debug for FwNodeReferenceArgs {
|
impl fmt::Debug for FwNodeReferenceArgs {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{:?}", self.as_slice())
|
write!(f, "{:?}", self.as_slice())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -377,8 +378,8 @@ enum Node<'a> {
|
||||||
Owned(ARef<FwNode>),
|
Owned(ARef<FwNode>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl core::fmt::Display for FwNode {
|
impl fmt::Display for FwNode {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
// The logic here is the same as the one in lib/vsprintf.c
|
// The logic here is the same as the one in lib/vsprintf.c
|
||||||
// (fwnode_full_name_string).
|
// (fwnode_full_name_string).
|
||||||
|
|
||||||
|
|
@ -413,9 +414,9 @@ impl core::fmt::Display for FwNode {
|
||||||
// SAFETY: `fwnode_get_name_prefix` returns null or a
|
// SAFETY: `fwnode_get_name_prefix` returns null or a
|
||||||
// valid C string.
|
// valid C string.
|
||||||
let prefix = unsafe { CStr::from_char_ptr(prefix) };
|
let prefix = unsafe { CStr::from_char_ptr(prefix) };
|
||||||
write!(f, "{prefix}")?;
|
fmt::Display::fmt(prefix, f)?;
|
||||||
}
|
}
|
||||||
write!(f, "{}", fwnode.display_name())?;
|
fmt::Display::fmt(&fwnode.display_name(), f)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ use crate::{
|
||||||
device::{Bound, Core},
|
device::{Bound, Core},
|
||||||
error::{to_result, Result},
|
error::{to_result, Result},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
|
sync::aref::ARef,
|
||||||
transmute::{AsBytes, FromBytes},
|
transmute::{AsBytes, FromBytes},
|
||||||
types::ARef,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Trait to be implemented by DMA capable bus devices.
|
/// Trait to be implemented by DMA capable bus devices.
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
//! DRM device.
|
//! DRM device.
|
||||||
//!
|
//!
|
||||||
//! C header: [`include/linux/drm/drm_device.h`](srctree/include/linux/drm/drm_device.h)
|
//! C header: [`include/drm/drm_device.h`](srctree/include/drm/drm_device.h)
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
alloc::allocator::Kmalloc,
|
alloc::allocator::Kmalloc,
|
||||||
|
|
@ -82,8 +82,8 @@ impl<T: drm::Driver> Device<T> {
|
||||||
major: T::INFO.major,
|
major: T::INFO.major,
|
||||||
minor: T::INFO.minor,
|
minor: T::INFO.minor,
|
||||||
patchlevel: T::INFO.patchlevel,
|
patchlevel: T::INFO.patchlevel,
|
||||||
name: T::INFO.name.as_char_ptr().cast_mut(),
|
name: crate::str::as_char_ptr_in_const_context(T::INFO.name).cast_mut(),
|
||||||
desc: T::INFO.desc.as_char_ptr().cast_mut(),
|
desc: crate::str::as_char_ptr_in_const_context(T::INFO.desc).cast_mut(),
|
||||||
|
|
||||||
driver_features: drm::driver::FEAT_GEM,
|
driver_features: drm::driver::FEAT_GEM,
|
||||||
ioctls: T::IOCTLS.as_ptr(),
|
ioctls: T::IOCTLS.as_ptr(),
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
//! DRM driver core.
|
//! DRM driver core.
|
||||||
//!
|
//!
|
||||||
//! C header: [`include/linux/drm/drm_drv.h`](srctree/include/linux/drm/drm_drv.h)
|
//! C header: [`include/drm/drm_drv.h`](srctree/include/drm/drm_drv.h)
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bindings, device, devres, drm,
|
bindings, device, devres, drm,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
//! DRM File objects.
|
//! DRM File objects.
|
||||||
//!
|
//!
|
||||||
//! C header: [`include/linux/drm/drm_file.h`](srctree/include/linux/drm/drm_file.h)
|
//! C header: [`include/drm/drm_file.h`](srctree/include/drm/drm_file.h)
|
||||||
|
|
||||||
use crate::{bindings, drm, error::Result, prelude::*, types::Opaque};
|
use crate::{bindings, drm, error::Result, prelude::*, types::Opaque};
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
//! DRM GEM API
|
//! DRM GEM API
|
||||||
//!
|
//!
|
||||||
//! C header: [`include/linux/drm/drm_gem.h`](srctree/include/linux/drm/drm_gem.h)
|
//! C header: [`include/drm/drm_gem.h`](srctree/include/drm/drm_gem.h)
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
alloc::flags::*,
|
alloc::flags::*,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
//! DRM IOCTL definitions.
|
//! DRM IOCTL definitions.
|
||||||
//!
|
//!
|
||||||
//! C header: [`include/linux/drm/drm_ioctl.h`](srctree/include/linux/drm/drm_ioctl.h)
|
//! C header: [`include/drm/drm_ioctl.h`](srctree/include/drm/drm_ioctl.h)
|
||||||
|
|
||||||
use crate::ioctl;
|
use crate::ioctl;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
|
|
||||||
//! Kernel errors.
|
//! Kernel errors.
|
||||||
//!
|
//!
|
||||||
//! C header: [`include/uapi/asm-generic/errno-base.h`](srctree/include/uapi/asm-generic/errno-base.h)
|
//! C header: [`include/uapi/asm-generic/errno-base.h`](srctree/include/uapi/asm-generic/errno-base.h)\
|
||||||
|
//! C header: [`include/uapi/asm-generic/errno.h`](srctree/include/uapi/asm-generic/errno.h)\
|
||||||
|
//! C header: [`include/linux/errno.h`](srctree/include/linux/errno.h)
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
alloc::{layout::LayoutError, AllocError},
|
alloc::{layout::LayoutError, AllocError},
|
||||||
|
|
@ -101,8 +103,23 @@ pub struct Error(NonZeroI32);
|
||||||
impl Error {
|
impl Error {
|
||||||
/// Creates an [`Error`] from a kernel error code.
|
/// Creates an [`Error`] from a kernel error code.
|
||||||
///
|
///
|
||||||
/// It is a bug to pass an out-of-range `errno`. `EINVAL` would
|
/// `errno` must be within error code range (i.e. `>= -MAX_ERRNO && < 0`).
|
||||||
/// be returned in such a case.
|
///
|
||||||
|
/// It is a bug to pass an out-of-range `errno`. [`code::EINVAL`] is returned in such a case.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// assert_eq!(Error::from_errno(-1), EPERM);
|
||||||
|
/// assert_eq!(Error::from_errno(-2), ENOENT);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// The following calls are considered a bug:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// assert_eq!(Error::from_errno(0), EINVAL);
|
||||||
|
/// assert_eq!(Error::from_errno(-1000000), EINVAL);
|
||||||
|
/// ```
|
||||||
pub fn from_errno(errno: crate::ffi::c_int) -> Error {
|
pub fn from_errno(errno: crate::ffi::c_int) -> Error {
|
||||||
if let Some(error) = Self::try_from_errno(errno) {
|
if let Some(error) = Self::try_from_errno(errno) {
|
||||||
error
|
error
|
||||||
|
|
@ -158,7 +175,7 @@ impl Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a string representing the error, if one exists.
|
/// Returns a string representing the error, if one exists.
|
||||||
#[cfg(not(any(test, testlib)))]
|
#[cfg(not(testlib))]
|
||||||
pub fn name(&self) -> Option<&'static CStr> {
|
pub fn name(&self) -> Option<&'static CStr> {
|
||||||
// SAFETY: Just an FFI call, there are no extra safety requirements.
|
// SAFETY: Just an FFI call, there are no extra safety requirements.
|
||||||
let ptr = unsafe { bindings::errname(-self.0.get()) };
|
let ptr = unsafe { bindings::errname(-self.0.get()) };
|
||||||
|
|
@ -175,7 +192,7 @@ impl Error {
|
||||||
/// When `testlib` is configured, this always returns `None` to avoid the dependency on a
|
/// When `testlib` is configured, this always returns `None` to avoid the dependency on a
|
||||||
/// kernel function so that tests that use this (e.g., by calling [`Result::unwrap`]) can still
|
/// kernel function so that tests that use this (e.g., by calling [`Result::unwrap`]) can still
|
||||||
/// run in userspace.
|
/// run in userspace.
|
||||||
#[cfg(any(test, testlib))]
|
#[cfg(testlib)]
|
||||||
pub fn name(&self) -> Option<&'static CStr> {
|
pub fn name(&self) -> Option<&'static CStr> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -375,8 +392,43 @@ impl From<core::convert::Infallible> for Error {
|
||||||
/// [Rust documentation]: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html
|
/// [Rust documentation]: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html
|
||||||
pub type Result<T = (), E = Error> = core::result::Result<T, E>;
|
pub type Result<T = (), E = Error> = core::result::Result<T, E>;
|
||||||
|
|
||||||
/// Converts an integer as returned by a C kernel function to an error if it's negative, and
|
/// Converts an integer as returned by a C kernel function to a [`Result`].
|
||||||
/// `Ok(())` otherwise.
|
///
|
||||||
|
/// If the integer is negative, an [`Err`] with an [`Error`] as given by [`Error::from_errno`] is
|
||||||
|
/// returned. This means the integer must be `>= -MAX_ERRNO`.
|
||||||
|
///
|
||||||
|
/// Otherwise, it returns [`Ok`].
|
||||||
|
///
|
||||||
|
/// It is a bug to pass an out-of-range negative integer. `Err(EINVAL)` is returned in such a case.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// This function may be used to easily perform early returns with the [`?`] operator when working
|
||||||
|
/// with C APIs within Rust abstractions:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use kernel::error::to_result;
|
||||||
|
/// # mod bindings {
|
||||||
|
/// # #![expect(clippy::missing_safety_doc)]
|
||||||
|
/// # use kernel::prelude::*;
|
||||||
|
/// # pub(super) unsafe fn f1() -> c_int { 0 }
|
||||||
|
/// # pub(super) unsafe fn f2() -> c_int { EINVAL.to_errno() }
|
||||||
|
/// # }
|
||||||
|
/// fn f() -> Result {
|
||||||
|
/// // SAFETY: ...
|
||||||
|
/// to_result(unsafe { bindings::f1() })?;
|
||||||
|
///
|
||||||
|
/// // SAFETY: ...
|
||||||
|
/// to_result(unsafe { bindings::f2() })?;
|
||||||
|
///
|
||||||
|
/// // ...
|
||||||
|
///
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// # assert_eq!(f(), Err(EINVAL));
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [`?`]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator
|
||||||
pub fn to_result(err: crate::ffi::c_int) -> Result {
|
pub fn to_result(err: crate::ffi::c_int) -> Result {
|
||||||
if err < 0 {
|
if err < 0 {
|
||||||
Err(Error::from_errno(err))
|
Err(Error::from_errno(err))
|
||||||
|
|
|
||||||
|
|
@ -291,7 +291,7 @@ impl<const N: usize> ModInfoBuilder<N> {
|
||||||
let module_name = this.module_name;
|
let module_name = this.module_name;
|
||||||
|
|
||||||
if !this.module_name.is_empty() {
|
if !this.module_name.is_empty() {
|
||||||
this = this.push_internal(module_name.as_bytes_with_nul());
|
this = this.push_internal(module_name.to_bytes_with_nul());
|
||||||
|
|
||||||
if N != 0 {
|
if N != 0 {
|
||||||
// Re-use the space taken by the NULL terminator and swap it with the '.' separator.
|
// Re-use the space taken by the NULL terminator and swap it with the '.' separator.
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ use crate::{
|
||||||
bindings,
|
bindings,
|
||||||
cred::Credential,
|
cred::Credential,
|
||||||
error::{code::*, to_result, Error, Result},
|
error::{code::*, to_result, Error, Result},
|
||||||
|
fmt,
|
||||||
sync::aref::{ARef, AlwaysRefCounted},
|
sync::aref::{ARef, AlwaysRefCounted},
|
||||||
types::{NotThreadSafe, Opaque},
|
types::{NotThreadSafe, Opaque},
|
||||||
};
|
};
|
||||||
|
|
@ -460,8 +461,8 @@ impl From<BadFdError> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl core::fmt::Debug for BadFdError {
|
impl fmt::Debug for BadFdError {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.pad("EBADF")
|
f.pad("EBADF")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@
|
||||||
//!
|
//!
|
||||||
//! Reference: <https://docs.kernel.org/dev-tools/kunit/index.html>
|
//! Reference: <https://docs.kernel.org/dev-tools/kunit/index.html>
|
||||||
|
|
||||||
|
use crate::fmt;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use core::fmt;
|
|
||||||
|
|
||||||
#[cfg(CONFIG_PRINTK)]
|
#[cfg(CONFIG_PRINTK)]
|
||||||
use crate::c_str;
|
use crate::c_str;
|
||||||
|
|
@ -74,14 +74,14 @@ macro_rules! kunit_assert {
|
||||||
// mistake (it is hidden to prevent that).
|
// mistake (it is hidden to prevent that).
|
||||||
//
|
//
|
||||||
// This mimics KUnit's failed assertion format.
|
// This mimics KUnit's failed assertion format.
|
||||||
$crate::kunit::err(format_args!(
|
$crate::kunit::err($crate::prelude::fmt!(
|
||||||
" # {}: ASSERTION FAILED at {FILE}:{LINE}\n",
|
" # {}: ASSERTION FAILED at {FILE}:{LINE}\n",
|
||||||
$name
|
$name
|
||||||
));
|
));
|
||||||
$crate::kunit::err(format_args!(
|
$crate::kunit::err($crate::prelude::fmt!(
|
||||||
" Expected {CONDITION} to be true, but is false\n"
|
" Expected {CONDITION} to be true, but is false\n"
|
||||||
));
|
));
|
||||||
$crate::kunit::err(format_args!(
|
$crate::kunit::err($crate::prelude::fmt!(
|
||||||
" Failure not reported to KUnit since this is a non-KUnit task\n"
|
" Failure not reported to KUnit since this is a non-KUnit task\n"
|
||||||
));
|
));
|
||||||
break 'out;
|
break 'out;
|
||||||
|
|
@ -102,12 +102,12 @@ macro_rules! kunit_assert {
|
||||||
unsafe impl Sync for UnaryAssert {}
|
unsafe impl Sync for UnaryAssert {}
|
||||||
|
|
||||||
static LOCATION: Location = Location($crate::bindings::kunit_loc {
|
static LOCATION: Location = Location($crate::bindings::kunit_loc {
|
||||||
file: FILE.as_char_ptr(),
|
file: $crate::str::as_char_ptr_in_const_context(FILE),
|
||||||
line: LINE,
|
line: LINE,
|
||||||
});
|
});
|
||||||
static ASSERTION: UnaryAssert = UnaryAssert($crate::bindings::kunit_unary_assert {
|
static ASSERTION: UnaryAssert = UnaryAssert($crate::bindings::kunit_unary_assert {
|
||||||
assert: $crate::bindings::kunit_assert {},
|
assert: $crate::bindings::kunit_assert {},
|
||||||
condition: CONDITION.as_char_ptr(),
|
condition: $crate::str::as_char_ptr_in_const_context(CONDITION),
|
||||||
expected_true: true,
|
expected_true: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -202,7 +202,7 @@ pub const fn kunit_case(
|
||||||
) -> kernel::bindings::kunit_case {
|
) -> kernel::bindings::kunit_case {
|
||||||
kernel::bindings::kunit_case {
|
kernel::bindings::kunit_case {
|
||||||
run_case: Some(run_case),
|
run_case: Some(run_case),
|
||||||
name: name.as_char_ptr(),
|
name: kernel::str::as_char_ptr_in_const_context(name),
|
||||||
attr: kernel::bindings::kunit_attributes {
|
attr: kernel::bindings::kunit_attributes {
|
||||||
speed: kernel::bindings::kunit_speed_KUNIT_SPEED_NORMAL,
|
speed: kernel::bindings::kunit_speed_KUNIT_SPEED_NORMAL,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
// the unstable features in use.
|
// the unstable features in use.
|
||||||
//
|
//
|
||||||
// Stable since Rust 1.79.0.
|
// Stable since Rust 1.79.0.
|
||||||
|
#![feature(generic_nonzero)]
|
||||||
#![feature(inline_const)]
|
#![feature(inline_const)]
|
||||||
//
|
//
|
||||||
// Stable since Rust 1.81.0.
|
// Stable since Rust 1.81.0.
|
||||||
|
|
@ -28,6 +29,7 @@
|
||||||
// Stable since Rust 1.83.0.
|
// Stable since Rust 1.83.0.
|
||||||
#![feature(const_maybe_uninit_as_mut_ptr)]
|
#![feature(const_maybe_uninit_as_mut_ptr)]
|
||||||
#![feature(const_mut_refs)]
|
#![feature(const_mut_refs)]
|
||||||
|
#![feature(const_option)]
|
||||||
#![feature(const_ptr_write)]
|
#![feature(const_ptr_write)]
|
||||||
#![feature(const_refs_to_cell)]
|
#![feature(const_refs_to_cell)]
|
||||||
//
|
//
|
||||||
|
|
@ -110,6 +112,7 @@ pub mod pid_namespace;
|
||||||
pub mod platform;
|
pub mod platform;
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
pub mod print;
|
pub mod print;
|
||||||
|
pub mod ptr;
|
||||||
pub mod rbtree;
|
pub mod rbtree;
|
||||||
pub mod regulator;
|
pub mod regulator;
|
||||||
pub mod revocable;
|
pub mod revocable;
|
||||||
|
|
@ -206,7 +209,7 @@ impl ThisModule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(testlib, test)))]
|
#[cfg(not(testlib))]
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
|
fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
|
||||||
pr_emerg!("{}\n", info);
|
pr_emerg!("{}\n", info);
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,8 @@ pub use self::arc_field::{define_list_arc_field_getter, ListArcField};
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
/// Use [`ListLinks`] as the type of the intrusive field.
|
||||||
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use kernel::list::*;
|
/// use kernel::list::*;
|
||||||
///
|
///
|
||||||
|
|
@ -140,6 +142,124 @@ pub use self::arc_field::{define_list_arc_field_getter, ListArcField};
|
||||||
/// }
|
/// }
|
||||||
/// # Result::<(), Error>::Ok(())
|
/// # Result::<(), Error>::Ok(())
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use [`ListLinksSelfPtr`] as the type of the intrusive field. This allows a list of trait object
|
||||||
|
/// type.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use kernel::list::*;
|
||||||
|
///
|
||||||
|
/// trait Foo {
|
||||||
|
/// fn foo(&self) -> (&'static str, i32);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// #[pin_data]
|
||||||
|
/// struct DTWrap<T: ?Sized> {
|
||||||
|
/// #[pin]
|
||||||
|
/// links: ListLinksSelfPtr<DTWrap<dyn Foo>>,
|
||||||
|
/// value: T,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl<T> DTWrap<T> {
|
||||||
|
/// fn new(value: T) -> Result<ListArc<Self>> {
|
||||||
|
/// ListArc::pin_init(try_pin_init!(Self {
|
||||||
|
/// value,
|
||||||
|
/// links <- ListLinksSelfPtr::new(),
|
||||||
|
/// }), GFP_KERNEL)
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl_list_arc_safe! {
|
||||||
|
/// impl{T: ?Sized} ListArcSafe<0> for DTWrap<T> { untracked; }
|
||||||
|
/// }
|
||||||
|
/// impl_list_item! {
|
||||||
|
/// impl ListItem<0> for DTWrap<dyn Foo> { using ListLinksSelfPtr { self.links }; }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Create a new empty list.
|
||||||
|
/// let mut list = List::<DTWrap<dyn Foo>>::new();
|
||||||
|
/// {
|
||||||
|
/// assert!(list.is_empty());
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// struct A(i32);
|
||||||
|
/// // `A` returns the inner value for `foo`.
|
||||||
|
/// impl Foo for A { fn foo(&self) -> (&'static str, i32) { ("a", self.0) } }
|
||||||
|
///
|
||||||
|
/// struct B;
|
||||||
|
/// // `B` always returns 42.
|
||||||
|
/// impl Foo for B { fn foo(&self) -> (&'static str, i32) { ("b", 42) } }
|
||||||
|
///
|
||||||
|
/// // Insert 3 element using `push_back()`.
|
||||||
|
/// list.push_back(DTWrap::new(A(15))?);
|
||||||
|
/// list.push_back(DTWrap::new(A(32))?);
|
||||||
|
/// list.push_back(DTWrap::new(B)?);
|
||||||
|
///
|
||||||
|
/// // Iterate over the list to verify the nodes were inserted correctly.
|
||||||
|
/// // [A(15), A(32), B]
|
||||||
|
/// {
|
||||||
|
/// let mut iter = list.iter();
|
||||||
|
/// assert_eq!(iter.next().ok_or(EINVAL)?.value.foo(), ("a", 15));
|
||||||
|
/// assert_eq!(iter.next().ok_or(EINVAL)?.value.foo(), ("a", 32));
|
||||||
|
/// assert_eq!(iter.next().ok_or(EINVAL)?.value.foo(), ("b", 42));
|
||||||
|
/// assert!(iter.next().is_none());
|
||||||
|
///
|
||||||
|
/// // Verify the length of the list.
|
||||||
|
/// assert_eq!(list.iter().count(), 3);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Pop the items from the list using `pop_back()` and verify the content.
|
||||||
|
/// {
|
||||||
|
/// assert_eq!(list.pop_back().ok_or(EINVAL)?.value.foo(), ("b", 42));
|
||||||
|
/// assert_eq!(list.pop_back().ok_or(EINVAL)?.value.foo(), ("a", 32));
|
||||||
|
/// assert_eq!(list.pop_back().ok_or(EINVAL)?.value.foo(), ("a", 15));
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Insert 3 elements using `push_front()`.
|
||||||
|
/// list.push_front(DTWrap::new(A(15))?);
|
||||||
|
/// list.push_front(DTWrap::new(A(32))?);
|
||||||
|
/// list.push_front(DTWrap::new(B)?);
|
||||||
|
///
|
||||||
|
/// // Iterate over the list to verify the nodes were inserted correctly.
|
||||||
|
/// // [B, A(32), A(15)]
|
||||||
|
/// {
|
||||||
|
/// let mut iter = list.iter();
|
||||||
|
/// assert_eq!(iter.next().ok_or(EINVAL)?.value.foo(), ("b", 42));
|
||||||
|
/// assert_eq!(iter.next().ok_or(EINVAL)?.value.foo(), ("a", 32));
|
||||||
|
/// assert_eq!(iter.next().ok_or(EINVAL)?.value.foo(), ("a", 15));
|
||||||
|
/// assert!(iter.next().is_none());
|
||||||
|
///
|
||||||
|
/// // Verify the length of the list.
|
||||||
|
/// assert_eq!(list.iter().count(), 3);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Pop the items from the list using `pop_front()` and verify the content.
|
||||||
|
/// {
|
||||||
|
/// assert_eq!(list.pop_back().ok_or(EINVAL)?.value.foo(), ("a", 15));
|
||||||
|
/// assert_eq!(list.pop_back().ok_or(EINVAL)?.value.foo(), ("a", 32));
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Push `list2` to `list` through `push_all_back()`.
|
||||||
|
/// // list: [B]
|
||||||
|
/// // list2: [B, A(25)]
|
||||||
|
/// {
|
||||||
|
/// let mut list2 = List::<DTWrap<dyn Foo>>::new();
|
||||||
|
/// list2.push_back(DTWrap::new(B)?);
|
||||||
|
/// list2.push_back(DTWrap::new(A(25))?);
|
||||||
|
///
|
||||||
|
/// list.push_all_back(&mut list2);
|
||||||
|
///
|
||||||
|
/// // list: [B, B, A(25)]
|
||||||
|
/// // list2: []
|
||||||
|
/// let mut iter = list.iter();
|
||||||
|
/// assert_eq!(iter.next().ok_or(EINVAL)?.value.foo(), ("b", 42));
|
||||||
|
/// assert_eq!(iter.next().ok_or(EINVAL)?.value.foo(), ("b", 42));
|
||||||
|
/// assert_eq!(iter.next().ok_or(EINVAL)?.value.foo(), ("a", 25));
|
||||||
|
/// assert!(iter.next().is_none());
|
||||||
|
/// assert!(list2.is_empty());
|
||||||
|
/// }
|
||||||
|
/// # Result::<(), Error>::Ok(())
|
||||||
|
/// ```
|
||||||
pub struct List<T: ?Sized + ListItem<ID>, const ID: u64 = 0> {
|
pub struct List<T: ?Sized + ListItem<ID>, const ID: u64 = 0> {
|
||||||
first: *mut ListLinksFields,
|
first: *mut ListLinksFields,
|
||||||
_ty: PhantomData<ListArc<T, ID>>,
|
_ty: PhantomData<ListArc<T, ID>>,
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ impl MiscDeviceOptions {
|
||||||
// SAFETY: All zeros is valid for this C type.
|
// SAFETY: All zeros is valid for this C type.
|
||||||
let mut result: bindings::miscdevice = unsafe { MaybeUninit::zeroed().assume_init() };
|
let mut result: bindings::miscdevice = unsafe { MaybeUninit::zeroed().assume_init() };
|
||||||
result.minor = bindings::MISC_DYNAMIC_MINOR as ffi::c_int;
|
result.minor = bindings::MISC_DYNAMIC_MINOR as ffi::c_int;
|
||||||
result.name = self.name.as_char_ptr();
|
result.name = crate::str::as_char_ptr_in_const_context(self.name);
|
||||||
result.fops = MiscdeviceVTable::<T>::build();
|
result.fops = MiscdeviceVTable::<T>::build();
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -497,7 +497,7 @@ unsafe impl Sync for DriverVTable {}
|
||||||
pub const fn create_phy_driver<T: Driver>() -> DriverVTable {
|
pub const fn create_phy_driver<T: Driver>() -> DriverVTable {
|
||||||
// INVARIANT: All the fields of `struct phy_driver` are initialized properly.
|
// INVARIANT: All the fields of `struct phy_driver` are initialized properly.
|
||||||
DriverVTable(Opaque::new(bindings::phy_driver {
|
DriverVTable(Opaque::new(bindings::phy_driver {
|
||||||
name: T::NAME.as_char_ptr().cast_mut(),
|
name: crate::str::as_char_ptr_in_const_context(T::NAME).cast_mut(),
|
||||||
flags: T::FLAGS,
|
flags: T::FLAGS,
|
||||||
phy_id: T::PHY_DEVICE_ID.id(),
|
phy_id: T::PHY_DEVICE_ID.id(),
|
||||||
phy_id_mask: T::PHY_DEVICE_ID.mask_as_int(),
|
phy_id_mask: T::PHY_DEVICE_ID.mask_as_int(),
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ unsafe impl RawDeviceIdIndex for DeviceId {
|
||||||
impl DeviceId {
|
impl DeviceId {
|
||||||
/// Create a new device id from an OF 'compatible' string.
|
/// Create a new device id from an OF 'compatible' string.
|
||||||
pub const fn new(compatible: &'static CStr) -> Self {
|
pub const fn new(compatible: &'static CStr) -> Self {
|
||||||
let src = compatible.as_bytes_with_nul();
|
let src = compatible.to_bytes_with_nul();
|
||||||
// Replace with `bindings::of_device_id::default()` once stabilized for `const`.
|
// Replace with `bindings::of_device_id::default()` once stabilized for `const`.
|
||||||
// SAFETY: FFI type is valid to be zero-initialized.
|
// SAFETY: FFI type is valid to be zero-initialized.
|
||||||
let mut of: bindings::of_device_id = unsafe { core::mem::zeroed() };
|
let mut of: bindings::of_device_id = unsafe { core::mem::zeroed() };
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,10 @@
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use core::pin::Pin;
|
pub use core::{
|
||||||
|
mem::{align_of, align_of_val, size_of, size_of_val},
|
||||||
|
pin::Pin,
|
||||||
|
};
|
||||||
|
|
||||||
pub use ::ffi::{
|
pub use ::ffi::{
|
||||||
c_char, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, c_ulong, c_ulonglong,
|
c_char, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, c_ulong, c_ulonglong,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,228 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
//! Types and functions to work with pointers and addresses.
|
||||||
|
|
||||||
|
use core::fmt::Debug;
|
||||||
|
use core::mem::align_of;
|
||||||
|
use core::num::NonZero;
|
||||||
|
|
||||||
|
use crate::build_assert;
|
||||||
|
|
||||||
|
/// Type representing an alignment, which is always a power of two.
|
||||||
|
///
|
||||||
|
/// It is used to validate that a given value is a valid alignment, and to perform masking and
|
||||||
|
/// alignment operations.
|
||||||
|
///
|
||||||
|
/// This is a temporary substitute for the [`Alignment`] nightly type from the standard library,
|
||||||
|
/// and to be eventually replaced by it.
|
||||||
|
///
|
||||||
|
/// [`Alignment`]: https://github.com/rust-lang/rust/issues/102070
|
||||||
|
///
|
||||||
|
/// # Invariants
|
||||||
|
///
|
||||||
|
/// An alignment is always a power of two.
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct Alignment(NonZero<usize>);
|
||||||
|
|
||||||
|
impl Alignment {
|
||||||
|
/// Validates that `ALIGN` is a power of two at build-time, and returns an [`Alignment`] of the
|
||||||
|
/// same value.
|
||||||
|
///
|
||||||
|
/// A build error is triggered if `ALIGN` is not a power of two.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use kernel::ptr::Alignment;
|
||||||
|
///
|
||||||
|
/// let v = Alignment::new::<16>();
|
||||||
|
/// assert_eq!(v.as_usize(), 16);
|
||||||
|
/// ```
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn new<const ALIGN: usize>() -> Self {
|
||||||
|
build_assert!(
|
||||||
|
ALIGN.is_power_of_two(),
|
||||||
|
"Provided alignment is not a power of two."
|
||||||
|
);
|
||||||
|
|
||||||
|
// INVARIANT: `align` is a power of two.
|
||||||
|
// SAFETY: `align` is a power of two, and thus non-zero.
|
||||||
|
Self(unsafe { NonZero::new_unchecked(ALIGN) })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validates that `align` is a power of two at runtime, and returns an
|
||||||
|
/// [`Alignment`] of the same value.
|
||||||
|
///
|
||||||
|
/// Returns [`None`] if `align` is not a power of two.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use kernel::ptr::Alignment;
|
||||||
|
///
|
||||||
|
/// assert_eq!(Alignment::new_checked(16), Some(Alignment::new::<16>()));
|
||||||
|
/// assert_eq!(Alignment::new_checked(15), None);
|
||||||
|
/// assert_eq!(Alignment::new_checked(1), Some(Alignment::new::<1>()));
|
||||||
|
/// assert_eq!(Alignment::new_checked(0), None);
|
||||||
|
/// ```
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn new_checked(align: usize) -> Option<Self> {
|
||||||
|
if align.is_power_of_two() {
|
||||||
|
// INVARIANT: `align` is a power of two.
|
||||||
|
// SAFETY: `align` is a power of two, and thus non-zero.
|
||||||
|
Some(Self(unsafe { NonZero::new_unchecked(align) }))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the alignment of `T`.
|
||||||
|
///
|
||||||
|
/// This is equivalent to [`align_of`], but with the return value provided as an [`Alignment`].
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn of<T>() -> Self {
|
||||||
|
#![allow(clippy::incompatible_msrv)]
|
||||||
|
// This cannot panic since alignments are always powers of two.
|
||||||
|
//
|
||||||
|
// We unfortunately cannot use `new` as it would require the `generic_const_exprs` feature.
|
||||||
|
const { Alignment::new_checked(align_of::<T>()).unwrap() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns this alignment as a [`usize`].
|
||||||
|
///
|
||||||
|
/// It is guaranteed to be a power of two.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use kernel::ptr::Alignment;
|
||||||
|
///
|
||||||
|
/// assert_eq!(Alignment::new::<16>().as_usize(), 16);
|
||||||
|
/// ```
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn as_usize(self) -> usize {
|
||||||
|
self.as_nonzero().get()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns this alignment as a [`NonZero`].
|
||||||
|
///
|
||||||
|
/// It is guaranteed to be a power of two.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use kernel::ptr::Alignment;
|
||||||
|
///
|
||||||
|
/// assert_eq!(Alignment::new::<16>().as_nonzero().get(), 16);
|
||||||
|
/// ```
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn as_nonzero(self) -> NonZero<usize> {
|
||||||
|
// Allow the compiler to know that the value is indeed a power of two. This can help
|
||||||
|
// optimize some operations down the line, like e.g. replacing divisions by bit shifts.
|
||||||
|
if !self.0.is_power_of_two() {
|
||||||
|
// SAFETY: Per the invariants, `self.0` is always a power of two so this block will
|
||||||
|
// never be reached.
|
||||||
|
unsafe { core::hint::unreachable_unchecked() }
|
||||||
|
}
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the base-2 logarithm of the alignment.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use kernel::ptr::Alignment;
|
||||||
|
///
|
||||||
|
/// assert_eq!(Alignment::of::<u8>().log2(), 0);
|
||||||
|
/// assert_eq!(Alignment::new::<16>().log2(), 4);
|
||||||
|
/// ```
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn log2(self) -> u32 {
|
||||||
|
self.0.ilog2()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the mask for this alignment.
|
||||||
|
///
|
||||||
|
/// This is equivalent to `!(self.as_usize() - 1)`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use kernel::ptr::Alignment;
|
||||||
|
///
|
||||||
|
/// assert_eq!(Alignment::new::<0x10>().mask(), !0xf);
|
||||||
|
/// ```
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn mask(self) -> usize {
|
||||||
|
// No underflow can occur as the alignment is guaranteed to be a power of two, and thus is
|
||||||
|
// non-zero.
|
||||||
|
!(self.as_usize() - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait for items that can be aligned against an [`Alignment`].
|
||||||
|
pub trait Alignable: Sized {
|
||||||
|
/// Aligns `self` down to `alignment`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use kernel::ptr::{Alignable, Alignment};
|
||||||
|
///
|
||||||
|
/// assert_eq!(0x2f_usize.align_down(Alignment::new::<0x10>()), 0x20);
|
||||||
|
/// assert_eq!(0x30usize.align_down(Alignment::new::<0x10>()), 0x30);
|
||||||
|
/// assert_eq!(0xf0u8.align_down(Alignment::new::<0x1000>()), 0x0);
|
||||||
|
/// ```
|
||||||
|
fn align_down(self, alignment: Alignment) -> Self;
|
||||||
|
|
||||||
|
/// Aligns `self` up to `alignment`, returning `None` if aligning would result in an overflow.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use kernel::ptr::{Alignable, Alignment};
|
||||||
|
///
|
||||||
|
/// assert_eq!(0x4fusize.align_up(Alignment::new::<0x10>()), Some(0x50));
|
||||||
|
/// assert_eq!(0x40usize.align_up(Alignment::new::<0x10>()), Some(0x40));
|
||||||
|
/// assert_eq!(0x0usize.align_up(Alignment::new::<0x10>()), Some(0x0));
|
||||||
|
/// assert_eq!(u8::MAX.align_up(Alignment::new::<0x10>()), None);
|
||||||
|
/// assert_eq!(0x10u8.align_up(Alignment::new::<0x100>()), None);
|
||||||
|
/// assert_eq!(0x0u8.align_up(Alignment::new::<0x100>()), Some(0x0));
|
||||||
|
/// ```
|
||||||
|
fn align_up(self, alignment: Alignment) -> Option<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implement [`Alignable`] for unsigned integer types.
|
||||||
|
macro_rules! impl_alignable_uint {
|
||||||
|
($($t:ty),*) => {
|
||||||
|
$(
|
||||||
|
impl Alignable for $t {
|
||||||
|
#[inline(always)]
|
||||||
|
fn align_down(self, alignment: Alignment) -> Self {
|
||||||
|
// The operands of `&` need to be of the same type so convert the alignment to
|
||||||
|
// `Self`. This means we need to compute the mask ourselves.
|
||||||
|
::core::num::NonZero::<Self>::try_from(alignment.as_nonzero())
|
||||||
|
.map(|align| self & !(align.get() - 1))
|
||||||
|
// An alignment larger than `Self` always aligns down to `0`.
|
||||||
|
.unwrap_or(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn align_up(self, alignment: Alignment) -> Option<Self> {
|
||||||
|
let aligned_down = self.align_down(alignment);
|
||||||
|
if self == aligned_down {
|
||||||
|
Some(aligned_down)
|
||||||
|
} else {
|
||||||
|
Self::try_from(alignment.as_usize())
|
||||||
|
.ok()
|
||||||
|
.and_then(|align| aligned_down.checked_add(align))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_alignable_uint!(u8, u16, u32, u64, usize);
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
//!
|
//!
|
||||||
//! C header: [`include/linux/seq_file.h`](srctree/include/linux/seq_file.h)
|
//! C header: [`include/linux/seq_file.h`](srctree/include/linux/seq_file.h)
|
||||||
|
|
||||||
use crate::{bindings, c_str, types::NotThreadSafe, types::Opaque};
|
use crate::{bindings, c_str, fmt, types::NotThreadSafe, types::Opaque};
|
||||||
|
|
||||||
/// A utility for generating the contents of a seq file.
|
/// A utility for generating the contents of a seq file.
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
|
|
@ -31,7 +31,7 @@ impl SeqFile {
|
||||||
|
|
||||||
/// Used by the [`seq_print`] macro.
|
/// Used by the [`seq_print`] macro.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn call_printf(&self, args: core::fmt::Arguments<'_>) {
|
pub fn call_printf(&self, args: fmt::Arguments<'_>) {
|
||||||
// SAFETY: Passing a void pointer to `Arguments` is valid for `%pA`.
|
// SAFETY: Passing a void pointer to `Arguments` is valid for `%pA`.
|
||||||
unsafe {
|
unsafe {
|
||||||
bindings::seq_printf(
|
bindings::seq_printf(
|
||||||
|
|
@ -47,7 +47,7 @@ impl SeqFile {
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! seq_print {
|
macro_rules! seq_print {
|
||||||
($m:expr, $($arg:tt)+) => (
|
($m:expr, $($arg:tt)+) => (
|
||||||
$m.call_printf(format_args!($($arg)+))
|
$m.call_printf($crate::prelude::fmt!($($arg)+))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
pub use seq_print;
|
pub use seq_print;
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
alloc::{AllocError, Flags, KBox},
|
alloc::{AllocError, Flags, KBox},
|
||||||
ffi::c_void,
|
ffi::c_void,
|
||||||
|
fmt,
|
||||||
init::InPlaceInit,
|
init::InPlaceInit,
|
||||||
sync::Refcount,
|
sync::Refcount,
|
||||||
try_init,
|
try_init,
|
||||||
|
|
@ -27,7 +28,6 @@ use crate::{
|
||||||
use core::{
|
use core::{
|
||||||
alloc::Layout,
|
alloc::Layout,
|
||||||
borrow::{Borrow, BorrowMut},
|
borrow::{Borrow, BorrowMut},
|
||||||
fmt,
|
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
mem::{ManuallyDrop, MaybeUninit},
|
mem::{ManuallyDrop, MaybeUninit},
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
|
|
@ -367,10 +367,10 @@ impl<T: ?Sized> Arc<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: The pointer returned by `into_foreign` comes from a well aligned
|
// SAFETY: The pointer returned by `into_foreign` was originally allocated as an
|
||||||
// pointer to `ArcInner<T>`.
|
// `KBox<ArcInner<T>>`, so that type is what determines the alignment.
|
||||||
unsafe impl<T: 'static> ForeignOwnable for Arc<T> {
|
unsafe impl<T: 'static> ForeignOwnable for Arc<T> {
|
||||||
const FOREIGN_ALIGN: usize = core::mem::align_of::<ArcInner<T>>();
|
const FOREIGN_ALIGN: usize = <KBox<ArcInner<T>> as ForeignOwnable>::FOREIGN_ALIGN;
|
||||||
|
|
||||||
type Borrowed<'a> = ArcBorrow<'a, T>;
|
type Borrowed<'a> = ArcBorrow<'a, T>;
|
||||||
type BorrowedMut<'a> = Self::Borrowed<'a>;
|
type BorrowedMut<'a> = Self::Borrowed<'a>;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,21 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
//! Internal reference counting support.
|
//! Internal reference counting support.
|
||||||
|
//!
|
||||||
|
//! Many C types already have their own reference counting mechanism (e.g. by storing a
|
||||||
|
//! `refcount_t`). This module provides support for directly using their internal reference count
|
||||||
|
//! from Rust; instead of making users have to use an additional Rust-reference count in the form of
|
||||||
|
//! [`Arc`].
|
||||||
|
//!
|
||||||
|
//! The smart pointer [`ARef<T>`] acts similarly to [`Arc<T>`] in that it holds a refcount on the
|
||||||
|
//! underlying object, but this refcount is internal to the object. It essentially is a Rust
|
||||||
|
//! implementation of the `get_` and `put_` pattern used in C for reference counting.
|
||||||
|
//!
|
||||||
|
//! To make use of [`ARef<MyType>`], `MyType` needs to implement [`AlwaysRefCounted`]. It is a trait
|
||||||
|
//! for accessing the internal reference count of an object of the `MyType` type.
|
||||||
|
//!
|
||||||
|
//! [`Arc`]: crate::sync::Arc
|
||||||
|
//! [`Arc<T>`]: crate::sync::Arc
|
||||||
|
|
||||||
use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref, ptr::NonNull};
|
use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref, ptr::NonNull};
|
||||||
|
|
||||||
|
|
@ -97,7 +112,7 @@ impl<T: AlwaysRefCounted> ARef<T> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use core::ptr::NonNull;
|
/// use core::ptr::NonNull;
|
||||||
/// use kernel::types::{ARef, AlwaysRefCounted};
|
/// use kernel::sync::aref::{ARef, AlwaysRefCounted};
|
||||||
///
|
///
|
||||||
/// struct Empty {}
|
/// struct Empty {}
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@ use crate::{
|
||||||
ffi::{c_int, c_long, c_uint},
|
ffi::{c_int, c_long, c_uint},
|
||||||
mm::MmWithUser,
|
mm::MmWithUser,
|
||||||
pid_namespace::PidNamespace,
|
pid_namespace::PidNamespace,
|
||||||
types::{ARef, NotThreadSafe, Opaque},
|
sync::aref::ARef,
|
||||||
|
types::{NotThreadSafe, Opaque},
|
||||||
};
|
};
|
||||||
use core::{
|
use core::{
|
||||||
cmp::{Eq, PartialEq},
|
cmp::{Eq, PartialEq},
|
||||||
|
|
@ -76,7 +77,7 @@ macro_rules! current {
|
||||||
/// incremented when creating `State` and decremented when it is dropped:
|
/// incremented when creating `State` and decremented when it is dropped:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use kernel::{task::Task, types::ARef};
|
/// use kernel::{task::Task, sync::aref::ARef};
|
||||||
///
|
///
|
||||||
/// struct State {
|
/// struct State {
|
||||||
/// creator: ARef<Task>,
|
/// creator: ARef<Task>,
|
||||||
|
|
@ -347,7 +348,7 @@ impl CurrentTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: The type invariants guarantee that `Task` is always refcounted.
|
// SAFETY: The type invariants guarantee that `Task` is always refcounted.
|
||||||
unsafe impl crate::types::AlwaysRefCounted for Task {
|
unsafe impl crate::sync::aref::AlwaysRefCounted for Task {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inc_ref(&self) {
|
fn inc_ref(&self) {
|
||||||
// SAFETY: The existence of a shared reference means that the refcount is nonzero.
|
// SAFETY: The existence of a shared reference means that the refcount is nonzero.
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
//! C header: [`include/linux/ktime.h`](srctree/include/linux/ktime.h).
|
//! C header: [`include/linux/ktime.h`](srctree/include/linux/ktime.h).
|
||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
use core::ops;
|
||||||
|
|
||||||
pub mod delay;
|
pub mod delay;
|
||||||
pub mod hrtimer;
|
pub mod hrtimer;
|
||||||
|
|
@ -200,9 +201,31 @@ impl<C: ClockSource> Instant<C> {
|
||||||
pub(crate) fn as_nanos(&self) -> i64 {
|
pub(crate) fn as_nanos(&self) -> i64 {
|
||||||
self.inner
|
self.inner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create an [`Instant`] from a `ktime_t` without checking if it is non-negative.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// On debug builds, this function will panic if `ktime` is not in the range from 0 to
|
||||||
|
/// `KTIME_MAX`.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The caller promises that `ktime` is in the range from 0 to `KTIME_MAX`.
|
||||||
|
#[inline]
|
||||||
|
pub(crate) unsafe fn from_ktime(ktime: bindings::ktime_t) -> Self {
|
||||||
|
debug_assert!(ktime >= 0);
|
||||||
|
|
||||||
|
// INVARIANT: Our safety contract ensures that `ktime` is in the range from 0 to
|
||||||
|
// `KTIME_MAX`.
|
||||||
|
Self {
|
||||||
|
inner: ktime,
|
||||||
|
_c: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: ClockSource> core::ops::Sub for Instant<C> {
|
impl<C: ClockSource> ops::Sub for Instant<C> {
|
||||||
type Output = Delta;
|
type Output = Delta;
|
||||||
|
|
||||||
// By the type invariant, it never overflows.
|
// By the type invariant, it never overflows.
|
||||||
|
|
@ -214,6 +237,46 @@ impl<C: ClockSource> core::ops::Sub for Instant<C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: ClockSource> ops::Add<Delta> for Instant<T> {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn add(self, rhs: Delta) -> Self::Output {
|
||||||
|
// INVARIANT: With arithmetic over/underflow checks enabled, this will panic if we overflow
|
||||||
|
// (e.g. go above `KTIME_MAX`)
|
||||||
|
let res = self.inner + rhs.nanos;
|
||||||
|
|
||||||
|
// INVARIANT: With overflow checks enabled, we verify here that the value is >= 0
|
||||||
|
#[cfg(CONFIG_RUST_OVERFLOW_CHECKS)]
|
||||||
|
assert!(res >= 0);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
inner: res,
|
||||||
|
_c: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ClockSource> ops::Sub<Delta> for Instant<T> {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn sub(self, rhs: Delta) -> Self::Output {
|
||||||
|
// INVARIANT: With arithmetic over/underflow checks enabled, this will panic if we overflow
|
||||||
|
// (e.g. go above `KTIME_MAX`)
|
||||||
|
let res = self.inner - rhs.nanos;
|
||||||
|
|
||||||
|
// INVARIANT: With overflow checks enabled, we verify here that the value is >= 0
|
||||||
|
#[cfg(CONFIG_RUST_OVERFLOW_CHECKS)]
|
||||||
|
assert!(res >= 0);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
inner: res,
|
||||||
|
_c: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A span of time.
|
/// A span of time.
|
||||||
///
|
///
|
||||||
/// This struct represents a span of time, with its value stored as nanoseconds.
|
/// This struct represents a span of time, with its value stored as nanoseconds.
|
||||||
|
|
@ -224,6 +287,78 @@ pub struct Delta {
|
||||||
nanos: i64,
|
nanos: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ops::Add for Delta {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn add(self, rhs: Self) -> Self {
|
||||||
|
Self {
|
||||||
|
nanos: self.nanos + rhs.nanos,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::AddAssign for Delta {
|
||||||
|
#[inline]
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
self.nanos += rhs.nanos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Sub for Delta {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
nanos: self.nanos - rhs.nanos,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::SubAssign for Delta {
|
||||||
|
#[inline]
|
||||||
|
fn sub_assign(&mut self, rhs: Self) {
|
||||||
|
self.nanos -= rhs.nanos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Mul<i64> for Delta {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, rhs: i64) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
nanos: self.nanos * rhs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::MulAssign<i64> for Delta {
|
||||||
|
#[inline]
|
||||||
|
fn mul_assign(&mut self, rhs: i64) {
|
||||||
|
self.nanos *= rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Div for Delta {
|
||||||
|
type Output = i64;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn div(self, rhs: Self) -> Self::Output {
|
||||||
|
#[cfg(CONFIG_64BIT)]
|
||||||
|
{
|
||||||
|
self.nanos / rhs.nanos
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(CONFIG_64BIT))]
|
||||||
|
{
|
||||||
|
// SAFETY: This function is always safe to call regardless of the input values
|
||||||
|
unsafe { bindings::div64_s64(self.nanos, rhs.nanos) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Delta {
|
impl Delta {
|
||||||
/// A span of time equal to zero.
|
/// A span of time equal to zero.
|
||||||
pub const ZERO: Self = Self { nanos: 0 };
|
pub const ZERO: Self = Self { nanos: 0 };
|
||||||
|
|
@ -312,4 +447,30 @@ impl Delta {
|
||||||
bindings::ktime_to_ms(self.as_nanos())
|
bindings::ktime_to_ms(self.as_nanos())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return `self % dividend` where `dividend` is in nanoseconds.
|
||||||
|
///
|
||||||
|
/// The kernel doesn't have any emulation for `s64 % s64` on 32 bit platforms, so this is
|
||||||
|
/// limited to 32 bit dividends.
|
||||||
|
#[inline]
|
||||||
|
pub fn rem_nanos(self, dividend: i32) -> Self {
|
||||||
|
#[cfg(CONFIG_64BIT)]
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
nanos: self.as_nanos() % i64::from(dividend),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(CONFIG_64BIT))]
|
||||||
|
{
|
||||||
|
let mut rem = 0;
|
||||||
|
|
||||||
|
// SAFETY: `rem` is in the stack, so we can always provide a valid pointer to it.
|
||||||
|
unsafe { bindings::div_s64_rem(self.as_nanos(), dividend, &mut rem) };
|
||||||
|
|
||||||
|
Self {
|
||||||
|
nanos: i64::from(rem),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,9 +69,14 @@
|
||||||
|
|
||||||
use super::{ClockSource, Delta, Instant};
|
use super::{ClockSource, Delta, Instant};
|
||||||
use crate::{prelude::*, types::Opaque};
|
use crate::{prelude::*, types::Opaque};
|
||||||
use core::marker::PhantomData;
|
use core::{marker::PhantomData, ptr::NonNull};
|
||||||
use pin_init::PinInit;
|
use pin_init::PinInit;
|
||||||
|
|
||||||
|
/// A type-alias to refer to the [`Instant<C>`] for a given `T` from [`HrTimer<T>`].
|
||||||
|
///
|
||||||
|
/// Where `C` is the [`ClockSource`] of the [`HrTimer`].
|
||||||
|
pub type HrTimerInstant<T> = Instant<<<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Clock>;
|
||||||
|
|
||||||
/// A timer backed by a C `struct hrtimer`.
|
/// A timer backed by a C `struct hrtimer`.
|
||||||
///
|
///
|
||||||
/// # Invariants
|
/// # Invariants
|
||||||
|
|
@ -163,6 +168,84 @@ impl<T> HrTimer<T> {
|
||||||
// handled on the C side.
|
// handled on the C side.
|
||||||
unsafe { bindings::hrtimer_cancel(c_timer_ptr) != 0 }
|
unsafe { bindings::hrtimer_cancel(c_timer_ptr) != 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Forward the timer expiry for a given timer pointer.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// - `self_ptr` must point to a valid `Self`.
|
||||||
|
/// - The caller must either have exclusive access to the data pointed at by `self_ptr`, or be
|
||||||
|
/// within the context of the timer callback.
|
||||||
|
#[inline]
|
||||||
|
unsafe fn raw_forward(self_ptr: *mut Self, now: HrTimerInstant<T>, interval: Delta) -> u64
|
||||||
|
where
|
||||||
|
T: HasHrTimer<T>,
|
||||||
|
{
|
||||||
|
// SAFETY:
|
||||||
|
// * The C API requirements for this function are fulfilled by our safety contract.
|
||||||
|
// * `self_ptr` is guaranteed to point to a valid `Self` via our safety contract
|
||||||
|
unsafe {
|
||||||
|
bindings::hrtimer_forward(Self::raw_get(self_ptr), now.as_nanos(), interval.as_nanos())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Conditionally forward the timer.
|
||||||
|
///
|
||||||
|
/// If the timer expires after `now`, this function does nothing and returns 0. If the timer
|
||||||
|
/// expired at or before `now`, this function forwards the timer by `interval` until the timer
|
||||||
|
/// expires after `now` and then returns the number of times the timer was forwarded by
|
||||||
|
/// `interval`.
|
||||||
|
///
|
||||||
|
/// This function is mainly useful for timer types which can provide exclusive access to the
|
||||||
|
/// timer when the timer is not running. For forwarding the timer from within the timer callback
|
||||||
|
/// context, see [`HrTimerCallbackContext::forward()`].
|
||||||
|
///
|
||||||
|
/// Returns the number of overruns that occurred as a result of the timer expiry change.
|
||||||
|
pub fn forward(self: Pin<&mut Self>, now: HrTimerInstant<T>, interval: Delta) -> u64
|
||||||
|
where
|
||||||
|
T: HasHrTimer<T>,
|
||||||
|
{
|
||||||
|
// SAFETY: `raw_forward` does not move `Self`
|
||||||
|
let this = unsafe { self.get_unchecked_mut() };
|
||||||
|
|
||||||
|
// SAFETY: By existence of `Pin<&mut Self>`, the pointer passed to `raw_forward` points to a
|
||||||
|
// valid `Self` that we have exclusive access to.
|
||||||
|
unsafe { Self::raw_forward(this, now, interval) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Conditionally forward the timer.
|
||||||
|
///
|
||||||
|
/// This is a variant of [`forward()`](Self::forward) that uses an interval after the current
|
||||||
|
/// time of the base clock for the [`HrTimer`].
|
||||||
|
pub fn forward_now(self: Pin<&mut Self>, interval: Delta) -> u64
|
||||||
|
where
|
||||||
|
T: HasHrTimer<T>,
|
||||||
|
{
|
||||||
|
self.forward(HrTimerInstant::<T>::now(), interval)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the time expiry for this [`HrTimer`].
|
||||||
|
///
|
||||||
|
/// This value should only be used as a snapshot, as the actual expiry time could change after
|
||||||
|
/// this function is called.
|
||||||
|
pub fn expires(&self) -> HrTimerInstant<T>
|
||||||
|
where
|
||||||
|
T: HasHrTimer<T>,
|
||||||
|
{
|
||||||
|
// SAFETY: `self` is an immutable reference and thus always points to a valid `HrTimer`.
|
||||||
|
let c_timer_ptr = unsafe { HrTimer::raw_get(self) };
|
||||||
|
|
||||||
|
// SAFETY:
|
||||||
|
// - Timers cannot have negative ktime_t values as their expiration time.
|
||||||
|
// - There's no actual locking here, a racy read is fine and expected
|
||||||
|
unsafe {
|
||||||
|
Instant::from_ktime(
|
||||||
|
// This `read_volatile` is intended to correspond to a READ_ONCE call.
|
||||||
|
// FIXME(read_once): Replace with `read_once` when available on the Rust side.
|
||||||
|
core::ptr::read_volatile(&raw const ((*c_timer_ptr).node.expires)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implemented by pointer types that point to structs that contain a [`HrTimer`].
|
/// Implemented by pointer types that point to structs that contain a [`HrTimer`].
|
||||||
|
|
@ -300,9 +383,13 @@ pub trait HrTimerCallback {
|
||||||
type Pointer<'a>: RawHrTimerCallback;
|
type Pointer<'a>: RawHrTimerCallback;
|
||||||
|
|
||||||
/// Called by the timer logic when the timer fires.
|
/// Called by the timer logic when the timer fires.
|
||||||
fn run(this: <Self::Pointer<'_> as RawHrTimerCallback>::CallbackTarget<'_>) -> HrTimerRestart
|
fn run(
|
||||||
|
this: <Self::Pointer<'_> as RawHrTimerCallback>::CallbackTarget<'_>,
|
||||||
|
ctx: HrTimerCallbackContext<'_, Self>,
|
||||||
|
) -> HrTimerRestart
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized,
|
||||||
|
Self: HasHrTimer<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A handle representing a potentially running timer.
|
/// A handle representing a potentially running timer.
|
||||||
|
|
@ -324,6 +411,8 @@ pub unsafe trait HrTimerHandle {
|
||||||
/// Note that the timer might be started by a concurrent start operation. If
|
/// Note that the timer might be started by a concurrent start operation. If
|
||||||
/// so, the timer might not be in the **stopped** state when this function
|
/// so, the timer might not be in the **stopped** state when this function
|
||||||
/// returns.
|
/// returns.
|
||||||
|
///
|
||||||
|
/// Returns `true` if the timer was running.
|
||||||
fn cancel(&mut self) -> bool;
|
fn cancel(&mut self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -585,6 +674,63 @@ impl<C: ClockSource> HrTimerMode for RelativePinnedHardMode<C> {
|
||||||
type Expires = Delta;
|
type Expires = Delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Privileged smart-pointer for a [`HrTimer`] callback context.
|
||||||
|
///
|
||||||
|
/// Many [`HrTimer`] methods can only be called in two situations:
|
||||||
|
///
|
||||||
|
/// * When the caller has exclusive access to the `HrTimer` and the `HrTimer` is guaranteed not to
|
||||||
|
/// be running.
|
||||||
|
/// * From within the context of an `HrTimer`'s callback method.
|
||||||
|
///
|
||||||
|
/// This type provides access to said methods from within a timer callback context.
|
||||||
|
///
|
||||||
|
/// # Invariants
|
||||||
|
///
|
||||||
|
/// * The existence of this type means the caller is currently within the callback for an
|
||||||
|
/// [`HrTimer`].
|
||||||
|
/// * `self.0` always points to a live instance of [`HrTimer<T>`].
|
||||||
|
pub struct HrTimerCallbackContext<'a, T: HasHrTimer<T>>(NonNull<HrTimer<T>>, PhantomData<&'a ()>);
|
||||||
|
|
||||||
|
impl<'a, T: HasHrTimer<T>> HrTimerCallbackContext<'a, T> {
|
||||||
|
/// Create a new [`HrTimerCallbackContext`].
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This function relies on the caller being within the context of a timer callback, so it must
|
||||||
|
/// not be used anywhere except for within implementations of [`RawHrTimerCallback::run`]. The
|
||||||
|
/// caller promises that `timer` points to a valid initialized instance of
|
||||||
|
/// [`bindings::hrtimer`].
|
||||||
|
///
|
||||||
|
/// The returned `Self` must not outlive the function context of [`RawHrTimerCallback::run`]
|
||||||
|
/// where this function is called.
|
||||||
|
pub(crate) unsafe fn from_raw(timer: *mut HrTimer<T>) -> Self {
|
||||||
|
// SAFETY: The caller guarantees `timer` is a valid pointer to an initialized
|
||||||
|
// `bindings::hrtimer`
|
||||||
|
// INVARIANT: Our safety contract ensures that we're within the context of a timer callback
|
||||||
|
// and that `timer` points to a live instance of `HrTimer<T>`.
|
||||||
|
Self(unsafe { NonNull::new_unchecked(timer) }, PhantomData)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Conditionally forward the timer.
|
||||||
|
///
|
||||||
|
/// This function is identical to [`HrTimer::forward()`] except that it may only be used from
|
||||||
|
/// within the context of a [`HrTimer`] callback.
|
||||||
|
pub fn forward(&mut self, now: HrTimerInstant<T>, interval: Delta) -> u64 {
|
||||||
|
// SAFETY:
|
||||||
|
// - We are guaranteed to be within the context of a timer callback by our type invariants
|
||||||
|
// - By our type invariants, `self.0` always points to a valid `HrTimer<T>`
|
||||||
|
unsafe { HrTimer::<T>::raw_forward(self.0.as_ptr(), now, interval) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Conditionally forward the timer.
|
||||||
|
///
|
||||||
|
/// This is a variant of [`HrTimerCallbackContext::forward()`] that uses an interval after the
|
||||||
|
/// current time of the base clock for the [`HrTimer`].
|
||||||
|
pub fn forward_now(&mut self, duration: Delta) -> u64 {
|
||||||
|
self.forward(HrTimerInstant::<T>::now(), duration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Use to implement the [`HasHrTimer<T>`] trait.
|
/// Use to implement the [`HasHrTimer<T>`] trait.
|
||||||
///
|
///
|
||||||
/// See [`module`] documentation for an example.
|
/// See [`module`] documentation for an example.
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
use super::HasHrTimer;
|
use super::HasHrTimer;
|
||||||
use super::HrTimer;
|
use super::HrTimer;
|
||||||
use super::HrTimerCallback;
|
use super::HrTimerCallback;
|
||||||
|
use super::HrTimerCallbackContext;
|
||||||
use super::HrTimerHandle;
|
use super::HrTimerHandle;
|
||||||
use super::HrTimerMode;
|
use super::HrTimerMode;
|
||||||
use super::HrTimerPointer;
|
use super::HrTimerPointer;
|
||||||
|
|
@ -99,6 +100,12 @@ where
|
||||||
// allocation from other `Arc` clones.
|
// allocation from other `Arc` clones.
|
||||||
let receiver = unsafe { ArcBorrow::from_raw(data_ptr) };
|
let receiver = unsafe { ArcBorrow::from_raw(data_ptr) };
|
||||||
|
|
||||||
T::run(receiver).into_c()
|
// SAFETY:
|
||||||
|
// - By C API contract `timer_ptr` is the pointer that we passed when queuing the timer, so
|
||||||
|
// it is a valid pointer to a `HrTimer<T>` embedded in a `T`.
|
||||||
|
// - We are within `RawHrTimerCallback::run`
|
||||||
|
let context = unsafe { HrTimerCallbackContext::from_raw(timer_ptr) };
|
||||||
|
|
||||||
|
T::run(receiver, context).into_c()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
use super::HasHrTimer;
|
use super::HasHrTimer;
|
||||||
use super::HrTimer;
|
use super::HrTimer;
|
||||||
use super::HrTimerCallback;
|
use super::HrTimerCallback;
|
||||||
|
use super::HrTimerCallbackContext;
|
||||||
use super::HrTimerHandle;
|
use super::HrTimerHandle;
|
||||||
use super::HrTimerMode;
|
use super::HrTimerMode;
|
||||||
use super::RawHrTimerCallback;
|
use super::RawHrTimerCallback;
|
||||||
|
|
@ -103,6 +104,12 @@ where
|
||||||
// here.
|
// here.
|
||||||
let receiver_pin = unsafe { Pin::new_unchecked(receiver_ref) };
|
let receiver_pin = unsafe { Pin::new_unchecked(receiver_ref) };
|
||||||
|
|
||||||
T::run(receiver_pin).into_c()
|
// SAFETY:
|
||||||
|
// - By C API contract `timer_ptr` is the pointer that we passed when queuing the timer, so
|
||||||
|
// it is a valid pointer to a `HrTimer<T>` embedded in a `T`.
|
||||||
|
// - We are within `RawHrTimerCallback::run`
|
||||||
|
let context = unsafe { HrTimerCallbackContext::from_raw(timer_ptr) };
|
||||||
|
|
||||||
|
T::run(receiver_pin, context).into_c()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
HasHrTimer, HrTimer, HrTimerCallback, HrTimerHandle, HrTimerMode, RawHrTimerCallback,
|
HasHrTimer, HrTimer, HrTimerCallback, HrTimerCallbackContext, HrTimerHandle, HrTimerMode,
|
||||||
UnsafeHrTimerPointer,
|
RawHrTimerCallback, UnsafeHrTimerPointer,
|
||||||
};
|
};
|
||||||
use core::{marker::PhantomData, pin::Pin, ptr::NonNull};
|
use core::{marker::PhantomData, pin::Pin, ptr::NonNull};
|
||||||
|
|
||||||
|
|
@ -107,6 +107,12 @@ where
|
||||||
// here.
|
// here.
|
||||||
let receiver_pin = unsafe { Pin::new_unchecked(receiver_ref) };
|
let receiver_pin = unsafe { Pin::new_unchecked(receiver_ref) };
|
||||||
|
|
||||||
T::run(receiver_pin).into_c()
|
// SAFETY:
|
||||||
|
// - By C API contract `timer_ptr` is the pointer that we passed when queuing the timer, so
|
||||||
|
// it is a valid pointer to a `HrTimer<T>` embedded in a `T`.
|
||||||
|
// - We are within `RawHrTimerCallback::run`
|
||||||
|
let context = unsafe { HrTimerCallbackContext::from_raw(timer_ptr) };
|
||||||
|
|
||||||
|
T::run(receiver_pin, context).into_c()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
use super::HasHrTimer;
|
use super::HasHrTimer;
|
||||||
use super::HrTimer;
|
use super::HrTimer;
|
||||||
use super::HrTimerCallback;
|
use super::HrTimerCallback;
|
||||||
|
use super::HrTimerCallbackContext;
|
||||||
use super::HrTimerHandle;
|
use super::HrTimerHandle;
|
||||||
use super::HrTimerMode;
|
use super::HrTimerMode;
|
||||||
use super::HrTimerPointer;
|
use super::HrTimerPointer;
|
||||||
|
|
@ -119,6 +120,12 @@ where
|
||||||
// `data_ptr` exist.
|
// `data_ptr` exist.
|
||||||
let data_mut_ref = unsafe { Pin::new_unchecked(&mut *data_ptr) };
|
let data_mut_ref = unsafe { Pin::new_unchecked(&mut *data_ptr) };
|
||||||
|
|
||||||
T::run(data_mut_ref).into_c()
|
// SAFETY:
|
||||||
|
// - By C API contract `timer_ptr` is the pointer that we passed when queuing the timer, so
|
||||||
|
// it is a valid pointer to a `HrTimer<T>` embedded in a `T`.
|
||||||
|
// - We are within `RawHrTimerCallback::run`
|
||||||
|
let context = unsafe { HrTimerCallbackContext::from_raw(timer_ptr) };
|
||||||
|
|
||||||
|
T::run(data_mut_ref, context).into_c()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
use proc_macro::{TokenStream, TokenTree};
|
use proc_macro::{TokenStream, TokenTree};
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub(crate) trait ToTokens {
|
pub(crate) trait ToTokens {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream);
|
fn to_tokens(&self, tokens: &mut TokenStream);
|
||||||
}
|
}
|
||||||
|
|
@ -47,121 +46,116 @@ impl ToTokens for TokenStream {
|
||||||
/// `quote` crate but provides only just enough functionality needed by the current `macros` crate.
|
/// `quote` crate but provides only just enough functionality needed by the current `macros` crate.
|
||||||
macro_rules! quote_spanned {
|
macro_rules! quote_spanned {
|
||||||
($span:expr => $($tt:tt)*) => {{
|
($span:expr => $($tt:tt)*) => {{
|
||||||
let mut tokens: ::std::vec::Vec<::proc_macro::TokenTree>;
|
let mut tokens = ::proc_macro::TokenStream::new();
|
||||||
#[allow(clippy::vec_init_then_push)]
|
|
||||||
{
|
{
|
||||||
tokens = ::std::vec::Vec::new();
|
|
||||||
let span = $span;
|
let span = $span;
|
||||||
quote_spanned!(@proc tokens span $($tt)*);
|
quote_spanned!(@proc tokens span $($tt)*);
|
||||||
}
|
}
|
||||||
::proc_macro::TokenStream::from_iter(tokens)
|
tokens
|
||||||
}};
|
}};
|
||||||
(@proc $v:ident $span:ident) => {};
|
(@proc $v:ident $span:ident) => {};
|
||||||
(@proc $v:ident $span:ident #$id:ident $($tt:tt)*) => {
|
(@proc $v:ident $span:ident #$id:ident $($tt:tt)*) => {
|
||||||
let mut ts = ::proc_macro::TokenStream::new();
|
$crate::quote::ToTokens::to_tokens(&$id, &mut $v);
|
||||||
$crate::quote::ToTokens::to_tokens(&$id, &mut ts);
|
|
||||||
$v.extend(ts);
|
|
||||||
quote_spanned!(@proc $v $span $($tt)*);
|
quote_spanned!(@proc $v $span $($tt)*);
|
||||||
};
|
};
|
||||||
(@proc $v:ident $span:ident #(#$id:ident)* $($tt:tt)*) => {
|
(@proc $v:ident $span:ident #(#$id:ident)* $($tt:tt)*) => {
|
||||||
for token in $id {
|
for token in $id {
|
||||||
let mut ts = ::proc_macro::TokenStream::new();
|
$crate::quote::ToTokens::to_tokens(&token, &mut $v);
|
||||||
$crate::quote::ToTokens::to_tokens(&token, &mut ts);
|
|
||||||
$v.extend(ts);
|
|
||||||
}
|
}
|
||||||
quote_spanned!(@proc $v $span $($tt)*);
|
quote_spanned!(@proc $v $span $($tt)*);
|
||||||
};
|
};
|
||||||
(@proc $v:ident $span:ident ( $($inner:tt)* ) $($tt:tt)*) => {
|
(@proc $v:ident $span:ident ( $($inner:tt)* ) $($tt:tt)*) => {
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
let mut tokens = ::std::vec::Vec::<::proc_macro::TokenTree>::new();
|
let mut tokens = ::proc_macro::TokenStream::new();
|
||||||
quote_spanned!(@proc tokens $span $($inner)*);
|
quote_spanned!(@proc tokens $span $($inner)*);
|
||||||
$v.push(::proc_macro::TokenTree::Group(::proc_macro::Group::new(
|
$v.extend([::proc_macro::TokenTree::Group(::proc_macro::Group::new(
|
||||||
::proc_macro::Delimiter::Parenthesis,
|
::proc_macro::Delimiter::Parenthesis,
|
||||||
::proc_macro::TokenStream::from_iter(tokens)
|
tokens,
|
||||||
)));
|
))]);
|
||||||
quote_spanned!(@proc $v $span $($tt)*);
|
quote_spanned!(@proc $v $span $($tt)*);
|
||||||
};
|
};
|
||||||
(@proc $v:ident $span:ident [ $($inner:tt)* ] $($tt:tt)*) => {
|
(@proc $v:ident $span:ident [ $($inner:tt)* ] $($tt:tt)*) => {
|
||||||
let mut tokens = ::std::vec::Vec::new();
|
let mut tokens = ::proc_macro::TokenStream::new();
|
||||||
quote_spanned!(@proc tokens $span $($inner)*);
|
quote_spanned!(@proc tokens $span $($inner)*);
|
||||||
$v.push(::proc_macro::TokenTree::Group(::proc_macro::Group::new(
|
$v.extend([::proc_macro::TokenTree::Group(::proc_macro::Group::new(
|
||||||
::proc_macro::Delimiter::Bracket,
|
::proc_macro::Delimiter::Bracket,
|
||||||
::proc_macro::TokenStream::from_iter(tokens)
|
tokens,
|
||||||
)));
|
))]);
|
||||||
quote_spanned!(@proc $v $span $($tt)*);
|
quote_spanned!(@proc $v $span $($tt)*);
|
||||||
};
|
};
|
||||||
(@proc $v:ident $span:ident { $($inner:tt)* } $($tt:tt)*) => {
|
(@proc $v:ident $span:ident { $($inner:tt)* } $($tt:tt)*) => {
|
||||||
let mut tokens = ::std::vec::Vec::new();
|
let mut tokens = ::proc_macro::TokenStream::new();
|
||||||
quote_spanned!(@proc tokens $span $($inner)*);
|
quote_spanned!(@proc tokens $span $($inner)*);
|
||||||
$v.push(::proc_macro::TokenTree::Group(::proc_macro::Group::new(
|
$v.extend([::proc_macro::TokenTree::Group(::proc_macro::Group::new(
|
||||||
::proc_macro::Delimiter::Brace,
|
::proc_macro::Delimiter::Brace,
|
||||||
::proc_macro::TokenStream::from_iter(tokens)
|
tokens,
|
||||||
)));
|
))]);
|
||||||
quote_spanned!(@proc $v $span $($tt)*);
|
quote_spanned!(@proc $v $span $($tt)*);
|
||||||
};
|
};
|
||||||
(@proc $v:ident $span:ident :: $($tt:tt)*) => {
|
(@proc $v:ident $span:ident :: $($tt:tt)*) => {
|
||||||
$v.push(::proc_macro::TokenTree::Punct(
|
$v.extend([::proc_macro::Spacing::Joint, ::proc_macro::Spacing::Alone].map(|spacing| {
|
||||||
::proc_macro::Punct::new(':', ::proc_macro::Spacing::Joint)
|
::proc_macro::TokenTree::Punct(::proc_macro::Punct::new(':', spacing))
|
||||||
));
|
}));
|
||||||
$v.push(::proc_macro::TokenTree::Punct(
|
|
||||||
::proc_macro::Punct::new(':', ::proc_macro::Spacing::Alone)
|
|
||||||
));
|
|
||||||
quote_spanned!(@proc $v $span $($tt)*);
|
quote_spanned!(@proc $v $span $($tt)*);
|
||||||
};
|
};
|
||||||
(@proc $v:ident $span:ident : $($tt:tt)*) => {
|
(@proc $v:ident $span:ident : $($tt:tt)*) => {
|
||||||
$v.push(::proc_macro::TokenTree::Punct(
|
$v.extend([::proc_macro::TokenTree::Punct(
|
||||||
::proc_macro::Punct::new(':', ::proc_macro::Spacing::Alone)
|
::proc_macro::Punct::new(':', ::proc_macro::Spacing::Alone),
|
||||||
));
|
)]);
|
||||||
quote_spanned!(@proc $v $span $($tt)*);
|
quote_spanned!(@proc $v $span $($tt)*);
|
||||||
};
|
};
|
||||||
(@proc $v:ident $span:ident , $($tt:tt)*) => {
|
(@proc $v:ident $span:ident , $($tt:tt)*) => {
|
||||||
$v.push(::proc_macro::TokenTree::Punct(
|
$v.extend([::proc_macro::TokenTree::Punct(
|
||||||
::proc_macro::Punct::new(',', ::proc_macro::Spacing::Alone)
|
::proc_macro::Punct::new(',', ::proc_macro::Spacing::Alone),
|
||||||
));
|
)]);
|
||||||
quote_spanned!(@proc $v $span $($tt)*);
|
quote_spanned!(@proc $v $span $($tt)*);
|
||||||
};
|
};
|
||||||
(@proc $v:ident $span:ident @ $($tt:tt)*) => {
|
(@proc $v:ident $span:ident @ $($tt:tt)*) => {
|
||||||
$v.push(::proc_macro::TokenTree::Punct(
|
$v.extend([::proc_macro::TokenTree::Punct(
|
||||||
::proc_macro::Punct::new('@', ::proc_macro::Spacing::Alone)
|
::proc_macro::Punct::new('@', ::proc_macro::Spacing::Alone),
|
||||||
));
|
)]);
|
||||||
quote_spanned!(@proc $v $span $($tt)*);
|
quote_spanned!(@proc $v $span $($tt)*);
|
||||||
};
|
};
|
||||||
(@proc $v:ident $span:ident ! $($tt:tt)*) => {
|
(@proc $v:ident $span:ident ! $($tt:tt)*) => {
|
||||||
$v.push(::proc_macro::TokenTree::Punct(
|
$v.extend([::proc_macro::TokenTree::Punct(
|
||||||
::proc_macro::Punct::new('!', ::proc_macro::Spacing::Alone)
|
::proc_macro::Punct::new('!', ::proc_macro::Spacing::Alone),
|
||||||
));
|
)]);
|
||||||
quote_spanned!(@proc $v $span $($tt)*);
|
quote_spanned!(@proc $v $span $($tt)*);
|
||||||
};
|
};
|
||||||
(@proc $v:ident $span:ident ; $($tt:tt)*) => {
|
(@proc $v:ident $span:ident ; $($tt:tt)*) => {
|
||||||
$v.push(::proc_macro::TokenTree::Punct(
|
$v.extend([::proc_macro::TokenTree::Punct(
|
||||||
::proc_macro::Punct::new(';', ::proc_macro::Spacing::Alone)
|
::proc_macro::Punct::new(';', ::proc_macro::Spacing::Alone),
|
||||||
));
|
)]);
|
||||||
quote_spanned!(@proc $v $span $($tt)*);
|
quote_spanned!(@proc $v $span $($tt)*);
|
||||||
};
|
};
|
||||||
(@proc $v:ident $span:ident + $($tt:tt)*) => {
|
(@proc $v:ident $span:ident + $($tt:tt)*) => {
|
||||||
$v.push(::proc_macro::TokenTree::Punct(
|
$v.extend([::proc_macro::TokenTree::Punct(
|
||||||
::proc_macro::Punct::new('+', ::proc_macro::Spacing::Alone)
|
::proc_macro::Punct::new('+', ::proc_macro::Spacing::Alone),
|
||||||
));
|
)]);
|
||||||
quote_spanned!(@proc $v $span $($tt)*);
|
quote_spanned!(@proc $v $span $($tt)*);
|
||||||
};
|
};
|
||||||
(@proc $v:ident $span:ident = $($tt:tt)*) => {
|
(@proc $v:ident $span:ident = $($tt:tt)*) => {
|
||||||
$v.push(::proc_macro::TokenTree::Punct(
|
$v.extend([::proc_macro::TokenTree::Punct(
|
||||||
::proc_macro::Punct::new('=', ::proc_macro::Spacing::Alone)
|
::proc_macro::Punct::new('=', ::proc_macro::Spacing::Alone),
|
||||||
));
|
)]);
|
||||||
quote_spanned!(@proc $v $span $($tt)*);
|
quote_spanned!(@proc $v $span $($tt)*);
|
||||||
};
|
};
|
||||||
(@proc $v:ident $span:ident # $($tt:tt)*) => {
|
(@proc $v:ident $span:ident # $($tt:tt)*) => {
|
||||||
$v.push(::proc_macro::TokenTree::Punct(
|
$v.extend([::proc_macro::TokenTree::Punct(
|
||||||
::proc_macro::Punct::new('#', ::proc_macro::Spacing::Alone)
|
::proc_macro::Punct::new('#', ::proc_macro::Spacing::Alone),
|
||||||
));
|
)]);
|
||||||
quote_spanned!(@proc $v $span $($tt)*);
|
quote_spanned!(@proc $v $span $($tt)*);
|
||||||
};
|
};
|
||||||
(@proc $v:ident $span:ident _ $($tt:tt)*) => {
|
(@proc $v:ident $span:ident _ $($tt:tt)*) => {
|
||||||
$v.push(::proc_macro::TokenTree::Ident(::proc_macro::Ident::new("_", $span)));
|
$v.extend([::proc_macro::TokenTree::Ident(
|
||||||
|
::proc_macro::Ident::new("_", $span),
|
||||||
|
)]);
|
||||||
quote_spanned!(@proc $v $span $($tt)*);
|
quote_spanned!(@proc $v $span $($tt)*);
|
||||||
};
|
};
|
||||||
(@proc $v:ident $span:ident $id:ident $($tt:tt)*) => {
|
(@proc $v:ident $span:ident $id:ident $($tt:tt)*) => {
|
||||||
$v.push(::proc_macro::TokenTree::Ident(::proc_macro::Ident::new(stringify!($id), $span)));
|
$v.extend([::proc_macro::TokenTree::Ident(
|
||||||
|
::proc_macro::Ident::new(stringify!($id), $span),
|
||||||
|
)]);
|
||||||
quote_spanned!(@proc $v $span $($tt)*);
|
quote_spanned!(@proc $v $span $($tt)*);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,4 +34,6 @@ type __kernel_size_t = usize;
|
||||||
type __kernel_ssize_t = isize;
|
type __kernel_ssize_t = isize;
|
||||||
type __kernel_ptrdiff_t = isize;
|
type __kernel_ptrdiff_t = isize;
|
||||||
|
|
||||||
|
use pin_init::MaybeZeroable;
|
||||||
|
|
||||||
include!(concat!(env!("OBJTREE"), "/rust/uapi/uapi_generated.rs"));
|
include!(concat!(env!("OBJTREE"), "/rust/uapi/uapi_generated.rs"));
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ impl configfs::AttributeOperations<0> for Configuration {
|
||||||
|
|
||||||
fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
|
fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
|
||||||
pr_info!("Show message\n");
|
pr_info!("Show message\n");
|
||||||
let data = container.message;
|
let data = container.message.to_bytes();
|
||||||
page[0..data.len()].copy_from_slice(data);
|
page[0..data.len()].copy_from_slice(data);
|
||||||
Ok(data.len())
|
Ok(data.len())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ use kernel::{
|
||||||
dma::{CoherentAllocation, Device, DmaMask},
|
dma::{CoherentAllocation, Device, DmaMask},
|
||||||
pci,
|
pci,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
types::ARef,
|
sync::aref::ARef,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DmaSampleDriver {
|
struct DmaSampleDriver {
|
||||||
|
|
|
||||||
|
|
@ -139,8 +139,8 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit
|
||||||
"exclude_dirs": [],
|
"exclude_dirs": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
append_crate_with_generated("bindings", ["core", "ffi"])
|
append_crate_with_generated("bindings", ["core", "ffi", "pin_init"])
|
||||||
append_crate_with_generated("uapi", ["core", "ffi"])
|
append_crate_with_generated("uapi", ["core", "ffi", "pin_init"])
|
||||||
append_crate_with_generated("kernel", ["core", "macros", "build_error", "pin_init", "ffi", "bindings", "uapi"])
|
append_crate_with_generated("kernel", ["core", "macros", "build_error", "pin_init", "ffi", "bindings", "uapi"])
|
||||||
|
|
||||||
def is_root_crate(build_file, target):
|
def is_root_crate(build_file, target):
|
||||||
|
|
|
||||||
|
|
@ -202,7 +202,7 @@ pub extern "C" fn {kunit_name}(__kunit_test: *mut ::kernel::bindings::kunit) {{
|
||||||
// This follows the syntax for declaring test metadata in the proposed KTAP v2 spec, which may
|
// This follows the syntax for declaring test metadata in the proposed KTAP v2 spec, which may
|
||||||
// be used for the proposed KUnit test attributes API. Thus hopefully this will make migration
|
// be used for the proposed KUnit test attributes API. Thus hopefully this will make migration
|
||||||
// easier later on.
|
// easier later on.
|
||||||
::kernel::kunit::info(format_args!(" # {kunit_name}.location: {real_path}:{line}\n"));
|
::kernel::kunit::info(fmt!(" # {kunit_name}.location: {real_path}:{line}\n"));
|
||||||
|
|
||||||
/// The anchor where the test code body starts.
|
/// The anchor where the test code body starts.
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue