mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-20 04:56:32 +00:00
Polish tdx-guest crate and Jinux VE handler
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
82518955d7
commit
c90f757b86
@ -12,10 +12,9 @@ pub use self::tdcall::{get_veinfo, TdxVirtualExceptionType};
|
||||
pub use self::tdvmcall::print;
|
||||
|
||||
use raw_cpuid::{native_cpuid::cpuid_count, CpuIdResult};
|
||||
use tdcall::{InitError, TdgVeInfo, TdgVpInfo};
|
||||
use tdvmcall::*;
|
||||
use tdcall::{InitError, TdgVpInfo};
|
||||
|
||||
pub fn tdx_early_init() -> Result<TdgVpInfo, InitError> {
|
||||
pub fn init_tdx() -> Result<TdgVpInfo, InitError> {
|
||||
check_tdx_guest()?;
|
||||
Ok(tdcall::get_tdinfo()?)
|
||||
}
|
||||
|
@ -364,20 +364,16 @@ pub fn get_tdinfo() -> Result<TdgVpInfo, TdCallError> {
|
||||
rax: TdcallNum::VpInfo as u64,
|
||||
..Default::default()
|
||||
};
|
||||
match td_call(&mut args) {
|
||||
Ok(()) => {
|
||||
let td_info = TdgVpInfo {
|
||||
gpaw: Gpaw::from(args.rcx),
|
||||
attributes: GuestTdAttributes::from_bits_truncate(args.rdx),
|
||||
num_vcpus: args.r8 as u32,
|
||||
max_vcpus: (args.r8 >> 32) as u32,
|
||||
vcpu_index: args.r9 as u32,
|
||||
sys_rd: args.r10 as u32,
|
||||
};
|
||||
Ok(td_info)
|
||||
}
|
||||
Err(res) => Err(res),
|
||||
}
|
||||
td_call(&mut args)?;
|
||||
let td_info = TdgVpInfo {
|
||||
gpaw: Gpaw::from(args.rcx),
|
||||
attributes: GuestTdAttributes::from_bits_truncate(args.rdx),
|
||||
num_vcpus: args.r8 as u32,
|
||||
max_vcpus: (args.r8 >> 32) as u32,
|
||||
vcpu_index: args.r9 as u32,
|
||||
sys_rd: args.r10 as u32,
|
||||
};
|
||||
Ok(td_info)
|
||||
}
|
||||
|
||||
/// Get Virtualization Exception Information for the recent #VE exception.
|
||||
@ -386,20 +382,16 @@ pub fn get_veinfo() -> Result<TdgVeInfo, TdCallError> {
|
||||
rax: TdcallNum::VpVeinfoGet as u64,
|
||||
..Default::default()
|
||||
};
|
||||
match td_call(&mut args) {
|
||||
Ok(()) => {
|
||||
let ve_info = TdgVeInfo {
|
||||
exit_reason: args.rcx as u32,
|
||||
exit_qualification: args.rdx,
|
||||
guest_linear_address: args.r8,
|
||||
guest_physical_address: args.r9,
|
||||
exit_instruction_length: args.r10 as u32,
|
||||
exit_instruction_info: (args.r10 >> 32) as u32,
|
||||
};
|
||||
Ok(ve_info)
|
||||
}
|
||||
Err(res) => Err(res),
|
||||
}
|
||||
td_call(&mut args)?;
|
||||
let ve_info = TdgVeInfo {
|
||||
exit_reason: args.rcx as u32,
|
||||
exit_qualification: args.rdx,
|
||||
guest_linear_address: args.r8,
|
||||
guest_physical_address: args.r9,
|
||||
exit_instruction_length: args.r10 as u32,
|
||||
exit_instruction_info: (args.r10 >> 32) as u32,
|
||||
};
|
||||
Ok(ve_info)
|
||||
}
|
||||
|
||||
/// Extend a TDCS.RTMR measurement register.
|
||||
@ -408,72 +400,58 @@ pub fn extend_rtmr() -> Result<(), TdCallError> {
|
||||
rax: TdcallNum::MrRtmrExtend as u64,
|
||||
..Default::default()
|
||||
};
|
||||
match td_call(&mut args) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(res) => Err(res),
|
||||
}
|
||||
td_call(&mut args)
|
||||
}
|
||||
|
||||
/// TDG.MR.REPORT creates a TDREPORT_STRUCT structure that contains the measurements/configuration
|
||||
/// information of the guest TD that called the function, measurements/configuration information
|
||||
/// of the Intel TDX module and a REPORTMACSTRUCT.
|
||||
pub fn get_report(report_addr: u64, data_addr: u64) -> Result<(), TdCallError> {
|
||||
pub fn get_report(report_gpa: &[u8], data_gpa: &[u8]) -> Result<(), TdCallError> {
|
||||
let mut args = TdcallArgs {
|
||||
rax: TdcallNum::MrReport as u64,
|
||||
rcx: report_addr,
|
||||
rdx: data_addr,
|
||||
rcx: report_gpa.as_ptr() as u64,
|
||||
rdx: data_gpa.as_ptr() as u64,
|
||||
..Default::default()
|
||||
};
|
||||
match td_call(&mut args) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(res) => Err(res),
|
||||
}
|
||||
td_call(&mut args)
|
||||
}
|
||||
|
||||
/// Verify a cryptographic REPORTMACSTRUCT that describes the contents of a TD,
|
||||
/// to determine that it was created on the current TEE on the current platform.
|
||||
pub fn verify_report(report_mac_addr: u64) -> Result<(), TdCallError> {
|
||||
pub fn verify_report(report_mac_gpa: &[u8]) -> Result<(), TdCallError> {
|
||||
let mut args = TdcallArgs {
|
||||
rax: TdcallNum::MrVerifyreport as u64,
|
||||
rcx: report_mac_addr,
|
||||
rcx: report_mac_gpa.as_ptr() as u64,
|
||||
..Default::default()
|
||||
};
|
||||
match td_call(&mut args) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(res) => Err(res),
|
||||
}
|
||||
td_call(&mut args)
|
||||
}
|
||||
|
||||
/// Accept a pending private page and initialize it to all-0 using the TD ephemeral private key.
|
||||
pub fn accept_page(sept_level: u64, addr: u64) -> Result<(), TdCallError> {
|
||||
/// # Safety
|
||||
/// The 'gpa' parameter must be a valid address.
|
||||
pub unsafe fn accept_page(sept_level: u64, gpa: &[u8]) -> Result<(), TdCallError> {
|
||||
let mut args = TdcallArgs {
|
||||
rax: TdcallNum::MemPageAccept as u64,
|
||||
rcx: sept_level | (addr << 12),
|
||||
rcx: sept_level | ((gpa.as_ptr() as u64) << 12),
|
||||
..Default::default()
|
||||
};
|
||||
match td_call(&mut args) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(res) => Err(res),
|
||||
}
|
||||
td_call(&mut args)
|
||||
}
|
||||
|
||||
/// Read the GPA mapping and attributes of a TD private page.
|
||||
pub fn read_page_attr(phy_addr: u64) -> Result<PageAttr, TdCallError> {
|
||||
pub fn read_page_attr(gpa: &[u8]) -> Result<PageAttr, TdCallError> {
|
||||
let mut args = TdcallArgs {
|
||||
rax: TdcallNum::MemPageAttrRd as u64,
|
||||
rcx: phy_addr,
|
||||
rcx: gpa.as_ptr() as u64,
|
||||
..Default::default()
|
||||
};
|
||||
match td_call(&mut args) {
|
||||
Ok(()) => {
|
||||
let page_attr = PageAttr {
|
||||
gpa_mapping: args.rcx,
|
||||
gpa_attr: GpaAttrAll::from(args.rdx),
|
||||
};
|
||||
Ok(page_attr)
|
||||
}
|
||||
Err(res) => Err(res),
|
||||
}
|
||||
td_call(&mut args)?;
|
||||
let page_attr = PageAttr {
|
||||
gpa_mapping: args.rcx,
|
||||
gpa_attr: GpaAttrAll::from(args.rdx),
|
||||
};
|
||||
Ok(page_attr)
|
||||
}
|
||||
|
||||
/// Write the attributes of a private page. Create or remove L2 page aliases as required.
|
||||
@ -485,16 +463,12 @@ pub fn write_page_attr(page_attr: PageAttr, attr_flags: u64) -> Result<PageAttr,
|
||||
r8: attr_flags,
|
||||
..Default::default()
|
||||
};
|
||||
match td_call(&mut args) {
|
||||
Ok(()) => {
|
||||
let page_attr = PageAttr {
|
||||
gpa_mapping: args.rcx,
|
||||
gpa_attr: GpaAttrAll::from(args.rdx),
|
||||
};
|
||||
Ok(page_attr)
|
||||
}
|
||||
Err(res) => Err(res),
|
||||
}
|
||||
td_call(&mut args)?;
|
||||
let page_attr = PageAttr {
|
||||
gpa_mapping: args.rcx,
|
||||
gpa_attr: GpaAttrAll::from(args.rdx),
|
||||
};
|
||||
Ok(page_attr)
|
||||
}
|
||||
|
||||
/// Read a TD-scope metadata field (control structure field) of a TD.
|
||||
@ -504,10 +478,8 @@ pub fn read_td_metadata(field_identifier: u64) -> Result<u64, TdCallError> {
|
||||
rdx: field_identifier,
|
||||
..Default::default()
|
||||
};
|
||||
match td_call(&mut args) {
|
||||
Ok(()) => Ok(args.r8),
|
||||
Err(res) => Err(res),
|
||||
}
|
||||
td_call(&mut args)?;
|
||||
Ok(args.r8)
|
||||
}
|
||||
|
||||
/// Write a TD-scope metadata field (control structure field) of a TD.
|
||||
@ -545,17 +517,13 @@ pub fn set_cpuidve(cpuidve_flag: u64) -> Result<(), TdCallError> {
|
||||
rcx: cpuidve_flag,
|
||||
..Default::default()
|
||||
};
|
||||
match td_call(&mut args) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(res) => Err(res),
|
||||
}
|
||||
td_call(&mut args)
|
||||
}
|
||||
|
||||
fn td_call(args: &mut TdcallArgs) -> Result<(), TdCallError> {
|
||||
let td_call_result = unsafe { asm_td_call(args) };
|
||||
if td_call_result == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(td_call_result.into())
|
||||
let result = unsafe { asm_td_call(args) };
|
||||
match result {
|
||||
0 => Ok(()),
|
||||
_ => Err(result.into()),
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
//! resumes the TD via a SEAMCALL [TDH.VP.ENTER] invocation.
|
||||
extern crate alloc;
|
||||
|
||||
use crate::{asm::asm_td_vmcall, tdcall::TdgVeInfo};
|
||||
use crate::asm::asm_td_vmcall;
|
||||
use alloc::fmt;
|
||||
use bitflags::bitflags;
|
||||
use core::fmt::Write;
|
||||
@ -16,7 +16,7 @@ use x86_64::{
|
||||
|
||||
/// TDVMCALL Instruction Leaf Numbers Definition.
|
||||
#[repr(u64)]
|
||||
pub enum TdvmcallNum {
|
||||
pub enum TdVmcallNum {
|
||||
Cpuid = 0x0000a,
|
||||
Hlt = 0x0000c,
|
||||
Io = 0x0001e,
|
||||
@ -88,132 +88,121 @@ pub enum Operand {
|
||||
Immediate,
|
||||
}
|
||||
|
||||
pub enum IoSize {
|
||||
Size1 = 1,
|
||||
Size2 = 2,
|
||||
Size4 = 4,
|
||||
Size8 = 8,
|
||||
}
|
||||
|
||||
pub fn cpuid(eax: u32, ecx: u32) -> Result<CpuIdInfo, TdVmcallError> {
|
||||
let mut args = TdVmcallArgs {
|
||||
r11: TdvmcallNum::Cpuid as u64,
|
||||
r11: TdVmcallNum::Cpuid as u64,
|
||||
r12: eax as u64,
|
||||
r13: ecx as u64,
|
||||
..Default::default()
|
||||
};
|
||||
match td_vmcall(&mut args) {
|
||||
Ok(()) => Ok(CpuIdInfo {
|
||||
eax: args.r12 as usize,
|
||||
ebx: args.r13 as usize,
|
||||
ecx: args.r14 as usize,
|
||||
edx: args.r15 as usize,
|
||||
}),
|
||||
Err(res) => Err(res),
|
||||
}
|
||||
td_vmcall(&mut args)?;
|
||||
Ok(CpuIdInfo {
|
||||
eax: args.r12 as usize,
|
||||
ebx: args.r13 as usize,
|
||||
ecx: args.r14 as usize,
|
||||
edx: args.r15 as usize,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn hlt() {
|
||||
let interrupt_blocked = !rflags::read().contains(RFlags::INTERRUPT_FLAG);
|
||||
let mut args = TdVmcallArgs {
|
||||
r11: TdvmcallNum::Hlt as u64,
|
||||
r11: TdVmcallNum::Hlt as u64,
|
||||
r12: interrupt_blocked as u64,
|
||||
..Default::default()
|
||||
};
|
||||
let _ = td_vmcall(&mut args);
|
||||
}
|
||||
|
||||
pub fn rdmsr(index: u32) -> Result<u64, TdVmcallError> {
|
||||
/// # Safety
|
||||
/// Make sure the index is valid.
|
||||
pub unsafe fn rdmsr(index: u32) -> Result<u64, TdVmcallError> {
|
||||
let mut args = TdVmcallArgs {
|
||||
r11: TdvmcallNum::Rdmsr as u64,
|
||||
r11: TdVmcallNum::Rdmsr as u64,
|
||||
r12: index as u64,
|
||||
..Default::default()
|
||||
};
|
||||
match td_vmcall(&mut args) {
|
||||
Ok(()) => Ok(args.r11),
|
||||
Err(res) => Err(res),
|
||||
}
|
||||
td_vmcall(&mut args)?;
|
||||
Ok(args.r11)
|
||||
}
|
||||
|
||||
pub fn wrmsr(index: u32, value: u64) -> Result<(), TdVmcallError> {
|
||||
/// # Safety
|
||||
/// Make sure the index and the corresponding value are valid.
|
||||
pub unsafe fn wrmsr(index: u32, value: u64) -> Result<(), TdVmcallError> {
|
||||
let mut args = TdVmcallArgs {
|
||||
r11: TdvmcallNum::Wrmsr as u64,
|
||||
r11: TdVmcallNum::Wrmsr as u64,
|
||||
r12: index as u64,
|
||||
r13: value,
|
||||
..Default::default()
|
||||
};
|
||||
match td_vmcall(&mut args) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(res) => Err(res),
|
||||
}
|
||||
td_vmcall(&mut args)
|
||||
}
|
||||
|
||||
/// Used to help perform WBINVD operation.
|
||||
pub fn wbinvd(wbinvd: u64) -> Result<(), TdVmcallError> {
|
||||
/// Used to help perform WBINVD or WBNOINVD operation.
|
||||
/// - cache_operation: 0: WBINVD, 1: WBNOINVD
|
||||
pub fn perform_cache_operation(cache_operation: u64) -> Result<(), TdVmcallError> {
|
||||
let mut args = TdVmcallArgs {
|
||||
r11: TdvmcallNum::Wbinvd as u64,
|
||||
r12: wbinvd,
|
||||
r11: TdVmcallNum::Wbinvd as u64,
|
||||
r12: cache_operation,
|
||||
..Default::default()
|
||||
};
|
||||
match td_vmcall(&mut args) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(res) => Err(res),
|
||||
}
|
||||
td_vmcall(&mut args)
|
||||
}
|
||||
|
||||
pub fn read_mmio(size: u64, mmio_addr: u64) -> Result<u64, TdVmcallError> {
|
||||
match size {
|
||||
1 | 2 | 4 | 8 => {}
|
||||
_ => return Err(TdVmcallError::TdxInvalidOperand),
|
||||
}
|
||||
/// # Safety
|
||||
/// Make sure the mmio address is valid.
|
||||
pub unsafe fn read_mmio(size: IoSize, mmio_gpa: &[u8]) -> Result<u64, TdVmcallError> {
|
||||
let mut args = TdVmcallArgs {
|
||||
r11: TdvmcallNum::RequestMmio as u64,
|
||||
r12: size,
|
||||
r11: TdVmcallNum::RequestMmio as u64,
|
||||
r12: size as u64,
|
||||
r13: 0,
|
||||
r14: mmio_addr,
|
||||
r14: mmio_gpa.as_ptr() as u64,
|
||||
..Default::default()
|
||||
};
|
||||
match td_vmcall(&mut args) {
|
||||
Ok(()) => Ok(args.r11),
|
||||
Err(res) => Err(res),
|
||||
}
|
||||
td_vmcall(&mut args)?;
|
||||
Ok(args.r11)
|
||||
}
|
||||
|
||||
pub fn write_mmio(size: u64, mmio_addr: u64, data: u64) -> Result<(), TdVmcallError> {
|
||||
match size {
|
||||
1 | 2 | 4 | 8 => {}
|
||||
_ => {
|
||||
return Err(TdVmcallError::TdxInvalidOperand);
|
||||
}
|
||||
}
|
||||
/// # Safety
|
||||
/// Make sure the mmio address is valid.
|
||||
pub unsafe fn write_mmio(size: IoSize, mmio_gpa: &[u8], data: u64) -> Result<(), TdVmcallError> {
|
||||
let mut args = TdVmcallArgs {
|
||||
r11: TdvmcallNum::RequestMmio as u64,
|
||||
r12: size,
|
||||
r11: TdVmcallNum::RequestMmio as u64,
|
||||
r12: size as u64,
|
||||
r13: 1,
|
||||
r14: mmio_addr,
|
||||
r14: mmio_gpa.as_ptr() as u64,
|
||||
r15: data,
|
||||
..Default::default()
|
||||
};
|
||||
match td_vmcall(&mut args) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(res) => Err(res),
|
||||
}
|
||||
td_vmcall(&mut args)
|
||||
}
|
||||
|
||||
macro_rules! io_read {
|
||||
($port:expr, $ty:ty) => {{
|
||||
let mut args = TdVmcallArgs {
|
||||
r11: TdvmcallNum::Io as u64,
|
||||
r11: TdVmcallNum::Io as u64,
|
||||
r12: core::mem::size_of::<$ty>() as u64,
|
||||
r13: IO_READ,
|
||||
r14: $port as u64,
|
||||
..Default::default()
|
||||
};
|
||||
match td_vmcall(&mut args) {
|
||||
Ok(()) => Ok(args.r11 as u32),
|
||||
Err(res) => Err(res),
|
||||
}
|
||||
td_vmcall(&mut args)?;
|
||||
Ok(args.r11 as u32)
|
||||
}};
|
||||
}
|
||||
|
||||
pub fn io_read(size: usize, port: u16) -> Result<u32, TdVmcallError> {
|
||||
pub fn io_read(size: IoSize, port: u16) -> Result<u32, TdVmcallError> {
|
||||
match size {
|
||||
1 => io_read!(port, u8),
|
||||
2 => io_read!(port, u16),
|
||||
4 => io_read!(port, u32),
|
||||
IoSize::Size1 => io_read!(port, u8),
|
||||
IoSize::Size2 => io_read!(port, u16),
|
||||
IoSize::Size4 => io_read!(port, u32),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
@ -221,39 +210,36 @@ pub fn io_read(size: usize, port: u16) -> Result<u32, TdVmcallError> {
|
||||
macro_rules! io_write {
|
||||
($port:expr, $byte:expr, $size:expr) => {{
|
||||
let mut args = TdVmcallArgs {
|
||||
r11: TdvmcallNum::Io as u64,
|
||||
r11: TdVmcallNum::Io as u64,
|
||||
r12: core::mem::size_of_val(&$byte) as u64,
|
||||
r13: IO_WRITE,
|
||||
r14: $port as u64,
|
||||
r15: $byte as u64,
|
||||
..Default::default()
|
||||
};
|
||||
match td_vmcall(&mut args) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(res) => Err(res),
|
||||
}
|
||||
td_vmcall(&mut args)
|
||||
}};
|
||||
}
|
||||
|
||||
pub fn io_write(size: usize, port: u16, byte: u32) -> Result<(), TdVmcallError> {
|
||||
pub fn io_write(size: IoSize, port: u16, byte: u32) -> Result<(), TdVmcallError> {
|
||||
match size {
|
||||
1 => io_write!(port, byte, u8),
|
||||
2 => io_write!(port, byte, u16),
|
||||
4 => io_write!(port, byte, u32),
|
||||
IoSize::Size1 => io_write!(port, byte, u8),
|
||||
IoSize::Size2 => io_write!(port, byte, u16),
|
||||
IoSize::Size4 => io_write!(port, byte, u32),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn td_vmcall(args: &mut TdVmcallArgs) -> Result<(), TdVmcallError> {
|
||||
let td_vmcall_result = unsafe { asm_td_vmcall(args) };
|
||||
if td_vmcall_result == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(td_vmcall_result.into())
|
||||
let result = unsafe { asm_td_vmcall(args) };
|
||||
match result {
|
||||
0 => Ok(()),
|
||||
_ => Err(result.into()),
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// LineSts: Line Status
|
||||
struct LineSts: u8 {
|
||||
const INPUT_FULL = 1;
|
||||
const OUTPUT_EMPTY = 1 << 5;
|
||||
|
Reference in New Issue
Block a user