Skip to content

Commit 6226245

Browse files
committed
gdt: Improve panic message when SystemSegment is pushed
Signed-off-by: Joe Richey <joerichey@google.com>
1 parent 3a16af0 commit 6226245

File tree

1 file changed

+60
-10
lines changed

1 file changed

+60
-10
lines changed

src/structures/gdt.rs

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,21 @@ impl GlobalDescriptorTable {
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.next_free > self.table.len() - 1 {
105+
panic!("GDT full")
106+
}
107+
self.push(value)
108+
}
104109
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+
}
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.next_free;
169+
self.table[index] = value;
170+
self.next_free += 1;
171+
index
168172
}
169173

170174
/// Creates the descriptor pointer for this table. This pointer can only be
@@ -334,6 +338,7 @@ impl Descriptor {
334338
#[cfg(test)]
335339
mod tests {
336340
use super::DescriptorFlags as Flags;
341+
use super::*;
337342

338343
#[test]
339344
#[rustfmt::skip]
@@ -347,4 +352,49 @@ 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+
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+
}
350400
}

0 commit comments

Comments
 (0)