From 821e4ff0a91aa01efdc4b48b18ef9dcb6e9a8b43 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Mon, 28 Mar 2022 19:09:55 -0700 Subject: [PATCH 1/2] tss: Update documentation Hopefully, this help address confusion like that seen in: https://github.com/rust-osdev/x86_64/issues/322 Signed-off-by: Joe Richey --- src/instructions/tables.rs | 11 +++++++++-- src/structures/gdt.rs | 7 +++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/instructions/tables.rs b/src/instructions/tables.rs index 095f66129..201855886 100644 --- a/src/instructions/tables.rs +++ b/src/instructions/tables.rs @@ -70,11 +70,18 @@ pub fn sidt() -> DescriptorTablePointer { /// Load the task state register using the `ltr` instruction. /// +/// Note that loading a TSS segment selector marks the corresponding TSS +/// Descriptor in the GDT as "busy", preventing it from being loaded again +/// (either on this CPU or another CPU). TSS structures (including Descriptors +/// and Selectors) should generally be per-CPU. See +/// [`tss_segment`](crate::structures::gdt::Descriptor::tss_segment) +/// for more information. +/// /// ## Safety /// /// This function is unsafe because the caller must ensure that the given -/// `SegmentSelector` points to a valid TSS entry in the GDT and that loading -/// this TSS is safe. +/// `SegmentSelector` points to a valid TSS entry in the GDT, that is entry is +/// not busy, and that the corresponding data in the TSS is valid. #[inline] pub unsafe fn load_tss(sel: SegmentSelector) { unsafe { diff --git a/src/structures/gdt.rs b/src/structures/gdt.rs index 2ce58a88e..5942030d0 100644 --- a/src/structures/gdt.rs +++ b/src/structures/gdt.rs @@ -312,6 +312,13 @@ impl Descriptor { } /// Creates a TSS system descriptor for the given TSS. + /// + /// While it is possible to create multiple Descriptors that point to the + /// same TSS, this generally isn't recommended, as the TSS usually contains + /// per-CPU information such as the RSP and IST pointers. Instead, there + /// should be exactly one TSS and one corresponding TSS Descriptor per CPU. + /// Then, each of these descriptors should be placed in a GDT (which can + /// either be global or per-CPU). #[inline] pub fn tss_segment(tss: &'static TaskStateSegment) -> Descriptor { use self::DescriptorFlags as Flags; From 9ab8c707e43ee03ceaa9a0727a5d1ee7860581e4 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Wed, 30 Mar 2022 13:43:12 -0700 Subject: [PATCH 2/2] Move TSS busy information out of #Safety section Signed-off-by: Joe Richey --- src/instructions/tables.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/instructions/tables.rs b/src/instructions/tables.rs index 201855886..611d61175 100644 --- a/src/instructions/tables.rs +++ b/src/instructions/tables.rs @@ -77,11 +77,13 @@ pub fn sidt() -> DescriptorTablePointer { /// [`tss_segment`](crate::structures::gdt::Descriptor::tss_segment) /// for more information. /// +/// Calling `load_tss` with a busy TSS selector results in a `#GP` exception. +/// /// ## Safety /// /// This function is unsafe because the caller must ensure that the given -/// `SegmentSelector` points to a valid TSS entry in the GDT, that is entry is -/// not busy, and that the corresponding data in the TSS is valid. +/// `SegmentSelector` points to a valid TSS entry in the GDT and that the +/// corresponding data in the TSS is valid. #[inline] pub unsafe fn load_tss(sel: SegmentSelector) { unsafe {