mirror of
https://github.com/rcore-os/rCore.git
synced 2024-11-23 00:16:17 +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 core::fmt::Debug;
|
||||||
use spin::{Mutex, MutexGuard, Once};
|
use spin::{Mutex, MutexGuard, Once};
|
||||||
use x86_64::{PrivilegeLevel, VirtAddr};
|
use x86_64::{PrivilegeLevel, VirtAddr};
|
||||||
use x86_64::structures::gdt::SegmentSelector;
|
use x86_64::structures::gdt::*;
|
||||||
use x86_64::structures::tss::TaskStateSegment;
|
use x86_64::structures::tss::TaskStateSegment;
|
||||||
|
|
||||||
/// Alloc TSS & GDT at kernel heap, then init and load it.
|
/// 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 tss = Box::into_raw(tss);
|
||||||
|
|
||||||
let gdt = Box::new({
|
let gdt = Box::new({
|
||||||
let mut gdt = Gdt::new();
|
let mut gdt = GlobalDescriptorTable::new();
|
||||||
gdt.add_entry(KCODE);
|
gdt.add_entry(KCODE);
|
||||||
gdt.add_entry(UCODE);
|
gdt.add_entry(UCODE);
|
||||||
gdt.add_entry(KDATA);
|
// KDATA use segment 0
|
||||||
|
// gdt.add_entry(KDATA);
|
||||||
gdt.add_entry(UDATA);
|
gdt.add_entry(UDATA);
|
||||||
gdt.add_entry(UCODE32);
|
gdt.add_entry(UCODE32);
|
||||||
gdt.add_entry(UDATA32);
|
gdt.add_entry(UDATA32);
|
||||||
@ -60,7 +61,7 @@ static CPUS: [Once<Mutex<Cpu>>; MAX_CPU_NUM] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
pub struct Cpu {
|
pub struct Cpu {
|
||||||
gdt: &'static Gdt,
|
gdt: &'static GlobalDescriptorTable,
|
||||||
tss: &'static mut TaskStateSegment,
|
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 KCODE_SELECTOR: SegmentSelector = SegmentSelector::new(1, PrivilegeLevel::Ring0);
|
||||||
pub const UCODE_SELECTOR: SegmentSelector = SegmentSelector::new(2, PrivilegeLevel::Ring3);
|
pub const UCODE_SELECTOR: SegmentSelector = SegmentSelector::new(2, PrivilegeLevel::Ring3);
|
||||||
pub const KDATA_SELECTOR: SegmentSelector = SegmentSelector::new(3, PrivilegeLevel::Ring0);
|
pub const KDATA_SELECTOR: SegmentSelector = SegmentSelector::new(0, PrivilegeLevel::Ring0);
|
||||||
pub const UDATA_SELECTOR: SegmentSelector = SegmentSelector::new(4, PrivilegeLevel::Ring3);
|
pub const UDATA_SELECTOR: SegmentSelector = SegmentSelector::new(3, PrivilegeLevel::Ring3);
|
||||||
pub const UCODE32_SELECTOR: SegmentSelector = SegmentSelector::new(5, PrivilegeLevel::Ring3);
|
pub const UCODE32_SELECTOR: SegmentSelector = SegmentSelector::new(4, PrivilegeLevel::Ring3);
|
||||||
pub const UDATA32_SELECTOR: SegmentSelector = SegmentSelector::new(6, PrivilegeLevel::Ring3);
|
pub const UDATA32_SELECTOR: SegmentSelector = SegmentSelector::new(5, PrivilegeLevel::Ring3);
|
||||||
pub const TSS_SELECTOR: SegmentSelector = SegmentSelector::new(7, PrivilegeLevel::Ring0);
|
pub const TSS_SELECTOR: SegmentSelector = SegmentSelector::new(6, 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user