Skip to content

Make PhysicalMapping safely Send / Sync - #361

Merged
IsaacWoods merged 3 commits into
rust-osdev:mainfrom
martin-hughes:safer-physical-mapping
Oct 4, 2026
Merged

IsaacWoods merged 3 commits into
rust-osdev:mainfrom
martin-hughes:safer-physical-mapping

Conversation

@martin-hughes

Copy link
Copy Markdown
Contributor

The aim of this PR is to close #324 by getting the correct Send/Sync annotations on relevant types (such as PhysicalMapping and WrappedObject).

This is a work-in-progress. The outstanding work is to figure out what to do with NativeMethod.

As mentioned in #324, PhysicalMapping presented an interface that was not truly Send or Sync due to the public access to the virtual_start: NonNull<T>.

I've made it correct by hiding that field (* although access is still allowed if needed through an unsafe function!) / only allowing access through the deref methods, and I've increased the difficulty of misusing PhysicalMapping and RawPhysicalMapping by making their fields be private.

That would fix @ChocolateLoverRaj's initial request in #324 to have Sync for FixedRegisters.

If WrappedObject is Send + Sync then this would allow Interpreter to truly be Send + Sync, thus fixing @ChocolateLoverRaj's request to be able to store Interpreter globally. However, via Object and NativeMethod, WrappedObject is not Send + Sync.

In this PR I've marked it as though it is - it tries to be, but isn't. For this PR to be ready, those lines really need removing.

Happy to take thoughts/comments from anyone interested: @ChocolateLoverRaj, @IsaacWoods and anyone else.

This is a prerequisite to removing the `pub` modifiers. Without moving
these structs, the fields are visible to the whole crate, which removes
much of the benefit of making the interface safer.
@martin-hughes

Copy link
Copy Markdown
Contributor Author

Definitely should have tested this after rebasing onto the newest main 😭

The internals of `RawPhysicalMapping` and `PhysicalMapping` have been
hidden, and can now only ba accessed via accessors.

This is largely for the purpose of hiding `virtual_start`, to allow for
an interface that can be made Send & Sync. The other fields are hidden
for consistency.
@martin-hughes martin-hughes changed the title Draft: Add correct Send/Sync annotations to relevant types Make PhysicalMapping safely Send / Sync Sep 23, 2026
@martin-hughes

Copy link
Copy Markdown
Contributor Author

I've had a think about it, and decided that the WrappedObject and NativeMethod changes needed would be a bit too much and clutter up this PR. So I've focussed it purely on PhysicalMapping, which also makes FixedRegisters Sync.

Ready for review.

@martin-hughes
martin-hughes marked this pull request as ready for review September 23, 2026 19:52

// If all other types are correctly labelled with Send and/or Sync, then Interpreter should
// naturally become Send/Sync.
assert_impl_all!(Interpreter<NullHandler>: Send, Sync);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably superfluous given that we've added unsafe impls, but I've left it in as a statement of intent / so it won't be forgotten.

@IsaacWoods IsaacWoods left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies - realised I'd left this as a pending review for a few days! Just some thoughts from my end - thanks for working on this!

Comment thread src/lib.rs Outdated
};
use core::{mem, ptr};
use log::warn;
pub use physical_mapping::{PhysicalMapping, RawPhysicalMapping};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: could we group pub uses together separately to use

Comment thread src/physical_mapping.rs Outdated
Self { physical_start, virtual_start, region_length, mapped_length }
}

pub fn get_physical_start(&self) -> usize {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: applies throughout - just as convention, getters don't need get (e.g. this should just be fn physical_start)

Comment thread src/aml/mod.rs
let stream = unsafe {
slice::from_raw_parts(
mapping.raw.virtual_start.as_ptr().byte_add(mem::size_of::<SdtHeader>()) as *const u8,
ptr::from_ref(&*mapping).byte_add(size_of::<SdtHeader>()) as *const u8,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applies throughout: I get why the pattern here works (Deref to create a reference to the underlying and then turn that into a pointer) but I wonder if unsafe helpers to create pointers directly as_ptr and as_mut would be clearer?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps as_mut_ptr to distinguish it from the existing as_mut from trait AsMut that takes &mut self and returns a mut ref?

(Agree otherwise though, seems sensible)

Comment thread src/address.rs Outdated
// SAFETY: We would really prefer to have a mut ref to mapping here, but that
// requires `&mut self`.
//
// We rely on the write being to memory outside the Rust allocation system in order

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we create helpers as the above, this could move to there as a safety requirement on the caller?

* Remove `get_` from names
* Add `as_ptr` and `as_mut_ptr` helpers to simplify some use cases.
@martin-hughes

Copy link
Copy Markdown
Contributor Author

No worries at all, thanks for the comments - all sensible and addressed, with the exception that I created as_mut_ptr to avoid confusion with other as_mut functions that return a mut ref. Hope that's OK.

@IsaacWoods

IsaacWoods commented Oct 4, 2026 •

Copy link
Copy Markdown
Member

Lovely, thanks :)

At some point we should probably think a little more about provenance (addresses from 'outside' Rust's memory model should likely have their provenance exposed, the rest should likely use the strict provenance APIs a little more etc., but this is obviously a nice improvement in the meantime.

@IsaacWoods
IsaacWoods merged commit a5b0ad1 into rust-osdev:main Oct 4, 2026
6 checks passed
@martin-hughes

Copy link
Copy Markdown
Contributor Author

At some point we should probably think a little more about providence

True - that would be nice to get properly correct! I guess there's scope for a "things to think about" / todo list - perhaps the first wiki page?

@martin-hughes
martin-hughes deleted the safer-physical-mapping branch October 4, 2026 10:25
martin-hughes added a commit to martin-hughes/acpi that referenced this pull request Oct 4, 2026
This makes Object Send + Sync, and by extension WrappedObject (although
gain_mut is still a potential footgun). If rust-osdev#361 is merged as well, then
Interpreter becomes Send + Sync without needing an `unsafe impl` block.
martin-hughes added a commit to martin-hughes/acpi that referenced this pull request Oct 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

impl Sync for FixedRegisters?

2 participants