-
Notifications
You must be signed in to change notification settings - Fork 148
Description
unmap
and map_to
have different semantics for determining when a page is mapped, which causes problems handling entries that are non-zero but do not have the present flag set. translate
mixes both semantics.
unmap
checks the entry's present flag, while map_to
checks if the entry is non-zero.
translate
has mixed behavior. Non-present 4KiB page entries with bits set are returned as mapped, while non-present huge page entries with the huge page flag and potentially other bits set but not the present flag are returned as unmapped. (huge page behavior inferred from reading the code, do not use huge pages in my OS and have no easy way of confirming that).
This causes issues trying to store info about unmapped but mappable on-demand pages in the page tables. I ran into this trying to add memory overcommit to my kernel, wanting to set an OS-reserved bit in the entry to mark it as being allocated but not backed by physical memory yet. Making the entry worked, but in the code to back the allocated page on initial access and thus page fault, map
errored saying the page was already mapped while unmap
errored saying the page wasn't mapped. I made it work by calling update_flags
to set the present flag on the entry than calling unmap
followed by map
but it's not an ideal solution. I would expect to be able to just call map
on the entry since the entry's not marked present.
translate
should definitely be made consistent between huge pages and regular pages, but I'm not sure whether non-zero non-present entries should be considered mapped. Only having to call map
is somewhat more elegant but runs the risk of accidentally overwriting stored info if you mix up a page. Having to call unmap
before that fixes things but might(?) add overhead and an unnecessary TLB flush. Maybe add a ```(re?)map_nonzero_nonpresent`` method? (obviously that wouldn't be the actual name)
Also, if translate
gets changed to return non-zero non-present page entries as unmapped, the flags of the unmapped entry should be added to TranslateResult, as well as the level the translation stopped at (to determine page size), as otherwise there would be no easy way to retrieve the stored info on a page fault with available APIs outside of writing your own table walker.