@@ -47,7 +47,7 @@ use crate::registers::segmentation::{Segment, CS, SS};
4747#[ derive( Debug , Clone ) ]
4848pub struct GlobalDescriptorTable {
4949 table : [ u64 ; 8 ] ,
50- next_free : usize ,
50+ len : usize ,
5151}
5252
5353impl GlobalDescriptorTable {
@@ -56,7 +56,7 @@ impl GlobalDescriptorTable {
5656 pub const fn new ( ) -> GlobalDescriptorTable {
5757 GlobalDescriptorTable {
5858 table : [ 0 ; 8 ] ,
59- next_free : 1 ,
59+ len : 1 ,
6060 }
6161 }
6262
@@ -68,40 +68,48 @@ impl GlobalDescriptorTable {
6868 /// * The provided slice **must not be larger than 8 items** (only up to the first 8 will be observed.)
6969 #[ inline]
7070 pub const unsafe fn from_raw_slice ( slice : & [ u64 ] ) -> GlobalDescriptorTable {
71- let next_free = slice. len ( ) ;
71+ let len = slice. len ( ) ;
7272 let mut table = [ 0 ; 8 ] ;
7373 let mut idx = 0 ;
7474
7575 assert ! (
76- next_free <= 8 ,
76+ len <= 8 ,
7777 "initializing a GDT from a slice requires it to be **at most** 8 elements."
7878 ) ;
7979
80- while idx != next_free {
80+ while idx < len {
8181 table[ idx] = slice[ idx] ;
8282 idx += 1 ;
8383 }
8484
85- GlobalDescriptorTable { table, next_free }
85+ GlobalDescriptorTable { table, len }
8686 }
8787
8888 /// Get a reference to the internal table.
8989 ///
9090 /// The resulting slice may contain system descriptors, which span two `u64`s.
9191 #[ inline]
9292 pub fn as_raw_slice ( & self ) -> & [ u64 ] {
93- & self . table [ ..self . next_free ]
93+ & self . table [ ..self . len ]
9494 }
9595
9696 /// Adds the given segment descriptor to the GDT, returning the segment selector.
9797 ///
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 .
9999 #[ inline]
100100 #[ cfg_attr( feature = "const_fn" , rustversion:: attr( all( ) , const ) ) ]
101101 pub fn add_entry ( & mut self , entry : Descriptor ) -> SegmentSelector {
102102 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+ }
104109 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+ }
105113 let index = self . push ( value_low) ;
106114 self . push ( value_high) ;
107115 index
@@ -157,14 +165,10 @@ impl GlobalDescriptorTable {
157165 #[ inline]
158166 #[ cfg_attr( feature = "const_fn" , rustversion:: attr( all( ) , const ) ) ]
159167 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
168172 }
169173
170174 /// Creates the descriptor pointer for this table. This pointer can only be
@@ -174,7 +178,7 @@ impl GlobalDescriptorTable {
174178 use core:: mem:: size_of;
175179 super :: DescriptorTablePointer {
176180 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 ,
178182 }
179183 }
180184}
@@ -334,6 +338,7 @@ impl Descriptor {
334338#[ cfg( test) ]
335339mod tests {
336340 use super :: DescriptorFlags as Flags ;
341+ use super :: * ;
337342
338343 #[ test]
339344 #[ rustfmt:: skip]
@@ -347,4 +352,53 @@ mod tests {
347352 assert_eq ! ( Flags :: USER_CODE32 . bits( ) , 0x00cffb000000ffff ) ;
348353 assert_eq ! ( Flags :: USER_DATA . bits( ) , 0x00cff3000000ffff ) ;
349354 }
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+ }
350404}
0 commit comments