-
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
Allow GDT to be loaded with shared reference #381
Conversation
The current documentation for the GDT often confuses entries and `Descriptor`s. For example, adding a new `Descriptor` uses a method confusingly named `add_entry`. An entry is a raw 64-bit value that is indexed by a segment selector. The `MAX` length of the GDT is a number of _entries_, not `Descriptor`s. To fix this confusion, this PR makes the following changes: - Adds a transparent `u64` newtype called `Entry`. - Updates the `GlobalDescriptorTable` documentation to correctly use `Entry` or `Descriptor` where appropriate. - Renames the `add_entry` to `append`. - This better expresses that this method might add multiple entries. - Renames `from_raw_slice` to `from_raw_entries` - Renames `as_raw_slice` to `entries` - This method now returns a slice of `Entry`s instead of `u64`s This also fixes an issue where our `assert!`s in `empty()` wouldn't trigger if the GDT was constructed from raw values. Signed-off-by: Joe Richey <[email protected]>
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.
Looks mostly good to me!
* We only need to use `AtomicU64` if it's possible for code to call `load` and `load_tss`, so we can gate this on `#[cfg(feature = "instructions")]`.
That's very clever!
Signed-off-by: Joe Richey <[email protected]>
Also update the documentation Signed-off-by: Joe Richey <[email protected]>
Signed-off-by: Joe Richey <[email protected]>
This gives our GDT the appropriate atomic interior mutablity if we could potentially call `lgdt` and `ltr`. Signed-off-by: Joe Richey <[email protected]>
Signed-off-by: Joe Richey <[email protected]>
Now that the `Entry` type has the appropriate interior mutability, we can safely load a GDT using `&'static self`. Signed-off-by: Joe Richey <[email protected]>
It's no longer used, so we don't need it anymore. Signed-off-by: Joe Richey <[email protected]>
Signed-off-by: Joe Richey <[email protected]>
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.
Looks good to me, thanks!
I don't see any problems sharing the code/data segments, but sharing the same TSS can lead to problems, right? How would we avoid that? Add multiple TSS entries to the same TSS? |
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.
The code changes look good to me, I just think that we need some additional docs about sharing a GDT between cores (i.e. what is allowed and what not).
Sharing a TSS is still not possible because the CPU marks the TSS descriptor as busy. Attempting to load a busy TSS descriptor will cause a general protection fault. If we really wanted to share a GDT between cores, we'd have to use multiple TSS descriptors. |
So this roughly what I added in #366. Those additional docs make it clear that I think @Freax13's answer mostly explains why it wouldn't be possible (without nasty |
Thanks a lot for clarifying! I missed #366, looks very good! |
Depends on #380
In #322 it was pointed out that calling
load_tss
would modify the GDT entry for the TSS (to mark it as busy). This meant our GDT required some sort of interior mutability if we wanted to use it in astatic
context. #323 solved this problem by requiring&mut
to callload
andload_unsafe
, thus ensuring that the GDT would be mutable after it was loaded. It also introducedSingleUseCell
to make such manipulations more ergonomic.This PR takes a different approach. The idea is basically the initial version of #323 using
AtomicU64
. The main difference is that:Entry
type from Add structures::gdt::Entry type #380 to make the code cleaner.AtomicU64
if it's possible for code to callload
andload_tss
, so we can gate this on#[cfg(feature = "instructions")]
.By doing things this way, we can go back to using shared references for
load
andload_unsafe
, which is much more ergonomic. We can then get rid ofSingleUseCell
(which doesn't really fit well with this x86_64-specific crate). Also, using an atomic, shared, static type better reflects how the processor uses the GDT. It's almost always read-only, can be shared between cores, and once in use is only updated atomically. In fact, the Intel documentation forLTR
even says:In the future, we could also use the interior mutability of our GDT structure to add a method like:
which would allow for a GDT to be a normal
static
item, and eliminate some uses oflazy_static!
.Finally, I also added some tests to make sure that
load_tss
changing the TSS entry is actually observable.