Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions src/structures/gdt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,15 @@ impl GlobalDescriptorTable {
///
/// Panics if the GDT has no free entries left.
pub fn add_entry(&mut self, entry: Descriptor) -> SegmentSelector {
let index = match entry {
Descriptor::UserSegment(value) => self.push(value),
let (index, privilege) = match entry {
Descriptor::UserSegment(value) => (self.push(value), (value >> 45) & 0b11),
Descriptor::SystemSegment(value_low, value_high) => {
let index = self.push(value_low);
self.push(value_high);
index
(index, (value_low >> 45) & 0b11)
}
};
SegmentSelector::new(index as u16, PrivilegeLevel::Ring0)
SegmentSelector::new(index as u16, PrivilegeLevel::from_u16(privilege as u16))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about adding a privilege_level(&self) -> PrivilegeLevel method to Descriptor? Then we could keep the bit shifts at one place. Also, we could use the get_bits method instead of doing the shift and logical AND ourselves.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, will do.

}

/// Loads the GDT in the CPU using the `lgdt` instruction.
Expand Down Expand Up @@ -148,8 +148,8 @@ impl Descriptor {
Descriptor::UserSegment(flags.bits())
}

/// Creates a TSS system descriptor for the given TSS.
pub fn tss_segment(tss: &'static TaskStateSegment) -> Descriptor {
/// Creates a TSS system descriptor for the given TSS and IO permissions bitmap size.
pub fn tss_segment(tss: &'static TaskStateSegment, iomap_size: u16) -> Descriptor {
use self::DescriptorFlags as Flags;
use core::mem::size_of;

Expand All @@ -159,8 +159,11 @@ impl Descriptor {
// base
low.set_bits(16..40, ptr.get_bits(0..24));
low.set_bits(56..64, ptr.get_bits(24..32));
// limit (the `-1` in needed since the bound is inclusive)
low.set_bits(0..16, (size_of::<TaskStateSegment>() - 1) as u64);
// limit (the `-1` is needed since the bound is inclusive)
low.set_bits(
0..16,
(size_of::<TaskStateSegment>() + (tss.iomap_base + iomap_size) as usize - 1) as u64
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code only works if the iomap is directly adjacent to the tss. Also, it makes the function unsafe because setting an iomap_size with no iomap would lead to invalid memory accesses.

To solve this, we could create an internal (non-public) tss_segment_with_limit(tss, limit) function and move the complete implementation to it. The function would then just do low.set_bits(0..16, limit - 1). On top of that function we can recreate the current tss_segment function by calling tss_segment_with_limit(tss, size_of::<TaskStateSegment>()).

Now we can create a new pub unsafe fn tss_segment_with_custom_limit(tss: […], limit: u64) function that allows taking the iomap_size into account. Internally, the function just calls tss_segment_with_limit(tss, limit). This way, the original tss_segment function can stay safe and we avoid the breaking parameter addition. This approach also allows us to create a TssWithIomap struct in the future and add a safe tss_segment_with_iomap function.

What do you think about this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code only works if the iomap is directly adjacent to the tss.

I think that it should work for the TSS anywhere (so long as it is within a 16 bit pointer)? That's why iomap_base is added to the size.

What do you think about this?

Sounds good. Will do.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's why iomap_base is added to the size.

Sorry, missed that!

Sounds good. Will do.

Thanks!

// type (0b1001 = available 64-bit tss)
low.set_bits(40..44, 0b1001);

Expand Down