Add tdx early init and ve handler functions

This commit is contained in:
Hsy-Intel
2023-08-28 11:30:19 +08:00
committed by Tate, Hongliang Tian
parent d7710207bb
commit 4f0df44b29
3 changed files with 166 additions and 1 deletions

View File

@ -6,6 +6,8 @@ use core::fmt::Debug;
use trapframe::{GeneralRegs, UserContext as RawUserContext}; use trapframe::{GeneralRegs, UserContext as RawUserContext};
use log::debug; use log::debug;
#[cfg(feature = "intel_tdx")]
use tdx_guest::{serial_println, tdcall, tdvmcall, TdxVirtualExceptionType};
use x86_64::registers::rflags::RFlags; use x86_64::registers::rflags::RFlags;
use crate::trap::call_irq_callback_functions; use crate::trap::call_irq_callback_functions;
@ -39,6 +41,75 @@ pub struct TrapInformation {
pub err: usize, pub err: usize,
} }
#[cfg(feature = "intel_tdx")]
pub fn virtual_exception_handler(trapframe: &mut GeneralRegs, ve_info: &tdcall::TdgVeInfo) {
match ve_info.exit_reason.into() {
TdxVirtualExceptionType::Hlt => {
serial_println!("Ready to halt");
tdvmcall::hlt();
}
TdxVirtualExceptionType::Io => {
if !handle_ve_io(trapframe, ve_info) {
serial_println!("Handle tdx ioexit errors, ready to halt");
tdvmcall::hlt();
}
}
TdxVirtualExceptionType::MsrRead => {
let msr = tdvmcall::rdmsr(trapframe.rcx as u32).unwrap();
trapframe.rax = (msr as u32 & u32::MAX) as usize;
trapframe.rdx = ((msr >> 32) as u32 & u32::MAX) as usize;
}
TdxVirtualExceptionType::MsrWrite => {
let data = trapframe.rax as u64 | ((trapframe.rdx as u64) << 32);
tdvmcall::wrmsr(trapframe.rcx as u32, data).unwrap();
}
TdxVirtualExceptionType::CpuId => {
let cpuid_info = tdvmcall::cpuid(trapframe.rax as u32, trapframe.rcx as u32).unwrap();
let mask = 0xFFFF_FFFF_0000_0000_usize;
trapframe.rax = (trapframe.rax & mask) | cpuid_info.eax;
trapframe.rbx = (trapframe.rbx & mask) | cpuid_info.ebx;
trapframe.rcx = (trapframe.rcx & mask) | cpuid_info.ecx;
trapframe.rdx = (trapframe.rdx & mask) | cpuid_info.edx;
}
TdxVirtualExceptionType::Other => panic!("Unknown TDX vitrual exception type"),
_ => return,
}
trapframe.rip = trapframe.rip + ve_info.exit_instruction_length as usize;
}
#[cfg(feature = "intel_tdx")]
pub fn handle_ve_io(trapframe: &mut GeneralRegs, ve_info: &tdcall::TdgVeInfo) -> bool {
let size = match ve_info.exit_qualification & 0x3 {
0 => 1,
1 => 2,
3 => 4,
_ => panic!("Invalid size value"),
};
let direction = if (ve_info.exit_qualification >> 3) & 0x1 == 0 {
tdvmcall::Direction::Out
} else {
tdvmcall::Direction::In
};
let string = (ve_info.exit_qualification >> 4) & 0x1 == 1;
let repeat = (ve_info.exit_qualification >> 5) & 0x1 == 1;
let operand = if (ve_info.exit_qualification >> 6) & 0x1 == 0 {
tdvmcall::Operand::Dx
} else {
tdvmcall::Operand::Immediate
};
let port = (ve_info.exit_qualification >> 16) as u16;
match direction {
tdvmcall::Direction::In => {
trapframe.rax = tdvmcall::io_read(size, port).unwrap() as usize;
}
tdvmcall::Direction::Out => {
tdvmcall::io_write(size, port, trapframe.rax as u32).unwrap();
}
};
true
}
impl UserContext { impl UserContext {
pub fn general_regs(&self) -> &GeneralRegs { pub fn general_regs(&self) -> &GeneralRegs {
&self.user_context.general &self.user_context.general
@ -73,6 +144,13 @@ impl UserContextApiInternal for UserContext {
self.user_context.run(); self.user_context.run();
match CpuException::to_cpu_exception(self.user_context.trap_num as u16) { match CpuException::to_cpu_exception(self.user_context.trap_num as u16) {
Some(exception) => { Some(exception) => {
#[cfg(feature = "intel_tdx")]
if *exception == VIRTUALIZATION_EXCEPTION {
let ve_info =
tdcall::get_veinfo().expect("#VE handler: fail to get VE info\n");
virtual_exception_handler(self.general_regs_mut(), &ve_info);
continue;
}
if exception.typ == CpuExceptionType::FaultOrTrap if exception.typ == CpuExceptionType::FaultOrTrap
|| exception.typ == CpuExceptionType::Fault || exception.typ == CpuExceptionType::Fault
|| exception.typ == CpuExceptionType::Trap || exception.typ == CpuExceptionType::Trap

View File

@ -40,6 +40,8 @@ pub use self::prelude::Result;
use alloc::vec::Vec; use alloc::vec::Vec;
use arch::irq::{IrqCallbackHandle, IrqLine}; use arch::irq::{IrqCallbackHandle, IrqLine};
use core::{mem, panic::PanicInfo}; use core::{mem, panic::PanicInfo};
#[cfg(feature = "intel_tdx")]
use tdx_guest::tdx_early_init;
use trapframe::TrapFrame; use trapframe::TrapFrame;
static mut IRQ_CALLBACK_LIST: Vec<IrqCallbackHandle> = Vec::new(); static mut IRQ_CALLBACK_LIST: Vec<IrqCallbackHandle> = Vec::new();
@ -47,6 +49,13 @@ static mut IRQ_CALLBACK_LIST: Vec<IrqCallbackHandle> = Vec::new();
pub fn init() { pub fn init() {
arch::before_all_init(); arch::before_all_init();
logger::init(); logger::init();
#[cfg(feature = "intel_tdx")]
let td_info = tdx_early_init().unwrap();
#[cfg(feature = "intel_tdx")]
println!(
"td gpaw: {}, td attributes: {:?}\nTDX guest is initialized",
td_info.gpaw, td_info.attributes
);
vm::heap_allocator::init(); vm::heap_allocator::init();
boot::init(); boot::init();
vm::init(); vm::init();

View File

@ -1,15 +1,93 @@
use crate::{arch::irq::IRQ_LIST, cpu::CpuException}; use crate::{arch::irq::IRQ_LIST, cpu::CpuException};
#[cfg(feature = "intel_tdx")]
use tdx_guest::{serial_println, tdcall, tdvmcall, TdxVirtualExceptionType};
use trapframe::TrapFrame; use trapframe::TrapFrame;
#[cfg(feature = "intel_tdx")]
pub fn virtual_exception_handler(trapframe: &mut TrapFrame, ve_info: &tdcall::TdgVeInfo) {
match ve_info.exit_reason.into() {
TdxVirtualExceptionType::Hlt => {
serial_println!("Ready to halt");
tdvmcall::hlt();
}
TdxVirtualExceptionType::Io => {
if !handle_ve_io(trapframe, ve_info) {
serial_println!("Handle tdx ioexit errors, ready to halt");
tdvmcall::hlt();
}
}
TdxVirtualExceptionType::MsrRead => {
let msr = tdvmcall::rdmsr(trapframe.rcx as u32).unwrap();
trapframe.rax = (msr as u32 & u32::MAX) as usize;
trapframe.rdx = ((msr >> 32) as u32 & u32::MAX) as usize;
}
TdxVirtualExceptionType::MsrWrite => {
let data = trapframe.rax as u64 | ((trapframe.rdx as u64) << 32);
tdvmcall::wrmsr(trapframe.rcx as u32, data).unwrap();
}
TdxVirtualExceptionType::CpuId => {
let cpuid_info = tdvmcall::cpuid(trapframe.rax as u32, trapframe.rcx as u32).unwrap();
let mask = 0xFFFF_FFFF_0000_0000_usize;
trapframe.rax = (trapframe.rax & mask) | cpuid_info.eax;
trapframe.rbx = (trapframe.rbx & mask) | cpuid_info.ebx;
trapframe.rcx = (trapframe.rcx & mask) | cpuid_info.ecx;
trapframe.rdx = (trapframe.rdx & mask) | cpuid_info.edx;
}
TdxVirtualExceptionType::Other => panic!("Unknown TDX vitrual exception type"),
_ => return,
}
trapframe.rip = trapframe.rip + ve_info.exit_instruction_length as usize;
}
#[cfg(feature = "intel_tdx")]
pub fn handle_ve_io(trapframe: &mut TrapFrame, ve_info: &tdcall::TdgVeInfo) -> bool {
let size = match ve_info.exit_qualification & 0x3 {
0 => 1,
1 => 2,
3 => 4,
_ => panic!("Invalid size value"),
};
let direction = if (ve_info.exit_qualification >> 3) & 0x1 == 0 {
tdvmcall::Direction::Out
} else {
tdvmcall::Direction::In
};
let string = (ve_info.exit_qualification >> 4) & 0x1 == 1;
let repeat = (ve_info.exit_qualification >> 5) & 0x1 == 1;
let operand = if (ve_info.exit_qualification >> 6) & 0x1 == 0 {
tdvmcall::Operand::Dx
} else {
tdvmcall::Operand::Immediate
};
let port = (ve_info.exit_qualification >> 16) as u16;
match direction {
tdvmcall::Direction::In => {
trapframe.rax = tdvmcall::io_read(size, port).unwrap() as usize;
}
tdvmcall::Direction::Out => {
tdvmcall::io_write(size, port, trapframe.rax as u32).unwrap();
}
};
true
}
/// Only from kernel /// Only from kernel
#[no_mangle] #[no_mangle]
extern "sysv64" fn trap_handler(f: &mut TrapFrame) { extern "sysv64" fn trap_handler(f: &mut TrapFrame) {
if CpuException::is_cpu_exception(f.trap_num as u16) { if CpuException::is_cpu_exception(f.trap_num as u16) {
panic!("cannot handle kernel cpu fault now, information:{:#x?}", f); #[cfg(feature = "intel_tdx")]
if f.trap_num as u16 == 20 {
let ve_info = tdcall::get_veinfo().expect("#VE handler: fail to get VE info\n");
virtual_exception_handler(f, &ve_info);
} }
#[cfg(not(feature = "intel_tdx"))]
panic!("cannot handle kernel cpu fault now, information:{:#x?}", f);
} else {
call_irq_callback_functions(f); call_irq_callback_functions(f);
} }
}
pub(crate) fn call_irq_callback_functions(trap_frame: &TrapFrame) { pub(crate) fn call_irq_callback_functions(trap_frame: &TrapFrame) {
let irq_line = IRQ_LIST.get().unwrap().get(trap_frame.trap_num).unwrap(); let irq_line = IRQ_LIST.get().unwrap().get(trap_frame.trap_num).unwrap();