rust-osdev / rust-osdev/x86_64

Non-zero but non-present page table entries are handled poorly.

Open
#561 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
940
Forks
157
Avg merge
1d 10h
Merged PRs (30d)
3

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.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by comparing the existing unmap, map_to, and translate entry points for regular and huge page entries. Resolve whether non-zero, non-present entries are mapped, then make the behavior consistent and determine whether TranslateResult must expose flags and the translation level; the issue does not name files or tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
operating-systems
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.