use super::super::Command;
use std::mem::MaybeUninit;
use std::sync::Arc;
use anyhow::Result;
use sallyport::{syscall::SYS_ENARX_CPUID, Block};
use sgx::enclu::{EENTER, EEXIT, ERESUME};
use sgx::ssa::Vector;
use vdso::Symbol;
pub struct Thread {
enclave: Arc<super::Keep>,
vdso: &'static Symbol,
tcs: *const super::Tcs,
block: Block,
cssa: usize,
how: usize,
}
impl Drop for Thread {
fn drop(&mut self) {
self.enclave.tcs.write().unwrap().push(self.tcs)
}
}
impl super::super::Keep for super::Keep {
fn spawn(self: Arc<Self>) -> Result<Option<Box<dyn super::super::Thread>>> {
let vdso = vdso::Vdso::locate()
.expect("vDSO not found")
.lookup("__vdso_sgx_enter_enclave")
.expect("__vdso_sgx_enter_enclave not found");
let tcs = match self.tcs.write().unwrap().pop() {
Some(tcs) => tcs,
None => return Ok(None),
};
Ok(Some(Box::new(Thread {
enclave: self,
vdso,
tcs,
block: Block::default(),
cssa: usize::default(),
how: EENTER,
})))
}
}
impl super::super::Thread for Thread {
fn enter(&mut self) -> Result<Command> {
let mut run: Run = unsafe { MaybeUninit::zeroed().assume_init() };
run.tcs = self.tcs as u64;
let how = self.how;
unsafe {
asm!(
"push rbx", "push rbp", "mov rbp, rsp", "and rsp, ~0xf",
"push 0", "push r10", "call r11",
"mov rsp, rbp", "pop rbp", "pop rbx",
inout("rdi") &self.block => _,
lateout("rsi") _,
lateout("rdx") _,
inout("rcx") how => _,
lateout("r8") _,
lateout("r9") _,
inout("r10") &mut run => _,
inout("r11") self.vdso => _,
lateout("r12") _,
lateout("r13") _,
lateout("r14") _,
lateout("r15") _,
lateout("rax") _,
);
}
self.how = match run.function as usize {
EENTER | ERESUME if run.vector == Vector::InvalidOpcode => EENTER,
EEXIT => ERESUME,
_ => panic!("Unexpected AEX: {:?}", run.vector),
};
match self.how {
EENTER => self.cssa += 1,
ERESUME => match self.cssa {
0 => unreachable!(),
_ => self.cssa -= 1,
},
_ => unreachable!(),
}
if self.cssa > 0 {
if let (EENTER, ERESUME) = (how, self.how) {
match unsafe { self.block.msg.req }.num.into() {
SYS_ENARX_CPUID => return Ok(Command::CpuId(&mut self.block)),
_ => return Ok(Command::SysCall(&mut self.block)),
}
}
}
Ok(Command::Continue)
}
}
#[repr(C)]
#[derive(Debug)]
struct Run {
tcs: u64,
function: u32,
vector: Vector,
padding: u8,
exception_error_code: u16,
exception_addr: u64,
user_handler: u64,
user_data: u64,
reserved: [u64; 27],
}