use core::fmt;
use shared::descriptor;
use shared::PrivilegeLevel;
bitflags! {
#[repr(C, packed)]
pub flags SegmentSelector: u16 {
const RPL_0 = 0b00,
const RPL_1 = 0b01,
const RPL_2 = 0b10,
const RPL_3 = 0b11,
const TI_GDT = 0 << 2,
const TI_LDT = 1 << 2,
}
}
impl SegmentSelector {
pub const fn new(index: u16, rpl: PrivilegeLevel) -> SegmentSelector {
SegmentSelector { bits: index << 3 | (rpl as u16) }
}
pub const fn from_raw(bits: u16) -> SegmentSelector {
SegmentSelector { bits: bits }
}
}
impl fmt::Display for SegmentSelector {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let r0 = match self.contains(RPL_0) {
false => "",
true => "Ring 0 segment selector.",
};
let r1 = match self.contains(RPL_1) {
false => "",
true => "Ring 1 segment selector.",
};
let r2 = match self.contains(RPL_2) {
false => "",
true => "Ring 2 segment selector.",
};
let r3 = match self.contains(RPL_3) {
false => "",
true => "Ring 3 segment selector.",
};
let tbl = match self.contains(TI_LDT) {
false => "GDT Table",
true => "LDT Table",
};
write!(f,
"Index {} in {}, {}{}{}{}",
self.bits >> 3,
tbl,
r0,
r1,
r2,
r3)
}
}
pub unsafe fn load_ss(sel: SegmentSelector) {
asm!("movw $0, %ss " :: "r" (sel.bits()) : "memory");
}
pub unsafe fn load_ds(sel: SegmentSelector) {
asm!("movw $0, %ds " :: "r" (sel.bits()) : "memory");
}
pub unsafe fn load_es(sel: SegmentSelector) {
asm!("movw $0, %es " :: "r" (sel.bits()) : "memory");
}
pub unsafe fn load_fs(sel: SegmentSelector) {
asm!("movw $0, %fs " :: "r" (sel.bits()) : "memory");
}
pub unsafe fn load_gs(sel: SegmentSelector) {
asm!("movw $0, %gs " :: "r" (sel.bits()) : "memory");
}
pub fn cs() -> SegmentSelector {
let segment: u16;
unsafe { asm!("mov %cs, $0" : "=r" (segment) ) };
SegmentSelector::from_raw(segment)
}
bitflags! {
pub flags DataAccess: u8 {
const DATA_WRITE = 1 << 1,
const DATA_EXPAND_DOWN = 1 << 2,
}
}
bitflags! {
pub flags CodeAccess: u8 {
const CODE_READ = 1 << 1,
const CODE_CONFORMING = 1 << 2,
}
}
#[repr(u8)]
pub enum Type {
Data(DataAccess),
Code(CodeAccess),
}
impl Type {
pub fn pack(self) -> u8 {
match self {
Type::Data(d) => d.bits | 0b10_000,
Type::Code(c) => c.bits | 0b11_000,
}
}
}
#[derive(Copy, Clone, Debug)]
#[repr(C, packed)]
pub struct SegmentDescriptor {
limit1: u16,
base1: u16,
base2: u8,
access: descriptor::Flags,
limit2_flags: Flags,
base3: u8,
}
impl SegmentDescriptor {
pub const NULL: SegmentDescriptor = SegmentDescriptor {
limit1: 0,
base1: 0,
base2: 0,
access: descriptor::Flags::BLANK,
limit2_flags: Flags::BLANK,
base3: 0,
};
pub(crate) fn memory_or_tss(base: u32, limit: u32, ty: descriptor::Type, dpl: PrivilegeLevel, flags: Flags) -> SegmentDescriptor {
let fine_grained = limit < 0x100000;
let (limit1, limit2) = if fine_grained {
((limit & 0xFFFF) as u16, ((limit & 0xF0000) >> 16) as u8)
} else {
if ((limit - 0xFFF) & 0xFFF) > 0 {
panic!("bad segment limit for GDT entry");
}
(((limit & 0xFFFF000) >> 12) as u16, ((limit & 0xF0000000) >> 28) as u8)
};
SegmentDescriptor {
limit1: limit1,
base1: base as u16,
base2: ((base as usize & 0xFF0000) >> 16) as u8,
access: descriptor::Flags::from_type(ty)
| descriptor::Flags::from_priv(dpl)
| descriptor::FLAGS_PRESENT,
limit2_flags: if fine_grained { Flags::empty() } else { FLAGS_G }
| flags
| Flags::from_limit2(limit2),
base3: ((base as usize & 0xFF000000) >> 24) as u8,
}
}
pub(crate) const fn high(address: u64) -> SegmentDescriptor {
SegmentDescriptor {
limit1: (address >> 32) as u16,
base1: (address >> 48) as u16,
base2: 0,
access: descriptor::Flags::BLANK,
limit2_flags: Flags::BLANK,
base3: 0,
}
}
}
bitflags! {
pub flags Flags: u8 {
const FLAGS_AVL = 1 << 4,
const FLAGS_L = 1 << 5,
const FLAGS_DB = 1 << 6,
const FLAGS_G = 1 << 7,
}
}
impl Flags {
pub const BLANK: Flags = Flags { bits: 0 };
pub fn from_limit2(limit2: u8) -> Flags {
assert_eq!(limit2 & !0b1111, 0);
Flags { bits: limit2 }
}
}