Skip to content

Commit e8d02ab

Browse files
author
Jethro Beekman
committed
track_aex_count feature for enclave-runner
1 parent 9b51e65 commit e8d02ab

File tree

5 files changed

+119
-11
lines changed

5 files changed

+119
-11
lines changed

intel-sgx/enclave-runner/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,4 @@ futures = { version = "0.3", features = ["compat", "io-compat"] } # MIT/Apache-2
4242
[features]
4343
default = ["crypto-openssl"]
4444
crypto-openssl = ["openssl", "sgxs/crypto-openssl"]
45+
instrumentation = []

intel-sgx/enclave-runner/src/command.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub struct Command {
2525
force_time_usercalls: bool,
2626
cmd_args: Vec<Vec<u8>>,
2727
num_worker_threads: usize,
28+
track_aex_count: bool,
2829
}
2930

3031
impl MappingInfo for Command {
@@ -61,14 +62,20 @@ impl Command {
6162
force_time_usercalls,
6263
cmd_args,
6364
num_worker_threads,
65+
track_aex_count: false,
6466
}
6567
}
6668

6769
pub fn new<P: AsRef<Path>, L: Load>(enclave_path: P, loader: &mut L) -> Result<Command, Error> {
6870
EnclaveBuilder::new(enclave_path.as_ref()).build(loader)
6971
}
7072

73+
#[cfg(feature = "instrumentation")]
74+
pub fn track_aex_count(&mut self) {
75+
self.track_aex_count = true;
76+
}
77+
7178
pub fn run(self) -> Result<(), Error> {
72-
EnclaveState::main_entry(self.main, self.threads, self.usercall_ext, self.forward_panics, self.force_time_usercalls, self.cmd_args, self.num_worker_threads)
79+
EnclaveState::main_entry(self.main, self.threads, self.usercall_ext, self.forward_panics, self.force_time_usercalls, self.track_aex_count, self.cmd_args, self.num_worker_threads)
7380
}
7481
}

intel-sgx/enclave-runner/src/tcs.rs

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ use std::convert::{TryFrom, TryInto};
1010
use std::fmt;
1111
use std::io::Write;
1212
use std::os::raw::c_void;
13+
use std::sync::atomic::AtomicUsize;
14+
#[cfg(feature = "instrumentation")]
15+
use std::sync::Arc;
1316

1417
use sgx_isa::Enclu;
1518
use sgxs::loader::Tcs;
@@ -22,10 +25,41 @@ pub enum CoResult<Y, R> {
2225
Return(R),
2326
}
2427

28+
#[cfg(feature = "instrumentation")]
29+
#[derive(Clone, Debug)]
30+
pub(crate) struct AexCount(Option<Arc<AtomicUsize>>);
31+
#[cfg(not(feature = "instrumentation"))]
32+
#[derive(Clone, Debug)]
33+
pub(crate) struct AexCount(());
34+
35+
impl AexCount {
36+
pub fn none() -> AexCount {
37+
#[cfg(feature = "instrumentation")]
38+
{ AexCount(None) }
39+
#[cfg(not(feature = "instrumentation"))]
40+
{ AexCount(()) }
41+
}
42+
43+
fn get(&self) -> Option<&AtomicUsize> {
44+
#[cfg(feature = "instrumentation")]
45+
{ self.0.as_ref().map(|p| &**p) }
46+
#[cfg(not(feature = "instrumentation"))]
47+
{ None }
48+
}
49+
}
50+
51+
#[cfg(feature = "instrumentation")]
52+
impl From<Arc<AtomicUsize>> for AexCount {
53+
fn from(v: Arc<AtomicUsize>) -> AexCount {
54+
AexCount(Some(v))
55+
}
56+
}
57+
2558
#[derive(Debug)]
2659
pub struct Usercall<T: Tcs> {
2760
tcs: T,
2861
parameters: (u64, u64, u64, u64, u64),
62+
aex_count: AexCount,
2963
}
3064

3165
pub type ThreadResult<T> = CoResult<Usercall<T>, (T, u64, u64)>;
@@ -40,7 +74,7 @@ impl<T: Tcs> Usercall<T> {
4074
retval: (u64, u64),
4175
debug_buf: Option<&RefCell<DebugBuffer>>,
4276
) -> ThreadResult<T> {
43-
coenter(self.tcs, 0, retval.0, retval.1, 0, 0, debug_buf)
77+
coenter(self.tcs, 0, retval.0, retval.1, 0, 0, debug_buf, self.aex_count)
4478
}
4579

4680
pub fn tcs_address(&self) -> *mut c_void {
@@ -56,6 +90,7 @@ pub(crate) fn coenter<T: Tcs>(
5690
mut p4: u64,
5791
mut p5: u64,
5892
debug_buf: Option<&RefCell<DebugBuffer>>,
93+
aex_count: AexCount,
5994
) -> ThreadResult<T> {
6095
/// Check if __vdso_sgx_enter_enclave exists. We're using weak linkage, so
6196
/// it might not.
@@ -101,7 +136,33 @@ pub(crate) fn coenter<T: Tcs>(
101136
uninit_debug_buf.as_mut_ptr() as *mut _
102137
}
103138
};
104-
if has_vdso_sgx_enter_enclave() {
139+
if let Some(aex_count) = aex_count.get() {
140+
asm!("
141+
decq ({1})
142+
push {1}
143+
lea 1f(%rip), %rcx // set SGX AEP
144+
xchg {0}, %rbx
145+
1: mov (%rsp), %r12
146+
incq (%r12)
147+
enclu
148+
addq $8, %rsp
149+
xchg %rbx, {0}
150+
",
151+
inout(reg) tcs.address() => _, // rbx is used internally by LLVM and cannot be used as an operand for inline asm (#84658)
152+
in(reg) aex_count,
153+
inout("eax") Enclu::EEnter as u32 => sgx_result,
154+
out("rcx") _,
155+
inout("rdx") p3,
156+
inout("rdi") p1,
157+
inout("rsi") p2,
158+
inout("r8") p4,
159+
inout("r9") p5,
160+
inout("r10") debug_buf_ptr => _,
161+
lateout("r11") _,
162+
lateout("r12") _,
163+
options(nostack, att_syntax)
164+
);
165+
} else if has_vdso_sgx_enter_enclave() {
105166
#[repr(C)]
106167
#[derive(Default)]
107168
struct SgxEnclaveRun {
@@ -172,8 +233,9 @@ pub(crate) fn coenter<T: Tcs>(
172233
eprintln!("Enclave triggered exception, treating as panic: {:?}", run);
173234
}
174235
return CoResult::Yield(Usercall {
175-
tcs: tcs,
236+
tcs,
176237
parameters: (crate::usercalls::abi::UsercallList::exit as _, true as _, 0, 0, 0),
238+
aex_count,
177239
});
178240
},
179241
_ => panic!("Error entering enclave (VDSO): ret = success, run = {:?}", run),
@@ -211,8 +273,9 @@ pub(crate) fn coenter<T: Tcs>(
211273
CoResult::Return((tcs, p2, p3))
212274
} else {
213275
CoResult::Yield(Usercall {
214-
tcs: tcs,
276+
tcs,
215277
parameters: (p1, p2, p3, p4, p5),
278+
aex_count,
216279
})
217280
}
218281
}

intel-sgx/enclave-runner/src/usercalls/interface.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ impl<'future, 'ioinput: 'future, 'tcs: 'ioinput> Usercalls<'future> for Handler<
178178
self,
179179
) -> std::pin::Pin<Box<dyn Future<Output = (Self, UsercallResult<Result>)> + 'future>> {
180180
async move {
181-
let ret = Ok(self.0.launch_thread().to_sgx_result());
181+
let ret = Ok(self.0.launch_thread().await.to_sgx_result());
182182
return (self, ret);
183183
}.boxed_local()
184184
}

intel-sgx/enclave-runner/src/usercalls/mod.rs

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,7 @@ impl PendingEvents {
611611
struct RunningTcs {
612612
tcs_address: TcsAddress,
613613
mode: EnclaveEntry,
614+
aex_count: tcs::AexCount,
614615
}
615616

616617
enum EnclaveKind {
@@ -665,6 +666,7 @@ pub(crate) struct EnclaveState {
665666
// Once set to Some, the guards should not be dropped for the lifetime of the enclave.
666667
fifo_guards: Mutex<Option<FifoGuards>>,
667668
return_queue_tx: Mutex<Option<ipc_queue::AsyncSender<Return, QueueSynchronizer>>>,
669+
aex_counts: Option<Mutex<FnvHashMap<TcsAddress, Arc<AtomicUsize>>>>,
668670
}
669671

670672
struct Work {
@@ -682,7 +684,7 @@ impl Work {
682684
let buf = RefCell::new([0u8; 1024]);
683685
let usercall_send_data = match self.entry {
684686
CoEntry::Initial(erased_tcs, p1, p2, p3, p4, p5) => {
685-
let coresult = tcs::coenter(erased_tcs, p1, p2, p3, p4, p5, Some(&buf));
687+
let coresult = tcs::coenter(erased_tcs, p1, p2, p3, p4, p5, Some(&buf), self.tcs.aex_count.clone());
686688
UsercallSendData::Sync(coresult, self.tcs, buf)
687689
}
688690
CoEntry::Resume(usercall, coresult) => {
@@ -736,6 +738,7 @@ impl EnclaveState {
736738
threads_vector: Vec<ErasedTcs>,
737739
forward_panics: bool,
738740
force_time_usercalls: bool,
741+
aex_counts: Option<Mutex<FnvHashMap<TcsAddress, Arc<AtomicUsize>>>>,
739742
) -> Arc<Self> {
740743
let mut fds = FnvHashMap::default();
741744

@@ -779,6 +782,7 @@ impl EnclaveState {
779782
force_time_usercalls,
780783
fifo_guards: Mutex::new(None),
781784
return_queue_tx: Mutex::new(None),
785+
aex_counts,
782786
})
783787
}
784788

@@ -1053,7 +1057,10 @@ impl EnclaveState {
10531057
}
10541058
});
10551059

1056-
local_set.block_on(&mut rt, select_fut.unit_error()).unwrap()
1060+
let ret = local_set.block_on(&mut rt, select_fut.unit_error()).unwrap();
1061+
#[cfg(feature = "instrumentation")]
1062+
tokio::runtime::Runtime::new().unwrap().block_on(enclave.print_aex_counts());
1063+
ret
10571064
}
10581065

10591066
fn run(
@@ -1105,12 +1112,18 @@ impl EnclaveState {
11051112
usercall_ext: Option<Box<dyn UsercallExtension>>,
11061113
forward_panics: bool,
11071114
force_time_usercalls: bool,
1115+
track_aex_count: bool,
11081116
cmd_args: Vec<Vec<u8>>,
11091117
num_of_worker_threads: usize,
11101118
) -> StdResult<(), anyhow::Error> {
11111119
assert!(num_of_worker_threads > 0, "worker_threads cannot be zero");
11121120
let mut event_queues =
11131121
FnvHashMap::with_capacity_and_hasher(threads.len() + 1, Default::default());
1122+
let mut aex_counts: Option<FnvHashMap<TcsAddress, Arc<AtomicUsize>>> = if track_aex_count {
1123+
Some(FnvHashMap::with_capacity_and_hasher(threads.len() + 1, Default::default()))
1124+
} else {
1125+
None
1126+
};
11141127
let main = Self::event_queue_add_tcs(&mut event_queues, main);
11151128

11161129
let mut args = Vec::with_capacity(cmd_args.len());
@@ -1123,10 +1136,16 @@ impl EnclaveState {
11231136
let argc = args.len();
11241137
let argv = Box::into_raw(args.into_boxed_slice()) as *const u8;
11251138

1139+
let aex_count = match &mut aex_counts {
1140+
#[cfg(feature = "instrumentation")]
1141+
Some(aex_counts) => tcs::AexCount::from(aex_counts.entry(main.tcs.address()).or_default().clone()),
1142+
_ => tcs::AexCount::none(),
1143+
};
11261144
let main_work = Work {
11271145
tcs: RunningTcs {
11281146
tcs_address: main.tcs.address(),
11291147
mode: EnclaveEntry::ExecutableMain,
1148+
aex_count,
11301149
},
11311150
entry: CoEntry::Initial(main.tcs, argv as _, argc as _, 0, 0, 0),
11321151
};
@@ -1137,7 +1156,7 @@ impl EnclaveState {
11371156
other_reasons: vec![],
11381157
}),
11391158
});
1140-
let enclave = EnclaveState::new(kind, event_queues, usercall_ext, threads, forward_panics, force_time_usercalls);
1159+
let enclave = EnclaveState::new(kind, event_queues, usercall_ext, threads, forward_panics, force_time_usercalls, aex_counts.map(Mutex::new));
11411160

11421161
let main_result = EnclaveState::run(enclave.clone(), num_of_worker_threads, main_work);
11431162

@@ -1194,7 +1213,7 @@ impl EnclaveState {
11941213

11951214
let kind = EnclaveKind::Library(Library {});
11961215

1197-
let enclave = EnclaveState::new(kind, event_queues, usercall_ext, threads, forward_panics, force_time_usercalls);
1216+
let enclave = EnclaveState::new(kind, event_queues, usercall_ext, threads, forward_panics, force_time_usercalls, None);
11981217
return enclave;
11991218
}
12001219

@@ -1211,6 +1230,7 @@ impl EnclaveState {
12111230
tcs: RunningTcs {
12121231
tcs_address: thread.tcs.address(),
12131232
mode: EnclaveEntry::Library,
1233+
aex_count: tcs::AexCount::none(),
12141234
},
12151235
entry: CoEntry::Initial(thread.tcs, p1, p2, p3, p4, p5),
12161236
};
@@ -1244,6 +1264,17 @@ impl EnclaveState {
12441264
pending_events.abort();
12451265
}
12461266
}
1267+
1268+
#[cfg(feature = "instrumentation")]
1269+
async fn print_aex_counts(&self) {
1270+
if let Some(aex_counts) = &self.aex_counts {
1271+
eprintln!("===AEX counts per TCS===");
1272+
for (addr, count) in aex_counts.lock().await.iter() {
1273+
eprintln!("{:p} {}", *addr, count.load(Ordering::Relaxed));
1274+
}
1275+
eprintln!("========================");
1276+
}
1277+
}
12471278
}
12481279

12491280
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -1540,7 +1571,7 @@ impl<'tcs> IOHandlerInput<'tcs> {
15401571
}
15411572

15421573
#[inline(always)]
1543-
fn launch_thread(&self) -> IoResult<()> {
1574+
async fn launch_thread(&self) -> IoResult<()> {
15441575
// check if enclave is of type command
15451576
self.enclave
15461577
.kind
@@ -1553,10 +1584,16 @@ impl<'tcs> IOHandlerInput<'tcs> {
15531584
}
15541585
};
15551586

1587+
let aex_count = match &self.enclave.aex_counts {
1588+
#[cfg(feature = "instrumentation")]
1589+
Some(aex_counts) => tcs::AexCount::from(aex_counts.lock().await.entry(new_tcs.tcs.address()).or_default().clone()),
1590+
_ => tcs::AexCount::none(),
1591+
};
15561592
let ret = self.work_sender.send(Work {
15571593
tcs: RunningTcs {
15581594
tcs_address: new_tcs.tcs.address(),
15591595
mode: EnclaveEntry::ExecutableNonMain,
1596+
aex_count,
15601597
},
15611598
entry: CoEntry::Initial(new_tcs.tcs, 0, 0, 0, 0, 0),
15621599
});

0 commit comments

Comments
 (0)