Skip to content

Comments

Add support for stage-2 page tables#94

Open
m4tx wants to merge 2 commits intogoogle:mainfrom
m4tx:stage-2
Open

Add support for stage-2 page tables#94
m4tx wants to merge 2 commits intogoogle:mainfrom
m4tx:stage-2

Conversation

@m4tx
Copy link
Collaborator

@m4tx m4tx commented Nov 28, 2025

No description provided.

@qwandor qwandor marked this pull request as ready for review December 5, 2025 13:02
@qwandor qwandor marked this pull request as draft December 5, 2025 13:02
@qwandor qwandor added the enhancement New feature or request label Dec 5, 2025
@m4tx m4tx force-pushed the stage-2 branch 5 times, most recently from 74bc800 to 6e28cde Compare January 15, 2026 15:16
@m4tx m4tx marked this pull request as ready for review January 15, 2026 15:16
@m4tx
Copy link
Collaborator Author

m4tx commented Jan 15, 2026

@qwandor this still needs more polishing and testing, but may I ask to have a look when you have some free time to verify whether the overall approach and structure is something sensible for aarch64-paging? I don't ask for a full review yet; I just want to see whether it's worth finishing this, or is there any other way to implement this that we'd want to use.

Copy link
Collaborator

@qwandor qwandor left a comment

Choose a reason for hiding this comment

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

This seems like a broadly reasonable approach to me.

translation: T,
asid: usize,
rootlevel: usize,
translation_regime: TranslationRegime,
Copy link
Collaborator

Choose a reason for hiding this comment

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

This makes it possible to construct a Mapping with a TranslationRegime which doesn't match the attributes type. We should prevent that somehow. Maybe there could be separate types for Stage1TranslationRegime and Stage2TranslationRegime, and they could specify the corresponding attributes type via an associated type?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That's true - this is a pretty big refactor though, would it make sense to combine it with splitting the Stage 1 attributes into different types and making it a separate PR? I've got an initial version here: m4tx/aarch64-paging@stage-2...m4tx:aarch64-paging:attribute-refactor

Copy link
Collaborator

Choose a reason for hiding this comment

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

That looks reasonable, I'll review it separately once you send a PR for it.

El2And0,
/// Non-secure EL1&0, stage 1.
El1And0,
/// Non-secure Stage 2.
Copy link
Collaborator

Choose a reason for hiding this comment

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

This applies to the other existing options too, but does secure world actually use different translation regimes to normal world?

/// Attribute bits for a mapping in a Stage 1 page table.
#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Attributes: usize {
pub struct Stage1Attributes: usize {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Possibly we should split this into two different types, as some of the existing translation regimes have slightly different attribute bits too.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

See the comment above, I've got an initial version of this here: m4tx/aarch64-paging@stage-2...m4tx:aarch64-paging:attribute-refactor

Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks, that looks reasonable, I'll review it properly once this is merged.

@m4tx m4tx requested a review from qwandor February 16, 2026 15:15
const TABLE_OR_PAGE = 1 << 1;

const MEMATTR_DEVICE_nGnRnE = 0 << 2;
const MEMATTR_NORMAL = 0xf << 2; // Example value
Copy link
Collaborator

Choose a reason for hiding this comment

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

What do you mean by this being an "example value"?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Sorry, left it after prototyping quickly - I've replaced this with proper attributes now.


const PHYSICAL_ADDRESS_BITMASK: usize = !(PAGE_SIZE - 1) & !(0xffff << 48);

pub(crate) fn new(value: usize) -> Self {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can this be const? Then you can use it for EMPTY too.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good point - indeed, it can.

Copy link
Collaborator

@qwandor qwandor left a comment

Choose a reason for hiding this comment

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

This looks good to me. @ardbiesheuvel, do you want to have a look at it before we merge it?

@ardbiesheuvel
Copy link
Collaborator

This looks good to me. @ardbiesheuvel, do you want to have a look at it before we merge it?

Please squash these changes together so I can look at the end result, rather than the journey that brought us there :-)

(Multiple patches in a PR is fine, and even preferred, if they consist of logical discrete steps implementing the goal of the PR. Incremental changes in response to review feedback should be squashed together).

Thanks.

@m4tx
Copy link
Collaborator Author

m4tx commented Feb 23, 2026

@ardbiesheuvel sure, there you go!

if (old_bits ^ new_bits) & (MEM_ATTR_MASK | SH_MASK) != 0 {
return false;
}
true
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does this permit turning a block mapping into a table mapping? That is a problem, because it not only violates BBM, it also corrupts our data structures.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ah, that's a very fair point. I've changed this code to be written in an allowlist-style, similarly to the Stage1 implementation, so that even with new attributes potentially being added, it will still be safe.

@m4tx m4tx requested a review from ardbiesheuvel February 24, 2026 12:07
if !old.contains(Self::VALID) || !new.contains(Self::VALID) {
return true;
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

Are you removing this because it is redundant? That's fine, but please do it in a separate patch.

return false;
}
true
(!old & new & !allowed_mask).is_empty() && (old & !new & !allowed_mask).is_empty()
Copy link
Collaborator

Choose a reason for hiding this comment

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

This could be ((old ^ new) & !allowed_mask).is_empty(), right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants