Skip to content

Kernel: Adjustments to unsafe code - #2600

Open
jamesmunns wants to merge 9 commits into
masterfrom
james/unsafe-tweaks
Open

Kernel: Adjustments to unsafe code#2600
jamesmunns wants to merge 9 commits into
masterfrom
james/unsafe-tweaks

Conversation

@jamesmunns

Copy link
Copy Markdown
Contributor

The following is a number of tweaks to the kernel code that in my opinion, make some of the unsafe code a bit more direct to follow. In particular, these changes:

  1. Consolidates switch_to as a single method on Task, rather than one version in syscalls.rs, and a handful of semantically-equal copy/pastes
  2. Removes as many single/double blind as casts as is reasonable, e.g. x as *const _ as *mut _, replacing them with discrete steps that note the implicit casts (references to pointer), and explicit casts, using ptr::cast()
  3. Reduces unsafe usage a bit in startup when initializing each task slot
  4. Makes some methods take &mut Task instead of &Task, as these are used for setting CURRENT_TASK_PTR, which semantically allows us to write-through to that address (often in assembly) when returning to the kernel, and that feels a little sketch to me doing from a pointer with shared provenance
  5. Adjusts the codegen for Task slots from MaybeUninit<[Task; N]> to [MaybeUninit<Task>; N], as this makes startup a little less awkward

In my opinion, none of these are strictly necessary for soundness, so if we don't want to touch it, I could definitely understand that!

I think 1, 2, and 3 are pretty clear readability/clarity wins.

I think 4 is maybe a little nitpicky, and is a bit more semantically correct, but also unlikely to cause miscompilations in practice.

I think 5 is maybe a mixed bag (we can still make the changes for 3 without 5), and I need to check it isn't going to make humility upset as the types have changed (even though the before/after are guaranteed to have the same layout and semantics).

Happy to revert any chunks, or rework these into separate commits if that makes reviewing easier.

This is extracted from #2592, and most of these were noticed while I was hacking around on that.

@jamesmunns
jamesmunns requested review from cbiffle, hawkw and labbott July 17, 2026 12:23
@jamesmunns

Copy link
Copy Markdown
Contributor Author

Annoyingly, the RAM usage for g070 didn't increase because we are using more, it's just a quirk that the linker isn't packing statics as intelligently as it possibly could.

Screenshot 2026-07-17 at 15 14 40

Comment thread sys/kern/build.rs
Comment on lines +429 to +430
[core::mem::MaybeUninit<crate::task::Task>; HUBRIS_TASK_COUNT] =
[const { core::mem::MaybeUninit::uninit() }; HUBRIS_TASK_COUNT];

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

You certainly know more about this area than I do but is this a functional change? I don't think so but this is also accessed via humility so is there any chance this could be disruptive there?

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.

To the best of my knowledge an "executable" perspective, this is not a functional change: MaybeUninit is repr(transparent), therefore:

  • MaybeUninit<T> is the same size + align as T
  • MaybeUninit<[T; N]> is the same size + align as [T; N]

If this wasn't the case, this AsRef impl which is stable and safe, wouldn't be sound.

It might cause problems for humility, depending on how we access this symbol. The name and size are the same, but it might be a noticeable type change. I'll test this before going to merge it.

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.

I agree that this is probably not a functional change from Hubris' perspective and shouldn't actually impact how this is initialized. But, I think we should definitely check if it changes the DWARF in a way that makes Humility sad. If it does, it should be okay to change Humility to handle either type, just a bit annoying.

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.

Hilariously, I think we're good on this. Running humility tasks and humility dump, both over SWD and net-hiffy, works to totally fine, and I think it's because for legacy compat reasons, we return a base pointer and task count here:

https://github.com/oxidecomputer/humility/blob/68e7d145f633706fcf51a28071c637b48c70ca96/humility-core/src/hubris.rs#L1929-L1957

We then read back Task sized objects from the read blobs, which means it doesn't care about this shape change!

Comment thread sys/kern/src/startup.rs Outdated
Comment thread sys/kern/src/task.rs
Comment thread app/donglet/app-g031.toml
// this frame.
task.save_mut().psp = frame as *const _ as u32;
let frame: *const ExtendedExceptionFrame = frame;
task.save_mut().psp = frame as u32;

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.

i wonder if it would be more pedantically correct to use expose_provenance here? i do not think it actually matters, since from strict provenance's perspective, we are never actually turning the u32 back into a pointer in the kernel (while this does happen, it happens in the task when we return from the syscall and not in a way that's visible to Rust)... but it seems like this could technically be treated as a provenance exposing cast?

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.

I'm somewhat of the opinion that "that's another program's data", and it isn't necessarily relevant to us, the kernel.

The hardware itself swaps from psp back to msp before re-entering the kernel in an interrupt, so I don't think it's necessary. That explanation is all a little handwavey though.

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.

for the record, i also don't think it's necessary, i was thinking more from a position of "is this something we should generally be in the habit of doing?"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The expose_provenance docs specifically state: "This is equivalent to self as usize ... Furthermore, this (like the as cast) has the [...] effect of marking the provenance of 'exposed'" so there doesn't seem to be absolute any difference between these to.

What would be interesting if you could use addr(): probably not if it's the hardware using this data.

Comment thread sys/kern/src/arch/arm_m.rs

@aapoalas aapoalas left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please excuse my unrequested comments; the topic called out to me.

[[config.i2c.devices]]
controller = 1
mux = 1
segment = 1

@aapoalas aapoalas Jul 17, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

thought: Meh, I wish there was toml formatting. (Mostly because my editor formats it automatically, and has caused annoyance in PRs :) )

Comment thread sys/kern/src/task.rs
// this frame.
task.save_mut().psp = frame as *const _ as u32;
let frame: *const ExtendedExceptionFrame = frame;
task.save_mut().psp = frame as u32;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The expose_provenance docs specifically state: "This is equivalent to self as usize ... Furthermore, this (like the as cast) has the [...] effect of marking the provenance of 'exposed'" so there doesn't seem to be absolute any difference between these to.

What would be interesting if you could use addr(): probably not if it's the hardware using this data.

Comment thread sys/kern/src/task.rs Outdated
jamesmunns added a commit that referenced this pull request Aug 6, 2026
also add a contrasting comment vs static-cell

Similar to #2600.
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.

4 participants