@@ -47,7 +47,7 @@ use crate::registers::segmentation::{Segment, CS, SS};
47
47
#[ derive( Debug , Clone ) ]
48
48
pub struct GlobalDescriptorTable {
49
49
table : [ u64 ; 8 ] ,
50
- next_free : usize ,
50
+ len : usize ,
51
51
}
52
52
53
53
impl GlobalDescriptorTable {
@@ -56,7 +56,7 @@ impl GlobalDescriptorTable {
56
56
pub const fn new ( ) -> GlobalDescriptorTable {
57
57
GlobalDescriptorTable {
58
58
table : [ 0 ; 8 ] ,
59
- next_free : 1 ,
59
+ len : 1 ,
60
60
}
61
61
}
62
62
@@ -68,40 +68,48 @@ impl GlobalDescriptorTable {
68
68
/// * The provided slice **must not be larger than 8 items** (only up to the first 8 will be observed.)
69
69
#[ inline]
70
70
pub const unsafe fn from_raw_slice ( slice : & [ u64 ] ) -> GlobalDescriptorTable {
71
- let next_free = slice. len ( ) ;
71
+ let len = slice. len ( ) ;
72
72
let mut table = [ 0 ; 8 ] ;
73
73
let mut idx = 0 ;
74
74
75
75
assert ! (
76
- next_free <= 8 ,
76
+ len <= 8 ,
77
77
"initializing a GDT from a slice requires it to be **at most** 8 elements."
78
78
) ;
79
79
80
- while idx != next_free {
80
+ while idx < len {
81
81
table[ idx] = slice[ idx] ;
82
82
idx += 1 ;
83
83
}
84
84
85
- GlobalDescriptorTable { table, next_free }
85
+ GlobalDescriptorTable { table, len }
86
86
}
87
87
88
88
/// Get a reference to the internal table.
89
89
///
90
90
/// The resulting slice may contain system descriptors, which span two `u64`s.
91
91
#[ inline]
92
92
pub fn as_raw_slice ( & self ) -> & [ u64 ] {
93
- & self . table [ ..self . next_free ]
93
+ & self . table [ ..self . len ]
94
94
}
95
95
96
96
/// Adds the given segment descriptor to the GDT, returning the segment selector.
97
97
///
98
- /// Panics if the GDT has no free entries left .
98
+ /// Panics if the GDT doesn't have enough free entries to hold the Descriptor .
99
99
#[ inline]
100
100
#[ cfg_attr( feature = "const_fn" , rustversion:: attr( all( ) , const ) ) ]
101
101
pub fn add_entry ( & mut self , entry : Descriptor ) -> SegmentSelector {
102
102
let index = match entry {
103
- Descriptor :: UserSegment ( value) => self . push ( value) ,
103
+ Descriptor :: UserSegment ( value) => {
104
+ if self . len > self . table . len ( ) . saturating_sub ( 1 ) {
105
+ panic ! ( "GDT full" )
106
+ }
107
+ self . push ( value)
108
+ }
104
109
Descriptor :: SystemSegment ( value_low, value_high) => {
110
+ if self . len > self . table . len ( ) . saturating_sub ( 2 ) {
111
+ panic ! ( "GDT requires two free spaces to hold a SystemSegment" )
112
+ }
105
113
let index = self . push ( value_low) ;
106
114
self . push ( value_high) ;
107
115
index
@@ -157,14 +165,10 @@ impl GlobalDescriptorTable {
157
165
#[ inline]
158
166
#[ cfg_attr( feature = "const_fn" , rustversion:: attr( all( ) , const ) ) ]
159
167
fn push ( & mut self , value : u64 ) -> usize {
160
- if self . next_free < self . table . len ( ) {
161
- let index = self . next_free ;
162
- self . table [ index] = value;
163
- self . next_free += 1 ;
164
- index
165
- } else {
166
- panic ! ( "GDT full" ) ;
167
- }
168
+ let index = self . len ;
169
+ self . table [ index] = value;
170
+ self . len += 1 ;
171
+ index
168
172
}
169
173
170
174
/// Creates the descriptor pointer for this table. This pointer can only be
@@ -174,7 +178,7 @@ impl GlobalDescriptorTable {
174
178
use core:: mem:: size_of;
175
179
super :: DescriptorTablePointer {
176
180
base : crate :: VirtAddr :: new ( self . table . as_ptr ( ) as u64 ) ,
177
- limit : ( self . next_free * size_of :: < u64 > ( ) - 1 ) as u16 ,
181
+ limit : ( self . len * size_of :: < u64 > ( ) - 1 ) as u16 ,
178
182
}
179
183
}
180
184
}
@@ -334,6 +338,7 @@ impl Descriptor {
334
338
#[ cfg( test) ]
335
339
mod tests {
336
340
use super :: DescriptorFlags as Flags ;
341
+ use super :: * ;
337
342
338
343
#[ test]
339
344
#[ rustfmt:: skip]
@@ -347,4 +352,53 @@ mod tests {
347
352
assert_eq ! ( Flags :: USER_CODE32 . bits( ) , 0x00cffb000000ffff ) ;
348
353
assert_eq ! ( Flags :: USER_DATA . bits( ) , 0x00cff3000000ffff ) ;
349
354
}
355
+
356
+ // Makes a GDT that has two free slots
357
+ fn make_six_entry_gdt ( ) -> GlobalDescriptorTable {
358
+ let mut gdt = GlobalDescriptorTable :: new ( ) ;
359
+ gdt. add_entry ( Descriptor :: kernel_code_segment ( ) ) ;
360
+ gdt. add_entry ( Descriptor :: kernel_data_segment ( ) ) ;
361
+ gdt. add_entry ( Descriptor :: UserSegment ( DescriptorFlags :: USER_CODE32 . bits ( ) ) ) ;
362
+ gdt. add_entry ( Descriptor :: user_data_segment ( ) ) ;
363
+ gdt. add_entry ( Descriptor :: user_code_segment ( ) ) ;
364
+ assert_eq ! ( gdt. len, 6 ) ;
365
+ gdt
366
+ }
367
+
368
+ static TSS : TaskStateSegment = TaskStateSegment :: new ( ) ;
369
+
370
+ fn make_full_gdt ( ) -> GlobalDescriptorTable {
371
+ let mut gdt = make_six_entry_gdt ( ) ;
372
+ gdt. add_entry ( Descriptor :: tss_segment ( & TSS ) ) ;
373
+ assert_eq ! ( gdt. len, 8 ) ;
374
+ gdt
375
+ }
376
+
377
+ #[ test]
378
+ pub fn push_max_segments ( ) {
379
+ // Make sure we don't panic with user segments
380
+ let mut gdt = make_six_entry_gdt ( ) ;
381
+ gdt. add_entry ( Descriptor :: user_data_segment ( ) ) ;
382
+ assert_eq ! ( gdt. len, 7 ) ;
383
+ gdt. add_entry ( Descriptor :: user_data_segment ( ) ) ;
384
+ assert_eq ! ( gdt. len, 8 ) ;
385
+ // Make sure we don't panic with system segments
386
+ let _ = make_full_gdt ( ) ;
387
+ }
388
+
389
+ #[ test]
390
+ #[ should_panic]
391
+ pub fn panic_user_segment ( ) {
392
+ let mut gdt = make_full_gdt ( ) ;
393
+ gdt. add_entry ( Descriptor :: user_data_segment ( ) ) ;
394
+ }
395
+
396
+ #[ test]
397
+ #[ should_panic]
398
+ pub fn panic_system_segment ( ) {
399
+ let mut gdt = make_six_entry_gdt ( ) ;
400
+ gdt. add_entry ( Descriptor :: user_data_segment ( ) ) ;
401
+ // We have one free slot, but the GDT requires two
402
+ gdt. add_entry ( Descriptor :: tss_segment ( & TSS ) ) ;
403
+ }
350
404
}
0 commit comments