Repository navigation
feat(instructions): Add lldt and sldt - #621
Conversation
Kernels that give threads their own LDT, as Mach's `i386_set_ldt` and Linux's `modify_ldt` do, load the LDT register on context switches and read it to skip redundant loads.
Load an LDT through the GDT and check that `lldt` loads its selector, that `sldt` reads it back, and that a null selector invalidates the LDTR. `lldt` must leave the GDT entry alone, unlike `ltr`, which is why one LDT may be loaded on several CPUs. A segment load through the LDT shows that the table is really live.
Freax13
left a comment
There was a problem hiding this comment.
Thank you for your contribution!
The lldt and sldt wrappers looks good to me, but I'm wondering if we should also some more function and types to actually build and use an LDT (see ldt.rs for what's necessary to do that). Would you be interested in working on that? If not, I'm also fine with merging this as is.
|
Thank you! It’s an honor to contribute to the project. I'm fine with merging this as is for now. I do plan to open other PRs, but I'm preferring to keep my contributions atomic (small PRs) rather than giant ones. Right now, I'm adding features step-by-step according to the real demands of my own project, so I'll definitely look into the LDT building functions as soon as I need them. Feel free to merge this one when you're ready! |
Sounds good, thanks! |
Closes #620.
This adds
lldtandsldttoinstructions::tables, next toload_tss. #620 has the use case: a GNU Mach-compatible kernel in Rust loads each thread's own LDT (i386_set_ldt) on every context switch, and reads the LDT register to skip a redundant load.lldtisunsafelikeload_tss: the selector must be null or name an LDT descriptor in the GDT, and that LDT has to stay valid while it is loaded, since every segment load through an LDT selector reads it. Unlikeltr,lldtwrites nothing back to the descriptor (an LDT descriptor has no busy or accessed bit), so itsasm!isreadonlylikelgdt's, and the same LDT can be loaded on several CPUs.sldtis safe likesgdt; it only copies the LDTR selector into a register.The tests in
testing/tests/ldt.rsload an LDT through the GDT and check what the docs promise:lldt_and_sldt—lldtloads a selector,sldtreads it back.lldt_does_not_modify_gdt— the GDT entry is unchanged afterwards.lldt_null—SegmentSelector::NULLinvalidates the LDTR.ldt_segment_load— a segment load through an LDT selector picks up the base from the LDT entry.That last one is the one that matters: the others only look at the LDTR and would still pass if the table were never consulted. All four pass under QEMU's emulator and under KVM on an Intel i7-11800H.
I also ran
cargo build,docandtestwith the default features, with no default features, withmemory_encryptionand withnightly, pluscargo clippyandcargo fmt --check, on stable 1.99 and on nightly withRUSTFLAGS=-DwarningsandRUSTDOCFLAGS=-Dwarnings.Both functions are additive, so nothing existing changes except the
tablesmodule doc line.