@@ -9,18 +9,42 @@ use bitflags::bitflags;
9
9
#[ cfg( doc) ]
10
10
use crate :: registers:: segmentation:: { Segment , CS , SS } ;
11
11
12
+ /// 8-byte entry in a descriptor table.
13
+ ///
14
+ /// A [`GlobalDescriptorTable`] (or LDT) is an array of these entries, and
15
+ /// [`SegmentSelector`]s index into this array. Each [`Descriptor`] in the table
16
+ /// uses either 1 Entry (if it is a [`UserSegment`](Descriptor::UserSegment)) or
17
+ /// 2 Entries (if it is a [`SystemSegment`](Descriptor::SystemSegment)). This
18
+ /// type exists to give users access to the raw entry bits in a GDT.
19
+ #[ derive( Clone , Debug ) ]
20
+ #[ repr( transparent) ]
21
+ pub struct Entry ( u64 ) ;
22
+
23
+ impl Entry {
24
+ // Create a new Entry from a raw value.
25
+ const fn new ( raw : u64 ) -> Self {
26
+ Self ( raw)
27
+ }
28
+
29
+ /// The raw bits for this entry. Depending on the [`Descriptor`] type. This
30
+ /// bits may correspond to those in [`DescriptorFlags`].
31
+ pub fn raw ( & self ) -> u64 {
32
+ self . 0
33
+ }
34
+ }
35
+
12
36
/// A 64-bit mode global descriptor table (GDT).
13
37
///
14
38
/// In 64-bit mode, segmentation is not supported. The GDT is used nonetheless, for example for
15
39
/// switching between user and kernel mode or for loading a TSS.
16
40
///
17
41
/// The GDT has a fixed maximum size given by the `MAX` const generic parameter.
18
- /// Trying to add more entries than this maximum via [`GlobalDescriptorTable::add_entry`]
19
- /// will panic.
42
+ /// Overflowing this limit by adding too many [`Descriptor`]s via
43
+ /// [`GlobalDescriptorTable::append`] will panic.
20
44
///
21
45
/// You do **not** need to add a null segment descriptor yourself - this is already done
22
- /// internally. This means you can add up to `MAX - 1` additional [`Descriptor `]s to
23
- /// this table.
46
+ /// internally. This means you can add up to `MAX - 1` additional [`Entry `]s to
47
+ /// this table. Note that some [`Descriptor`]s may take up 2 [`Entry`]s.
24
48
///
25
49
/// Data segment registers in ring 0 can be loaded with the null segment selector. When running in
26
50
/// ring 3, the `ss` register must point to a valid data segment which can be obtained through the
@@ -40,16 +64,16 @@ use crate::registers::segmentation::{Segment, CS, SS};
40
64
/// use x86_64::structures::gdt::{GlobalDescriptorTable, Descriptor};
41
65
///
42
66
/// let mut gdt = GlobalDescriptorTable::new();
43
- /// gdt.add_entry (Descriptor::kernel_code_segment());
44
- /// gdt.add_entry (Descriptor::user_code_segment());
45
- /// gdt.add_entry (Descriptor::user_data_segment());
67
+ /// gdt.append (Descriptor::kernel_code_segment());
68
+ /// gdt.append (Descriptor::user_code_segment());
69
+ /// gdt.append (Descriptor::user_data_segment());
46
70
///
47
71
/// // Add entry for TSS, call gdt.load() then update segment registers
48
72
/// ```
49
73
50
74
#[ derive( Debug , Clone ) ]
51
75
pub struct GlobalDescriptorTable < const MAX : usize = 8 > {
52
- table : [ u64 ; MAX ] ,
76
+ table : [ Entry ; MAX ] ,
53
77
len : usize ,
54
78
}
55
79
@@ -61,28 +85,29 @@ impl GlobalDescriptorTable {
61
85
}
62
86
63
87
impl < const MAX : usize > GlobalDescriptorTable < MAX > {
64
- /// Creates an empty GDT which can hold `MAX` number of [`Descriptor `]s.
88
+ /// Creates an empty GDT which can hold `MAX` number of [`Entry `]s.
65
89
#[ inline]
66
90
pub const fn empty ( ) -> Self {
67
91
// TODO: Replace with compiler error when feature(generic_const_exprs) is stable.
68
92
assert ! ( MAX > 0 , "A GDT cannot have 0 entries" ) ;
69
93
assert ! ( MAX <= ( 1 << 13 ) , "A GDT can only have at most 2^13 entries" ) ;
94
+ const NULL : Entry = Entry :: new ( 0 ) ;
70
95
Self {
71
- table : [ 0 ; MAX ] ,
96
+ table : [ NULL ; MAX ] ,
72
97
len : 1 ,
73
98
}
74
99
}
75
100
76
- /// Forms a GDT from a slice of `u64` .
101
+ /// Forms a GDT from a slice of raw [`Entry`] values .
77
102
///
78
103
/// # Safety
79
104
///
80
105
/// * The user must make sure that the entries are well formed
81
106
/// * Panics if the provided slice has more than `MAX` entries
82
107
#[ inline]
83
- pub const unsafe fn from_raw_slice ( slice : & [ u64 ] ) -> Self {
108
+ pub const unsafe fn from_raw_entries ( slice : & [ u64 ] ) -> Self {
84
109
let len = slice. len ( ) ;
85
- let mut table = [ 0 ; MAX ] ;
110
+ let mut table = Self :: empty ( ) . table ;
86
111
let mut idx = 0 ;
87
112
88
113
assert ! (
@@ -91,27 +116,30 @@ impl<const MAX: usize> GlobalDescriptorTable<MAX> {
91
116
) ;
92
117
93
118
while idx < len {
94
- table[ idx] = slice[ idx] ;
119
+ table[ idx] = Entry :: new ( slice[ idx] ) ;
95
120
idx += 1 ;
96
121
}
97
122
98
123
Self { table, len }
99
124
}
100
125
101
- /// Get a reference to the internal table.
126
+ /// Get a reference to the internal [`Entry`] table.
102
127
///
103
- /// The resulting slice may contain system descriptors, which span two `u64` s.
128
+ /// The resulting slice may contain system descriptors, which span two [`Entry`] s.
104
129
#[ inline]
105
- pub fn as_raw_slice ( & self ) -> & [ u64 ] {
130
+ pub fn entries ( & self ) -> & [ Entry ] {
106
131
& self . table [ ..self . len ]
107
132
}
108
133
109
134
/// Adds the given segment descriptor to the GDT, returning the segment selector.
110
135
///
111
- /// Panics if the GDT doesn't have enough free entries to hold the Descriptor.
136
+ /// Note that depending on the type of the [`Descriptor`] this may add either
137
+ /// one or two new entries.
138
+ ///
139
+ /// Panics if the GDT doesn't have enough free entries.
112
140
#[ inline]
113
141
#[ cfg_attr( feature = "const_fn" , rustversion:: attr( all( ) , const ) ) ]
114
- pub fn add_entry ( & mut self , entry : Descriptor ) -> SegmentSelector {
142
+ pub fn append ( & mut self , entry : Descriptor ) -> SegmentSelector {
115
143
let index = match entry {
116
144
Descriptor :: UserSegment ( value) => {
117
145
if self . len > self . table . len ( ) . saturating_sub ( 1 ) {
@@ -179,7 +207,7 @@ impl<const MAX: usize> GlobalDescriptorTable<MAX> {
179
207
#[ cfg_attr( feature = "const_fn" , rustversion:: attr( all( ) , const ) ) ]
180
208
fn push ( & mut self , value : u64 ) -> usize {
181
209
let index = self . len ;
182
- self . table [ index] = value;
210
+ self . table [ index] = Entry :: new ( value) ;
183
211
self . len += 1 ;
184
212
index
185
213
}
@@ -378,11 +406,11 @@ mod tests {
378
406
// Makes a GDT that has two free slots
379
407
fn make_six_entry_gdt ( ) -> GlobalDescriptorTable {
380
408
let mut gdt = GlobalDescriptorTable :: new ( ) ;
381
- gdt. add_entry ( Descriptor :: kernel_code_segment ( ) ) ;
382
- gdt. add_entry ( Descriptor :: kernel_data_segment ( ) ) ;
383
- gdt. add_entry ( Descriptor :: UserSegment ( DescriptorFlags :: USER_CODE32 . bits ( ) ) ) ;
384
- gdt. add_entry ( Descriptor :: user_data_segment ( ) ) ;
385
- gdt. add_entry ( Descriptor :: user_code_segment ( ) ) ;
409
+ gdt. append ( Descriptor :: kernel_code_segment ( ) ) ;
410
+ gdt. append ( Descriptor :: kernel_data_segment ( ) ) ;
411
+ gdt. append ( Descriptor :: UserSegment ( DescriptorFlags :: USER_CODE32 . bits ( ) ) ) ;
412
+ gdt. append ( Descriptor :: user_data_segment ( ) ) ;
413
+ gdt. append ( Descriptor :: user_code_segment ( ) ) ;
386
414
assert_eq ! ( gdt. len, 6 ) ;
387
415
gdt
388
416
}
@@ -391,7 +419,7 @@ mod tests {
391
419
392
420
fn make_full_gdt ( ) -> GlobalDescriptorTable {
393
421
let mut gdt = make_six_entry_gdt ( ) ;
394
- gdt. add_entry ( Descriptor :: tss_segment ( & TSS ) ) ;
422
+ gdt. append ( Descriptor :: tss_segment ( & TSS ) ) ;
395
423
assert_eq ! ( gdt. len, 8 ) ;
396
424
gdt
397
425
}
@@ -400,9 +428,9 @@ mod tests {
400
428
pub fn push_max_segments ( ) {
401
429
// Make sure we don't panic with user segments
402
430
let mut gdt = make_six_entry_gdt ( ) ;
403
- gdt. add_entry ( Descriptor :: user_data_segment ( ) ) ;
431
+ gdt. append ( Descriptor :: user_data_segment ( ) ) ;
404
432
assert_eq ! ( gdt. len, 7 ) ;
405
- gdt. add_entry ( Descriptor :: user_data_segment ( ) ) ;
433
+ gdt. append ( Descriptor :: user_data_segment ( ) ) ;
406
434
assert_eq ! ( gdt. len, 8 ) ;
407
435
// Make sure we don't panic with system segments
408
436
let _ = make_full_gdt ( ) ;
@@ -412,15 +440,23 @@ mod tests {
412
440
#[ should_panic]
413
441
pub fn panic_user_segment ( ) {
414
442
let mut gdt = make_full_gdt ( ) ;
415
- gdt. add_entry ( Descriptor :: user_data_segment ( ) ) ;
443
+ gdt. append ( Descriptor :: user_data_segment ( ) ) ;
416
444
}
417
445
418
446
#[ test]
419
447
#[ should_panic]
420
448
pub fn panic_system_segment ( ) {
421
449
let mut gdt = make_six_entry_gdt ( ) ;
422
- gdt. add_entry ( Descriptor :: user_data_segment ( ) ) ;
450
+ gdt. append ( Descriptor :: user_data_segment ( ) ) ;
423
451
// We have one free slot, but the GDT requires two
424
- gdt. add_entry ( Descriptor :: tss_segment ( & TSS ) ) ;
452
+ gdt. append ( Descriptor :: tss_segment ( & TSS ) ) ;
453
+ }
454
+
455
+ #[ test]
456
+ pub fn from_entries ( ) {
457
+ let raw = [ 0 , Flags :: KERNEL_CODE64 . bits ( ) , Flags :: KERNEL_DATA . bits ( ) ] ;
458
+ let gdt = unsafe { GlobalDescriptorTable :: < 3 > :: from_raw_entries ( & raw ) } ;
459
+ assert_eq ! ( gdt. table. len( ) , 3 ) ;
460
+ assert_eq ! ( gdt. entries( ) . len( ) , 3 ) ;
425
461
}
426
462
}
0 commit comments