Skip to content

Commit 29c3630

Browse files
committed
gdt: make add_entry const
This requires making the push method const as well, which means we need the `const_panic` feature (not too much of a risk as this feature is failly well along). I also moved the pointer calculation (for GDT and IDT) into their own (currently private) methods. Eventually these methods can be public, but that's only useful if they can be const, which would require a breaking change. The caclulation for the GDT pointer was also updated to use: ```rust self.next_free * size_of::<u64>() - 1 ``` instead of ```rust self.table.len() * size_of::<u64>() - 1 ``` Signed-off-by: Joe Richey <[email protected]>
1 parent 3d988fc commit 29c3630

File tree

3 files changed

+80
-54
lines changed

3 files changed

+80
-54
lines changed

src/lib.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
44
#![cfg_attr(not(test), no_std)]
55
#![cfg_attr(feature = "const_fn", feature(const_fn))] // Needed for generic access to associated consts
6+
#![cfg_attr(feature = "const_fn", feature(const_panic))]
67
#![cfg_attr(feature = "const_fn", feature(const_mut_refs))]
78
#![cfg_attr(feature = "const_fn", feature(const_fn_fn_ptr_basics))]
89
#![cfg_attr(feature = "const_fn", feature(const_in_array_repeat_expressions))]
@@ -22,16 +23,28 @@ pub use crate::addr::{align_down, align_up, PhysAddr, VirtAddr};
2223
macro_rules! const_fn {
2324
(
2425
$(#[$attr:meta])*
25-
pub $($fn:tt)*
26+
$sv:vis fn $($fn:tt)*
2627
) => {
2728
$(#[$attr])*
2829
#[cfg(feature = "const_fn")]
29-
pub const $($fn)*
30+
$sv const fn $($fn)*
3031

3132
$(#[$attr])*
3233
#[cfg(not(feature = "const_fn"))]
33-
pub $($fn)*
34-
}
34+
$sv fn $($fn)*
35+
};
36+
(
37+
$(#[$attr:meta])*
38+
$sv:vis unsafe fn $($fn:tt)*
39+
) => {
40+
$(#[$attr])*
41+
#[cfg(feature = "const_fn")]
42+
$sv const unsafe fn $($fn)*
43+
44+
$(#[$attr])*
45+
#[cfg(not(feature = "const_fn"))]
46+
$sv unsafe fn $($fn)*
47+
};
3548
}
3649

3750
#[cfg(all(feature = "instructions", feature = "external_asm"))]

src/structures/gdt.rs

Lines changed: 52 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Types for the Global Descriptor Table and segment selectors.
22
3-
use crate::structures::tss::TaskStateSegment;
3+
use crate::structures::{tss::TaskStateSegment, DescriptorTablePointer};
44
use crate::PrivilegeLevel;
55
use bit_field::BitField;
66
use bitflags::bitflags;
@@ -105,33 +105,35 @@ impl GlobalDescriptorTable {
105105
}
106106
}
107107

108-
/// Adds the given segment descriptor to the GDT, returning the segment selector.
109-
///
110-
/// Panics if the GDT has no free entries left.
111-
#[inline]
112-
pub fn add_entry(&mut self, entry: Descriptor) -> SegmentSelector {
113-
let index = match entry {
114-
Descriptor::UserSegment(value) => self.push(value),
115-
Descriptor::SystemSegment(value_low, value_high) => {
116-
let index = self.push(value_low);
117-
self.push(value_high);
118-
index
119-
}
120-
};
121-
122-
let rpl = match entry {
123-
Descriptor::UserSegment(value) => {
124-
if DescriptorFlags::from_bits_truncate(value).contains(DescriptorFlags::DPL_RING_3)
125-
{
126-
PrivilegeLevel::Ring3
127-
} else {
128-
PrivilegeLevel::Ring0
108+
const_fn! {
109+
/// Adds the given segment descriptor to the GDT, returning the segment selector.
110+
///
111+
/// Panics if the GDT has no free entries left.
112+
#[inline]
113+
pub fn add_entry(&mut self, entry: Descriptor) -> SegmentSelector {
114+
let index = match entry {
115+
Descriptor::UserSegment(value) => self.push(value),
116+
Descriptor::SystemSegment(value_low, value_high) => {
117+
let index = self.push(value_low);
118+
self.push(value_high);
119+
index
129120
}
130-
}
131-
Descriptor::SystemSegment(_, _) => PrivilegeLevel::Ring0,
132-
};
121+
};
122+
123+
let rpl = match entry {
124+
Descriptor::UserSegment(value) => {
125+
if DescriptorFlags::from_bits_truncate(value).contains(DescriptorFlags::DPL_RING_3)
126+
{
127+
PrivilegeLevel::Ring3
128+
} else {
129+
PrivilegeLevel::Ring0
130+
}
131+
}
132+
Descriptor::SystemSegment(_, _) => PrivilegeLevel::Ring0,
133+
};
133134

134-
SegmentSelector::new(index as u16, rpl)
135+
SegmentSelector::new(index as u16, rpl)
136+
}
135137
}
136138

137139
/// Loads the GDT in the CPU using the `lgdt` instruction. This does **not** alter any of the
@@ -142,26 +144,33 @@ impl GlobalDescriptorTable {
142144
#[cfg(feature = "instructions")]
143145
#[inline]
144146
pub fn load(&'static self) {
145-
use crate::instructions::tables::{lgdt, DescriptorTablePointer};
146-
use core::mem::size_of;
147-
148-
let ptr = DescriptorTablePointer {
149-
base: self.table.as_ptr() as u64,
150-
limit: (self.table.len() * size_of::<u64>() - 1) as u16,
151-
};
147+
use crate::instructions::tables::lgdt;
148+
// SAFETY: static lifetime ensures no modification after loading.
149+
unsafe { lgdt(&self.pointer()) };
150+
}
152151

153-
unsafe { lgdt(&ptr) };
152+
const_fn! {
153+
#[inline]
154+
fn push(&mut self, value: u64) -> usize {
155+
if self.next_free < self.table.len() {
156+
let index = self.next_free;
157+
self.table[index] = value;
158+
self.next_free += 1;
159+
index
160+
} else {
161+
panic!("GDT full");
162+
}
163+
}
154164
}
155165

156-
#[inline]
157-
fn push(&mut self, value: u64) -> usize {
158-
if self.next_free < self.table.len() {
159-
let index = self.next_free;
160-
self.table[index] = value;
161-
self.next_free += 1;
162-
index
163-
} else {
164-
panic!("GDT full");
166+
/// Creates the descriptor pointer for this table. This pointer can only be
167+
/// safely used if the table is never modified or destroyed while in use.
168+
#[cfg(feature = "instructions")]
169+
fn pointer(&self) -> DescriptorTablePointer {
170+
use core::mem::size_of;
171+
DescriptorTablePointer {
172+
base: self.table.as_ptr() as u64,
173+
limit: (self.next_free * size_of::<u64>() - 1) as u16,
165174
}
166175
}
167176
}

src/structures/idt.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
//! Provides types for the Interrupt Descriptor Table and its entries.
1111
12-
use crate::{PrivilegeLevel, VirtAddr};
12+
use crate::{structures::DescriptorTablePointer, PrivilegeLevel, VirtAddr};
1313
use bit_field::BitField;
1414
use bitflags::bitflags;
1515
use core::fmt;
@@ -430,15 +430,19 @@ impl InterruptDescriptorTable {
430430
#[cfg(feature = "instructions")]
431431
#[inline]
432432
pub unsafe fn load_unsafe(&self) {
433-
use crate::instructions::tables::{lidt, DescriptorTablePointer};
434-
use core::mem::size_of;
433+
use crate::instructions::tables::lidt;
434+
lidt(&self.pointer());
435+
}
435436

436-
let ptr = DescriptorTablePointer {
437+
/// Creates the descriptor pointer for this table. This pointer can only be
438+
/// safely used if the table is never modified or destroyed while in use.
439+
#[cfg(feature = "instructions")]
440+
fn pointer(&self) -> DescriptorTablePointer {
441+
use core::mem::size_of;
442+
DescriptorTablePointer {
437443
base: self as *const _ as u64,
438444
limit: (size_of::<Self>() - 1) as u16,
439-
};
440-
441-
lidt(&ptr);
445+
}
442446
}
443447

444448
/// Returns a normalized and ranged check slice range from a RangeBounds trait object

0 commit comments

Comments
 (0)