mirror of
https://github.com/rcore-os/rCore.git
synced 2024-11-22 16:16:16 +04:00
Use x86_64 GDT structs
This commit is contained in:
parent
f707d7e757
commit
da4db141d0
@ -5,7 +5,7 @@ use core::fmt;
|
||||
use core::fmt::Debug;
|
||||
use spin::{Mutex, MutexGuard, Once};
|
||||
use x86_64::{PrivilegeLevel, VirtAddr};
|
||||
use x86_64::structures::gdt::SegmentSelector;
|
||||
use x86_64::structures::gdt::*;
|
||||
use x86_64::structures::tss::TaskStateSegment;
|
||||
|
||||
/// Alloc TSS & GDT at kernel heap, then init and load it.
|
||||
@ -29,10 +29,11 @@ pub fn init() {
|
||||
let tss = Box::into_raw(tss);
|
||||
|
||||
let gdt = Box::new({
|
||||
let mut gdt = Gdt::new();
|
||||
let mut gdt = GlobalDescriptorTable::new();
|
||||
gdt.add_entry(KCODE);
|
||||
gdt.add_entry(UCODE);
|
||||
gdt.add_entry(KDATA);
|
||||
// KDATA use segment 0
|
||||
// gdt.add_entry(KDATA);
|
||||
gdt.add_entry(UDATA);
|
||||
gdt.add_entry(UCODE32);
|
||||
gdt.add_entry(UDATA32);
|
||||
@ -60,7 +61,7 @@ static CPUS: [Once<Mutex<Cpu>>; MAX_CPU_NUM] = [
|
||||
];
|
||||
|
||||
pub struct Cpu {
|
||||
gdt: &'static Gdt,
|
||||
gdt: &'static GlobalDescriptorTable,
|
||||
tss: &'static mut TaskStateSegment,
|
||||
}
|
||||
|
||||
@ -92,131 +93,8 @@ const UDATA32: Descriptor = Descriptor::UserSegment(0x00cff200_0000ffff); // EX
|
||||
|
||||
pub const KCODE_SELECTOR: SegmentSelector = SegmentSelector::new(1, PrivilegeLevel::Ring0);
|
||||
pub const UCODE_SELECTOR: SegmentSelector = SegmentSelector::new(2, PrivilegeLevel::Ring3);
|
||||
pub const KDATA_SELECTOR: SegmentSelector = SegmentSelector::new(3, PrivilegeLevel::Ring0);
|
||||
pub const UDATA_SELECTOR: SegmentSelector = SegmentSelector::new(4, PrivilegeLevel::Ring3);
|
||||
pub const UCODE32_SELECTOR: SegmentSelector = SegmentSelector::new(5, PrivilegeLevel::Ring3);
|
||||
pub const UDATA32_SELECTOR: SegmentSelector = SegmentSelector::new(6, PrivilegeLevel::Ring3);
|
||||
pub const TSS_SELECTOR: SegmentSelector = SegmentSelector::new(7, PrivilegeLevel::Ring0);
|
||||
|
||||
|
||||
pub struct Gdt {
|
||||
table: [u64; 10],
|
||||
next_free: usize,
|
||||
}
|
||||
|
||||
impl Gdt {
|
||||
pub fn new() -> Gdt {
|
||||
Gdt {
|
||||
table: [0; 10],
|
||||
next_free: 1,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_entry(&mut self, entry: Descriptor) -> SegmentSelector {
|
||||
let index = match entry {
|
||||
Descriptor::UserSegment(value) => self.push(value),
|
||||
Descriptor::SystemSegment(value_low, value_high) => {
|
||||
let index = self.push(value_low);
|
||||
self.push(value_high);
|
||||
index
|
||||
}
|
||||
};
|
||||
SegmentSelector::new(index as u16, PrivilegeLevel::Ring0)
|
||||
}
|
||||
|
||||
pub fn load(&'static self) {
|
||||
use x86_64::instructions::tables::{DescriptorTablePointer, lgdt};
|
||||
use core::mem::size_of;
|
||||
|
||||
let ptr = DescriptorTablePointer {
|
||||
base: self.table.as_ptr() as u64,
|
||||
limit: (self.table.len() * size_of::<u64>() - 1) as u16,
|
||||
};
|
||||
|
||||
unsafe { lgdt(&ptr) };
|
||||
}
|
||||
|
||||
fn push(&mut self, value: u64) -> usize {
|
||||
if self.next_free < self.table.len() {
|
||||
let index = self.next_free;
|
||||
self.table[index] = value;
|
||||
self.next_free += 1;
|
||||
index
|
||||
} else {
|
||||
panic!("GDT full");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Descriptor {
|
||||
UserSegment(u64),
|
||||
SystemSegment(u64, u64),
|
||||
}
|
||||
|
||||
impl Descriptor {
|
||||
pub fn tss_segment(tss: &'static TaskStateSegment) -> Descriptor {
|
||||
use core::mem::size_of;
|
||||
use bit_field::BitField;
|
||||
|
||||
let ptr = tss as *const _ as u64;
|
||||
|
||||
let mut low = DescriptorFlags::PRESENT.bits();
|
||||
// base
|
||||
low.set_bits(16..40, ptr.get_bits(0..24));
|
||||
low.set_bits(56..64, ptr.get_bits(24..32));
|
||||
// limit (the `-1` in needed since the bound is inclusive)
|
||||
low.set_bits(0..16, (size_of::<TaskStateSegment>() - 1) as u64);
|
||||
// type (0b1001 = available 64-bit tss)
|
||||
low.set_bits(40..44, 0b1001);
|
||||
|
||||
let mut high = 0;
|
||||
high.set_bits(0..32, ptr.get_bits(32..64));
|
||||
|
||||
Descriptor::SystemSegment(low, high)
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Reference: https://wiki.osdev.org/GDT
|
||||
struct DescriptorFlags: u64 {
|
||||
const ACCESSED = 1 << 40;
|
||||
const DATA_WRITABLE = 1 << 41;
|
||||
const CODE_READABLE = 1 << 41;
|
||||
const CONFORMING = 1 << 42;
|
||||
const EXECUTABLE = 1 << 43;
|
||||
const USER_SEGMENT = 1 << 44;
|
||||
const USER_MODE = 1 << 45 | 1 << 46;
|
||||
const PRESENT = 1 << 47;
|
||||
const LONG_MODE = 1 << 53;
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Descriptor {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
match self {
|
||||
Descriptor::UserSegment(flags) =>
|
||||
write!(f, "UserSegment( {:?} )", DescriptorFlags{bits: *flags}),
|
||||
Descriptor::SystemSegment(low, high) =>
|
||||
write!(f, "SystemSegment{:?}", (low, high)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod test
|
||||
{
|
||||
pub fn print_flags() {
|
||||
use super::*;
|
||||
// The following 4 GDT entries were copied from xv6 x86_64
|
||||
let list: [(&str, Descriptor); 4] = [
|
||||
("KCODE", super::KCODE), // Code, DPL=0, R/X
|
||||
("UCODE", super::UCODE), // Code, DPL=3, R/X
|
||||
("KDATA", super::KDATA), // Data, DPL=0, W
|
||||
("UDATA", super::UDATA), // Data, DPL=3, W
|
||||
];
|
||||
// Let's see what that means
|
||||
println!("GDT Segments from xv6 x86_64:");
|
||||
for (name, desc) in list.iter() {
|
||||
println!(" {}: {:?}", name, desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
pub const KDATA_SELECTOR: SegmentSelector = SegmentSelector::new(0, PrivilegeLevel::Ring0);
|
||||
pub const UDATA_SELECTOR: SegmentSelector = SegmentSelector::new(3, PrivilegeLevel::Ring3);
|
||||
pub const UCODE32_SELECTOR: SegmentSelector = SegmentSelector::new(4, PrivilegeLevel::Ring3);
|
||||
pub const UDATA32_SELECTOR: SegmentSelector = SegmentSelector::new(5, PrivilegeLevel::Ring3);
|
||||
pub const TSS_SELECTOR: SegmentSelector = SegmentSelector::new(6, PrivilegeLevel::Ring0);
|
Loading…
Reference in New Issue
Block a user