x86/bits64/
sgx.rs

1//! Program x86 enclaves.
2
3use core::arch::asm;
4
5/// Execute an enclave system function of specified leaf number.
6///
7/// # Safety
8///   * Function needs to be executed in ring 0.
9macro_rules! encls {
10    ($rax:expr, $rbx:expr) => {
11        $crate::bits64::sgx::encls2($rax as u64, $rbx as u64)
12    };
13
14    ($rax:expr, $rbx:expr, $rcx:expr) => {
15        $crate::bits64::sgx::encls3($rax as u64, $rbx as u64, $rcx as u64)
16    };
17
18    ($rax:expr, $rbx:expr, $rcx:expr, $rdx:expr) => {
19        $crate::bits64::sgx::encls4($rax as u64, $rbx as u64, $rcx as u64, $rdx as u64)
20    };
21}
22
23/// encls with two arguments -- consider calling the encls! macro instead!
24unsafe fn encls2(rax: u64, rbx: u64) -> (u32, u64) {
25    let eax: u32;
26    let out_rbx: u64;
27    asm!(
28        "pushq %rbx; movq %rsi, %rbx; encls; movq %rbx, %rsi; popq %rbx",
29        lateout("eax") eax, lateout("rsi") out_rbx,
30        in("rax") rax, in("rsi") rbx,
31        options(att_syntax),
32    );
33    (eax, out_rbx)
34}
35
36/// encls with three arguments -- consider calling the encls! macro instead!
37unsafe fn encls3(rax: u64, rbx: u64, rcx: u64) -> (u32, u64) {
38    let eax: u32;
39    let out_rbx: u64;
40    asm!(
41        "pushq %rbx; movq %rsi, %rbx; encls; movq %rbx, %r11; popq %rbx",
42        lateout("eax") eax, lateout("rsi") out_rbx,
43        in("rax") rax, in("rsi") rbx, in("rcx") rcx,
44        options(att_syntax),
45    );
46    (eax, out_rbx)
47}
48
49/// encls with four arguments -- consider calling the encls! macro instead!
50unsafe fn encls4(rax: u64, rbx: u64, rcx: u64, rdx: u64) -> (u32, u64) {
51    let eax: u32;
52    let out_rbx: u64;
53    asm!(
54        "pushq %rbx; movq %rsi, %rbx; encls; movq %rbx, %rsi; popq %rbx",
55        lateout("eax") eax, lateout("rsi") out_rbx,
56        in("rax") rax, in("rsi") rbx, in("rcx") rcx, in("rdx") rdx,
57        options(att_syntax),
58    );
59    (eax, out_rbx)
60}
61
62#[allow(clippy::upper_case_acronyms)]
63enum EnclsCommand {
64    EADD = 0x01,
65    EAUG = 0x0D,
66    EBLOCK = 0x09,
67    ECREATE = 0x00,
68    EDBGRD = 0x04,
69    EDBGWR = 0x05,
70    EEXTEND = 0x06,
71    EINIT = 0x02,
72    ELDB = 0x07,
73    ELDU = 0x08,
74    EMODPR = 0x0E,
75    EMODT = 0x0F,
76    EPA = 0x0A,
77    EREMOVE = 0x03,
78    ETRACK = 0x0C,
79    EWB = 0x0B,
80}
81
82/// Add a Page to an Uninitialized Enclave.
83///
84/// # Arguments
85///  * Address of a PAGEINFO.
86///  * Address of the destination EPC page.
87///
88/// # Safety
89/// Requires SGX support.
90pub unsafe fn encls_eadd(pageinfo: u64, epc_page: u64) {
91    encls!(EnclsCommand::EADD as u64, pageinfo, epc_page);
92}
93
94/// Add a Page to an Initialized Enclave.
95///
96/// # Arguments
97///  * Address of a SECINFO
98///  * Address of the destination EPC page
99///
100/// # Safety
101/// Requires SGX support.
102pub unsafe fn encls_eaug(secinfo_address: u64, epc_page: u64) {
103    encls!(EnclsCommand::EAUG as u64, secinfo_address, epc_page);
104}
105
106/// Mark a page in EPC as Blocked.
107///
108/// # Arguments
109///  * Effective address of the EPC page
110///
111/// # Safety
112/// Requires SGX support.
113pub unsafe fn encls_eblock(epc_page: u64) -> u32 {
114    encls!(EnclsCommand::EBLOCK as u64, epc_page).0
115}
116
117/// Create an SECS page in the Enclave Page Cache
118///
119/// # Arguments
120///  * Address of a PAGEINFO
121///  * Address of the destination SECS page
122///
123/// # Safety
124/// Requires SGX support.
125pub unsafe fn encls_create(pageinfo: u64, secs_page: u64) {
126    encls!(EnclsCommand::ECREATE as u64, pageinfo, secs_page);
127}
128
129/// Read From a Debug Enclave.
130///
131/// # Return
132/// Data read from a debug enclave.
133///
134/// # Arguments
135///  * Address of source memory in the EPC
136///
137/// # Safety
138/// Requires SGX support.
139pub unsafe fn encls_edbgrd(source_address: u64) -> u64 {
140    encls!(EnclsCommand::EDBGRD as u64, source_address).1
141}
142
143/// Write to a Debug Enclave.
144///
145/// # Arguments
146///  * Data to be written to a debug enclave
147///  * Address of Target memory in the EPC
148///
149/// # Safety
150/// Requires SGX support.
151pub unsafe fn encls_edbgwr(data: u64, target_address: u64) {
152    encls!(EnclsCommand::EDBGWR as u64, data, target_address);
153}
154
155/// Extend Uninitialized Enclave Measurement by 256 Bytes
156///
157/// # Arguments
158///  * Effective address of the SECS of the data chunk
159///  * Effective address of a 256-byte chunk in the EPC
160///
161/// # Safety
162/// Requires SGX support.
163pub unsafe fn encls_eextend(secs_chunk: u64, epc_chunk: u64) {
164    encls!(EnclsCommand::EEXTEND as u64, secs_chunk, epc_chunk);
165}
166
167/// Initialize an Enclave for Execution
168///
169/// # Arguments
170///  * Address of SIGSTRUCT
171///  * Address of SECS
172///  * Address of EINITTOKEN
173///
174/// # Safety
175/// Requires SGX support.
176pub unsafe fn encls_einit(sigstruct: u64, secs: u64, einittoken: u64) -> u32 {
177    encls!(EnclsCommand::EINIT as u64, sigstruct, secs, einittoken).0
178}
179
180/// Loads and verifies an EPC page and marks the page as blocked.
181///
182/// # Arguments
183///  * Address of the PAGEINFO
184///  * Address of the EPC page
185///  * Address of the version-array slot
186///
187/// # Safety
188/// Requires SGX support.
189pub unsafe fn encls_eldb(pageinfo: u64, epc_page: u64, verion_array_slot: u64) -> u32 {
190    encls!(
191        EnclsCommand::ELDB as u64,
192        pageinfo,
193        epc_page,
194        verion_array_slot
195    )
196    .0
197}
198
199/// Loads, verifies an EPC page and marks the page as unblocked.
200///
201/// # Arguments
202///  * Address of the PAGEINFO
203///  * Address of the EPC page
204///  * Address of the version-array slot
205///
206/// # Safety
207/// Requires SGX support.
208pub unsafe fn encls_eldu(pageinfo: u64, epc_page: u64, verion_array_slot: u64) -> u32 {
209    encls!(
210        EnclsCommand::ELDU as u64,
211        pageinfo,
212        epc_page,
213        verion_array_slot
214    )
215    .0
216}
217
218/// Restrict the Permissions of an EPC Page.
219///
220/// # Arguments
221///  * Address of a SECINFO
222///  * Address of the destination EPC page
223///
224/// # Safety
225/// Requires SGX support.
226pub unsafe fn encls_emodpr(secinfo: u64, epc_page: u64) -> u32 {
227    encls!(EnclsCommand::EMODPR as u64, secinfo, epc_page).0
228}
229
230/// Change the Type of an EPC Page.
231///
232/// # Arguments
233///  * Address of a SECINFO
234///  * Address of the destination EPC page
235///
236/// # Safety
237/// Requires SGX support.
238pub unsafe fn encls_emodt(secinfo: u64, epc_page: u64) -> u32 {
239    encls!(EnclsCommand::EMODT as u64, secinfo, epc_page).0
240}
241
242/// Add Version Array.
243///
244/// # Arguments
245///  * PT_VA Constant
246///  * Effective address of the EPC page
247///
248/// # Safety
249/// Requires SGX support.
250pub unsafe fn encls_epa(pt_va: u64, epc_page: u64) {
251    encls!(EnclsCommand::EPA as u64, pt_va, epc_page);
252}
253
254/// Remove a page from the EPC.
255///
256/// # Arguments
257///  * Effective address of the EPC page
258///
259/// # Safety
260/// Requires SGX support.
261pub unsafe fn encls_eremove(epc_page: u64) {
262    encls!(EnclsCommand::EREMOVE as u64, epc_page);
263}
264
265/// Activates EBLOCK Checks.
266///
267/// # Arguments
268///  * Pointer to the SECS of the EPC page.
269///
270/// # Safety
271/// Requires SGX support.
272pub unsafe fn encls_etrack(secs_pointer: u64) -> u32 {
273    encls!(EnclsCommand::ETRACK as u64, secs_pointer).0
274}
275
276/// Invalidate an EPC Page and Write out to Main Memory.
277///
278/// # Arguments
279///  * Address of the EPC page.
280///  * Address of a VA slot.
281///
282/// # Safety
283/// Requires SGX support.
284pub unsafe fn encls_ewb(pageinfo: u64, epc_page: u64, va_slot: u64) -> u32 {
285    encls!(EnclsCommand::EWB as u64, pageinfo, epc_page, va_slot).0
286}
287
288/// Execute an enclave user function of specified leaf number.
289///
290/// # Safety
291///   * Function needs to be executed in ring 3.
292macro_rules! enclu {
293    ($rax:expr, $rbx:expr, $rcx:expr) => {
294        $crate::bits64::sgx::enclu3($rax as u64, $rbx as u64, $rcx as u64)
295    };
296
297    ($rax:expr, $rbx:expr, $rcx:expr, $rdx:expr) => {
298        $crate::bits64::sgx::enclu4($rax as u64, $rbx as u64, $rcx as u64, $rdx as u64)
299    };
300}
301
302/// enclu with three arguments -- consider calling the enclu! macro instead!
303unsafe fn enclu3(rax: u64, rbx: u64, rcx: u64) -> (u32, u64) {
304    let eax: u32;
305    let out_rcx: u64;
306    asm!(
307        "pushq %rbx; movq %rsi, %rbx; enclu; popq %rbx",
308        lateout("eax") eax, lateout("rcx") out_rcx,
309        in("rax") rax, in("rsi") rbx, in("rcx") rcx,
310        options(att_syntax),
311    );
312    (eax, out_rcx)
313}
314
315/// enclu with four arguments -- consider calling the enclu! macro instead!
316unsafe fn enclu4(rax: u64, rbx: u64, rcx: u64, rdx: u64) -> (u32, u64) {
317    let eax: u32;
318    let out_rcx: u64;
319    asm!(
320        "pushq %rbx; movq %rsi, %rbx; enclu; popq %rbx",
321        lateout("eax") eax, lateout("rcx") out_rcx,
322        in("rax") rax, in("rsi") rbx, in("rcx") rcx, in("rdx") rdx,
323        options(att_syntax),
324    );
325    (eax, out_rcx)
326}
327
328enum EncluCommand {
329    EAccept = 0x05,
330    EAcceptCopy = 0x07,
331    EEnter = 0x02,
332    EExit = 0x04,
333    EGetKey = 0x01,
334    EModePE = 0x06,
335    EReport = 0x00,
336    EResume = 0x03,
337}
338
339/// Accept Changes to an EPC Page.
340///
341/// # Arguments
342///  * Address of a SECINFO.
343///  * Address of the destination EPC page.
344///
345/// Returns an error code.
346///
347/// # Safety
348/// Requires SGX support.
349pub unsafe fn enclu_eaccept(secinfo: u64, epc_page: u64) -> u32 {
350    enclu!(EncluCommand::EAccept as u64, secinfo, epc_page).0
351}
352
353/// Initialize a Pending Page.
354///
355/// # Arguments
356///  * Address of a SECINFO.
357///  * Address of the destination EPC page.
358///  * Address of the source EPC page.
359///
360/// Returns an error code.
361///
362/// # Safety
363/// Requires SGX support.
364pub unsafe fn enclu_eacceptcopy(
365    secinfo: u64,
366    destination_epc_page: u64,
367    source_epc_page: u64,
368) -> u32 {
369    enclu!(
370        EncluCommand::EAcceptCopy as u64,
371        secinfo,
372        destination_epc_page,
373        source_epc_page
374    )
375    .0
376}
377
378/// Enters an Enclave.
379///
380/// # Arguments
381///  * Address of a TCS.
382///  * Address of AEP.
383///  * Address of IP following EEnter.
384///
385/// Returns content of RBX.CSSA and Address of IP following EEnter.
386///
387/// # Safety
388/// Requires SGX support.
389pub unsafe fn enclu_eenter(tcs: u64, aep: u64) -> (u32, u64) {
390    enclu!(EncluCommand::EEnter as u64, tcs, aep)
391}
392
393/// Exits an Enclave.
394///
395/// # Arguments
396///  * Target address outside the enclave
397///  * Address of the current AEP
398///
399/// # Safety
400/// Requires SGX support.
401pub unsafe fn enclu_eexit(ip: u64, aep: u64) {
402    enclu!(EncluCommand::EExit as u64, ip, aep);
403}
404
405/// Retrieves a Cryptographic Key.
406///
407/// # Arguments
408///  * Address to a KEYREQUEST
409///  * Address of the OUTPUTDATA
410///
411/// # Safety
412/// Requires SGX support.
413pub unsafe fn enclu_egetkey(keyrequest: u64, outputdata: u64) {
414    enclu!(EncluCommand::EGetKey as u64, keyrequest, outputdata);
415}
416
417/// Extend an EPC Page Permissions.
418///
419/// # Arguments
420///  * Address of a SECINFO
421///  * Address of the destination EPC page
422///
423/// # Safety
424/// Requires SGX support.
425pub unsafe fn enclu_emodepe(secinfo: u64, epc_page: u64) {
426    enclu!(EncluCommand::EModePE as u64, secinfo, epc_page);
427}
428
429/// Create a Cryptographic Report of the Enclave.
430///
431/// # Arguments
432///  * Address of TARGETINFO
433///  * Address of REPORTDATA
434///  * Address where the REPORT is written to in an OUTPUTDATA
435///
436/// # Safety
437/// Requires SGX support.
438pub unsafe fn enclu_ereport(targetinfo: u64, reportdata: u64, outputdata: u64) {
439    enclu!(
440        EncluCommand::EReport as u64,
441        targetinfo,
442        reportdata,
443        outputdata
444    );
445}
446
447/// Re-Enters an Enclave.
448///
449/// # Arguments
450///  * Address of a TCS.
451///  * Address of AEP.
452///
453/// # Safety
454/// Requires SGX support.
455pub unsafe fn enclu_eresume(tcs: u64, aep: u64) {
456    enclu!(EncluCommand::EResume as u64, tcs, aep);
457}