Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get rid of some mutable global statics #224

Merged
merged 5 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 108 additions & 66 deletions src/cpu/gdt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,98 +4,140 @@
//
// Author: Joerg Roedel <[email protected]>

use super::tss::{X86Tss, TSS_LIMIT};
use super::tss::X86Tss;
use crate::address::VirtAddr;
use crate::locking::{RWLock, ReadLockGuard, WriteLockGuard};
use crate::types::{SVSM_CS, SVSM_DS, SVSM_TSS};
use core::arch::asm;
use core::mem;

#[repr(C, packed(2))]
#[derive(Clone, Copy, Debug)]
pub struct GdtDesc {
struct GDTDesc {
size: u16,
addr: VirtAddr,
}

const GDT_SIZE: u16 = 8;

static mut GDT: [u64; GDT_SIZE as usize] = [
0,
0x00af9a000000ffff, // 64-bit code segment
0x00cf92000000ffff, // 64-bit data segment
0, // Reserved for User code
0, // Reserver for User data
0, // Reverved
0, // TSS
0, // TSS continued
];
#[derive(Copy, Clone, Debug)]
pub struct GDTEntry(u64);

pub fn load_tss(tss: &X86Tss) {
let addr = (tss as *const X86Tss) as u64;
impl GDTEntry {
pub const fn from_raw(entry: u64) -> Self {
Self(entry)
}

let mut desc0: u64 = 0;
let mut desc1: u64 = 0;
pub fn to_raw(&self) -> u64 {
self.0
}

// Limit
desc0 |= TSS_LIMIT & 0xffffu64;
desc0 |= ((TSS_LIMIT >> 16) & 0xfu64) << 48;
pub const fn null() -> Self {
Self(0u64)
}

// Address
desc0 |= (addr & 0x00ff_ffffu64) << 16;
desc0 |= (addr & 0xff00_0000u64) << 32;
desc1 |= addr >> 32;
pub const fn code_64_kernel() -> Self {
Self(0x00af9a000000ffffu64)
}

// Present
desc0 |= 1u64 << 47;
pub const fn data_64_kernel() -> Self {
Self(0x00cf92000000ffffu64)
}
}

// Type
desc0 |= 0x9u64 << 40;
const GDT_SIZE: u16 = 8;

unsafe {
let idx = (SVSM_TSS / 8) as usize;
GDT[idx] = desc0;
GDT[idx + 1] = desc1;
#[derive(Copy, Clone, Debug)]
pub struct GDT {
entries: [GDTEntry; GDT_SIZE as usize],
}

asm!("ltr %ax", in("ax") SVSM_TSS, options(att_syntax));
impl GDT {
pub const fn new() -> Self {
GDT {
entries: [
GDTEntry::null(),
GDTEntry::code_64_kernel(),
GDTEntry::data_64_kernel(),
GDTEntry::null(),
GDTEntry::null(),
GDTEntry::null(),
GDTEntry::null(),
GDTEntry::null(),
],
}
}
}

pub fn gdt_base_limit() -> (u64, u32) {
unsafe {
pub fn base_limit(&self) -> (u64, u32) {
let gdt_entries = GDT_SIZE as usize;
let base = (&GDT as *const [u64; GDT_SIZE as usize]) as u64;
let base = (self as *const GDT) as u64;
let limit = ((mem::size_of::<u64>() * gdt_entries) - 1) as u32;
(base, limit)
}
}

pub fn load_gdt() {
unsafe {
let gdt_desc: GdtDesc = GdtDesc {
fn descriptor(&self) -> GDTDesc {
GDTDesc {
size: (GDT_SIZE * 8) - 1,
addr: VirtAddr::from(GDT.as_ptr()),
};

asm!(r#" /* Load GDT */
lgdt (%rax)

/* Reload data segments */
movw %cx, %ds
movw %cx, %es
movw %cx, %fs
movw %cx, %gs
movw %cx, %ss

/* Reload code segment */
pushq %rdx
leaq 1f(%rip), %rax
pushq %rax
lretq
1:
"#,
in("rax") &gdt_desc,
in("rdx") SVSM_CS,
in("rcx") SVSM_DS,
options(att_syntax));
addr: VirtAddr::from(self.entries.as_ptr()),
}
}

pub fn load(&self) {
let gdt_desc = self.descriptor();
unsafe {
asm!(r#" /* Load GDT */
lgdt (%rax)

/* Reload data segments */
movw %cx, %ds
movw %cx, %es
movw %cx, %fs
movw %cx, %gs
movw %cx, %ss

/* Reload code segment */
pushq %rdx
leaq 1f(%rip), %rax
pushq %rax
lretq
1:
"#,
in("rax") &gdt_desc,
in("rdx") SVSM_CS,
in("rcx") SVSM_DS,
options(att_syntax));
}
}

fn set_tss_entry(&mut self, desc0: GDTEntry, desc1: GDTEntry) {
let idx = (SVSM_TSS / 8) as usize;

self.entries[idx] = desc0;
self.entries[idx + 1] = desc1;
}

fn clear_tss_entry(&mut self) {
let idx = (SVSM_TSS / 8) as usize;

self.entries[idx] = GDTEntry::null();
self.entries[idx + 1] = GDTEntry::null();
}

pub fn load_tss(&mut self, tss: &X86Tss) {
let (desc0, desc1) = tss.to_gdt_entry();

self.set_tss_entry(desc0, desc1);
unsafe {
asm!("ltr %ax", in("ax") SVSM_TSS, options(att_syntax));
}
self.clear_tss_entry()
}
}

static GDT: RWLock<GDT> = RWLock::new(GDT::new());

pub fn gdt() -> ReadLockGuard<'static, GDT> {
GDT.lock_read()
}

pub fn gdt_mut() -> WriteLockGuard<'static, GDT> {
GDT.lock_write()
}
63 changes: 50 additions & 13 deletions src/cpu/idt/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use crate::address::{Address, VirtAddr};
use crate::cpu::registers::{X86GeneralRegs, X86InterruptFrame};
use crate::locking::{RWLock, ReadLockGuard, WriteLockGuard};
use crate::types::SVSM_CS;
use core::arch::{asm, global_asm};
use core::mem;
Expand Down Expand Up @@ -104,27 +105,63 @@ struct IdtDesc {
address: VirtAddr,
}

pub type Idt = [IdtEntry; IDT_ENTRIES];
#[derive(Copy, Clone, Debug)]
pub struct IDT {
entries: [IdtEntry; IDT_ENTRIES],
}

pub static mut GLOBAL_IDT: Idt = [IdtEntry::no_handler(); IDT_ENTRIES];
impl IDT {
pub const fn new() -> Self {
IDT {
entries: [IdtEntry::no_handler(); IDT_ENTRIES],
}
}

pub fn idt_base_limit() -> (u64, u32) {
unsafe {
let base = (&GLOBAL_IDT as *const Idt) as u64;
pub fn init(&mut self, handler_array: *const u8, size: usize) -> &mut Self {
// Set IDT handlers
let handlers = VirtAddr::from(handler_array);

for idx in 0..size {
self.set_entry(idx, IdtEntry::entry(handlers + (32 * idx)));
}

self
}

pub fn set_entry(&mut self, idx: usize, entry: IdtEntry) -> &mut Self {
self.entries[idx] = entry;

self
}

pub fn load(&self) -> &Self {
let desc: IdtDesc = IdtDesc {
size: (IDT_ENTRIES * 16) as u16,
address: VirtAddr::from(self.entries.as_ptr()),
};

unsafe {
asm!("lidt (%rax)", in("rax") &desc, options(att_syntax));
}

self
}

pub fn base_limit(&self) -> (u64, u32) {
let base = (self as *const IDT) as u64;
let limit = (IDT_ENTRIES * mem::size_of::<IdtEntry>()) as u32;
(base, limit)
}
}

pub fn load_idt(idt: &Idt) {
let desc: IdtDesc = IdtDesc {
size: (IDT_ENTRIES * 16) as u16,
address: VirtAddr::from(idt.as_ptr()),
};
static IDT: RWLock<IDT> = RWLock::new(IDT::new());

unsafe {
asm!("lidt (%rax)", in("rax") &desc, options(att_syntax));
}
pub fn idt() -> ReadLockGuard<'static, IDT> {
IDT.lock_read()
}

pub fn idt_mut() -> WriteLockGuard<'static, IDT> {
IDT.lock_write()
}

pub fn triple_fault() {
Expand Down
2 changes: 2 additions & 0 deletions src/cpu/idt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@
pub mod common;
pub mod stage2;
pub mod svsm;

pub use common::{idt, idt_mut};
24 changes: 7 additions & 17 deletions src/cpu/idt/stage2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,25 @@
//
// Author: Joerg Roedel <[email protected]>

use super::common::{load_idt, Idt, IdtEntry, DF_VECTOR, GLOBAL_IDT, HV_VECTOR, VC_VECTOR};
use crate::address::VirtAddr;
use super::common::{idt_mut, DF_VECTOR, HV_VECTOR, VC_VECTOR};
use crate::cpu::control_regs::read_cr2;
use crate::cpu::vc::{stage2_handle_vc_exception, stage2_handle_vc_exception_no_ghcb};
use crate::cpu::X86ExceptionContext;
use core::arch::global_asm;

fn init_idt(idt: &mut Idt, handler_array: *const u8) {
// Set IDT handlers
let handlers = VirtAddr::from(handler_array);
for (i, entry) in idt.iter_mut().enumerate() {
*entry = IdtEntry::entry(handlers + (32 * i));
}
}

pub fn early_idt_init_no_ghcb() {
unsafe {
init_idt(
&mut GLOBAL_IDT,
&stage2_idt_handler_array_no_ghcb as *const u8,
);
load_idt(&GLOBAL_IDT);
idt_mut()
.init(&stage2_idt_handler_array_no_ghcb as *const u8, 32)
.load();
}
}

pub fn early_idt_init() {
unsafe {
init_idt(&mut GLOBAL_IDT, &stage2_idt_handler_array as *const u8);
load_idt(&GLOBAL_IDT);
idt_mut()
.init(&stage2_idt_handler_array as *const u8, 32)
.load();
}
}

Expand Down
29 changes: 12 additions & 17 deletions src/cpu/idt/svsm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,39 +11,34 @@ use super::super::tss::IST_DF;
use super::super::vc::handle_vc_exception;
use super::common::PF_ERROR_WRITE;
use super::common::{
load_idt, Idt, IdtEntry, BP_VECTOR, DF_VECTOR, GLOBAL_IDT, GP_VECTOR, HV_VECTOR, PF_VECTOR,
VC_VECTOR,
idt_mut, IdtEntry, BP_VECTOR, DF_VECTOR, GP_VECTOR, HV_VECTOR, PF_VECTOR, VC_VECTOR,
};
use crate::address::VirtAddr;
use crate::cpu::X86ExceptionContext;
use crate::debug::gdbstub::svsm_gdbstub::handle_debug_exception;
use core::arch::global_asm;

fn init_idt(idt: &mut Idt) {
// Set IDT handlers
let handlers = unsafe { VirtAddr::from(&svsm_idt_handler_array as *const u8) };
for (i, entry) in idt.iter_mut().enumerate() {
*entry = IdtEntry::entry(handlers + (32 * i));
fn init_ist_vectors() {
unsafe {
let handler = VirtAddr::from(&svsm_idt_handler_array as *const u8) + (32 * DF_VECTOR);
idt_mut().set_entry(
DF_VECTOR,
IdtEntry::ist_entry(handler, IST_DF.try_into().unwrap()),
);
}
}

unsafe fn init_ist_vectors(idt: &mut Idt) {
let handler = VirtAddr::from(&svsm_idt_handler_array as *const u8) + (32 * DF_VECTOR);
idt[DF_VECTOR] = IdtEntry::ist_entry(handler, IST_DF.try_into().unwrap());
}

pub fn early_idt_init() {
unsafe {
init_idt(&mut GLOBAL_IDT);
load_idt(&GLOBAL_IDT);
idt_mut()
.init(&svsm_idt_handler_array as *const u8, 32)
.load();
}
}

pub fn idt_init() {
// Set IST vectors
unsafe {
init_ist_vectors(&mut GLOBAL_IDT);
}
init_ist_vectors();
}

#[no_mangle]
Expand Down
Loading
Loading