Skip to content

Commit 710cfa2

Browse files
authored
Merge pull request #191 from josephlr/gdt-push
gdt: make add_entry const
2 parents 3d988fc + 29c3630 commit 710cfa2

File tree

3 files changed

+80
-54
lines changed

3 files changed

+80
-54
lines changed

src/lib.rs

+17-4
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

+52-43
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

+11-7
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)