diff --git a/Cargo.lock b/Cargo.lock index e09078ed5..68e600316 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3831,7 +3831,8 @@ dependencies = [ name = "sel4-externally-shared" version = "0.1.0" dependencies = [ - "rand", + "volatile", + "zerocopy 0.7.6", ] [[package]] @@ -4998,6 +4999,11 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +[[package]] +name = "volatile" +version = "0.5.1" +source = "git+https://github.com/coliasgroup/volatile.git?tag=keep/8aee5539716d3d38247f46eddd42b382#8aee5539716d3d38247f46eddd42b3828406c008" + [[package]] name = "vte" version = "0.10.1" diff --git a/crates/examples/microkit/banscii/pds/artist/Cargo.toml b/crates/examples/microkit/banscii/pds/artist/Cargo.toml index 99d5cc9de..b25bdaf8f 100644 --- a/crates/examples/microkit/banscii/pds/artist/Cargo.toml +++ b/crates/examples/microkit/banscii/pds/artist/Cargo.toml @@ -8,12 +8,9 @@ license = "BSD-2-Clause" [dependencies] banscii-artist-interface-types = { path = "./interface-types" } rsa = { version = "0.8.1", default-features = false, features = ["pem", "sha2"] } +sel4-externally-shared = { path = "../../../../../sel4-externally-shared", features = ["unstable"] } sel4-microkit-message = { path = "../../../../../sel4-microkit/message" } -[dependencies.sel4-externally-shared] -path = "../../../../../sel4-externally-shared" -features = ["unstable", "alloc"] - [dependencies.sel4-microkit] path = "../../../../../sel4-microkit" default-features = false diff --git a/crates/examples/microkit/banscii/pds/artist/src/main.rs b/crates/examples/microkit/banscii/pds/artist/src/main.rs index 692ec2047..bef2166fb 100644 --- a/crates/examples/microkit/banscii/pds/artist/src/main.rs +++ b/crates/examples/microkit/banscii/pds/artist/src/main.rs @@ -6,9 +6,11 @@ extern crate alloc; +use alloc::vec; + use sel4_externally_shared::{ access::{ReadOnly, ReadWrite}, - ExternallySharedRef, + ExternallySharedRef, ExternallySharedRefExt, }; use sel4_microkit::{memory_region_symbol, protection_domain, Channel, Handler, MessageInfo}; use sel4_microkit_message::MessageInfoExt as _; @@ -27,13 +29,11 @@ const REGION_SIZE: usize = 0x4_000; #[protection_domain(heap_size = 0x10000)] fn init() -> HandlerImpl { let region_in = unsafe { - ExternallySharedRef::<'static, [u8]>::new_read_only( - memory_region_symbol!(region_in_start: *mut [u8], n = REGION_SIZE), - ) + ExternallySharedRef::new(memory_region_symbol!(region_in_start: *mut [u8], n = REGION_SIZE)) }; let region_out = unsafe { - ExternallySharedRef::<'static, [u8]>::new( + ExternallySharedRef::new( memory_region_symbol!(region_out_start: *mut [u8], n = REGION_SIZE), ) }; @@ -62,11 +62,14 @@ impl Handler for HandlerImpl { Ok(req) => { let draft_height = req.height; let draft_width = req.width; - let draft = self - .region_in - .as_ptr() - .index(req.draft_start..req.draft_start + req.draft_size) - .copy_to_vec(); + let draft = { + let mut buf = vec![0; req.draft_size]; + self.region_in + .as_ptr() + .index(req.draft_start..req.draft_start + req.draft_size) + .copy_into_slice(&mut buf); + buf + }; let masterpiece = Masterpiece::complete(draft_height, draft_width, &draft); diff --git a/crates/examples/microkit/banscii/pds/assistant/Cargo.toml b/crates/examples/microkit/banscii/pds/assistant/Cargo.toml index fcc696597..190f0f023 100644 --- a/crates/examples/microkit/banscii/pds/assistant/Cargo.toml +++ b/crates/examples/microkit/banscii/pds/assistant/Cargo.toml @@ -10,12 +10,9 @@ banscii-artist-interface-types = { path = "../artist/interface-types" } banscii-assistant-core = { path = "./core" } banscii-pl011-driver-interface-types = { path = "../pl011-driver/interface-types" } hex = { version = "0.4.3", default-features = false, features = ["alloc"] } +sel4-externally-shared = { path = "../../../../../sel4-externally-shared", features = ["unstable"] } sel4-microkit-message = { path = "../../../../../sel4-microkit/message" } -[dependencies.sel4-externally-shared] -path = "../../../../../sel4-externally-shared" -features = ["unstable", "alloc"] - [dependencies.sel4-microkit] path = "../../../../../sel4-microkit" default-features = false diff --git a/crates/examples/microkit/banscii/pds/assistant/src/main.rs b/crates/examples/microkit/banscii/pds/assistant/src/main.rs index 4bd334782..d1d28e5da 100644 --- a/crates/examples/microkit/banscii/pds/assistant/src/main.rs +++ b/crates/examples/microkit/banscii/pds/assistant/src/main.rs @@ -5,6 +5,7 @@ extern crate alloc; +use alloc::vec; use alloc::vec::Vec; use core::fmt; use core::fmt::Write; @@ -13,7 +14,7 @@ use core::str; use sel4_externally_shared::{ access::{ReadOnly, ReadWrite}, - ExternallySharedRef, + ExternallySharedRef, ExternallySharedRefExt, }; use sel4_microkit::{memory_region_symbol, protection_domain, Channel, Handler, MessageInfo}; use sel4_microkit_message::MessageInfoExt as _; @@ -32,13 +33,11 @@ const MAX_SUBJECT_LEN: usize = 16; #[protection_domain(heap_size = 0x10000)] fn init() -> impl Handler { let region_in = unsafe { - ExternallySharedRef::<'static, [u8]>::new_read_only( - memory_region_symbol!(region_in_start: *mut [u8], n = REGION_SIZE), - ) + ExternallySharedRef::new(memory_region_symbol!(region_in_start: *mut [u8], n = REGION_SIZE)) }; let region_out = unsafe { - ExternallySharedRef::<'static, [u8]>::new( + ExternallySharedRef::new( memory_region_symbol!(region_out_start: *mut [u8], n = REGION_SIZE), ) }; @@ -135,17 +134,23 @@ impl HandlerImpl { let height = resp.height; let width = resp.width; - let pixel_data = self - .region_in - .as_ptr() - .index(resp.masterpiece_start..resp.masterpiece_start + resp.masterpiece_size) - .copy_to_vec(); - - let signature = self - .region_in - .as_ptr() - .index(resp.signature_start..resp.signature_start + resp.signature_size) - .copy_to_vec(); + let pixel_data = { + let mut buf = vec![0; resp.masterpiece_size]; + self.region_in + .as_ptr() + .index(resp.masterpiece_start..resp.masterpiece_start + resp.masterpiece_size) + .copy_into_slice(&mut buf); + buf + }; + + let signature = { + let mut buf = vec![0; resp.signature_size]; + self.region_in + .as_ptr() + .index(resp.signature_start..resp.signature_start + resp.signature_size) + .copy_into_slice(&mut buf); + buf + }; newline(); diff --git a/crates/examples/microkit/http-server/helpers/virtio-hal-impl/src/lib.rs b/crates/examples/microkit/http-server/helpers/virtio-hal-impl/src/lib.rs index ad3eda8ff..dab205b09 100644 --- a/crates/examples/microkit/http-server/helpers/virtio-hal-impl/src/lib.rs +++ b/crates/examples/microkit/http-server/helpers/virtio-hal-impl/src/lib.rs @@ -9,7 +9,7 @@ use core::ptr::{self, NonNull}; use virtio_drivers::{BufferDirection, Hal, PhysAddr, PAGE_SIZE}; use sel4_bounce_buffer_allocator::{Basic, BounceBufferAllocator}; -use sel4_externally_shared::ExternallySharedRef; +use sel4_externally_shared::{ExternallySharedRef, ExternallySharedRefExt}; use sel4_immediate_sync_once_cell::ImmediateSyncOnceCell; use sel4_sync::{GenericMutex, PanickingMutexSyncOps}; diff --git a/crates/examples/microkit/http-server/pds/server/Cargo.toml b/crates/examples/microkit/http-server/pds/server/Cargo.toml index c622bb692..9afe809cf 100644 --- a/crates/examples/microkit/http-server/pds/server/Cargo.toml +++ b/crates/examples/microkit/http-server/pds/server/Cargo.toml @@ -16,6 +16,7 @@ sel4-async-block-io-fat = { path = "../../../../../sel4-async/block-io/fat" } sel4-async-network = { path = "../../../../../sel4-async/network" } sel4-async-time = { path = "../../../../../sel4-async/time" } sel4-bounce-buffer-allocator = { path = "../../../../../sel4-bounce-buffer-allocator" } +sel4-externally-shared = { path = "../../../../../sel4-externally-shared", features = ["unstable"] } sel4-immediate-sync-once-cell = { path = "../../../../../sel4-immediate-sync-once-cell" } sel4-logging = { path = "../../../../../sel4-logging" } sel4-microkit-message = { path = "../../../../../sel4-microkit/message" } @@ -36,10 +37,6 @@ path = "../virtio-net-driver/interface-types" [dependencies.sel4-async-single-threaded-executor] path = "../../../../../sel4-async/single-threaded-executor" -[dependencies.sel4-externally-shared] -path = "../../../../../sel4-externally-shared" -features = ["unstable", "alloc"] - [dependencies.sel4-microkit] path = "../../../../../sel4-microkit" default-features = false diff --git a/crates/examples/microkit/http-server/pds/server/src/main.rs b/crates/examples/microkit/http-server/pds/server/src/main.rs index fc8e8569b..3b1b4bc5d 100644 --- a/crates/examples/microkit/http-server/pds/server/src/main.rs +++ b/crates/examples/microkit/http-server/pds/server/src/main.rs @@ -21,7 +21,7 @@ use sel4_async_block_io::{ constant_block_sizes::BlockSize512, disk::Disk, CachedBlockIO, ConstantBlockSize, }; use sel4_bounce_buffer_allocator::{Basic, BounceBufferAllocator}; -use sel4_externally_shared::ExternallySharedRef; +use sel4_externally_shared::{ExternallySharedRef, ExternallySharedRefExt}; use sel4_logging::{LevelFilter, Logger, LoggerBuilder}; use sel4_microkit::{memory_region_symbol, protection_domain, var, Channel, Handler}; use sel4_shared_ring_buffer::RingBuffers; diff --git a/crates/examples/microkit/http-server/pds/virtio-blk-driver/src/main.rs b/crates/examples/microkit/http-server/pds/virtio-blk-driver/src/main.rs index 143a87aa9..781ffbe4d 100644 --- a/crates/examples/microkit/http-server/pds/virtio-blk-driver/src/main.rs +++ b/crates/examples/microkit/http-server/pds/virtio-blk-driver/src/main.rs @@ -17,7 +17,7 @@ use virtio_drivers::{ }, }; -use sel4_externally_shared::ExternallySharedRef; +use sel4_externally_shared::{ExternallySharedRef, ExternallySharedRefExt}; use sel4_microkit::{memory_region_symbol, protection_domain, var, Channel, Handler, MessageInfo}; use sel4_microkit_message::MessageInfoExt as _; use sel4_shared_ring_buffer::{roles::Use, RingBuffers}; diff --git a/crates/examples/microkit/http-server/pds/virtio-net-driver/src/main.rs b/crates/examples/microkit/http-server/pds/virtio-net-driver/src/main.rs index 5c752b8fb..94257d413 100644 --- a/crates/examples/microkit/http-server/pds/virtio-net-driver/src/main.rs +++ b/crates/examples/microkit/http-server/pds/virtio-net-driver/src/main.rs @@ -12,7 +12,7 @@ use virtio_drivers::{ }, }; -use sel4_externally_shared::ExternallySharedRef; +use sel4_externally_shared::{ExternallySharedRef, ExternallySharedRefExt}; use sel4_microkit::{memory_region_symbol, protection_domain, var, Channel, Handler, MessageInfo}; use sel4_microkit_message::MessageInfoExt as _; use sel4_shared_ring_buffer::{roles::Use, RingBuffers}; diff --git a/crates/private/meta/Cargo.toml b/crates/private/meta/Cargo.toml index edccbb015..a49b75e68 100644 --- a/crates/private/meta/Cargo.toml +++ b/crates/private/meta/Cargo.toml @@ -40,7 +40,7 @@ sel4-sys = { path = "../../sel4/sys" } [dependencies.sel4-externally-shared] path = "../../sel4-externally-shared" -features = ["alloc", "unstable", "very_unstable"] +features = ["unstable", "very_unstable"] [target."cfg(not(target_arch = \"x86_64\"))".dependencies] sel4-platform-info = { path = "../../sel4-platform-info", optional = true } diff --git a/crates/sel4-externally-shared/Cargo.toml b/crates/sel4-externally-shared/Cargo.toml index 455f43dca..70b0aff5d 100644 --- a/crates/sel4-externally-shared/Cargo.toml +++ b/crates/sel4-externally-shared/Cargo.toml @@ -3,12 +3,15 @@ name = "sel4-externally-shared" version = "0.1.0" authors = ["Nick Spinale "] edition = "2021" -license = "MIT OR Apache-2.0" +license = "BSD-2-Clause" [features] -alloc = [] -unstable = [] -very_unstable = ["unstable"] +unstable = ["volatile/unstable"] +very_unstable = ["volatile/very_unstable"] -[dev-dependencies] -rand = "0.8.3" +[dependencies] +zerocopy = "0.7.6" + +[dependencies.volatile] +git = "https://github.com/coliasgroup/volatile.git" +tag = "keep/8aee5539716d3d38247f46eddd42b382" diff --git a/crates/sel4-externally-shared/sel4-externally-shared.LICENSE-APACHE b/crates/sel4-externally-shared/sel4-externally-shared.LICENSE-APACHE deleted file mode 100644 index 261eeb9e9..000000000 --- a/crates/sel4-externally-shared/sel4-externally-shared.LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/crates/sel4-externally-shared/sel4-externally-shared.LICENSE-MIT b/crates/sel4-externally-shared/sel4-externally-shared.LICENSE-MIT deleted file mode 100644 index 43dbb67cc..000000000 --- a/crates/sel4-externally-shared/sel4-externally-shared.LICENSE-MIT +++ /dev/null @@ -1,22 +0,0 @@ -MIT License - -Copyright (c) 2020 Philipp Oppermann -Copyright (c) 2023 Nick Spinale - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/crates/sel4-externally-shared/sel4-externally-shared.README b/crates/sel4-externally-shared/sel4-externally-shared.README deleted file mode 100644 index c0347074b..000000000 --- a/crates/sel4-externally-shared/sel4-externally-shared.README +++ /dev/null @@ -1,5 +0,0 @@ -The 'sel4-externally-shared' crate is derived, with minor modification, from: - -https://github.com/rust-osdev/volatile - -See sel4-externally-shared.LICENSE-{MIT,APACHE} for copyright information. diff --git a/crates/sel4-externally-shared/src/access.rs b/crates/sel4-externally-shared/src/access.rs deleted file mode 100644 index fae6bb359..000000000 --- a/crates/sel4-externally-shared/src/access.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! Marker types for limiting access. - -/// Private trait that is implemented for the types in this module. -pub trait Access: Copy + Default { - /// Ensures that this trait cannot be implemented outside of this crate. - #[doc(hidden)] - fn _private() -> _Private { - _Private - } - - /// Reduced access level to safely share the corresponding value. - type RestrictShared: Access; -} - -/// Helper trait that is implemented by [`ReadWrite`] and [`ReadOnly`]. -pub trait Readable: Copy + Default { - /// Reduced access level to safely share the corresponding value. - type RestrictShared: Readable + Access; - - /// Ensures that this trait cannot be implemented outside of this crate. - fn _private() -> _Private { - _Private - } -} - -/// Helper trait that is implemented by [`ReadWrite`] and [`WriteOnly`]. -pub trait Writable: Access { - /// Ensures that this trait cannot be implemented outside of this crate. - fn _private() -> _Private { - _Private - } -} - -/// Implemented for access types that permit copying of `ExternallySharedRef`. -pub trait Copyable { - /// Ensures that this trait cannot be implemented outside of this crate. - fn _private() -> _Private { - _Private - } -} - -impl Access for T -where - T: Readable + Default + Copy, -{ - type RestrictShared = ::RestrictShared; -} - -/// Zero-sized marker type for allowing both read and write access. -#[derive(Debug, Default, Copy, Clone)] -pub struct ReadWrite; -impl Readable for ReadWrite { - type RestrictShared = ReadOnly; -} -impl Writable for ReadWrite {} - -/// Zero-sized marker type for allowing only read access. -#[derive(Debug, Default, Copy, Clone)] -pub struct ReadOnly; -impl Readable for ReadOnly { - type RestrictShared = ReadOnly; -} -impl Copyable for ReadOnly {} - -/// Zero-sized marker type for allowing only write access. -#[derive(Debug, Default, Copy, Clone)] -pub struct WriteOnly; -impl Access for WriteOnly { - type RestrictShared = NoAccess; -} -impl Writable for WriteOnly {} - -/// Zero-sized marker type that grants no access. -#[derive(Debug, Default, Copy, Clone)] -pub struct NoAccess; -impl Access for NoAccess { - type RestrictShared = NoAccess; -} -impl Copyable for NoAccess {} - -#[non_exhaustive] -#[doc(hidden)] -pub struct _Private; diff --git a/crates/sel4-externally-shared/src/atomics/generic.rs b/crates/sel4-externally-shared/src/atomics/generic.rs new file mode 100644 index 000000000..88a07f87f --- /dev/null +++ b/crates/sel4-externally-shared/src/atomics/generic.rs @@ -0,0 +1,274 @@ +use core::intrinsics; + +use super::OrderingExhaustive as Ordering; + +use Ordering::*; + +#[inline] +pub(crate) unsafe fn atomic_store(dst: *mut T, val: T, order: Ordering) { + // SAFETY: the caller must uphold the safety contract for `atomic_store`. + unsafe { + match order { + Relaxed => intrinsics::atomic_store_relaxed(dst, val), + Release => intrinsics::atomic_store_release(dst, val), + SeqCst => intrinsics::atomic_store_seqcst(dst, val), + Acquire => panic!("there is no such thing as an acquire store"), + AcqRel => panic!("there is no such thing as an acquire-release store"), + } + } +} + +#[inline] +pub(crate) unsafe fn atomic_load(dst: *const T, order: Ordering) -> T { + // SAFETY: the caller must uphold the safety contract for `atomic_load`. + unsafe { + match order { + Relaxed => intrinsics::atomic_load_relaxed(dst), + Acquire => intrinsics::atomic_load_acquire(dst), + SeqCst => intrinsics::atomic_load_seqcst(dst), + Release => panic!("there is no such thing as a release load"), + AcqRel => panic!("there is no such thing as an acquire-release load"), + } + } +} + +#[inline] +#[cfg(target_has_atomic)] +pub(crate) unsafe fn atomic_swap(dst: *mut T, val: T, order: Ordering) -> T { + // SAFETY: the caller must uphold the safety contract for `atomic_swap`. + unsafe { + match order { + Relaxed => intrinsics::atomic_xchg_relaxed(dst, val), + Acquire => intrinsics::atomic_xchg_acquire(dst, val), + Release => intrinsics::atomic_xchg_release(dst, val), + AcqRel => intrinsics::atomic_xchg_acqrel(dst, val), + SeqCst => intrinsics::atomic_xchg_seqcst(dst, val), + } + } +} + +#[inline] +#[cfg(target_has_atomic)] +pub(crate) unsafe fn atomic_add(dst: *mut T, val: T, order: Ordering) -> T { + // SAFETY: the caller must uphold the safety contract for `atomic_add`. + unsafe { + match order { + Relaxed => intrinsics::atomic_xadd_relaxed(dst, val), + Acquire => intrinsics::atomic_xadd_acquire(dst, val), + Release => intrinsics::atomic_xadd_release(dst, val), + AcqRel => intrinsics::atomic_xadd_acqrel(dst, val), + SeqCst => intrinsics::atomic_xadd_seqcst(dst, val), + } + } +} + +#[inline] +#[cfg(target_has_atomic)] +pub(crate) unsafe fn atomic_sub(dst: *mut T, val: T, order: Ordering) -> T { + // SAFETY: the caller must uphold the safety contract for `atomic_sub`. + unsafe { + match order { + Relaxed => intrinsics::atomic_xsub_relaxed(dst, val), + Acquire => intrinsics::atomic_xsub_acquire(dst, val), + Release => intrinsics::atomic_xsub_release(dst, val), + AcqRel => intrinsics::atomic_xsub_acqrel(dst, val), + SeqCst => intrinsics::atomic_xsub_seqcst(dst, val), + } + } +} + +#[inline] +#[cfg(target_has_atomic)] +pub(crate) unsafe fn atomic_compare_exchange( + dst: *mut T, + old: T, + new: T, + success: Ordering, + failure: Ordering, +) -> Result { + // SAFETY: the caller must uphold the safety contract for `atomic_compare_exchange`. + let (val, ok) = unsafe { + match (success, failure) { + (Relaxed, Relaxed) => intrinsics::atomic_cxchg_relaxed_relaxed(dst, old, new), + (Relaxed, Acquire) => intrinsics::atomic_cxchg_relaxed_acquire(dst, old, new), + (Relaxed, SeqCst) => intrinsics::atomic_cxchg_relaxed_seqcst(dst, old, new), + (Acquire, Relaxed) => intrinsics::atomic_cxchg_acquire_relaxed(dst, old, new), + (Acquire, Acquire) => intrinsics::atomic_cxchg_acquire_acquire(dst, old, new), + (Acquire, SeqCst) => intrinsics::atomic_cxchg_acquire_seqcst(dst, old, new), + (Release, Relaxed) => intrinsics::atomic_cxchg_release_relaxed(dst, old, new), + (Release, Acquire) => intrinsics::atomic_cxchg_release_acquire(dst, old, new), + (Release, SeqCst) => intrinsics::atomic_cxchg_release_seqcst(dst, old, new), + (AcqRel, Relaxed) => intrinsics::atomic_cxchg_acqrel_relaxed(dst, old, new), + (AcqRel, Acquire) => intrinsics::atomic_cxchg_acqrel_acquire(dst, old, new), + (AcqRel, SeqCst) => intrinsics::atomic_cxchg_acqrel_seqcst(dst, old, new), + (SeqCst, Relaxed) => intrinsics::atomic_cxchg_seqcst_relaxed(dst, old, new), + (SeqCst, Acquire) => intrinsics::atomic_cxchg_seqcst_acquire(dst, old, new), + (SeqCst, SeqCst) => intrinsics::atomic_cxchg_seqcst_seqcst(dst, old, new), + (_, AcqRel) => panic!("there is no such thing as an acquire-release failure ordering"), + (_, Release) => panic!("there is no such thing as a release failure ordering"), + } + }; + if ok { + Ok(val) + } else { + Err(val) + } +} + +#[inline] +#[cfg(target_has_atomic)] +pub(crate) unsafe fn atomic_compare_exchange_weak( + dst: *mut T, + old: T, + new: T, + success: Ordering, + failure: Ordering, +) -> Result { + // SAFETY: the caller must uphold the safety contract for `atomic_compare_exchange_weak`. + let (val, ok) = unsafe { + match (success, failure) { + (Relaxed, Relaxed) => intrinsics::atomic_cxchgweak_relaxed_relaxed(dst, old, new), + (Relaxed, Acquire) => intrinsics::atomic_cxchgweak_relaxed_acquire(dst, old, new), + (Relaxed, SeqCst) => intrinsics::atomic_cxchgweak_relaxed_seqcst(dst, old, new), + (Acquire, Relaxed) => intrinsics::atomic_cxchgweak_acquire_relaxed(dst, old, new), + (Acquire, Acquire) => intrinsics::atomic_cxchgweak_acquire_acquire(dst, old, new), + (Acquire, SeqCst) => intrinsics::atomic_cxchgweak_acquire_seqcst(dst, old, new), + (Release, Relaxed) => intrinsics::atomic_cxchgweak_release_relaxed(dst, old, new), + (Release, Acquire) => intrinsics::atomic_cxchgweak_release_acquire(dst, old, new), + (Release, SeqCst) => intrinsics::atomic_cxchgweak_release_seqcst(dst, old, new), + (AcqRel, Relaxed) => intrinsics::atomic_cxchgweak_acqrel_relaxed(dst, old, new), + (AcqRel, Acquire) => intrinsics::atomic_cxchgweak_acqrel_acquire(dst, old, new), + (AcqRel, SeqCst) => intrinsics::atomic_cxchgweak_acqrel_seqcst(dst, old, new), + (SeqCst, Relaxed) => intrinsics::atomic_cxchgweak_seqcst_relaxed(dst, old, new), + (SeqCst, Acquire) => intrinsics::atomic_cxchgweak_seqcst_acquire(dst, old, new), + (SeqCst, SeqCst) => intrinsics::atomic_cxchgweak_seqcst_seqcst(dst, old, new), + (_, AcqRel) => panic!("there is no such thing as an acquire-release failure ordering"), + (_, Release) => panic!("there is no such thing as a release failure ordering"), + } + }; + if ok { + Ok(val) + } else { + Err(val) + } +} + +#[inline] +#[cfg(target_has_atomic)] +pub(crate) unsafe fn atomic_and(dst: *mut T, val: T, order: Ordering) -> T { + // SAFETY: the caller must uphold the safety contract for `atomic_and` + unsafe { + match order { + Relaxed => intrinsics::atomic_and_relaxed(dst, val), + Acquire => intrinsics::atomic_and_acquire(dst, val), + Release => intrinsics::atomic_and_release(dst, val), + AcqRel => intrinsics::atomic_and_acqrel(dst, val), + SeqCst => intrinsics::atomic_and_seqcst(dst, val), + } + } +} + +#[inline] +#[cfg(target_has_atomic)] +pub(crate) unsafe fn atomic_nand(dst: *mut T, val: T, order: Ordering) -> T { + // SAFETY: the caller must uphold the safety contract for `atomic_nand` + unsafe { + match order { + Relaxed => intrinsics::atomic_nand_relaxed(dst, val), + Acquire => intrinsics::atomic_nand_acquire(dst, val), + Release => intrinsics::atomic_nand_release(dst, val), + AcqRel => intrinsics::atomic_nand_acqrel(dst, val), + SeqCst => intrinsics::atomic_nand_seqcst(dst, val), + } + } +} + +#[inline] +#[cfg(target_has_atomic)] +pub(crate) unsafe fn atomic_or(dst: *mut T, val: T, order: Ordering) -> T { + // SAFETY: the caller must uphold the safety contract for `atomic_or` + unsafe { + match order { + SeqCst => intrinsics::atomic_or_seqcst(dst, val), + Acquire => intrinsics::atomic_or_acquire(dst, val), + Release => intrinsics::atomic_or_release(dst, val), + AcqRel => intrinsics::atomic_or_acqrel(dst, val), + Relaxed => intrinsics::atomic_or_relaxed(dst, val), + } + } +} + +#[inline] +#[cfg(target_has_atomic)] +pub(crate) unsafe fn atomic_xor(dst: *mut T, val: T, order: Ordering) -> T { + // SAFETY: the caller must uphold the safety contract for `atomic_xor` + unsafe { + match order { + SeqCst => intrinsics::atomic_xor_seqcst(dst, val), + Acquire => intrinsics::atomic_xor_acquire(dst, val), + Release => intrinsics::atomic_xor_release(dst, val), + AcqRel => intrinsics::atomic_xor_acqrel(dst, val), + Relaxed => intrinsics::atomic_xor_relaxed(dst, val), + } + } +} + +#[inline] +#[cfg(target_has_atomic)] +pub(crate) unsafe fn atomic_max(dst: *mut T, val: T, order: Ordering) -> T { + // SAFETY: the caller must uphold the safety contract for `atomic_max` + unsafe { + match order { + Relaxed => intrinsics::atomic_max_relaxed(dst, val), + Acquire => intrinsics::atomic_max_acquire(dst, val), + Release => intrinsics::atomic_max_release(dst, val), + AcqRel => intrinsics::atomic_max_acqrel(dst, val), + SeqCst => intrinsics::atomic_max_seqcst(dst, val), + } + } +} + +#[inline] +#[cfg(target_has_atomic)] +pub(crate) unsafe fn atomic_min(dst: *mut T, val: T, order: Ordering) -> T { + // SAFETY: the caller must uphold the safety contract for `atomic_min` + unsafe { + match order { + Relaxed => intrinsics::atomic_min_relaxed(dst, val), + Acquire => intrinsics::atomic_min_acquire(dst, val), + Release => intrinsics::atomic_min_release(dst, val), + AcqRel => intrinsics::atomic_min_acqrel(dst, val), + SeqCst => intrinsics::atomic_min_seqcst(dst, val), + } + } +} + +#[inline] +#[cfg(target_has_atomic)] +pub(crate) unsafe fn atomic_umax(dst: *mut T, val: T, order: Ordering) -> T { + // SAFETY: the caller must uphold the safety contract for `atomic_umax` + unsafe { + match order { + Relaxed => intrinsics::atomic_umax_relaxed(dst, val), + Acquire => intrinsics::atomic_umax_acquire(dst, val), + Release => intrinsics::atomic_umax_release(dst, val), + AcqRel => intrinsics::atomic_umax_acqrel(dst, val), + SeqCst => intrinsics::atomic_umax_seqcst(dst, val), + } + } +} + +#[inline] +#[cfg(target_has_atomic)] +pub(crate) unsafe fn atomic_umin(dst: *mut T, val: T, order: Ordering) -> T { + // SAFETY: the caller must uphold the safety contract for `atomic_umin` + unsafe { + match order { + Relaxed => intrinsics::atomic_umin_relaxed(dst, val), + Acquire => intrinsics::atomic_umin_acquire(dst, val), + Release => intrinsics::atomic_umin_release(dst, val), + AcqRel => intrinsics::atomic_umin_acqrel(dst, val), + SeqCst => intrinsics::atomic_umin_seqcst(dst, val), + } + } +} diff --git a/crates/sel4-externally-shared/src/atomics/mod.rs b/crates/sel4-externally-shared/src/atomics/mod.rs new file mode 100644 index 000000000..3ed7f471a --- /dev/null +++ b/crates/sel4-externally-shared/src/atomics/mod.rs @@ -0,0 +1,99 @@ +use core::fmt; +use core::marker::PhantomData; +use core::ptr::NonNull; + +use volatile::access::{ReadOnly, ReadWrite, WriteOnly}; + +mod generic; +mod ops; +mod ordering; + +use ordering::OrderingExhaustive; + +#[repr(transparent)] +pub struct AtomicPtr<'a, T, A = ReadWrite> { + pointer: NonNull, + reference: PhantomData<&'a T>, + access: PhantomData, +} + +impl<'a, T, A> Copy for AtomicPtr<'a, T, A> {} + +impl Clone for AtomicPtr<'_, T, A> { + fn clone(&self) -> Self { + *self + } +} + +impl fmt::Debug for AtomicPtr<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("AtomicPtr") + .field("pointer", &self.pointer) + .field("access", &self.access) + .finish() + } +} + +impl<'a, T, A> AtomicPtr<'a, T, A> { + pub const unsafe fn new(pointer: NonNull) -> Self { + AtomicPtr { + pointer, + reference: PhantomData, + access: PhantomData, + } + } + + pub fn as_raw_ptr(self) -> NonNull { + self.pointer + } + + pub fn read_only(self) -> AtomicPtr<'a, T, ReadOnly> { + unsafe { AtomicPtr::new(self.pointer) } + } + + pub fn write_only(self) -> AtomicPtr<'a, T, WriteOnly> { + unsafe { AtomicPtr::new(self.pointer) } + } +} + +pub unsafe trait Atomic: AtomicSealed + Copy { + const IS_SIGNED: bool; +} + +use sealing::AtomicSealed; + +mod sealing { + pub trait AtomicSealed {} +} + +macro_rules! impl_atomic { + ($t:ty, $target_has_atomic_key:literal, $is_signed:literal) => { + // TODO these attributes are overly conservative + #[cfg(target_has_atomic = $target_has_atomic_key)] + #[cfg(target_has_atomic_equal_alignment = $target_has_atomic_key)] + unsafe impl Atomic for $t { + const IS_SIGNED: bool = $is_signed; + } + + impl AtomicSealed for $t {} + }; +} + +macro_rules! impl_atomic_for_each_signedness { + ($t_unsigned:ty, $t_signed:ty, $target_has_atomic_key:literal) => { + impl_atomic!($t_unsigned, $target_has_atomic_key, false); + impl_atomic!($t_signed, $target_has_atomic_key, true); + }; +} + +impl_atomic_for_each_signedness!(u8, i8, "8"); +impl_atomic_for_each_signedness!(u16, i16, "16"); +impl_atomic_for_each_signedness!(u32, i32, "32"); +impl_atomic_for_each_signedness!(u64, i64, "64"); +impl_atomic_for_each_signedness!(u128, i128, "128"); + +#[cfg(target_pointer_width = "32")] +impl_atomic_for_each_signedness!(usize, isize, "32"); + +#[cfg(target_pointer_width = "64")] +impl_atomic_for_each_signedness!(usize, isize, "64"); diff --git a/crates/sel4-externally-shared/src/atomics/ops.rs b/crates/sel4-externally-shared/src/atomics/ops.rs new file mode 100644 index 000000000..233a0f56a --- /dev/null +++ b/crates/sel4-externally-shared/src/atomics/ops.rs @@ -0,0 +1,159 @@ +use core::sync::atomic::Ordering; + +use volatile::access::{Readable, Writable}; + +use super::{generic, Atomic, AtomicPtr}; + +impl<'a, T, A> AtomicPtr<'a, T, A> { + fn as_mut_ptr(self) -> *mut T { + self.pointer.as_ptr() + } + + fn as_const_ptr(self) -> *const T { + self.as_mut_ptr().cast_const() + } +} + +impl<'a, T: Atomic, A: Readable> AtomicPtr<'a, T, A> { + #[inline] + pub fn load(&self, order: Ordering) -> T { + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { generic::atomic_load(self.as_const_ptr(), order.into()) } + } +} + +impl<'a, T: Atomic, A: Readable + Writable> AtomicPtr<'a, T, A> { + #[inline] + pub fn store(&self, val: T, order: Ordering) { + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + generic::atomic_store(self.as_mut_ptr(), val, order.into()); + } + } + + #[inline] + pub fn swap(&self, val: T, order: Ordering) -> T { + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { generic::atomic_swap(self.as_mut_ptr(), val, order.into()) } + } + + #[inline] + pub fn compare_exchange( + &self, + current: T, + new: T, + success: Ordering, + failure: Ordering, + ) -> Result { + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + generic::atomic_compare_exchange( + self.as_mut_ptr(), + current, + new, + success.into(), + failure.into(), + ) + } + } + + #[inline] + pub fn compare_exchange_weak( + &self, + current: T, + new: T, + success: Ordering, + failure: Ordering, + ) -> Result { + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + generic::atomic_compare_exchange_weak( + self.as_mut_ptr(), + current, + new, + success.into(), + failure.into(), + ) + } + } + + #[inline] + pub fn fetch_add(&self, val: T, order: Ordering) -> T { + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { generic::atomic_add(self.as_mut_ptr(), val, order.into()) } + } + + #[inline] + pub fn fetch_sub(&self, val: T, order: Ordering) -> T { + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { generic::atomic_sub(self.as_mut_ptr(), val, order.into()) } + } + + #[inline] + pub fn fetch_and(&self, val: T, order: Ordering) -> T { + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { generic::atomic_and(self.as_mut_ptr(), val, order.into()) } + } + + #[inline] + pub fn fetch_nand(&self, val: T, order: Ordering) -> T { + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { generic::atomic_nand(self.as_mut_ptr(), val, order.into()) } + } + + #[inline] + pub fn fetch_or(&self, val: T, order: Ordering) -> T { + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { generic::atomic_or(self.as_mut_ptr(), val, order.into()) } + } + + #[inline] + pub fn fetch_xor(&self, val: T, order: Ordering) -> T { + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { generic::atomic_xor(self.as_mut_ptr(), val, order.into()) } + } + + #[inline] + pub fn fetch_update( + &self, + set_order: Ordering, + fetch_order: Ordering, + mut f: F, + ) -> Result + where + F: FnMut(T) -> Option, + { + let mut prev = self.load(fetch_order.into()); + while let Some(next) = f(prev) { + match self.compare_exchange_weak(prev, next, set_order.into(), fetch_order.into()) { + x @ Ok(_) => return x, + Err(next_prev) => prev = next_prev, + } + } + Err(prev) + } + + #[inline] + pub fn fetch_max(&self, val: T, order: Ordering) -> T { + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + if T::IS_SIGNED { + generic::atomic_max(self.as_mut_ptr(), val, order.into()) + } else { + generic::atomic_umax(self.as_mut_ptr(), val, order.into()) + } + } + } + + #[inline] + pub fn fetch_min(&self, val: T, order: Ordering) -> T { + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + if T::IS_SIGNED { + generic::atomic_min(self.as_mut_ptr(), val, order.into()) + } else { + generic::atomic_umin(self.as_mut_ptr(), val, order.into()) + } + } + } +} diff --git a/crates/sel4-externally-shared/src/atomics/ordering.rs b/crates/sel4-externally-shared/src/atomics/ordering.rs new file mode 100644 index 000000000..8a849685a --- /dev/null +++ b/crates/sel4-externally-shared/src/atomics/ordering.rs @@ -0,0 +1,34 @@ +use core::sync::atomic::Ordering; + +pub(crate) enum OrderingExhaustive { + Relaxed, + Release, + Acquire, + AcqRel, + SeqCst, +} + +impl From for Ordering { + fn from(order: OrderingExhaustive) -> Self { + match order { + OrderingExhaustive::Relaxed => Self::Relaxed, + OrderingExhaustive::Release => Self::Release, + OrderingExhaustive::Acquire => Self::Acquire, + OrderingExhaustive::AcqRel => Self::AcqRel, + OrderingExhaustive::SeqCst => Self::SeqCst, + } + } +} + +impl From for OrderingExhaustive { + fn from(order: Ordering) -> Self { + match order { + Ordering::Relaxed => Self::Relaxed, + Ordering::Release => Self::Release, + Ordering::Acquire => Self::Acquire, + Ordering::AcqRel => Self::AcqRel, + Ordering::SeqCst => Self::SeqCst, + _ => panic!(), + } + } +} diff --git a/crates/sel4-externally-shared/src/externally_shared_ptr/atomic.rs b/crates/sel4-externally-shared/src/externally_shared_ptr/atomic.rs deleted file mode 100644 index 770f20e42..000000000 --- a/crates/sel4-externally-shared/src/externally_shared_ptr/atomic.rs +++ /dev/null @@ -1,63 +0,0 @@ -use core::sync::atomic; - -use crate::{ - access::{Readable, Writable}, - ExternallySharedPtr, -}; - -pub trait AtomicPrimitive { - type Atomic; - - unsafe fn wrap_atomic<'a>(ptr: *mut Self) -> &'a Self::Atomic; -} - -macro_rules! atomic_primitive_impl { - ($prim:path, $wrapper:path) => { - impl AtomicPrimitive for $prim { - type Atomic = $wrapper; - - unsafe fn wrap_atomic<'a>(ptr: *mut Self) -> &'a Self::Atomic { - unsafe { Self::Atomic::from_ptr(ptr) } - } - } - }; -} - -#[cfg(target_has_atomic = "8")] -atomic_primitive_impl!(bool, atomic::AtomicBool); -#[cfg(target_has_atomic = "8")] -atomic_primitive_impl!(u8, atomic::AtomicU8); -#[cfg(target_has_atomic = "8")] -atomic_primitive_impl!(i8, atomic::AtomicI8); -#[cfg(target_has_atomic = "16")] -atomic_primitive_impl!(u16, atomic::AtomicU16); -#[cfg(target_has_atomic = "16")] -atomic_primitive_impl!(i16, atomic::AtomicI16); -#[cfg(target_has_atomic = "32")] -atomic_primitive_impl!(u32, atomic::AtomicU32); -#[cfg(target_has_atomic = "32")] -atomic_primitive_impl!(i32, atomic::AtomicI32); -#[cfg(target_has_atomic = "64")] -atomic_primitive_impl!(u64, atomic::AtomicU64); -#[cfg(target_has_atomic = "64")] -atomic_primitive_impl!(i64, atomic::AtomicI64); -#[cfg(target_has_atomic = "usize")] -atomic_primitive_impl!(usize, atomic::AtomicUsize); -#[cfg(target_has_atomic = "isize")] -atomic_primitive_impl!(isize, atomic::AtomicIsize); - -#[cfg(target_has_atomic = "ptr")] -impl AtomicPrimitive for *mut T { - type Atomic = atomic::AtomicPtr; - - unsafe fn wrap_atomic<'a>(ptr: *mut Self) -> &'a Self::Atomic { - unsafe { Self::Atomic::from_ptr(ptr) } - } -} - -impl<'a, T: AtomicPrimitive, A: Readable + Writable> ExternallySharedPtr<'a, T, A> { - /// `TODO` - pub fn with_atomic R>(self, f: F) -> R { - f(unsafe { T::wrap_atomic(self.as_raw_ptr().as_ptr()) }) - } -} diff --git a/crates/sel4-externally-shared/src/externally_shared_ptr/macros.rs b/crates/sel4-externally-shared/src/externally_shared_ptr/macros.rs deleted file mode 100644 index a0fb49f3d..000000000 --- a/crates/sel4-externally-shared/src/externally_shared_ptr/macros.rs +++ /dev/null @@ -1,49 +0,0 @@ -/// Provides safe field projection for externally shared pointers referencing structs. -/// -/// ## Examples -/// -/// Accessing a struct field: -/// -/// ``` -/// use sel4_externally_shared::{ExternallySharedPtr, map_field}; -/// use core::ptr::NonNull; -/// -/// struct Example { field_1: u32, field_2: u8, } -/// let mut value = Example { field_1: 15, field_2: 255 }; -/// let mut shared = unsafe { ExternallySharedPtr::new((&mut value).into()) }; -/// -/// // construct an externally shared reference to a field -/// let field_2 = map_field!(shared.field_2); -/// assert_eq!(field_2.read(), 255); -/// ``` -/// -/// Creating `ExternallySharedPtr`s to unaligned field in packed structs is not allowed: -/// ```compile_fail -/// use sel4_externally_shared::{ExternallySharedPtr, map_field}; -/// use core::ptr::NonNull; -/// -/// #[repr(packed)] -/// struct Example { field_1: u8, field_2: usize, } -/// let mut value = Example { field_1: 15, field_2: 255 }; -/// let mut shared = unsafe { ExternallySharedPtr::new((&mut value).into()) }; -/// -/// // Constructing an externally shared reference to an unaligned field doesn't compile. -/// let field_2 = map_field!(shared.field_2); -/// ``` -#[macro_export] -macro_rules! map_field { - ($shared:ident.$place:ident) => {{ - // Simulate creating a reference to the field. This is done to make - // sure that the field is not potentially unaligned. The body of the - // if statement will never be executed, so it can never cause any UB. - if false { - let _ref_to_field = &(unsafe { &*$shared.as_raw_ptr().as_ptr() }).$place; - } - - unsafe { - $shared.map(|ptr| { - core::ptr::NonNull::new(core::ptr::addr_of_mut!((*ptr.as_ptr()).$place)).unwrap() - }) - } - }}; -} diff --git a/crates/sel4-externally-shared/src/externally_shared_ptr/mod.rs b/crates/sel4-externally-shared/src/externally_shared_ptr/mod.rs deleted file mode 100644 index 450625b32..000000000 --- a/crates/sel4-externally-shared/src/externally_shared_ptr/mod.rs +++ /dev/null @@ -1,59 +0,0 @@ -use core::{fmt, marker::PhantomData, ptr::NonNull}; - -use crate::access::ReadWrite; - -mod macros; -mod operations; - -#[cfg(feature = "unstable")] -mod atomic; -#[cfg(test)] -mod tests; -#[cfg(feature = "unstable")] -mod unstable; -#[cfg(feature = "very_unstable")] -mod very_unstable; - -/// Wraps a pointer for convenient accesses. -/// -/// The referenced value needs to be `Copy` for reading and writing, as raw pointer reads and writes -/// take and return copies of the value. -/// -/// Since not all externally shared resources (e.g. memory mapped device registers) are both -/// readable and writable, this type supports limiting the allowed access types through an optional -/// second generic parameter `A` that can be one of `ReadWrite`, `ReadOnly`, or `WriteOnly`. It -/// defaults to `ReadWrite`, which allows all operations. -/// -/// The size of this struct is the same as the size of the contained reference. -#[repr(transparent)] -pub struct ExternallySharedPtr<'a, T, A = ReadWrite> -where - T: ?Sized, -{ - pointer: NonNull, - reference: PhantomData<&'a T>, - access: PhantomData, -} - -impl<'a, T, A> Copy for ExternallySharedPtr<'a, T, A> where T: ?Sized {} - -impl Clone for ExternallySharedPtr<'_, T, A> -where - T: ?Sized, -{ - fn clone(&self) -> Self { - *self - } -} - -impl fmt::Debug for ExternallySharedPtr<'_, T, A> -where - T: Copy + fmt::Debug + ?Sized, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ExternallySharedPtr") - .field("pointer", &self.pointer) - .field("access", &self.access) - .finish() - } -} diff --git a/crates/sel4-externally-shared/src/externally_shared_ptr/operations.rs b/crates/sel4-externally-shared/src/externally_shared_ptr/operations.rs deleted file mode 100644 index c3dd34bd7..000000000 --- a/crates/sel4-externally-shared/src/externally_shared_ptr/operations.rs +++ /dev/null @@ -1,256 +0,0 @@ -use core::{marker::PhantomData, ptr::NonNull}; - -use crate::{ - access::{Access, ReadOnly, ReadWrite, Readable, Writable, WriteOnly}, - ExternallySharedPtr, -}; - -/// Constructor functions. -/// -/// These functions construct new `ExternallySharedPtr` values. While the `new` -/// function creates a `ExternallySharedPtr` instance with unrestricted access, there -/// are also functions for creating read-only or write-only instances. -impl<'a, T> ExternallySharedPtr<'a, T> -where - T: ?Sized, -{ - /// Turns the given pointer into a `ExternallySharedPtr`. - /// - /// ## Safety - /// - /// - The given pointer must be valid. - /// - No other thread must have access to the given pointer. This must remain true - /// for the whole lifetime of the `ExternallySharedPtr`. - pub unsafe fn new(pointer: NonNull) -> ExternallySharedPtr<'a, T, ReadWrite> { - unsafe { ExternallySharedPtr::new_restricted(ReadWrite, pointer) } - } - - /// Creates a new read-only wrapped pointer from the given raw pointer. - /// - /// ## Safety - /// - /// The requirements for [`Self::new`] apply to this function too. - pub const unsafe fn new_read_only(pointer: NonNull) -> ExternallySharedPtr<'a, T, ReadOnly> { - unsafe { Self::new_restricted(ReadOnly, pointer) } - } - - /// Creates a new wrapped pointer with restricted access from the given raw pointer. - /// - /// ## Safety - /// - /// The requirements for [`Self::new`] apply to this function too. - pub const unsafe fn new_restricted( - access: A, - pointer: NonNull, - ) -> ExternallySharedPtr<'a, T, A> - where - A: Access, - { - let _ = access; - unsafe { Self::new_generic(pointer) } - } - - pub(super) const unsafe fn new_generic( - pointer: NonNull, - ) -> ExternallySharedPtr<'a, T, A> { - ExternallySharedPtr { - pointer, - reference: PhantomData, - access: PhantomData, - } - } -} - -impl<'a, T, A> ExternallySharedPtr<'a, T, A> -where - T: ?Sized, -{ - /// Performs a read of the contained value. - /// - /// ## Examples - /// - /// ```rust - /// use sel4_externally_shared::{ExternallySharedPtr, access}; - /// use core::ptr::NonNull; - /// - /// let value = 42; - /// let pointer = unsafe { - /// ExternallySharedPtr::new_restricted(access::ReadOnly, NonNull::from(&value)) - /// }; - /// assert_eq!(pointer.read(), 42); - /// ``` - pub fn read(self) -> T - where - T: Copy, - A: Readable, - { - unsafe { self.pointer.as_ptr().read() } - } - - /// Performs a write, setting the contained value to the given `value`. - /// - /// ## Example - /// - /// ```rust - /// use sel4_externally_shared::ExternallySharedPtr; - /// use core::ptr::NonNull; - /// - /// let mut value = 42; - /// let mut shared = unsafe { ExternallySharedPtr::new((&mut value).into()) }; - /// shared.write(50); - /// - /// assert_eq!(shared.read(), 50); - /// ``` - pub fn write(self, value: T) - where - T: Copy, - A: Writable, - { - unsafe { self.pointer.as_ptr().write(value) }; - } - - /// Updates the contained value using the given closure. - /// - /// Performs a read of the contained value, passes it to the - /// function `f`, and then performs a write of the returned value back to - /// the target. - /// - /// ```rust - /// use sel4_externally_shared::ExternallySharedPtr; - /// use core::ptr::NonNull; - /// - /// let mut value = 42; - /// let mut shared = unsafe { ExternallySharedPtr::new((&mut value).into()) }; - /// shared.update(|val| val + 1); - /// - /// assert_eq!(shared.read(), 43); - /// ``` - pub fn update(self, f: F) - where - T: Copy, - A: Readable + Writable, - F: FnOnce(T) -> T, - { - let new = f(self.read()); - self.write(new); - } - - /// Extracts the wrapped raw pointer. - /// - /// ## Example - /// - /// ``` - /// use sel4_externally_shared::ExternallySharedPtr; - /// use core::ptr::NonNull; - /// - /// let mut value = 42; - /// let mut shared = unsafe { ExternallySharedPtr::new((&mut value).into()) }; - /// shared.write(50); - /// let unwrapped: *mut i32 = shared.as_raw_ptr().as_ptr(); - /// - /// assert_eq!(unsafe { *unwrapped }, 50); - /// ``` - pub fn as_raw_ptr(self) -> NonNull { - self.pointer - } - - /// Constructs a new `ExternallySharedPtr` by mapping the wrapped pointer. - /// - /// This method is useful for accessing only a part of a value, e.g. a subslice or - /// a struct field. For struct field access, there is also the safe - /// [`map_field`][crate::map_field] macro that wraps this function. - /// - /// ## Examples - /// - /// Accessing a struct field: - /// - /// ``` - /// use sel4_externally_shared::ExternallySharedPtr; - /// use core::ptr::NonNull; - /// - /// struct Example { field_1: u32, field_2: u8, } - /// let mut value = Example { field_1: 15, field_2: 255 }; - /// let mut shared = unsafe { ExternallySharedPtr::new((&mut value).into()) }; - /// - /// // construct a wrapped pointer to a field - /// let field_2 = unsafe { shared.map(|ptr| NonNull::new(core::ptr::addr_of_mut!((*ptr.as_ptr()).field_2)).unwrap()) }; - /// assert_eq!(field_2.read(), 255); - /// ``` - /// - /// Don't misuse this method to do a read of the referenced value: - /// - /// ``` - /// use sel4_externally_shared::ExternallySharedPtr; - /// use core::ptr::NonNull; - /// - /// let mut value = 5; - /// let mut shared = unsafe { ExternallySharedPtr::new((&mut value).into()) }; - /// - /// // DON'T DO THIS: - /// let mut readout = 0; - /// unsafe { shared.map(|value| { - /// readout = *value.as_ptr(); - /// value - /// })}; - /// ``` - /// - /// ## Safety - /// - /// The pointer returned by `f` must satisfy the requirements of [`Self::new`]. - pub unsafe fn map(self, f: F) -> ExternallySharedPtr<'a, U, A> - where - F: FnOnce(NonNull) -> NonNull, - A: Access, - U: ?Sized, - { - unsafe { ExternallySharedPtr::new_restricted(A::default(), f(self.pointer)) } - } -} - -/// Methods for restricting access. -impl<'a, T> ExternallySharedPtr<'a, T, ReadWrite> -where - T: ?Sized, -{ - /// Restricts access permissions to read-only. - /// - /// ## Example - /// - /// ``` - /// use sel4_externally_shared::ExternallySharedPtr; - /// use core::ptr::NonNull; - /// - /// let mut value: i16 = -4; - /// let mut shared = unsafe { ExternallySharedPtr::new((&mut value).into()) }; - /// - /// let read_only = shared.read_only(); - /// assert_eq!(read_only.read(), -4); - /// // read_only.write(10); // compile-time error - /// ``` - pub fn read_only(self) -> ExternallySharedPtr<'a, T, ReadOnly> { - unsafe { ExternallySharedPtr::new_restricted(ReadOnly, self.pointer) } - } - - /// Restricts access permissions to write-only. - /// - /// ## Example - /// - /// Creating a write-only pointer to a struct field: - /// - /// ``` - /// use sel4_externally_shared::{ExternallySharedPtr, map_field}; - /// use core::ptr::NonNull; - /// - /// struct Example { field_1: u32, field_2: u8, } - /// let mut value = Example { field_1: 15, field_2: 255 }; - /// let mut shared = unsafe { ExternallySharedPtr::new((&mut value).into()) }; - /// - /// // construct a wrapped write-only pointer to `field_2` - /// let mut field_2 = map_field!(shared.field_2).write_only(); - /// field_2.write(14); - /// // field_2.read(); // compile-time error - /// ``` - pub fn write_only(self) -> ExternallySharedPtr<'a, T, WriteOnly> { - unsafe { ExternallySharedPtr::new_restricted(WriteOnly, self.pointer) } - } -} diff --git a/crates/sel4-externally-shared/src/externally_shared_ptr/tests.rs b/crates/sel4-externally-shared/src/externally_shared_ptr/tests.rs deleted file mode 100644 index a298e264b..000000000 --- a/crates/sel4-externally-shared/src/externally_shared_ptr/tests.rs +++ /dev/null @@ -1,180 +0,0 @@ -use crate::{ - access::{ReadOnly, ReadWrite, WriteOnly}, - map_field, ExternallySharedPtr, -}; -use core::ptr::NonNull; - -#[test] -fn test_read() { - let val = 42; - assert_eq!( - unsafe { ExternallySharedPtr::new_read_only(NonNull::from(&val)) }.read(), - 42 - ); -} - -#[test] -fn test_write() { - let mut val = 50; - let shared = unsafe { ExternallySharedPtr::new(NonNull::from(&mut val)) }; - shared.write(50); - assert_eq!(val, 50); -} - -#[test] -fn test_update() { - let mut val = 42; - let shared = unsafe { ExternallySharedPtr::new(NonNull::from(&mut val)) }; - shared.update(|v| v + 1); - assert_eq!(val, 43); -} - -#[test] -fn test_access() { - let mut val: i64 = 42; - - // ReadWrite - assert_eq!( - unsafe { ExternallySharedPtr::new_restricted(ReadWrite, NonNull::from(&mut val)) }.read(), - 42 - ); - unsafe { ExternallySharedPtr::new_restricted(ReadWrite, NonNull::from(&mut val)) }.write(50); - assert_eq!(val, 50); - unsafe { ExternallySharedPtr::new_restricted(ReadWrite, NonNull::from(&mut val)) } - .update(|i| i + 1); - assert_eq!(val, 51); - - // ReadOnly and WriteOnly - assert_eq!( - unsafe { ExternallySharedPtr::new_restricted(ReadOnly, NonNull::from(&mut val)) }.read(), - 51 - ); - unsafe { ExternallySharedPtr::new_restricted(WriteOnly, NonNull::from(&mut val)) }.write(12); - assert_eq!(val, 12); -} - -#[test] -fn test_struct() { - #[derive(Debug, PartialEq)] - struct S { - field_1: u32, - field_2: bool, - } - - let mut val = S { - field_1: 60, - field_2: true, - }; - let shared = unsafe { ExternallySharedPtr::new(NonNull::from(&mut val)) }; - unsafe { - shared.map(|s| NonNull::new(core::ptr::addr_of_mut!((*s.as_ptr()).field_1)).unwrap()) - } - .update(|v| v + 1); - let field_2 = unsafe { - shared.map(|s| NonNull::new(core::ptr::addr_of_mut!((*s.as_ptr()).field_2)).unwrap()) - }; - assert!(field_2.read()); - field_2.write(false); - assert_eq!( - val, - S { - field_1: 61, - field_2: false - } - ); -} - -#[test] -fn test_struct_macro() { - #[derive(Debug, PartialEq)] - struct S { - field_1: u32, - field_2: bool, - } - - let mut val = S { - field_1: 60, - field_2: true, - }; - let shared = unsafe { ExternallySharedPtr::new(NonNull::from(&mut val)) }; - let field_1 = map_field!(shared.field_1); - field_1.update(|v| v + 1); - let field_2 = map_field!(shared.field_2); - assert!(field_2.read()); - field_2.write(false); - assert_eq!( - val, - S { - field_1: 61, - field_2: false - } - ); -} - -#[cfg(feature = "unstable")] -#[test] -fn test_slice() { - let val: &mut [u32] = &mut [1, 2, 3]; - let shared = unsafe { ExternallySharedPtr::new(NonNull::from(val)) }; - shared.index(0).update(|v| v + 1); - - let mut dst = [0; 3]; - shared.copy_into_slice(&mut dst); - assert_eq!(dst, [2, 2, 3]); -} - -#[cfg(feature = "unstable")] -#[test] -#[should_panic] -fn test_bounds_check_1() { - let val: &mut [u32] = &mut [1, 2, 3]; - let shared = unsafe { ExternallySharedPtr::new(NonNull::from(val)) }; - shared.index(3); -} - -#[cfg(feature = "unstable")] -#[test] -#[should_panic] -fn test_bounds_check_2() { - let val: &mut [u32] = &mut [1, 2, 3]; - let shared = unsafe { ExternallySharedPtr::new(NonNull::from(val)) }; - #[allow(clippy::reversed_empty_ranges)] - shared.index(2..1); -} - -#[cfg(feature = "unstable")] -#[test] -#[should_panic] -fn test_bounds_check_3() { - let val: &mut [u32] = &mut [1, 2, 3]; - let shared = unsafe { ExternallySharedPtr::new(NonNull::from(val)) }; - shared.index(4..); // `3..` is is still ok (see next test) -} - -#[cfg(feature = "unstable")] -#[test] -fn test_bounds_check_4() { - let val: &mut [u32] = &mut [1, 2, 3]; - let shared = unsafe { ExternallySharedPtr::new(NonNull::from(val)) }; - assert_eq!(shared.index(3..).len(), 0); -} - -#[cfg(feature = "unstable")] -#[test] -#[should_panic] -fn test_bounds_check_5() { - let val: &mut [u32] = &mut [1, 2, 3]; - let shared = unsafe { ExternallySharedPtr::new(NonNull::from(val)) }; - shared.index(..4); -} - -#[cfg(feature = "unstable")] -#[test] -fn test_chunks() { - let val: &mut [u32] = &mut [1, 2, 3, 4, 5, 6]; - let shared = unsafe { ExternallySharedPtr::new(NonNull::from(val)) }; - let chunks = shared.as_chunks().0; - chunks.index(1).write([10, 11, 12]); - assert_eq!(chunks.index(0).read(), [1, 2, 3]); - assert_eq!(chunks.index(1).read(), [10, 11, 12]); -} diff --git a/crates/sel4-externally-shared/src/externally_shared_ptr/unstable.rs b/crates/sel4-externally-shared/src/externally_shared_ptr/unstable.rs deleted file mode 100644 index fbcb465e1..000000000 --- a/crates/sel4-externally-shared/src/externally_shared_ptr/unstable.rs +++ /dev/null @@ -1,425 +0,0 @@ -use core::{ - ops::{Range, RangeBounds}, - ptr::{self, NonNull}, - slice::{range, SliceIndex}, -}; - -#[cfg(feature = "alloc")] -use alloc::vec::Vec; - -use crate::{ - access::{Access, Readable, Writable}, - ExternallySharedPtr, -}; - -impl<'a, T, A> ExternallySharedPtr<'a, [T], A> { - /// Returns the length of the slice. - pub fn len(self) -> usize { - self.pointer.len() - } - - /// Returns whether the slice is empty. - pub fn is_empty(self) -> bool { - self.pointer.len() == 0 - } - - /// Applies the index operation on the wrapped slice. - /// - /// Returns a shared `ExternallySharedPtr` reference to the resulting subslice. - /// - /// This is a convenience method for the `map(|slice| slice.index(index))` operation, so it - /// has the same behavior as the indexing operation on slice (e.g. panic if index is - /// out-of-bounds). - /// - /// ## Examples - /// - /// Accessing a single slice element: - /// - /// ``` - /// use sel4_externally_shared::ExternallySharedPtr; - /// use core::ptr::NonNull; - /// - /// let array = [1, 2, 3]; - /// let slice = &array[..]; - /// let shared = unsafe { ExternallySharedPtr::new_read_only(NonNull::from(slice)) }; - /// assert_eq!(shared.index(1).read(), 2); - /// ``` - /// - /// Accessing a subslice: - /// - /// ``` - /// use sel4_externally_shared::ExternallySharedPtr; - /// use core::ptr::NonNull; - /// - /// let array = [1, 2, 3]; - /// let slice = &array[..]; - /// let shared = unsafe { ExternallySharedPtr::new_read_only(NonNull::from(slice)) }; - /// let subslice = shared.index(1..); - /// assert_eq!(subslice.index(0).read(), 2); - /// ``` - pub fn index(self, index: I) -> ExternallySharedPtr<'a, >::Output, A> - where - I: SliceIndex<[T]> + SliceIndex<[()]> + Clone, - A: Access, - { - bounds_check(self.pointer.len(), index.clone()); - - unsafe { self.map(|slice| slice.get_unchecked_mut(index)) } - } - - /// Returns an iterator over the slice. - pub fn iter(self) -> impl Iterator> - where - A: Access, - { - let ptr = self.as_raw_ptr().as_ptr() as *mut T; - let len = self.len(); - (0..len).map(move |i| unsafe { - ExternallySharedPtr::new_generic(NonNull::new_unchecked(ptr.add(i))) - }) - } - - /// Copies all elements from `self` into `dst`, using memcpy. - /// - /// The length of `dst` must be the same as `self`. - /// - /// The method is only available with the `unstable` feature enabled (requires a nightly - /// Rust compiler). - /// - /// ## Panics - /// - /// This function will panic if the two slices have different lengths. - /// - /// ## Examples - /// - /// Copying two elements from a wrapped slice: - /// - /// ``` - /// use sel4_externally_shared::ExternallySharedPtr; - /// use core::ptr::NonNull; - /// - /// let src = [1, 2]; - /// // the `ExternallySharedPtr` type does not work with arrays, so convert `src` to a slice - /// let slice = &src[..]; - /// let shared = unsafe { ExternallySharedPtr::new_read_only(NonNull::from(slice)) }; - /// let mut dst = [5, 0, 0]; - /// - /// // Because the slices have to be the same length, - /// // we slice the destination slice from three elements - /// // to two. It will panic if we don't do this. - /// shared.copy_into_slice(&mut dst[1..]); - /// - /// assert_eq!(src, [1, 2]); - /// assert_eq!(dst, [5, 1, 2]); - /// ``` - pub fn copy_into_slice(self, dst: &mut [T]) - where - T: Copy, - A: Readable, - { - let len = self.pointer.len(); - assert_eq!( - len, - dst.len(), - "destination and source slices have different lengths" - ); - unsafe { - dst.as_mut_ptr() - .copy_from_nonoverlapping(self.pointer.as_mut_ptr(), len); - } - } - - /// Copies all elements from `src` into `self`, using memcpy. - /// - /// The length of `src` must be the same as `self`. - /// - /// The method is only available with the `unstable` feature enabled (requires a nightly - /// Rust compiler). - /// - /// ## Panics - /// - /// This function will panic if the two slices have different lengths. - /// - /// ## Examples - /// - /// Copying two elements from a slice into a wrapped slice: - /// - /// ``` - /// use sel4_externally_shared::ExternallySharedPtr; - /// use core::ptr::NonNull; - /// - /// let src = [1, 2, 3, 4]; - /// let mut dst = [0, 0]; - /// // the `ExternallySharedPtr` type does not work with arrays, so convert `dst` to a slice - /// let slice = &mut dst[..]; - /// let mut shared = unsafe { ExternallySharedPtr::new(NonNull::from(slice)) }; - /// // Because the slices have to be the same length, - /// // we slice the source slice from four elements - /// // to two. It will panic if we don't do this. - /// shared.copy_from_slice(&src[2..]); - /// - /// assert_eq!(src, [1, 2, 3, 4]); - /// assert_eq!(dst, [3, 4]); - /// ``` - pub fn copy_from_slice(self, src: &[T]) - where - T: Copy, - A: Writable, - { - let len = self.pointer.len(); - assert_eq!( - len, - src.len(), - "destination and source slices have different lengths" - ); - unsafe { - self.pointer - .as_mut_ptr() - .copy_from_nonoverlapping(src.as_ptr(), len); - } - } - - /// Copies elements from one part of the slice to another part of itself, using `memmove`. - /// - /// `src` is the range within `self` to copy from. `dest` is the starting index of the - /// range within `self` to copy to, which will have the same length as `src`. The two ranges - /// may overlap. The ends of the two ranges must be less than or equal to `self.len()`. - /// - /// This method is only available with the `unstable` feature enabled (requires a nightly - /// Rust compiler). - /// - /// ## Panics - /// - /// This function will panic if either range exceeds the end of the slice, or if the end - /// of `src` is before the start. - /// - /// ## Examples - /// - /// Copying four bytes within a slice: - /// - /// ``` - /// extern crate core; - /// use sel4_externally_shared::ExternallySharedPtr; - /// use core::ptr::NonNull; - /// - /// let mut byte_array = *b"Hello, World!"; - /// let mut slice: &mut [u8] = &mut byte_array[..]; - /// let mut shared = unsafe { ExternallySharedPtr::new(NonNull::from(slice)) }; - /// shared.copy_within(1..5, 8); - /// - /// assert_eq!(&byte_array, b"Hello, Wello!"); - pub fn copy_within(self, src: impl RangeBounds, dest: usize) - where - T: Copy, - A: Readable + Writable, - { - let len = self.pointer.len(); - // implementation taken from https://github.com/rust-lang/rust/blob/683d1bcd405727fcc9209f64845bd3b9104878b8/library/core/src/slice/mod.rs#L2726-L2738 - let Range { - start: src_start, - end: src_end, - } = range(src, ..len); - let count = src_end - src_start; - assert!(dest <= len - count, "dest is out of bounds"); - unsafe { - self.pointer - .as_mut_ptr() - .add(dest) - .copy_from(self.pointer.as_mut_ptr().add(src_start), count); - } - } - - /// Divides one slice into two at an index. - /// - /// The first will contain all indices from `[0, mid)` (excluding - /// the index `mid` itself) and the second will contain all - /// indices from `[mid, len)` (excluding the index `len` itself). - /// - /// # Panics - /// - /// Panics if `mid > len`. - /// - pub fn split_at( - self, - mid: usize, - ) -> ( - ExternallySharedPtr<'a, [T], A>, - ExternallySharedPtr<'a, [T], A>, - ) - where - A: Access, - { - assert!(mid <= self.pointer.len()); - // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which - // fulfills the requirements of `from_raw_parts_mut`. - unsafe { self.split_at_unchecked(mid) } - } - - unsafe fn split_at_unchecked( - self, - mid: usize, - ) -> ( - ExternallySharedPtr<'a, [T], A>, - ExternallySharedPtr<'a, [T], A>, - ) - where - A: Access, - { - // SAFETY: Caller has to check that `0 <= mid <= self.len()` - unsafe { - ( - ExternallySharedPtr::new_generic((self.pointer).get_unchecked_mut(..mid)), - ExternallySharedPtr::new_generic((self.pointer).get_unchecked_mut(mid..)), - ) - } - } - - /// Splits the slice into a slice of `N`-element arrays, - /// starting at the beginning of the slice, - /// and a remainder slice with length strictly less than `N`. - /// - /// # Panics - /// - /// Panics if `N` is 0. - #[allow(clippy::type_complexity)] - pub fn as_chunks( - self, - ) -> ( - ExternallySharedPtr<'a, [[T; N]], A>, - ExternallySharedPtr<'a, [T], A>, - ) - where - A: Access, - { - assert_ne!(N, 0); - let len = self.pointer.len() / N; - let (multiple_of_n, remainder) = self.split_at(len * N); - // SAFETY: We already panicked for zero, and ensured by construction - // that the length of the subslice is a multiple of N. - let array_slice = unsafe { multiple_of_n.as_chunks_unchecked() }; - (array_slice, remainder) - } - - /// Splits the slice into a slice of `N`-element arrays, - /// assuming that there's no remainder. - /// - /// # Safety - /// - /// This may only be called when - /// - The slice splits exactly into `N`-element chunks (aka `self.len() % N == 0`). - /// - `N != 0`. - pub unsafe fn as_chunks_unchecked(self) -> ExternallySharedPtr<'a, [[T; N]], A> - where - A: Access, - { - debug_assert_ne!(N, 0); - debug_assert_eq!(self.pointer.len() % N, 0); - let new_len = - // SAFETY: Our precondition is exactly what's needed to call this - unsafe { core::intrinsics::exact_div(self.pointer.len(), N) }; - // SAFETY: We cast a slice of `new_len * N` elements into - // a slice of `new_len` many `N` elements chunks. - let pointer = NonNull::new(ptr::slice_from_raw_parts_mut( - self.pointer.as_mut_ptr().cast(), - new_len, - )) - .unwrap(); - unsafe { ExternallySharedPtr::new_generic(pointer) } - } - - /// Copies all elements from `self` into a `Vec`. - #[cfg(feature = "alloc")] - pub fn copy_to_vec(&self) -> Vec - where - T: Copy, - { - let src = self.pointer.as_mut_ptr(); - let n = self.pointer.len(); - let mut v = Vec::with_capacity(n); - // SAFETY: - // allocated above with the capacity of `src`, and initialize to `src.len()` in - // ptr::copy_to_non_overlapping below. - unsafe { - src.copy_to_nonoverlapping(v.as_mut_ptr(), n); - v.set_len(n); - } - v - } -} - -/// Methods for wrapped byte slices -impl ExternallySharedPtr<'_, [u8], A> { - /// Sets all elements of the byte slice to the given `value` using `memset`. - /// - /// This method is only available with the `unstable` feature enabled (requires a nightly - /// Rust compiler). - /// - /// ## Example - /// - /// ```rust - /// use sel4_externally_shared::ExternallySharedPtr; - /// use core::ptr::NonNull; - /// - /// let mut vec = vec![0; 10]; - /// let mut buf = unsafe { ExternallySharedPtr::new(NonNull::from(vec.as_mut_slice())) }; - /// buf.fill(1); - /// assert_eq!(unsafe { buf.as_raw_ptr().as_mut() }, &mut vec![1; 10]); - /// ``` - pub fn fill(self, value: u8) - where - A: Writable, - { - unsafe { - self.pointer - .as_mut_ptr() - .write_bytes(value, self.pointer.len()); - } - } -} - -/// Methods for converting arrays to slices -/// -/// These methods are only available with the `unstable` feature enabled (requires a nightly -/// Rust compiler). -impl<'a, T, A, const N: usize> ExternallySharedPtr<'a, [T; N], A> { - /// Converts an array pointer to a slice pointer. - /// - /// This makes it possible to use the methods defined on slices. - /// - /// ## Example - /// - /// Copying two elements from an array reference using `copy_into_slice`: - /// - /// ``` - /// use sel4_externally_shared::ExternallySharedPtr; - /// use core::ptr::NonNull; - /// - /// let src = [1, 2]; - /// let shared = unsafe { ExternallySharedPtr::new_read_only(NonNull::from(&src)) }; - /// let mut dst = [0, 0]; - /// - /// // convert the `ExternallySharedPtr<&[i32; 2]>` array reference to a `ExternallySharedPtr<&[i32]>` slice - /// let shared_slice = shared.as_slice(); - /// // we can now use the slice methods - /// shared_slice.copy_into_slice(&mut dst); - /// - /// assert_eq!(dst, [1, 2]); - /// ``` - pub fn as_slice(self) -> ExternallySharedPtr<'a, [T], A> - where - A: Access, - { - unsafe { - self.map(|array| { - NonNull::new(ptr::slice_from_raw_parts_mut(array.as_ptr() as *mut T, N)).unwrap() - }) - } - } -} - -fn bounds_check(len: usize, index: impl SliceIndex<[()]>) { - const MAX_ARRAY: [(); usize::MAX] = [(); usize::MAX]; - - let bound_check_slice = &MAX_ARRAY[..len]; - let _ = &bound_check_slice[index]; -} diff --git a/crates/sel4-externally-shared/src/externally_shared_ptr/very_unstable.rs b/crates/sel4-externally-shared/src/externally_shared_ptr/very_unstable.rs deleted file mode 100644 index 8780ef26c..000000000 --- a/crates/sel4-externally-shared/src/externally_shared_ptr/very_unstable.rs +++ /dev/null @@ -1,49 +0,0 @@ -use core::ptr::NonNull; - -use crate::ExternallySharedPtr; - -impl<'a, T, A> ExternallySharedPtr<'a, T, A> -where - T: ?Sized, -{ - /// Compile-time evaluable variant of [`Self::map`]. - /// - /// This function is a copy of [`Self::map`] that uses unstable compiler functions - /// to be callable from `const` contexts. - /// - /// ## Safety - /// - /// The safety requirements of [`Self::map`] apply to this method too. - pub const unsafe fn map_const(self, f: F) -> ExternallySharedPtr<'a, U, A> - where - F: ~const FnOnce(NonNull) -> NonNull, - U: ?Sized, - { - unsafe { ExternallySharedPtr::new_generic(f(self.pointer)) } - } -} - -/// Methods for externally shared slices -#[cfg(feature = "unstable")] -impl<'a, T, A> ExternallySharedPtr<'a, [T], A> { - /// Compile-time evaluable variant of [`Self::index`]. - /// - /// This function is a copy of [`Self::index`] that uses unstable compiler functions - /// to be callable from `const` contexts. - pub const fn index_const(self, index: usize) -> ExternallySharedPtr<'a, T, A> { - assert!(index < self.pointer.len(), "index out of bounds"); - - struct Mapper { - index: usize, - } - impl const FnOnce<(NonNull<[T]>,)> for Mapper { - type Output = NonNull; - - extern "rust-call" fn call_once(self, (slice,): (NonNull<[T]>,)) -> Self::Output { - unsafe { NonNull::new_unchecked(slice.as_non_null_ptr().as_ptr().add(self.index)) } - } - } - - unsafe { self.map_const(Mapper { index }) } - } -} diff --git a/crates/sel4-externally-shared/src/externally_shared_ref.rs b/crates/sel4-externally-shared/src/externally_shared_ref.rs deleted file mode 100644 index 9bb275adc..000000000 --- a/crates/sel4-externally-shared/src/externally_shared_ref.rs +++ /dev/null @@ -1,241 +0,0 @@ -use crate::{ - access::{Access, Copyable, ReadOnly, ReadWrite, WriteOnly}, - externally_shared_ptr::ExternallySharedPtr, -}; -use core::{fmt, marker::PhantomData, ptr::NonNull}; - -/// Externally shared pointer type that respects Rust's aliasing rules. -/// -/// This pointer type behaves similar to Rust's reference types: -/// -/// - it requires exclusive `&mut self` access for mutability -/// - only read-only types implement [`Clone`] and [`Copy`] -/// - [`Send`] and [`Sync`] are implemented if `T: Sync` -/// -/// To perform pointer operations on `ExternallySharedRef` types, use the [`as_ptr`][Self::as_ptr] -/// or [`as_mut_ptr`](Self::as_mut_ptr) methods to create a temporary -/// [`ExternallySharedPtr`][crate::ExternallySharedPtr] instance. -/// -/// Since not all externallyshared resources (e.g. memory mapped device registers) are both readable -/// and writable, this type supports limiting the allowed access types through an optional second -/// generic parameter `A` that can be one of `ReadWrite`, `ReadOnly`, or `WriteOnly`. It defaults -/// to `ReadWrite`, which allows all operations. -/// -/// The size of this struct is the same as the size of the contained reference. -#[repr(transparent)] -pub struct ExternallySharedRef<'a, T, A = ReadWrite> -where - T: ?Sized, -{ - pointer: NonNull, - reference: PhantomData<&'a T>, - access: PhantomData, -} - -/// Constructor functions. -/// -/// These functions construct new `ExternallySharedRef` values. While the `new` -/// function creates a `ExternallySharedRef` instance with unrestricted access, there -/// are also functions for creating read-only or write-only instances. -impl<'a, T> ExternallySharedRef<'a, T> -where - T: ?Sized, -{ - /// Turns the given pointer into a `ExternallySharedRef`. - /// - /// ## Safety - /// - /// - The pointer must be properly aligned. - /// - It must be “dereferenceable” in the sense defined in the [`core::ptr`] documentation. - /// - The pointer must point to an initialized instance of T. - /// - You must enforce Rust’s aliasing rules, since the returned lifetime 'a is arbitrarily - /// chosen and does not necessarily reflect the actual lifetime of the data. In particular, - /// while this `ExternallySharedRef` exists, the memory the pointer points to must not get accessed - /// (_read or written_) through any other pointer. - pub unsafe fn new(pointer: NonNull) -> Self { - unsafe { ExternallySharedRef::new_restricted(ReadWrite, pointer) } - } - - /// Turns the given pointer into a read-only `ExternallySharedRef`. - /// - /// ## Safety - /// - /// - The pointer must be properly aligned. - /// - It must be “dereferenceable” in the sense defined in the [`core::ptr`] documentation. - /// - The pointer must point to an initialized instance of T. - /// - You must enforce Rust’s aliasing rules, since the returned lifetime 'a is arbitrarily - /// chosen and does not necessarily reflect the actual lifetime of the data. In particular, - /// while this `ExternallySharedRef` exists, the memory the pointer points to _must not get mutated_. - pub const unsafe fn new_read_only(pointer: NonNull) -> ExternallySharedRef<'a, T, ReadOnly> { - unsafe { Self::new_restricted(ReadOnly, pointer) } - } - - /// Turns the given pointer into a `ExternallySharedRef` instance with the given access. - /// - /// ## Safety - /// - /// - The pointer must be properly aligned. - /// - It must be “dereferenceable” in the sense defined in the [`core::ptr`] documentation. - /// - The pointer must point to an initialized instance of T. - /// - You must enforce Rust’s aliasing rules, since the returned lifetime 'a is arbitrarily - /// chosen and does not necessarily reflect the actual lifetime of the data. In particular, - /// while this `ExternallySharedRef` exists, the memory the pointer points to _must not get mutated_. - /// If the given `access` parameter allows write access, the pointer _must not get read - /// either_ while this `ExternallySharedRef` exists. - pub const unsafe fn new_restricted( - access: A, - pointer: NonNull, - ) -> ExternallySharedRef<'a, T, A> - where - A: Access, - { - let _ = access; - unsafe { Self::new_generic(pointer) } - } - - /// Creates a `ExternallySharedRef` from the given shared reference. - /// - /// **Note:** This function is only intended for testing. - pub fn from_ref(reference: &'a T) -> ExternallySharedRef<'a, T, ReadOnly> - where - T: 'a, - { - unsafe { ExternallySharedRef::new_restricted(ReadOnly, reference.into()) } - } - - /// Creates a `ExternallySharedRef` from the given mutable reference. - /// - /// **Note:** This function is only intended for testing. - pub fn from_mut_ref(reference: &'a mut T) -> Self - where - T: 'a, - { - unsafe { ExternallySharedRef::new(reference.into()) } - } - - const unsafe fn new_generic(pointer: NonNull) -> ExternallySharedRef<'a, T, A> { - ExternallySharedRef { - pointer, - reference: PhantomData, - access: PhantomData, - } - } -} - -impl<'a, T, A> ExternallySharedRef<'a, T, A> -where - T: ?Sized, -{ - /// Borrows this `ExternallySharedRef` as a read-only [`ExternallySharedPtr`]. - /// - /// Use this method to do (partial) reads of the referenced data. - pub fn as_ptr(&self) -> ExternallySharedPtr<'_, T, A::RestrictShared> - where - A: Access, - { - unsafe { ExternallySharedPtr::new_restricted(Default::default(), self.pointer) } - } - - /// Borrows this `ExternallySharedRef` as a mutable [`ExternallySharedPtr`]. - /// - /// Use this method to do (partial) reads or writes of the referenced data. - pub fn as_mut_ptr(&mut self) -> ExternallySharedPtr<'_, T, A> - where - A: Access, - { - unsafe { ExternallySharedPtr::new_restricted(Default::default(), self.pointer) } - } - - /// Converts this `ExternallySharedRef` into a [`ExternallySharedPtr`] with full access without shortening - /// the lifetime. - /// - /// Use this method when you need a [`ExternallySharedPtr`] instance that lives for the full - /// lifetime `'a`. - /// - /// This method consumes the `ExternallySharedRef`. - pub fn into_ptr(self) -> ExternallySharedPtr<'a, T, A> - where - A: Access, - { - unsafe { ExternallySharedPtr::new_restricted(Default::default(), self.pointer) } - } -} - -/// Methods for restricting access. -impl<'a, T> ExternallySharedRef<'a, T, ReadWrite> -where - T: ?Sized, -{ - /// Restricts access permissions to read-only. - /// - /// ## Example - /// - /// ``` - /// use sel4_externally_shared::ExternallySharedRef; - /// use core::ptr::NonNull; - /// - /// let mut value: i16 = -4; - /// let mut shared = ExternallySharedRef::from_mut_ref(&mut value); - /// - /// let read_only = shared.read_only(); - /// assert_eq!(read_only.as_ptr().read(), -4); - /// // read_only.as_ptr().write(10); // compile-time error - /// ``` - pub fn read_only(self) -> ExternallySharedRef<'a, T, ReadOnly> { - unsafe { ExternallySharedRef::new_restricted(ReadOnly, self.pointer) } - } - - /// Restricts access permissions to write-only. - /// - /// ## Example - /// - /// Creating a write-only reference to a struct field: - /// - /// ``` - /// use sel4_externally_shared::{ExternallySharedRef}; - /// use core::ptr::NonNull; - /// - /// #[derive(Clone, Copy)] - /// struct Example { field_1: u32, field_2: u8, } - /// let mut value = Example { field_1: 15, field_2: 255 }; - /// let mut shared = ExternallySharedRef::from_mut_ref(&mut value); - /// - /// let write_only = shared.write_only(); - /// // write_only.as_ptr().read(); // compile-time error - /// ``` - pub fn write_only(self) -> ExternallySharedRef<'a, T, WriteOnly> { - unsafe { ExternallySharedRef::new_restricted(WriteOnly, self.pointer) } - } -} - -impl<'a, T, A> Clone for ExternallySharedRef<'a, T, A> -where - T: ?Sized, - A: Access + Copyable, -{ - fn clone(&self) -> Self { - *self - } -} - -impl<'a, T, A> Copy for ExternallySharedRef<'a, T, A> -where - T: ?Sized, - A: Access + Copyable, -{ -} - -unsafe impl Send for ExternallySharedRef<'_, T, A> where T: Sync + ?Sized {} -unsafe impl Sync for ExternallySharedRef<'_, T, A> where T: Sync + ?Sized {} - -impl fmt::Debug for ExternallySharedRef<'_, T, A> -where - T: Copy + fmt::Debug + ?Sized, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ExternallySharedRef") - .field("pointer", &self.pointer) - .field("access", &self.access) - .finish() - } -} diff --git a/crates/sel4-externally-shared/src/lib.rs b/crates/sel4-externally-shared/src/lib.rs index a91eaf19d..63c61c995 100644 --- a/crates/sel4-externally-shared/src/lib.rs +++ b/crates/sel4-externally-shared/src/lib.rs @@ -1,26 +1,55 @@ -//! Provides wrapper types for raw pointers to externally shared data. -//! -//! This crate provides two different wrapper types: [`ExternallySharedPtr`] and [`ExternallySharedRef`]. The -//! difference between the two types is that the former behaves like a raw pointer, while the -//! latter behaves like a Rust reference type. - #![no_std] -#![cfg_attr(feature = "unstable", feature(atomic_from_ptr))] -#![cfg_attr(feature = "unstable", feature(core_intrinsics))] -#![cfg_attr(feature = "unstable", feature(slice_range))] -#![cfg_attr(feature = "unstable", feature(slice_ptr_get))] -#![cfg_attr(feature = "very_unstable", feature(const_trait_impl))] -#![cfg_attr(feature = "very_unstable", feature(unboxed_closures))] -#![cfg_attr(feature = "very_unstable", feature(fn_traits))] -#![warn(missing_docs)] -#![deny(unsafe_op_in_unsafe_fn)] - -#[cfg(feature = "alloc")] -extern crate alloc; - -pub use externally_shared_ptr::ExternallySharedPtr; -pub use externally_shared_ref::ExternallySharedRef; - -pub mod access; -mod externally_shared_ptr; -mod externally_shared_ref; +#![feature(cfg_target_has_atomic_equal_alignment)] +#![feature(concat_idents)] +#![feature(core_intrinsics)] + +use core::ptr::NonNull; + +use volatile::{ + access::{Access, ReadWrite}, + VolatilePtr, VolatileRef, +}; + +pub use volatile::{access, map_field}; + +mod atomics; +mod ops; + +pub use atomics::{Atomic, AtomicPtr}; +pub use ops::{ByteWiseOps, DistrustfulOps, NormalOps, UnorderedAtomicOps}; + +// TODO +pub type ExternallySharedOps = DistrustfulOps; +// pub type ExternallySharedOps = DistrustfulOps; +// pub type ExternallySharedOps = DistrustfulOps>; + +pub type ExternallySharedRef<'a, T, A = ReadWrite> = VolatileRef<'a, T, A, ExternallySharedOps>; + +pub type ExternallySharedPtr<'a, T, A = ReadWrite> = VolatilePtr<'a, T, A, ExternallySharedOps>; + +pub trait ExternallySharedRefExt<'a, T: ?Sized, A: Access> { + unsafe fn new(pointer: NonNull) -> ExternallySharedRef<'a, T, A>; +} + +impl<'a, T: ?Sized, A: Access> ExternallySharedRefExt<'a, T, A> for ExternallySharedRef<'a, T, A> { + unsafe fn new(pointer: NonNull) -> ExternallySharedRef<'a, T, A> { + unsafe { + VolatileRef::new_restricted_with_ops(Default::default(), Default::default(), pointer) + } + } +} + +pub trait ExternallySharedPtrExt<'a, T: ?Sized, A> { + fn atomic(self) -> AtomicPtr<'a, T, A> + where + T: Atomic; +} + +impl<'a, T: ?Sized, A> ExternallySharedPtrExt<'a, T, A> for ExternallySharedPtr<'a, T, A> { + fn atomic(self) -> AtomicPtr<'a, T, A> + where + T: Atomic, + { + unsafe { AtomicPtr::new(self.as_raw_ptr()) } + } +} diff --git a/crates/sel4-externally-shared/src/ops/bytewise_ops.rs b/crates/sel4-externally-shared/src/ops/bytewise_ops.rs new file mode 100644 index 000000000..aba2f85b5 --- /dev/null +++ b/crates/sel4-externally-shared/src/ops/bytewise_ops.rs @@ -0,0 +1,44 @@ +#![cfg_attr(not(feature = "unstable"), allow(unused_imports))] + +use core::mem; + +use volatile::ops::{Ops, UnitaryOps}; +use zerocopy::{AsBytes, FromBytes}; + +#[cfg(feature = "unstable")] +use volatile::ops::BulkOps; + +#[derive(Debug, Default, Copy, Clone)] +pub struct ByteWiseOps(O); + +impl Ops for ByteWiseOps {} + +#[cfg(feature = "unstable")] +impl, T: FromBytes + AsBytes> UnitaryOps for ByteWiseOps { + unsafe fn read(src: *const T) -> T { + let mut val = T::new_zeroed(); + let view = val.as_bytes_mut(); + unsafe { O::memcpy(view.as_mut_ptr(), src.cast(), mem::size_of::()) }; + val + } + + unsafe fn write(dst: *mut T, src: T) { + let view = src.as_bytes(); + unsafe { O::memcpy(dst.cast(), view.as_ptr(), mem::size_of::()) }; + } +} + +#[cfg(feature = "unstable")] +impl, T: FromBytes + AsBytes> BulkOps for ByteWiseOps { + unsafe fn memmove(dst: *mut T, src: *const T, count: usize) { + unsafe { O::memmove(dst.cast(), src.cast(), count * mem::size_of::()) } + } + + unsafe fn memcpy(dst: *mut T, src: *const T, count: usize) { + unsafe { O::memcpy(dst.cast(), src.cast(), count * mem::size_of::()) } + } + + unsafe fn memset(dst: *mut T, val: u8, count: usize) { + unsafe { O::memset(dst.cast(), val, count * mem::size_of::()) } + } +} diff --git a/crates/sel4-externally-shared/src/ops/distrustful_ops.rs b/crates/sel4-externally-shared/src/ops/distrustful_ops.rs new file mode 100644 index 000000000..d1e980fb8 --- /dev/null +++ b/crates/sel4-externally-shared/src/ops/distrustful_ops.rs @@ -0,0 +1,35 @@ +use volatile::ops::{Ops, UnitaryOps}; +use zerocopy::{AsBytes, FromBytes}; + +#[cfg(feature = "unstable")] +use volatile::ops::BulkOps; + +#[derive(Debug, Default, Copy, Clone)] +pub struct DistrustfulOps(O); + +impl Ops for DistrustfulOps {} + +impl, T: FromBytes + AsBytes> UnitaryOps for DistrustfulOps { + unsafe fn read(src: *const T) -> T { + unsafe { O::read(src) } + } + + unsafe fn write(dst: *mut T, src: T) { + unsafe { O::write(dst, src) } + } +} + +#[cfg(feature = "unstable")] +impl, T: FromBytes + AsBytes> BulkOps for DistrustfulOps { + unsafe fn memmove(dst: *mut T, src: *const T, count: usize) { + unsafe { O::memmove(dst, src, count) } + } + + unsafe fn memcpy(dst: *mut T, src: *const T, count: usize) { + unsafe { O::memcpy(dst, src, count) } + } + + unsafe fn memset(dst: *mut T, val: u8, count: usize) { + unsafe { O::memset(dst, val, count) } + } +} diff --git a/crates/sel4-externally-shared/src/ops/mod.rs b/crates/sel4-externally-shared/src/ops/mod.rs new file mode 100644 index 000000000..b94d82e8c --- /dev/null +++ b/crates/sel4-externally-shared/src/ops/mod.rs @@ -0,0 +1,9 @@ +mod bytewise_ops; +mod distrustful_ops; +mod normal_ops; +mod unordered_atomic_ops; + +pub use bytewise_ops::ByteWiseOps; +pub use distrustful_ops::DistrustfulOps; +pub use normal_ops::NormalOps; +pub use unordered_atomic_ops::UnorderedAtomicOps; diff --git a/crates/sel4-externally-shared/src/ops/normal_ops.rs b/crates/sel4-externally-shared/src/ops/normal_ops.rs new file mode 100644 index 000000000..9afe43f97 --- /dev/null +++ b/crates/sel4-externally-shared/src/ops/normal_ops.rs @@ -0,0 +1,36 @@ +use core::ptr; + +use volatile::ops::{Ops, UnitaryOps}; + +#[cfg(feature = "unstable")] +use volatile::ops::BulkOps; + +#[derive(Debug, Default, Copy, Clone)] +pub struct NormalOps; + +impl Ops for NormalOps {} + +impl UnitaryOps for NormalOps { + unsafe fn read(src: *const T) -> T { + unsafe { ptr::read(src) } + } + + unsafe fn write(dst: *mut T, src: T) { + unsafe { ptr::write(dst, src) } + } +} + +#[cfg(feature = "unstable")] +impl BulkOps for NormalOps { + unsafe fn memmove(dst: *mut T, src: *const T, count: usize) { + unsafe { ptr::copy(src, dst, count) } + } + + unsafe fn memcpy(dst: *mut T, src: *const T, count: usize) { + unsafe { ptr::copy_nonoverlapping(src, dst, count) } + } + + unsafe fn memset(dst: *mut T, val: u8, count: usize) { + unsafe { ptr::write_bytes(dst, val, count) } + } +} diff --git a/crates/sel4-externally-shared/src/ops/unordered_atomic_ops.rs b/crates/sel4-externally-shared/src/ops/unordered_atomic_ops.rs new file mode 100644 index 000000000..3f9d8b488 --- /dev/null +++ b/crates/sel4-externally-shared/src/ops/unordered_atomic_ops.rs @@ -0,0 +1,140 @@ +#![cfg_attr(not(feature = "unstable"), allow(dead_code))] +#![cfg_attr(not(feature = "unstable"), allow(unused_imports))] + +use core::mem; + +#[cfg(feature = "unstable")] +use core::intrinsics; + +use volatile::ops::{Ops, UnitaryOps}; + +#[cfg(feature = "unstable")] +use volatile::ops::BulkOps; + +#[derive(Debug, Default, Copy, Clone)] +pub struct UnorderedAtomicOps; + +impl Ops for UnorderedAtomicOps {} + +#[cfg(feature = "unstable")] +impl UnitaryOps for UnorderedAtomicOps { + unsafe fn read(src: *const T) -> T { + unsafe { intrinsics::atomic_load_unordered(src) } + } + + unsafe fn write(dst: *mut T, src: T) { + unsafe { intrinsics::atomic_store_unordered(dst, src) } + } +} + +pub unsafe trait UnsignedPrimitiveWithUnorderedAtomics {} + +macro_rules! impl_unsigned_primitive_with_unordered_atomics { + ($prim:path, $target_has_atomic_key:literal, $bulk_op_suffix:ident) => { + #[cfg(target_has_atomic = $target_has_atomic_key)] + unsafe impl UnsignedPrimitiveWithUnorderedAtomics for $prim {} + + #[cfg(feature = "unstable")] + #[cfg(target_has_atomic = $target_has_atomic_key)] + impl BulkOps<$prim> for UnorderedAtomicOps { + unsafe fn memmove(dst: *mut $prim, src: *const $prim, count: usize) { + unsafe { + concat_idents!(__llvm_memmove_element_unordered_atomic, $bulk_op_suffix)( + dst, + src, + count * mem::size_of::<$prim>(), + ) + } + } + + unsafe fn memcpy(dst: *mut $prim, src: *const $prim, count: usize) { + unsafe { + concat_idents!(__llvm_memcpy_element_unordered_atomic, $bulk_op_suffix)( + dst, + src, + count * mem::size_of::<$prim>(), + ) + } + } + + unsafe fn memset(dst: *mut $prim, val: u8, count: usize) { + unsafe { + concat_idents!(__llvm_memset_element_unordered_atomic, $bulk_op_suffix)( + dst, + val, + count * mem::size_of::<$prim>(), + ) + } + } + } + }; +} + +impl_unsigned_primitive_with_unordered_atomics!(u8, "8", _1); +impl_unsigned_primitive_with_unordered_atomics!(u16, "16", _2); +impl_unsigned_primitive_with_unordered_atomics!(u32, "32", _4); +impl_unsigned_primitive_with_unordered_atomics!(u64, "64", _8); + +#[cfg(target_pointer_width = "32")] +type UsizeCastTarget = u32; + +#[cfg(target_pointer_width = "64")] +type UsizeCastTarget = u64; + +#[cfg(feature = "unstable")] +#[cfg(any( + all(target_pointer_width = "32", target_has_atomic = "32"), + all(target_pointer_width = "64", target_has_atomic = "64"), +))] +impl BulkOps for UnorderedAtomicOps { + unsafe fn memmove(dst: *mut usize, src: *const usize, count: usize) { + unsafe { + >::memmove(dst.cast(), src.cast(), count) + } + } + + unsafe fn memcpy(dst: *mut usize, src: *const usize, count: usize) { + unsafe { + >::memcpy(dst.cast(), src.cast(), count) + } + } + + unsafe fn memset(dst: *mut usize, val: u8, count: usize) { + unsafe { >::memset(dst.cast(), val, count) } + } +} + +macro_rules! decl_intrinsics { + ($ty:ty, $memcpy:ident, $memmove:ident, $memset:ident) => { + fn $memcpy(dest: *mut $ty, src: *const $ty, bytes: usize); + fn $memmove(dest: *mut $ty, src: *const $ty, bytes: usize); + fn $memset(s: *mut $ty, c: u8, bytes: usize); + }; +} + +extern "C" { + decl_intrinsics!( + u8, + __llvm_memcpy_element_unordered_atomic_1, + __llvm_memmove_element_unordered_atomic_1, + __llvm_memset_element_unordered_atomic_1 + ); + decl_intrinsics!( + u16, + __llvm_memcpy_element_unordered_atomic_2, + __llvm_memmove_element_unordered_atomic_2, + __llvm_memset_element_unordered_atomic_2 + ); + decl_intrinsics!( + u32, + __llvm_memcpy_element_unordered_atomic_4, + __llvm_memmove_element_unordered_atomic_4, + __llvm_memset_element_unordered_atomic_4 + ); + decl_intrinsics!( + u64, + __llvm_memcpy_element_unordered_atomic_8, + __llvm_memmove_element_unordered_atomic_8, + __llvm_memset_element_unordered_atomic_8 + ); +} diff --git a/crates/sel4-shared-ring-buffer/src/lib.rs b/crates/sel4-shared-ring-buffer/src/lib.rs index 6a13e2f87..37f73e1eb 100644 --- a/crates/sel4-shared-ring-buffer/src/lib.rs +++ b/crates/sel4-shared-ring-buffer/src/lib.rs @@ -4,7 +4,11 @@ use core::marker::PhantomData; use core::num::Wrapping; use core::sync::atomic::Ordering; -use sel4_externally_shared::{map_field, ExternallySharedPtr, ExternallySharedRef}; +use zerocopy::{AsBytes, FromBytes}; + +use sel4_externally_shared::{ + map_field, ExternallySharedPtr, ExternallySharedPtrExt, ExternallySharedRef, +}; pub mod roles; @@ -209,7 +213,7 @@ impl<'a, R: RingBufferRole, T: Copy> RingBuffer<'a, R, T> { } } -impl<'a, T: Copy> RingBuffer<'a, Write, T> { +impl<'a, T: Copy + FromBytes + AsBytes> RingBuffer<'a, Write, T> { pub fn enqueue_and_commit(&mut self, desc: T) -> Result, PeerMisbehaviorError> { self.enqueue(desc, true) } @@ -248,11 +252,12 @@ impl<'a, T: Copy> RingBuffer<'a, Write, T> { fn expose_write_index(&mut self) { let write_index = self.stored_write_index.0; self.write_index() - .with_atomic(|x| x.store(write_index, Ordering::Release)); + .atomic() + .store(write_index, Ordering::Release); } } -impl<'a, T: Copy> RingBuffer<'a, Read, T> { +impl<'a, T: Copy + FromBytes + AsBytes> RingBuffer<'a, Read, T> { pub fn dequeue(&mut self) -> Result, PeerMisbehaviorError> { if self.is_empty()? { return Ok(None); @@ -270,7 +275,8 @@ impl<'a, T: Copy> RingBuffer<'a, Read, T> { fn expose_read_index(&mut self) { let read_index = self.stored_read_index.0; self.read_index() - .with_atomic(|x| x.store(read_index, Ordering::Release)); + .atomic() + .store(read_index, Ordering::Release); } } diff --git a/hacking/cargo-manifest-sources/crates/examples/microkit/banscii/pds/artist/crate.nix b/hacking/cargo-manifest-sources/crates/examples/microkit/banscii/pds/artist/crate.nix index bf259e689..da16135a2 100644 --- a/hacking/cargo-manifest-sources/crates/examples/microkit/banscii/pds/artist/crate.nix +++ b/hacking/cargo-manifest-sources/crates/examples/microkit/banscii/pds/artist/crate.nix @@ -5,7 +5,7 @@ mk { dependencies = { sel4-microkit = { default-features = false; features = [ "alloc" ]; }; rsa = { version = "0.8.1"; default-features = false; features = [ "pem" "sha2" ]; }; - sel4-externally-shared.features = [ "unstable" "alloc" ]; + sel4-externally-shared.features = [ "unstable" ]; }; build-dependencies = { rsa = "0.8.1"; diff --git a/hacking/cargo-manifest-sources/crates/examples/microkit/banscii/pds/assistant/crate.nix b/hacking/cargo-manifest-sources/crates/examples/microkit/banscii/pds/assistant/crate.nix index 1b4a6b430..d186371c5 100644 --- a/hacking/cargo-manifest-sources/crates/examples/microkit/banscii/pds/assistant/crate.nix +++ b/hacking/cargo-manifest-sources/crates/examples/microkit/banscii/pds/assistant/crate.nix @@ -13,6 +13,6 @@ mk { dependencies = { sel4-microkit = { default-features = false; features = [ "alloc" ]; }; hex = { version = "0.4.3"; default-features = false; features = [ "alloc" ]; }; - sel4-externally-shared.features = [ "unstable" "alloc" ]; + sel4-externally-shared.features = [ "unstable" ]; }; } diff --git a/hacking/cargo-manifest-sources/crates/examples/microkit/http-server/pds/server/crate.nix b/hacking/cargo-manifest-sources/crates/examples/microkit/http-server/pds/server/crate.nix index b13516509..95b7828f3 100644 --- a/hacking/cargo-manifest-sources/crates/examples/microkit/http-server/pds/server/crate.nix +++ b/hacking/cargo-manifest-sources/crates/examples/microkit/http-server/pds/server/crate.nix @@ -31,7 +31,7 @@ mk { ]; sel4-microkit = { default-features = false; features = [ "alloc" ]; }; - sel4-externally-shared.features = [ "unstable" "alloc" ]; + sel4-externally-shared.features = [ "unstable" ]; }; build-dependencies = { rcgen = "0.11.1"; diff --git a/hacking/cargo-manifest-sources/crates/private/meta/crate.nix b/hacking/cargo-manifest-sources/crates/private/meta/crate.nix index b4ea3311f..c28578c5a 100644 --- a/hacking/cargo-manifest-sources/crates/private/meta/crate.nix +++ b/hacking/cargo-manifest-sources/crates/private/meta/crate.nix @@ -35,7 +35,7 @@ mk { ]; dependencies = { inherit (versions) cfg-if log; - sel4-externally-shared = { features = [ "alloc" "unstable" "very_unstable" ]; }; + sel4-externally-shared = { features = [ "unstable" "very_unstable" ]; }; sel4-root-task = { features = [ "full" ]; optional = true; }; sel4-microkit = { features = [ "full" ]; optional = true; }; sel4-microkit-message = { optional = true; }; diff --git a/hacking/cargo-manifest-sources/crates/sel4-externally-shared/crate.nix b/hacking/cargo-manifest-sources/crates/sel4-externally-shared/crate.nix index 0b8d8471d..0cbda4984 100644 --- a/hacking/cargo-manifest-sources/crates/sel4-externally-shared/crate.nix +++ b/hacking/cargo-manifest-sources/crates/sel4-externally-shared/crate.nix @@ -1,14 +1,16 @@ -{ mk }: +{ mk, localCrates, versions, volatileSource }: mk { package.name = "sel4-externally-shared"; - package.license = "MIT OR Apache-2.0"; - features = { - alloc = []; - unstable = []; - very_unstable = ["unstable"]; + nix.local.dependencies = with localCrates; [ + # volatile + ]; + dependencies = { + inherit (versions) zerocopy; + volatile = volatileSource; }; - dev-dependencies = { - rand = "0.8.3"; + features = { + "unstable" = [ "volatile/unstable" ]; + "very_unstable" = [ "volatile/very_unstable" ]; }; } diff --git a/hacking/nix/scope/generated-cargo-manifests/default.nix b/hacking/nix/scope/generated-cargo-manifests/default.nix index 422806b8d..f79df2fa3 100644 --- a/hacking/nix/scope/generated-cargo-manifests/default.nix +++ b/hacking/nix/scope/generated-cargo-manifests/default.nix @@ -48,6 +48,7 @@ let # "mbedtls-sys-auto" = "tmp/rust-mbedtls/mbedtls-sys"; # "mbedtls-platform-support" = "tmp/rust-mbedtls/mbedtls-platform-support"; # "embedded-fat" = "tmp/rust-embedded-fat"; + # "volatile" = "tmp/volatile"; }; cratePathAttrs = localCratePathAttrs // externalCratePathAttrs; @@ -166,12 +167,16 @@ let "packetmeta-id" "async" ]; + volatileSource = { + git = "https://github.com/coliasgroup/volatile.git"; + tag = "keep/8aee5539716d3d38247f46eddd42b382"; # branch coliasgroup + }; + fatSource = { git = "https://github.com/coliasgroup/rust-embedded-fat.git"; tag = "keep/e1465a43c9f550ef58701a275b313310"; # branch sel4 }; - mbedtlsSource = { git = "https://github.com/coliasgroup/rust-mbedtls"; tag = "keep/30d001b63baea36135b2590c4fd05e95"; # branch sel4