@@ -95,13 +95,21 @@ impl GlobalDescriptorTable {
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 . next_free > self . table . len ( ) - 1 {
105
+ panic ! ( "GDT full" )
106
+ }
107
+ self . push ( value)
108
+ }
104
109
Descriptor :: SystemSegment ( value_low, value_high) => {
110
+ if self . next_free > self . table . len ( ) - 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 . next_free ;
169
+ self . table [ index] = value;
170
+ self . next_free += 1 ;
171
+ index
168
172
}
169
173
170
174
/// Creates the descriptor pointer for this table. This pointer can only be
@@ -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,49 @@ 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
+ gdt
365
+ }
366
+
367
+ static TSS : TaskStateSegment = TaskStateSegment :: new ( ) ;
368
+
369
+ fn make_full_gdt ( ) -> GlobalDescriptorTable {
370
+ let mut gdt = make_six_entry_gdt ( ) ;
371
+ gdt. add_entry ( Descriptor :: tss_segment ( & TSS ) ) ;
372
+ gdt
373
+ }
374
+
375
+ #[ test]
376
+ pub fn push_max_segments ( ) {
377
+ // Make sure we don't panic with user segments
378
+ let mut gdt = make_six_entry_gdt ( ) ;
379
+ gdt. add_entry ( Descriptor :: user_data_segment ( ) ) ;
380
+ gdt. add_entry ( Descriptor :: user_data_segment ( ) ) ;
381
+ // Make sure we don't panic with system segments
382
+ let _ = make_full_gdt ( ) ;
383
+ }
384
+
385
+ #[ test]
386
+ #[ should_panic]
387
+ pub fn panic_user_segment ( ) {
388
+ let mut gdt = make_full_gdt ( ) ;
389
+ gdt. add_entry ( Descriptor :: user_data_segment ( ) ) ;
390
+ }
391
+
392
+ #[ test]
393
+ #[ should_panic]
394
+ pub fn panic_system_segment ( ) {
395
+ let mut gdt = make_six_entry_gdt ( ) ;
396
+ gdt. add_entry ( Descriptor :: user_data_segment ( ) ) ;
397
+ // We have one free slot, but the GDT requires two
398
+ gdt. add_entry ( Descriptor :: tss_segment ( & TSS ) ) ;
399
+ }
350
400
}
0 commit comments