mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-21 08:26:30 +00:00
Abstract the virtual_exception_handler function.
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
4f0df44b29
commit
82518955d7
@ -5,9 +5,11 @@ use core::fmt::Debug;
|
|||||||
|
|
||||||
use trapframe::{GeneralRegs, UserContext as RawUserContext};
|
use trapframe::{GeneralRegs, UserContext as RawUserContext};
|
||||||
|
|
||||||
|
#[cfg(feature = "intel_tdx")]
|
||||||
|
use crate::arch::tdx_guest::{virtual_exception_handler, TdxTrapFrame};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
#[cfg(feature = "intel_tdx")]
|
#[cfg(feature = "intel_tdx")]
|
||||||
use tdx_guest::{serial_println, tdcall, tdvmcall, TdxVirtualExceptionType};
|
use tdx_guest::tdcall;
|
||||||
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;
|
||||||
@ -42,72 +44,52 @@ pub struct TrapInformation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "intel_tdx")]
|
#[cfg(feature = "intel_tdx")]
|
||||||
pub fn virtual_exception_handler(trapframe: &mut GeneralRegs, ve_info: &tdcall::TdgVeInfo) {
|
struct VeGeneralRegs<'a>(&'a mut GeneralRegs);
|
||||||
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")]
|
#[cfg(feature = "intel_tdx")]
|
||||||
pub fn handle_ve_io(trapframe: &mut GeneralRegs, ve_info: &tdcall::TdgVeInfo) -> bool {
|
impl TdxTrapFrame for VeGeneralRegs<'_> {
|
||||||
let size = match ve_info.exit_qualification & 0x3 {
|
fn rax(&self) -> usize {
|
||||||
0 => 1,
|
self.0.rax
|
||||||
1 => 2,
|
}
|
||||||
3 => 4,
|
fn set_rax(&mut self, rax: usize) {
|
||||||
_ => panic!("Invalid size value"),
|
self.0.rax = rax;
|
||||||
};
|
}
|
||||||
let direction = if (ve_info.exit_qualification >> 3) & 0x1 == 0 {
|
fn rbx(&self) -> usize {
|
||||||
tdvmcall::Direction::Out
|
self.0.rbx
|
||||||
} else {
|
}
|
||||||
tdvmcall::Direction::In
|
fn set_rbx(&mut self, rbx: usize) {
|
||||||
};
|
self.0.rbx = rbx;
|
||||||
let string = (ve_info.exit_qualification >> 4) & 0x1 == 1;
|
}
|
||||||
let repeat = (ve_info.exit_qualification >> 5) & 0x1 == 1;
|
fn rcx(&self) -> usize {
|
||||||
let operand = if (ve_info.exit_qualification >> 6) & 0x1 == 0 {
|
self.0.rcx
|
||||||
tdvmcall::Operand::Dx
|
}
|
||||||
} else {
|
fn set_rcx(&mut self, rcx: usize) {
|
||||||
tdvmcall::Operand::Immediate
|
self.0.rcx = rcx;
|
||||||
};
|
}
|
||||||
let port = (ve_info.exit_qualification >> 16) as u16;
|
fn rdx(&self) -> usize {
|
||||||
|
self.0.rdx
|
||||||
match direction {
|
}
|
||||||
tdvmcall::Direction::In => {
|
fn set_rdx(&mut self, rdx: usize) {
|
||||||
trapframe.rax = tdvmcall::io_read(size, port).unwrap() as usize;
|
self.0.rdx = rdx;
|
||||||
}
|
}
|
||||||
tdvmcall::Direction::Out => {
|
fn rsi(&self) -> usize {
|
||||||
tdvmcall::io_write(size, port, trapframe.rax as u32).unwrap();
|
self.0.rsi
|
||||||
}
|
}
|
||||||
};
|
fn set_rsi(&mut self, rsi: usize) {
|
||||||
true
|
self.0.rsi = rsi;
|
||||||
|
}
|
||||||
|
fn rdi(&self) -> usize {
|
||||||
|
self.0.rdi
|
||||||
|
}
|
||||||
|
fn set_rdi(&mut self, rdi: usize) {
|
||||||
|
self.0.rdi = rdi;
|
||||||
|
}
|
||||||
|
fn rip(&self) -> usize {
|
||||||
|
self.0.rip
|
||||||
|
}
|
||||||
|
fn set_rip(&mut self, rip: usize) {
|
||||||
|
self.0.rip = rip;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserContext {
|
impl UserContext {
|
||||||
@ -148,7 +130,8 @@ impl UserContextApiInternal for UserContext {
|
|||||||
if *exception == VIRTUALIZATION_EXCEPTION {
|
if *exception == VIRTUALIZATION_EXCEPTION {
|
||||||
let ve_info =
|
let ve_info =
|
||||||
tdcall::get_veinfo().expect("#VE handler: fail to get VE info\n");
|
tdcall::get_veinfo().expect("#VE handler: fail to get VE info\n");
|
||||||
virtual_exception_handler(self.general_regs_mut(), &ve_info);
|
let mut ve_f = VeGeneralRegs(self.general_regs_mut());
|
||||||
|
virtual_exception_handler(&mut ve_f, &ve_info);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if exception.typ == CpuExceptionType::FaultOrTrap
|
if exception.typ == CpuExceptionType::FaultOrTrap
|
||||||
|
@ -6,6 +6,8 @@ pub(crate) mod irq;
|
|||||||
mod kernel;
|
mod kernel;
|
||||||
pub(crate) mod mm;
|
pub(crate) mod mm;
|
||||||
pub(crate) mod pci;
|
pub(crate) mod pci;
|
||||||
|
#[cfg(feature = "intel_tdx")]
|
||||||
|
pub(crate) mod tdx_guest;
|
||||||
pub(crate) mod timer;
|
pub(crate) mod timer;
|
||||||
|
|
||||||
use alloc::fmt;
|
use alloc::fmt;
|
||||||
|
89
framework/jinux-frame/src/arch/x86/tdx_guest.rs
Normal file
89
framework/jinux-frame/src/arch/x86/tdx_guest.rs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
use tdx_guest::{
|
||||||
|
tdcall::TdgVeInfo,
|
||||||
|
tdvmcall::{cpuid, hlt, rdmsr, wrmsr},
|
||||||
|
{serial_println, tdcall, tdvmcall, TdxVirtualExceptionType},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait TdxTrapFrame {
|
||||||
|
fn rax(&self) -> usize;
|
||||||
|
fn set_rax(&mut self, rax: usize);
|
||||||
|
fn rbx(&self) -> usize;
|
||||||
|
fn set_rbx(&mut self, rbx: usize);
|
||||||
|
fn rcx(&self) -> usize;
|
||||||
|
fn set_rcx(&mut self, rcx: usize);
|
||||||
|
fn rdx(&self) -> usize;
|
||||||
|
fn set_rdx(&mut self, rdx: usize);
|
||||||
|
fn rsi(&self) -> usize;
|
||||||
|
fn set_rsi(&mut self, rsi: usize);
|
||||||
|
fn rdi(&self) -> usize;
|
||||||
|
fn set_rdi(&mut self, rdi: usize);
|
||||||
|
fn rip(&self) -> usize;
|
||||||
|
fn set_rip(&mut self, rip: usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn io_handler(trapframe: &mut dyn TdxTrapFrame, 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.set_rax(tdvmcall::io_read(size, port).unwrap() as usize);
|
||||||
|
}
|
||||||
|
tdvmcall::Direction::Out => {
|
||||||
|
tdvmcall::io_write(size, port, trapframe.rax() as u32).unwrap();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn virtual_exception_handler(trapframe: &mut impl TdxTrapFrame, ve_info: &TdgVeInfo) {
|
||||||
|
match ve_info.exit_reason.into() {
|
||||||
|
TdxVirtualExceptionType::Hlt => {
|
||||||
|
serial_println!("Ready to halt");
|
||||||
|
hlt();
|
||||||
|
}
|
||||||
|
TdxVirtualExceptionType::Io => {
|
||||||
|
if !io_handler(trapframe, ve_info) {
|
||||||
|
serial_println!("Handle tdx ioexit errors, ready to halt");
|
||||||
|
hlt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TdxVirtualExceptionType::MsrRead => {
|
||||||
|
let msr = rdmsr(trapframe.rcx() as u32).unwrap();
|
||||||
|
trapframe.set_rax((msr as u32 & u32::MAX) as usize);
|
||||||
|
trapframe.set_rdx(((msr >> 32) as u32 & u32::MAX) as usize);
|
||||||
|
}
|
||||||
|
TdxVirtualExceptionType::MsrWrite => {
|
||||||
|
let data = trapframe.rax() as u64 | ((trapframe.rdx() as u64) << 32);
|
||||||
|
wrmsr(trapframe.rcx() as u32, data).unwrap();
|
||||||
|
}
|
||||||
|
TdxVirtualExceptionType::CpuId => {
|
||||||
|
let cpuid_info = cpuid(trapframe.rax() as u32, trapframe.rcx() as u32).unwrap();
|
||||||
|
let mask = 0xFFFF_FFFF_0000_0000_usize;
|
||||||
|
trapframe.set_rax((trapframe.rax() & mask) | cpuid_info.eax);
|
||||||
|
trapframe.set_rbx((trapframe.rbx() & mask) | cpuid_info.ebx);
|
||||||
|
trapframe.set_rcx((trapframe.rcx() & mask) | cpuid_info.ecx);
|
||||||
|
trapframe.set_rdx((trapframe.rdx() & mask) | cpuid_info.edx);
|
||||||
|
}
|
||||||
|
TdxVirtualExceptionType::Other => panic!("Unknown TDX vitrual exception type"),
|
||||||
|
_ => return,
|
||||||
|
}
|
||||||
|
trapframe.set_rip(trapframe.rip() + ve_info.exit_instruction_length as usize);
|
||||||
|
}
|
@ -1,76 +1,58 @@
|
|||||||
use crate::{arch::irq::IRQ_LIST, cpu::CpuException};
|
use crate::{arch::irq::IRQ_LIST, cpu::CpuException};
|
||||||
|
|
||||||
#[cfg(feature = "intel_tdx")]
|
#[cfg(feature = "intel_tdx")]
|
||||||
use tdx_guest::{serial_println, tdcall, tdvmcall, TdxVirtualExceptionType};
|
use crate::arch::tdx_guest::{virtual_exception_handler, TdxTrapFrame};
|
||||||
|
#[cfg(feature = "intel_tdx")]
|
||||||
|
use tdx_guest::tdcall;
|
||||||
use trapframe::TrapFrame;
|
use trapframe::TrapFrame;
|
||||||
|
|
||||||
#[cfg(feature = "intel_tdx")]
|
#[cfg(feature = "intel_tdx")]
|
||||||
pub fn virtual_exception_handler(trapframe: &mut TrapFrame, ve_info: &tdcall::TdgVeInfo) {
|
struct VeTrapFrame<'a>(&'a mut TrapFrame);
|
||||||
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")]
|
#[cfg(feature = "intel_tdx")]
|
||||||
pub fn handle_ve_io(trapframe: &mut TrapFrame, ve_info: &tdcall::TdgVeInfo) -> bool {
|
impl TdxTrapFrame for VeTrapFrame<'_> {
|
||||||
let size = match ve_info.exit_qualification & 0x3 {
|
fn rax(&self) -> usize {
|
||||||
0 => 1,
|
self.0.rax
|
||||||
1 => 2,
|
}
|
||||||
3 => 4,
|
fn set_rax(&mut self, rax: usize) {
|
||||||
_ => panic!("Invalid size value"),
|
self.0.rax = rax;
|
||||||
};
|
}
|
||||||
let direction = if (ve_info.exit_qualification >> 3) & 0x1 == 0 {
|
fn rbx(&self) -> usize {
|
||||||
tdvmcall::Direction::Out
|
self.0.rbx
|
||||||
} else {
|
}
|
||||||
tdvmcall::Direction::In
|
fn set_rbx(&mut self, rbx: usize) {
|
||||||
};
|
self.0.rbx = rbx;
|
||||||
let string = (ve_info.exit_qualification >> 4) & 0x1 == 1;
|
}
|
||||||
let repeat = (ve_info.exit_qualification >> 5) & 0x1 == 1;
|
fn rcx(&self) -> usize {
|
||||||
let operand = if (ve_info.exit_qualification >> 6) & 0x1 == 0 {
|
self.0.rcx
|
||||||
tdvmcall::Operand::Dx
|
}
|
||||||
} else {
|
fn set_rcx(&mut self, rcx: usize) {
|
||||||
tdvmcall::Operand::Immediate
|
self.0.rcx = rcx;
|
||||||
};
|
}
|
||||||
let port = (ve_info.exit_qualification >> 16) as u16;
|
fn rdx(&self) -> usize {
|
||||||
|
self.0.rdx
|
||||||
match direction {
|
}
|
||||||
tdvmcall::Direction::In => {
|
fn set_rdx(&mut self, rdx: usize) {
|
||||||
trapframe.rax = tdvmcall::io_read(size, port).unwrap() as usize;
|
self.0.rdx = rdx;
|
||||||
}
|
}
|
||||||
tdvmcall::Direction::Out => {
|
fn rsi(&self) -> usize {
|
||||||
tdvmcall::io_write(size, port, trapframe.rax as u32).unwrap();
|
self.0.rsi
|
||||||
}
|
}
|
||||||
};
|
fn set_rsi(&mut self, rsi: usize) {
|
||||||
true
|
self.0.rsi = rsi;
|
||||||
|
}
|
||||||
|
fn rdi(&self) -> usize {
|
||||||
|
self.0.rdi
|
||||||
|
}
|
||||||
|
fn set_rdi(&mut self, rdi: usize) {
|
||||||
|
self.0.rdi = rdi;
|
||||||
|
}
|
||||||
|
fn rip(&self) -> usize {
|
||||||
|
self.0.rip
|
||||||
|
}
|
||||||
|
fn set_rip(&mut self, rip: usize) {
|
||||||
|
self.0.rip = rip;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Only from kernel
|
/// Only from kernel
|
||||||
@ -80,7 +62,8 @@ extern "sysv64" fn trap_handler(f: &mut TrapFrame) {
|
|||||||
#[cfg(feature = "intel_tdx")]
|
#[cfg(feature = "intel_tdx")]
|
||||||
if f.trap_num as u16 == 20 {
|
if f.trap_num as u16 == 20 {
|
||||||
let ve_info = tdcall::get_veinfo().expect("#VE handler: fail to get VE info\n");
|
let ve_info = tdcall::get_veinfo().expect("#VE handler: fail to get VE info\n");
|
||||||
virtual_exception_handler(f, &ve_info);
|
let mut ve_f = VeTrapFrame(f);
|
||||||
|
virtual_exception_handler(&mut ve_f, &ve_info);
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "intel_tdx"))]
|
#[cfg(not(feature = "intel_tdx"))]
|
||||||
panic!("cannot handle kernel cpu fault now, information:{:#x?}", f);
|
panic!("cannot handle kernel cpu fault now, information:{:#x?}", f);
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
pub mod asm;
|
mod asm;
|
||||||
pub mod tdcall;
|
pub mod tdcall;
|
||||||
pub mod tdvmcall;
|
pub mod tdvmcall;
|
||||||
|
|
||||||
@ -15,79 +15,23 @@ use raw_cpuid::{native_cpuid::cpuid_count, CpuIdResult};
|
|||||||
use tdcall::{InitError, TdgVeInfo, TdgVpInfo};
|
use tdcall::{InitError, TdgVeInfo, TdgVpInfo};
|
||||||
use tdvmcall::*;
|
use tdvmcall::*;
|
||||||
|
|
||||||
const TDX_CPUID_LEAF_ID: u64 = 0x21;
|
|
||||||
|
|
||||||
pub fn tdx_early_init() -> Result<TdgVpInfo, InitError> {
|
pub fn tdx_early_init() -> Result<TdgVpInfo, InitError> {
|
||||||
match is_tdx_guest() {
|
check_tdx_guest()?;
|
||||||
Ok(_) => Ok(tdcall::get_tdinfo()?),
|
Ok(tdcall::get_tdinfo()?)
|
||||||
Err(err) => Err(err),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_tdx_guest() -> Result<(), InitError> {
|
fn check_tdx_guest() -> Result<(), InitError> {
|
||||||
|
const TDX_CPUID_LEAF_ID: u64 = 0x21;
|
||||||
let cpuid_leaf = cpuid_count(0, 0).eax as u64;
|
let cpuid_leaf = cpuid_count(0, 0).eax as u64;
|
||||||
if cpuid_leaf < TDX_CPUID_LEAF_ID {
|
if cpuid_leaf < TDX_CPUID_LEAF_ID {
|
||||||
return Err(InitError::TdxCpuLeafIdError);
|
return Err(InitError::TdxCpuLeafIdError);
|
||||||
}
|
}
|
||||||
let cpuid_result: CpuIdResult = cpuid_count(TDX_CPUID_LEAF_ID as u32, 0);
|
let cpuid_result: CpuIdResult = cpuid_count(TDX_CPUID_LEAF_ID as u32, 0);
|
||||||
if &cpuid_result.ebx.to_ne_bytes() == b"Inte"
|
if &cpuid_result.ebx.to_ne_bytes() != b"Inte"
|
||||||
&& &cpuid_result.ebx.to_ne_bytes() == b"lTDX"
|
|| &cpuid_result.ebx.to_ne_bytes() != b"lTDX"
|
||||||
&& &cpuid_result.ecx.to_ne_bytes() == b" "
|
|| &cpuid_result.ecx.to_ne_bytes() != b" "
|
||||||
{
|
{
|
||||||
Ok(())
|
return Err(InitError::TdxVendorIdError);
|
||||||
} else {
|
|
||||||
Err(InitError::TdxVendorIdError)
|
|
||||||
}
|
}
|
||||||
}
|
Ok(())
|
||||||
|
|
||||||
pub trait TdxTrapFrame {
|
|
||||||
fn rax(&self) -> usize;
|
|
||||||
fn set_rax(&mut self, rax: usize);
|
|
||||||
fn rbx(&self) -> usize;
|
|
||||||
fn set_rbx(&mut self, rbx: usize);
|
|
||||||
fn rcx(&self) -> usize;
|
|
||||||
fn set_rcx(&mut self, rcx: usize);
|
|
||||||
fn rdx(&self) -> usize;
|
|
||||||
fn set_rdx(&mut self, rdx: usize);
|
|
||||||
fn rsi(&self) -> usize;
|
|
||||||
fn set_rsi(&mut self, rsi: usize);
|
|
||||||
fn rdi(&self) -> usize;
|
|
||||||
fn set_rdi(&mut self, rdi: usize);
|
|
||||||
fn rip(&self) -> usize;
|
|
||||||
fn set_rip(&mut self, rip: usize);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn virtual_exception_handler(trapframe: &mut impl TdxTrapFrame, ve_info: &TdgVeInfo) {
|
|
||||||
match ve_info.exit_reason.into() {
|
|
||||||
TdxVirtualExceptionType::Hlt => {
|
|
||||||
serial_println!("Ready to halt");
|
|
||||||
hlt();
|
|
||||||
}
|
|
||||||
TdxVirtualExceptionType::Io => {
|
|
||||||
if !handle_io(trapframe, ve_info) {
|
|
||||||
serial_println!("Handle tdx ioexit errors, ready to halt");
|
|
||||||
hlt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TdxVirtualExceptionType::MsrRead => {
|
|
||||||
let msr = rdmsr(trapframe.rcx() as u32).unwrap();
|
|
||||||
trapframe.set_rax((msr as u32 & u32::MAX) as usize);
|
|
||||||
trapframe.set_rdx(((msr >> 32) as u32 & u32::MAX) as usize);
|
|
||||||
}
|
|
||||||
TdxVirtualExceptionType::MsrWrite => {
|
|
||||||
let data = trapframe.rax() as u64 | ((trapframe.rdx() as u64) << 32);
|
|
||||||
wrmsr(trapframe.rcx() as u32, data).unwrap();
|
|
||||||
}
|
|
||||||
TdxVirtualExceptionType::CpuId => {
|
|
||||||
let cpuid_info = cpuid(trapframe.rax() as u32, trapframe.rcx() as u32).unwrap();
|
|
||||||
let mask = 0xFFFF_FFFF_0000_0000_usize;
|
|
||||||
trapframe.set_rax((trapframe.rax() & mask) | cpuid_info.eax);
|
|
||||||
trapframe.set_rbx((trapframe.rbx() & mask) | cpuid_info.ebx);
|
|
||||||
trapframe.set_rcx((trapframe.rcx() & mask) | cpuid_info.ecx);
|
|
||||||
trapframe.set_rdx((trapframe.rdx() & mask) | cpuid_info.edx);
|
|
||||||
}
|
|
||||||
TdxVirtualExceptionType::Other => panic!("Unknown TDX vitrual exception type"),
|
|
||||||
_ => return,
|
|
||||||
}
|
|
||||||
trapframe.set_rip(trapframe.rip() + ve_info.exit_instruction_length as usize);
|
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
//! resumes the TD via a SEAMCALL [TDH.VP.ENTER] invocation.
|
//! resumes the TD via a SEAMCALL [TDH.VP.ENTER] invocation.
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use crate::{asm::asm_td_vmcall, tdcall::TdgVeInfo, TdxTrapFrame};
|
use crate::{asm::asm_td_vmcall, tdcall::TdgVeInfo};
|
||||||
use alloc::fmt;
|
use alloc::fmt;
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
@ -193,38 +193,6 @@ pub fn write_mmio(size: u64, mmio_addr: u64, data: u64) -> Result<(), TdVmcallEr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_io(trapframe: &mut impl TdxTrapFrame, ve_info: &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 {
|
|
||||||
Direction::Out
|
|
||||||
} else {
|
|
||||||
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 {
|
|
||||||
Operand::Dx
|
|
||||||
} else {
|
|
||||||
Operand::Immediate
|
|
||||||
};
|
|
||||||
let port = (ve_info.exit_qualification >> 16) as u16;
|
|
||||||
|
|
||||||
match direction {
|
|
||||||
Direction::In => {
|
|
||||||
trapframe.set_rax(io_read(size, port).unwrap() as usize);
|
|
||||||
}
|
|
||||||
Direction::Out => {
|
|
||||||
io_write(size, port, trapframe.rax() as u32).unwrap();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! io_read {
|
macro_rules! io_read {
|
||||||
($port:expr, $ty:ty) => {{
|
($port:expr, $ty:ty) => {{
|
||||||
let mut args = TdVmcallArgs {
|
let mut args = TdVmcallArgs {
|
||||||
@ -286,22 +254,42 @@ fn td_vmcall(args: &mut TdVmcallArgs) -> Result<(), TdVmcallError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
struct LineSts: u8 {
|
struct LineSts: u8 {
|
||||||
const INPUT_FULL = 1;
|
const INPUT_FULL = 1;
|
||||||
const OUTPUT_EMPTY = 1 << 5;
|
const OUTPUT_EMPTY = 1 << 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn line_sts() -> LineSts {
|
fn read_line_sts() -> LineSts {
|
||||||
LineSts::from_bits_truncate(unsafe { PortRead::read_from_port(SERIAL_LINE_STS) })
|
LineSts::from_bits_truncate(unsafe { PortRead::read_from_port(SERIAL_LINE_STS) })
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Serial;
|
struct Serial;
|
||||||
|
|
||||||
|
impl Serial {
|
||||||
|
fn serial_write_byte(byte: u8) {
|
||||||
|
match byte {
|
||||||
|
// Backspace/Delete
|
||||||
|
8 | 0x7F => {
|
||||||
|
while !read_line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||||
|
io_write!(SERIAL_IO_PORT, 8, u8).unwrap();
|
||||||
|
while !read_line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||||
|
io_write!(SERIAL_IO_PORT, b' ', u8).unwrap();
|
||||||
|
while !read_line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||||
|
io_write!(SERIAL_IO_PORT, 8, u8).unwrap();
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
while !read_line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||||
|
io_write!(SERIAL_IO_PORT, byte, u8).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Write for Serial {
|
impl Write for Serial {
|
||||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
for &c in s.as_bytes() {
|
for &c in s.as_bytes() {
|
||||||
serial_write_byte(c);
|
Serial::serial_write_byte(c);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -313,23 +301,6 @@ pub fn print(args: fmt::Arguments) {
|
|||||||
.expect("Failed to write to serial port");
|
.expect("Failed to write to serial port");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serial_write_byte(byte: u8) {
|
|
||||||
match byte {
|
|
||||||
8 | 0x7F => {
|
|
||||||
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
|
||||||
io_write!(SERIAL_IO_PORT, 8, u8).unwrap();
|
|
||||||
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
|
||||||
io_write!(SERIAL_IO_PORT, b' ', u8).unwrap();
|
|
||||||
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
|
||||||
io_write!(SERIAL_IO_PORT, 8, u8).unwrap();
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
|
||||||
io_write!(SERIAL_IO_PORT, byte, u8).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! serial_print {
|
macro_rules! serial_print {
|
||||||
($fmt: literal $(, $($arg: tt)+)?) => {
|
($fmt: literal $(, $($arg: tt)+)?) => {
|
||||||
@ -339,7 +310,7 @@ macro_rules! serial_print {
|
|||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! serial_println {
|
macro_rules! serial_println {
|
||||||
($fmt: literal $(, $($arg: tt)+)?) => {
|
($fmt: literal $(, $($arg: tt)+)?) => {
|
||||||
$crate::tdvmcall::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?))
|
$crate::tdvmcall::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user