You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Question] Is there a reason to not support pagemaps level 5 ?聽#435
PML5 is an Intel extension to increase addressable space from 256TB to 128PB (see wikipedia).
I admit it is a niche use case 馃檪 But I was still wondering if there is any reason to not support it?
Since it uses bits from 48 to 57 for the new level, I guess it would break the safety checks for the VirtAddr type, are there other things that would break?
NB: The limine bootloader provides a way to detect if the CPU has the PML5 extension.
AFAIK there is no reason we don't support 5-level paging, it's just that no one has implemented it yet. It might require redesigning some of the abstractions to support both 4-level and 5-level paging. Feel free to come up with ideas.
Since it uses bits from 48 to 57 for the new level, I guess it would break the safety checks for the VirtAddr type, are there other things that would break?
This would also break/require redesign of the page table related abstraction including Mapper and its implementations.
For VirtAddr, we could add a new generic parameter that allows specifying 4-level or 5-level paging. If we default to 4-level paging, we might be even able to avoid a breaking change. Maybe it's also possible to something similar for OffsetPageTable, etc.
I noticed that the bitmask of the addr() function of PageTableEntry (see here) already supports 5-level paging (with 52 Bits) but the VirtAddr::new() function still only expects a 4-level address which is 47 bits long. This broke in my code when using SEV due to the C-Bit-Position being at either bit 47 (for older devices) or at bit 51 (for never AMD CPUs). I think we should adapt VirtAddr to allow bits 47-51 to be non-machting as well.
Side note: If we align the bitmasks here with VirtAddrs requirements, we can safely use VirtAddr::new_unchecked() at this location.
I noticed that the bitmask of the addr() function of PageTableEntry (see here) already supports 5-level paging (with 52 Bits) but the VirtAddr::new() function still only expects a 4-level address which is 47 bits long. This broke in my code when using SEV due to the C-Bit-Position being at either bit 47 (for older devices) or at bit 51 (for never AMD CPUs). I think we should adapt VirtAddr to allow bits 47-51 to be non-machting as well. Side note: If we align the bitmasks here with VirtAddrs requirements, we can safely use VirtAddr::new_unchecked() at this location.
(This misunderstands a few concepts/our APIs, there's been some discussion on this in #511).
For VirtAddr, we could add a new generic parameter that allows specifying 4-level or 5-level paging. If we default to 4-level paging, we might be even able to avoid a breaking change. Maybe it's also possible to something similar for OffsetPageTable, etc.
Unfortunately, I don't think this can work without a breaking change because Rust doesn't allow specifying a default for generic parameters in functions.
Here's another idea: We could add a cargo feature to enable 5 level paging. When this feature is enabled, the Page and VirtAddr address types would use 5 level paging. If enabled, we'd expose additional functions like p5_index(). The Mapper implementations (in this crate) would be aware of this and map one more level when the feature is active.
I wrote up a proof of concept for this a while ago and didn't come across any major issues.
One downside of this approach is that it's not possible to select between 4 level and 5 level paging at runtime. That said, I'm not sure if it's feasible to duplicate all code to have a generic instantiation for 4 level paging and one for 5 level paging. At best, we can probably make the mapper implementations aware of the current paging configuration, but I'm not sure that we can do this for the canonality checks.
Given that it's unlikely that we can avoid a breaking change while adding simultaneous 4 and 5 level paging support, I'd suggest that we go with adding a cargo feature for now and reevaluate this when there's a need to support both at the same time. Personally, I'm not really sure what users would want/need from us to support this.
Adding a cargo feature to enable 5 level paging shouldn't be a breaking change.
I don't think that that a cargo feature would be a good idea since cargo unifies features across dependencies. So if your kernel enables the 5 level paging feature, the bahavior of VirtAddr would also change in all dependencies that use x86_64 too.
The addional generic parameter on VirtAddr and the page table types still seems like the cleanest solution to me. We could add type aliases to avoid spilling the generics into normal user code.
This goes back to my assumption that users will know at compile times whether they want to use 4 or 5 level paging. In that case, users could set the feature in the top level crate and all dependencies would automatically use the correct paging config. Library authors would not need to add explicit support for 4 and 5 level paging because the address types would automatically do the right thing (thanks to feature unification). Library crates should not (unconditionally) set the feature.
Another way to phrase this would be that the feature doesn't indicate support, but the desired configuration. Libraries wouldn't set this flag because they support 5 level paging, they'd only set it if they require 5 level paging.
To be fair, I'm not sure that it's fair to assume that users will know the paging configuration at compile time, but wouldn't they also need to know this when using generics? Sure, they have the option to use types for both configurations, but in practice, I don't think it's feasible to make a whole kernel/user program generic over the paging config, so they'd likely have to pick one.
One downside of using generics to differentiate between 4 and 5 level paging is that library authors will have to explicitly opt-in by adding generic parameters to all of their types/traits/functions. Depending on how heavily they use the address types, that could be quite a large change. If we can't make adding support for 5 level page a non-breaking change, chances are libraries would have to make breaking changes as well if they wanted to add support.
5 level paging is only usable if the CPU supports it. Using a compile-time flag to enable it would surely reduce the compatibility of the OS you're writing, no?
I agree that Cargo features are not the right approach here. They are additive and have a tendency to get virally enabled.
For VirtAddr and PhysAddr (and structures containing them like Page and PhysFrame), I think it would make more sense to have generic parameters encoding the validity range. Something like:
However, such a generic approach would likely require rust-lang/rust#143874 (#![feature(const_trait_impl)]), as we would want check_virt_addr to be const for Virt48, but it cannot be const for VirtRt.
I started sketching out the generic parameter approach. I opened a draft PR: #586. It's still very much work in progress, but I gives us something to look at when discussing the right approach.
FWIW, I found my old WIP patch that uses a cargo feature instead: Freax13@d288b37. That patch is also not yet completely finished up, but it is fairly close because that approach doesn't require touching as many parts of the code base. I think that main thing that was missing is that I didn't do a whole lot of testing yet.
5 level paging is only usable if the CPU supports it. Using a compile-time flag to enable it would surely reduce the compatibility of the OS you're writing, no?
Yes, that's fair. That said, the OS itself could also have a build flag for 5 level paging and could forward that to the x86_64 crate. That way, it'd still be possible to support both although not in the same binary.
AFAICT that's what windows is doing with ntoskrnl.exe and ntkrla57.exe. The former only supports 4 level paging and the later supports 5 level paging (I'm not completely sure if it only supports 5 level paging or if it supports both).
Linux supports 4 and 5 level paging in the same kernel binary.
First of all, thank you to everyone who has investigated this, especially @Freax13 for the implementation work in #586 and @phil-opp for the review and API suggestions there.
I encountered this problem while adding LA57 support to my own OS program. On a machine that boots with five-level paging enabled, the current 48-bit VirtAddr invariant rejects addresses that are valid in the active address-space mode. I therefore studied #435 and #586 and built another prototype so that I could test the different design choices in a real kernel.
The prototype is available in #599 . It is intentionally not presented as a finished API. Its current implementation follows a runtime-validity-by-default design because that makes the consequences of full LA48/LA57 runtime compatibility visible throughout the crate (though I agree that VirtAddr48 should be the default for compatibility issues). While working on it, I found several additional design questions that appear to need agreement before either implementation can be completed. The draft PR describes these questions, the alternatives I considered, and the choices currently exercised by the prototype.
Page-table support itself, including P5 traversal and mapping APIs, is outside the scope of this prototype. The immediate goal is to agree on the virtual address abstraction and on the APIs that directly depend on it.
I would appreciate feedback on these design questions before I continue refining the implementation. I am also happy to adapt the existing prototype or help finish #586, depending on which direction is preferred.
Activity
Freax13 commentedon Sep 12, 2023
AFAIK there is no reason we don't support 5-level paging, it's just that no one has implemented it yet. It might require redesigning some of the abstractions to support both 4-level and 5-level paging. Feel free to come up with ideas.
This would also break/require redesign of the page table related abstraction including
Mapperand its implementations.phil-opp commentedon Sep 12, 2023
For
VirtAddr, we could add a new generic parameter that allows specifying 4-level or 5-level paging. If we default to 4-level paging, we might be even able to avoid a breaking change. Maybe it's also possible to something similar forOffsetPageTable, etc.sarahspberrypi commentedon Nov 20, 2024
I noticed that the bitmask of the
addr()function ofPageTableEntry(see here) already supports 5-level paging (with 52 Bits) but theVirtAddr::new()function still only expects a 4-level address which is 47 bits long. This broke in my code when using SEV due to the C-Bit-Position being at either bit 47 (for older devices) or at bit 51 (for never AMD CPUs). I think we should adaptVirtAddrto allow bits 47-51 to be non-machting as well.Side note: If we align the bitmasks here with
VirtAddrs requirements, we can safely useVirtAddr::new_unchecked()at this location.Freax13 commentedon Nov 21, 2024
(This misunderstands a few concepts/our APIs, there's been some discussion on this in #511).
Freax13 commentedon Nov 24, 2024
Unfortunately, I don't think this can work without a breaking change because Rust doesn't allow specifying a default for generic parameters in functions.
Freax13 commentedon Mar 2, 2026
Here's another idea: We could add a cargo feature to enable 5 level paging. When this feature is enabled, the
PageandVirtAddraddress types would use 5 level paging. If enabled, we'd expose additional functions likep5_index(). TheMapperimplementations (in this crate) would be aware of this and map one more level when the feature is active.I wrote up a proof of concept for this a while ago and didn't come across any major issues.
One downside of this approach is that it's not possible to select between 4 level and 5 level paging at runtime. That said, I'm not sure if it's feasible to duplicate all code to have a generic instantiation for 4 level paging and one for 5 level paging. At best, we can probably make the mapper implementations aware of the current paging configuration, but I'm not sure that we can do this for the canonality checks.
Given that it's unlikely that we can avoid a breaking change while adding simultaneous 4 and 5 level paging support, I'd suggest that we go with adding a cargo feature for now and reevaluate this when there's a need to support both at the same time. Personally, I'm not really sure what users would want/need from us to support this.
Adding a cargo feature to enable 5 level paging shouldn't be a breaking change.
phil-opp commentedon Mar 2, 2026
I don't think that that a cargo feature would be a good idea since cargo unifies features across dependencies. So if your kernel enables the 5 level paging feature, the bahavior of VirtAddr would also change in all dependencies that use x86_64 too.
The addional generic parameter on VirtAddr and the page table types still seems like the cleanest solution to me. We could add type aliases to avoid spilling the generics into normal user code.
Freax13 commentedon Mar 2, 2026
This goes back to my assumption that users will know at compile times whether they want to use 4 or 5 level paging. In that case, users could set the feature in the top level crate and all dependencies would automatically use the correct paging config. Library authors would not need to add explicit support for 4 and 5 level paging because the address types would automatically do the right thing (thanks to feature unification). Library crates should not (unconditionally) set the feature.
Another way to phrase this would be that the feature doesn't indicate support, but the desired configuration. Libraries wouldn't set this flag because they support 5 level paging, they'd only set it if they require 5 level paging.
To be fair, I'm not sure that it's fair to assume that users will know the paging configuration at compile time, but wouldn't they also need to know this when using generics? Sure, they have the option to use types for both configurations, but in practice, I don't think it's feasible to make a whole kernel/user program generic over the paging config, so they'd likely have to pick one.
One downside of using generics to differentiate between 4 and 5 level paging is that library authors will have to explicitly opt-in by adding generic parameters to all of their types/traits/functions. Depending on how heavily they use the address types, that could be quite a large change. If we can't make adding support for 5 level page a non-breaking change, chances are libraries would have to make breaking changes as well if they wanted to add support.
linkdd commentedon Mar 2, 2026
5 level paging is only usable if the CPU supports it. Using a compile-time flag to enable it would surely reduce the compatibility of the OS you're writing, no?
josephlr commentedon Mar 4, 2026
I agree that Cargo features are not the right approach here. They are additive and have a tendency to get virally enabled.
For
VirtAddrandPhysAddr(and structures containing them likePageandPhysFrame), I think it would make more sense to have generic parameters encoding the validity range. Something like:Then
VirtAddrbecomesVirtAddr<V: VirtValidity = Virt48>with:T: VirtValiditycheck_virt_addrbehaviorVirt48Virt57VirtRtCr4Flags::L5_PAGINGat runtime to get allowed rangeAnd
PhysAddrbecomesPhysAddr<V: PhysValidity = Phys52>with:T: PhysValiditycheck_phys_addrbehaviorPhys52Phys48PhysEncPhysRtCPUID[0x80000008]at runtime to get allowed rangeThis allows us to support extensions and different Physical/Virtual address ranges, while keeping a nice and ergonomic default.
josephlr commentedon Mar 4, 2026
However, such a generic approach would likely require rust-lang/rust#143874 (
#![feature(const_trait_impl)]), as we would wantcheck_virt_addrto be const forVirt48, but it cannot be const forVirtRt.Freax13 commentedon Mar 7, 2026
I started sketching out the generic parameter approach. I opened a draft PR: #586. It's still very much work in progress, but I gives us something to look at when discussing the right approach.
FWIW, I found my old WIP patch that uses a cargo feature instead: Freax13@d288b37. That patch is also not yet completely finished up, but it is fairly close because that approach doesn't require touching as many parts of the code base. I think that main thing that was missing is that I didn't do a whole lot of testing yet.
Freax13 commentedon Mar 7, 2026
Yes, that's fair. That said, the OS itself could also have a build flag for 5 level paging and could forward that to the x86_64 crate. That way, it'd still be possible to support both although not in the same binary.
AFAICT that's what windows is doing with ntoskrnl.exe and ntkrla57.exe. The former only supports 4 level paging and the later supports 5 level paging (I'm not completely sure if it only supports 5 level paging or if it supports both).
Linux supports 4 and 5 level paging in the same kernel binary.
aarkegz commentedon Aug 4, 2026
First of all, thank you to everyone who has investigated this, especially @Freax13 for the implementation work in #586 and @phil-opp for the review and API suggestions there.
I encountered this problem while adding LA57 support to my own OS program. On a machine that boots with five-level paging enabled, the current 48-bit
VirtAddrinvariant rejects addresses that are valid in the active address-space mode. I therefore studied #435 and #586 and built another prototype so that I could test the different design choices in a real kernel.The prototype is available in #599 . It is intentionally not presented as a finished API. Its current implementation follows a runtime-validity-by-default design because that makes the consequences of full LA48/LA57 runtime compatibility visible throughout the crate (though I agree that
VirtAddr48should be the default for compatibility issues). While working on it, I found several additional design questions that appear to need agreement before either implementation can be completed. The draft PR describes these questions, the alternatives I considered, and the choices currently exercised by the prototype.Page-table support itself, including P5 traversal and mapping APIs, is outside the scope of this prototype. The immediate goal is to agree on the virtual address abstraction and on the APIs that directly depend on it.
I would appreciate feedback on these design questions before I continue refining the implementation. I am also happy to adapt the existing prototype or help finish #586, depending on which direction is preferred.