use crate::enclave::is_within_enclave;
use crate::error;
use crate::sync::SpinMutex;
use crate::veh::list;
use core::num::NonZeroU64;
use sgx_types::error::{SgxResult, SgxStatus};
pub const MAX_REGISTER_COUNT: usize = 64;
impl_enum! {
#[repr(u32)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ExceptionVector {
DE = 0, DB = 1, BP = 3, BR = 5, UD = 6, GP = 13, PF = 14, MF = 16, AC = 17, XM = 19, CP = 21, }
}
impl_enum! {
#[repr(u32)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ExceptionType {
Hardware = 3,
Software = 6,
}
}
impl_struct! {
#[repr(C)]
#[derive(Debug)]
pub struct CpuContext {
pub rax: u64,
pub rcx: u64,
pub rdx: u64,
pub rbx: u64,
pub rsp: u64,
pub rbp: u64,
pub rsi: u64,
pub rdi: u64,
pub r8: u64,
pub r9: u64,
pub r10: u64,
pub r11: u64,
pub r12: u64,
pub r13: u64,
pub r14: u64,
pub r15: u64,
pub rflags: u64,
pub rip: u64,
}
}
impl_struct! {
#[repr(C)]
#[derive(Debug)]
pub struct ExceptionInfo {
pub context: CpuContext,
pub vector: ExceptionVector,
pub exception_type: ExceptionType,
}
}
impl_enum! {
#[repr(u32)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum HandleResult {
Search = 0,
Execution = 0xFFFFFFFF,
}
}
pub type ExceptionHandler = extern "C" fn(info: &mut ExceptionInfo) -> HandleResult;
#[repr(transparent)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct Handle(NonZeroU64);
impl Handle {
pub(crate) fn new() -> Handle {
static GUARD: SpinMutex<u64> = SpinMutex::new(1);
let mut counter = GUARD.lock();
if *counter == u64::MAX {
error::abort();
}
let id = *counter;
*counter += 1;
Handle(NonZeroU64::new(id).unwrap())
}
#[inline]
pub(crate) fn into_raw(self) -> u64 {
self.0.get()
}
#[inline]
pub(crate) unsafe fn from_raw(id: u64) -> Handle {
Handle(NonZeroU64::new_unchecked(id))
}
}
pub fn register_exception(first: bool, handler: ExceptionHandler) -> SgxResult<Handle> {
ensure!(
is_within_enclave(handler as *const u8, 0),
SgxStatus::InvalidParameter
);
let mut list_guard = list::EXCEPTION_LIST.lock();
ensure!(
list_guard.len() < MAX_REGISTER_COUNT,
SgxStatus::OutOfMemory
);
if first {
Ok(list_guard.push_front(handler))
} else {
Ok(list_guard.push_back(handler))
}
}
#[inline]
pub fn register(handler: ExceptionHandler) -> SgxResult<Handle> {
register_exception(false, handler)
}
pub fn unregister(id: Handle) -> bool {
list::EXCEPTION_LIST.lock().remove(id).is_some()
}