-
Notifications
You must be signed in to change notification settings - Fork 132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
implement core::iter::Step
for VirtAddr
and Page
#342
Conversation
Sorry for not reviewing this earlier. The implementation looks good to me, but I'm still a bit unsure about jumping the gap because of Intel's 5-level paging. It would result in a smaller gap, but we should not change the behavior of stepping/ranges e.g. based on the CPU. I guess that separate What do you think is the best approach? |
I agree that we shouldn't do that based on the CPU's configuration especially because
Will there just be different types for
I wonder if it's possible to decide between 4-level paging and 5-level paging with a new cargo feature. Probably not because that would limit a kernel (or any other program using the crate) to only one of the two. We could also run into problems because cargo features are meant to be purely additive. Maybe we could a new const generic parameter to all affected types to switch between 4-level paging and 5-level paging. This would probably allow reusing most types/functions/code for both modes. Either way, adding support for 5-level paging will very likely be a breaking change anyways, so I'm not sure if we should worry a lot about being forward compatible just yet. |
103314a
to
6f891df
Compare
I just rebased onto the new master to resolve some merge conflicts. |
We might be able to make some methods generic, but e.g. Changing behavior through cargo features is not a good idea because cargo unifies dependencies across the whole project. So adding a dependency to a crate that internally uses
Yeah, we could do that too if it doesn't make the API too complicated.
I don't think that this has to be a breaking change. Duplicating types would be fully backwards compatible. However, the feature is big enough that a new minor release would not be a problem either. But I still want to avoid silent behavior changes in minor releases, i.e. breaking changes that don't lead to any compile errors. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can use the design as is. The gap jumping behavior seems logical and useful to me and we will probably need to add some separate types (or new generic parameters) for 5-level paging anyway, so this change doesn't make it more difficult to add support for 5-level paging later.
I left a few minor comments, afterwards this is ready to be merged from my side. Thanks again!
src/addr.rs
Outdated
|
||
// Check if we jumped the gap. | ||
if end.0.get_bit(47) && !start.0.get_bit(47) { | ||
steps -= 0xffff_0000_0000_0000; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps add an assertion here that steps
is larger than 0xffff_0000_0000_0000
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assuming that the address is canonical steps
is always equal to or larger than 0xffff_0000_0000_0000
, is it not? I would be fine with adding a debug assertion just to make sure.
src/addr.rs
Outdated
let mut addr = start.0.checked_add(offset)?; | ||
|
||
// Jump the gap by sign extending the 47th bit. | ||
if addr.get_bits(47..) == 0x1 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if count
is so large that this get_bits
returns 0x3 or more? We should probably return None
, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if
count
is so large that thisget_bits
returns 0x3 or more? We should probably returnNone
, right?
Good point. Note that we can also get a larger value (0x1ffff
) if start
is in the upper half. We can check if offset
is bigger than the total address space and return None
if that's the case.
src/addr.rs
Outdated
let mut addr = start.0.checked_sub(offset)?; | ||
|
||
// Jump the gap by sign extending the 47th bit. | ||
if addr.get_bits(47..) == 0x1fffe { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same concern as above: If count is too large, this get_bits might return something smaller than 0x1fffe.
An overflow should not be possible since `VirtAddr` ise guarenteed to be a canoncial address, but it's better to be safe.
This ensures that we never return a non-canonical address from these methods, even if there is a bug in the address calculation. This is important because the `VirtAddr` type guarantees that all addresses are canoncial.
I don't think that the check that you added is enough. I pushed some more test cases to show examples that are still broken. To be safe, I also pushed a commit to re-check that addresses are canoncial after stepping, and I changed the |
The remaining issues should be fixed now.
Fair enough. |
This pr implements
core::iter::Step
forVirtAddr
andPage
and adds corresponding unit tests.This implementation jumps the gap between
0x7fff_ffff_ffff
and0xffff_8000_0000_0000
as discussed in #293 (comment).The
Step
trait is still unstable, so the implementation is put behind a new feature flagstep_trait
. This flag is enabled by thenightly
feature flag.Part of #212