diff --git a/Pal/src/host/Linux-SGX/Makefile b/Pal/src/host/Linux-SGX/Makefile index 8da3085f..70907745 100644 --- a/Pal/src/host/Linux-SGX/Makefile +++ b/Pal/src/host/Linux-SGX/Makefile @@ -15,7 +15,7 @@ ASFLAGS += $(defs) enclave-objs = $(addprefix db_,files devices pipes eventfd sockets streams memory \ threading mutex events process object main rtld \ exception misc) \ - $(addprefix enclave_,ocalls ecalls framework platform pages untrusted) + $(addprefix enclave_,ocalls ecalls framework platform pages untrusted xstate) enclave-asm-objs = enclave_entry urts-objs = $(addprefix sgx_,enclave framework platform main rtld thread process exception graphene) \ quote/aesm.pb-c clone-x86_64 diff --git a/Pal/src/host/Linux-SGX/enclave_ecalls.c b/Pal/src/host/Linux-SGX/enclave_ecalls.c index 0f4dab63..0f38d4f9 100644 --- a/Pal/src/host/Linux-SGX/enclave_ecalls.c +++ b/Pal/src/host/Linux-SGX/enclave_ecalls.c @@ -70,6 +70,9 @@ void handle_ecall (long ecall_index, void * ecall_args, void * exit_target, return; } + /* xsave size must be initialized early */ + init_xsave_size(ms->ms_sec_info->enclave_attributes.xfrm); + /* pal_linux_main is responsible to check the passed arguments */ pal_linux_main(ms->ms_args, ms->ms_args_size, ms->ms_env, ms->ms_env_size, diff --git a/Pal/src/host/Linux-SGX/enclave_entry.S b/Pal/src/host/Linux-SGX/enclave_entry.S index 3a6bfee4..608bf9fa 100644 --- a/Pal/src/host/Linux-SGX/enclave_entry.S +++ b/Pal/src/host/Linux-SGX/enclave_entry.S @@ -784,3 +784,75 @@ _restore_sgx_context: .Ltmp_rip_saved2: jmp *%gs:SGX_TMP_RIP .cfi_endproc + + # void __save_xregs(PAL_XREGS_STATE* xsave_area) + # RDI: argument: pointer to xsave_area + # R11: return address: in order to not touch stack + # In some situations, stack isn't available. + # RAX, RDX: clobbered + .global __save_xregs + .type __save_xregs, @function +__save_xregs: + .cfi_startproc + movl xsave_enabled(%rip), %eax + cmpl $0, %eax + jz 1f + + # clear xsave header + movq $0, XSAVE_HEADER_OFFSET + 0 * 8(%rdi) + movq $0, XSAVE_HEADER_OFFSET + 1 * 8(%rdi) + movq $0, XSAVE_HEADER_OFFSET + 2 * 8(%rdi) + movq $0, XSAVE_HEADER_OFFSET + 3 * 8(%rdi) + movq $0, XSAVE_HEADER_OFFSET + 4 * 8(%rdi) + movq $0, XSAVE_HEADER_OFFSET + 5 * 8(%rdi) + movq $0, XSAVE_HEADER_OFFSET + 6 * 8(%rdi) + movq $0, XSAVE_HEADER_OFFSET + 7 * 8(%rdi) + + movl $0xffffffff, %eax + movl $0xffffffff, %edx + xsave64 (%rdi) + jmp *%r11 +1: + fxsave64 (%rdi) + jmp *%r11 + .cfi_endproc + + # void save_xregs(PAL_XREGS_STATE* xsave_area) + .global save_xregs + .type save_xregs, @function +save_xregs: + .cfi_startproc + popq %r11 + jmp __save_xregs + .cfi_endproc + + # void restore_xregs(const PAL_XREGS_STATE* xsave_area) + # RDI: argument: pointer to xsave_area + # R11: return address: in order to not touch stack + # In some situations, stack isn't available. + # RAX, RDX: clobbered + .global __restore_xregs + .type __restore_xregs, @function +__restore_xregs: + .cfi_startproc + movl xsave_enabled(%rip), %eax + cmpl $0, %eax + jz 1f + + movl $0xffffffff, %eax + movl $0xffffffff, %edx + xrstor64 (%rdi) + jmp *%r11 +1: + fxrstor64 (%rdi) + jmp *%r11 + .cfi_endproc + + # void restore_xregs(const PAL_XREGS_STATE* xsave_area) + .global restore_xregs + .type restore_xregs, @function +restore_xregs: + .cfi_startproc + popq %r11 + jmp __restore_xregs + .cfi_endproc diff --git a/Pal/src/host/Linux-SGX/enclave_xstate.c b/Pal/src/host/Linux-SGX/enclave_xstate.c new file mode 100644 index 00000000..c50dca75 --- /dev/null +++ b/Pal/src/host/Linux-SGX/enclave_xstate.c @@ -0,0 +1,97 @@ +/* + * this function is shamelessly stolen from linux-sgx + * https://github.com/intel/linux-sgx/blob/9ddec08fb98c1636ed3b1a77bbc4fa3520344ede/sdk/trts/trts_xsave.cpp + * It has BSD lisence. + */ + +/* + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "enclave_pages.h" + +int xsave_enabled = 0; +uint64_t xsave_features = 0; +uint32_t xsave_size = 0; +//FXRSTOR only cares about the first 512 bytes, while +//XRSTOR in compacted mode will ignore the first 512 bytes. +const uint32_t xsave_reset_state[XSAVE_RESET_STATE_SIZE/sizeof(uint32_t)] +__attribute__((aligned(PAL_XSTATE_ALIGN))) = { + 0x037F, 0, 0, 0, 0, 0, 0x1F80, 0xFFFF, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0x80000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // XCOMP_BV[63] = 1, compaction mode +}; + +void init_xsave_size(uint64_t xfrm) { + const struct { + uint64_t bits; + uint32_t size; + } xsave_size_table[] = { // Note that the xsave_size should be in ascending order + {SGX_XFRM_LEGACY, 512 + 64}, // 512 for legacy features, 64 for xsave header + {SGX_XFRM_AVX, 512 + 64 + 256}, // 256 for YMM0_H - YMM15_H registers + {SGX_XFRM_MPX, 512 + 64 + 256 + 256}, // 256 for MPX + {SGX_XFRM_AVX512, 512 + 64 + 256 + 256 + 1600}, // 1600 for k0 - k7, ZMM0_H - ZMM15_H, ZMM16 - ZMM31 + }; + + /* fxsave/fxrstore as fallback */ + xsave_enabled = 0; + xsave_features = PAL_XFEATURE_MASK_FPSSE; + xsave_size = 512 + 64; + if (!xfrm || (xfrm & SGX_XFRM_RESERVED)) { + SGX_DBG(DBG_I, "xsave is disabled, xfrm 0x%lx\n", xfrm); + return; + } + + xsave_enabled = (xfrm == SGX_XFRM_LEGACY) ? 0 : 1; + for (size_t i = 0; i < ARRAY_SIZE(xsave_size_table); i++) { + if ((xfrm & xsave_size_table[i].bits) == xsave_size_table[i].bits) { + xsave_features = xfrm; + xsave_size = xsave_size_table[i].size; + } + } + SGX_DBG(DBG_I, "xsave is enabled with xsave_size: %u\n", xsave_size); +} diff --git a/Pal/src/host/Linux-SGX/generated-offsets.c b/Pal/src/host/Linux-SGX/generated-offsets.c index 752d7b19..cf3f7722 100644 --- a/Pal/src/host/Linux-SGX/generated-offsets.c +++ b/Pal/src/host/Linux-SGX/generated-offsets.c @@ -1,13 +1,14 @@ #include #include -#include "sgx_arch.h" -#include "sgx_tls.h" +#include "ecall_types.h" +#include "ocall_types.h" +#include "pal.h" #include "pal_linux.h" #include "pal_linux_defs.h" #include "pal_security.h" -#include "ecall_types.h" -#include "ocall_types.h" +#include "sgx_arch.h" +#include "sgx_tls.h" #include @@ -158,5 +159,9 @@ void dummy(void) /* Ocall Index */ DEFINE(OCALL_EXIT, OCALL_EXIT); -} + /* fp regs */ + OFFSET_T(XSAVE_HEADER_OFFSET, PAL_XREGS_STATE, header); + DEFINE(PAL_XSTATE_ALIGN, PAL_XSTATE_ALIGN); + DEFINE(PAL_FP_XSTATE_MAGIC2_SIZE, PAL_FP_XSTATE_MAGIC2_SIZE); +} diff --git a/Pal/src/host/Linux-SGX/pal_linux.h b/Pal/src/host/Linux-SGX/pal_linux.h index cce182fb..fbd8e3c5 100644 --- a/Pal/src/host/Linux-SGX/pal_linux.h +++ b/Pal/src/host/Linux-SGX/pal_linux.h @@ -113,6 +113,15 @@ extern char __text_start, __text_end, __data_start, __data_end; typedef struct { char bytes[32]; } sgx_checksum_t; typedef struct { char bytes[16]; } sgx_stub_t; +extern int xsave_enabled; +extern uint64_t xsave_features; +extern uint32_t xsave_size; +#define XSAVE_RESET_STATE_SIZE (512 + 64) // 512 for legacy regs, 64 for xsave header +extern const uint32_t xsave_reset_state[]; + +void init_xsave_size(uint64_t xfrm); +void save_xregs(PAL_XREGS_STATE* xsave_area); +void restore_xregs(const PAL_XREGS_STATE* xsave_area); noreturn void _restore_sgx_context(sgx_cpu_context_t* uc); int init_trusted_files (void); diff --git a/Pal/src/host/Linux-SGX/sgx_arch.h b/Pal/src/host/Linux-SGX/sgx_arch.h index 90f65a13..e7cc9a1c 100644 --- a/Pal/src/host/Linux-SGX/sgx_arch.h +++ b/Pal/src/host/Linux-SGX/sgx_arch.h @@ -78,6 +78,7 @@ typedef uint8_t sgx_isvfamily_id_t[SGX_ISV_FAMILY_ID_SIZE]; #define SGX_XFRM_AVX 0x06ULL #define SGX_XFRM_MPX 0x18ULL #define SGX_XFRM_AVX512 0xe6ULL +#define SGX_XFRM_RESERVED (~(SGX_XFRM_LEGACY | SGX_XFRM_AVX | SGX_XFRM_MPX | SGX_XFRM_AVX512)) #define SGX_MISCSELECT_EXINFO 0x01UL diff --git a/Pal/src/host/Linux/db_exception.c b/Pal/src/host/Linux/db_exception.c index 89b6d295..f4845fee 100644 --- a/Pal/src/host/Linux/db_exception.c +++ b/Pal/src/host/Linux/db_exception.c @@ -189,8 +189,10 @@ static void _DkGenericEventTrigger (PAL_IDX event_num, PAL_EVENT_HANDLER upcall, PAL_EVENT event; event.event_num = event_num; - if (uc) + if (uc) { memcpy(&event.context, uc->uc_mcontext.gregs, sizeof(PAL_CONTEXT)); + event.context.fpregs = (PAL_XREGS_STATE*)uc->uc_mcontext.fpregs; + } event.uc = uc; @@ -417,5 +419,6 @@ void _DkExceptionReturn (void * event) if (e->uc) { /* copy the context back to ucontext */ memcpy(e->uc->uc_mcontext.gregs, &e->context, sizeof(PAL_CONTEXT)); + e->uc->uc_mcontext.fpregs = (struct _libc_fpstate*)e->context.fpregs; } } diff --git a/Pal/src/pal.h b/Pal/src/pal.h index 57be736c..cdaf83a4 100644 --- a/Pal/src/pal.h +++ b/Pal/src/pal.h @@ -95,12 +95,138 @@ static inline PAL_TCB * pal_get_tcb (void) return tcb; } +#ifdef __x86_64__ +union pal_csgsfs { + struct { + uint16_t cs; + uint16_t gs; + uint16_t fs; + uint16_t ss; + }; + uint64_t csgsfs; +}; + +/* adopt Linux style fp layout, _libc_fpstate of glibc: + * Because self-contained definition is needed for Pal definition, + * same layout is defined with PAL prefix. + */ +#define PAL_FP_XSTATE_MAGIC1 0x46505853U +#define PAL_FP_XSTATE_MAGIC2 0x46505845U +#define PAL_FP_XSTATE_MAGIC2_SIZE (sizeof(PAL_FP_XSTATE_MAGIC2)) + +enum PAL_XFEATURE { + PAL_XFEATURE_FP, + PAL_XFEATURE_SSE, + PAL_XFEATURE_YMM, + PAL_XFEATURE_BNDREGS, + PAL_XFEATURE_BNDCSR, + PAL_XFEATURE_OPMASK, + PAL_XFEATURE_ZMM_Hi256, + PAL_XFEATURE_Hi16_ZMM, + PAL_XFEATURE_PT, + PAL_XFEATURE_PKRU, + + PAL_XFEATURE_MAX, +}; + +#define PAL_XFEATURE_MASK_FP (1UL << PAL_XFEATURE_FP) +#define PAL_XFEATURE_MASK_SSE (1UL << PAL_XFEATURE_SSE) +#define PAL_XFEATURE_MASK_YMM (1UL << PAL_XFEATURE_YMM) +#define PAL_XFEATURE_MASK_BNDREGS (1UL << PAL_XFEATURE_BNDREGS) +#define PAL_XFEATURE_MASK_BNDCSR (1UL << PAL_XFEATURE_BNDCSR) +#define PAL_XFEATURE_MASK_OPMASK (1UL << PAL_XFEATURE_OPMASK) +#define PAL_XFEATURE_MASK_ZMM_Hi256 (1UL << PAL_XFEATURE_ZMM_Hi256) +#define PAL_XFEATURE_MASK_Hi16_ZMM (1UL << PAL_XFEATURE_Hi16_ZMM) +#define PAL_XFEATURE_MASK_PT (1UL << PAL_XFEATURE_PT) +#define PAL_XFEATURE_MASK_PKRU (1UL << PAL_XFEATURE_PKRU) + +#define PAL_XFEATURE_MASK_FPSSE (PAL_XFEATURE_MASK_FP \ + | PAL_XFEATURE_MASK_SSE) +#define PAL_XFEATURE_MASK_AVX512 (PAL_XFEATURE_MASK_OPMASK \ + | PAL_XFEATURE_MASK_ZMM_Hi256 \ + | PAL_XFEATURE_MASK_Hi16_ZMM) + +typedef struct { + uint32_t magic1; /* PAL_FP_XSTATE_MAGIC1 */ + uint32_t extended_size; /* xsave_size */ + uint64_t xfeatures; /* XSAVE feature */ + uint32_t xstate_size; /* xsave_size + PAL_FP_STATE_MAGIC2_SIZE */ + uint32_t padding[7]; +} PAL_FPX_SW_BYTES; + +typedef struct { + uint32_t cwd; + uint32_t swd; + uint32_t twd; + uint32_t fip; + uint32_t fcs; + uint32_t foo; + uint32_t fos; + uint32_t st_space[20]; + uint8_t ftop; + uint8_t changed; + uint8_t lookahead; + uint8_t no_update; + uint8_t rm; + uint8_t alimit; + void* info; /* struct math_emu_info */ + uint32_t entry_eip; +} PAL_SWREGS_STATE; + +typedef struct { + uint16_t significand[4]; + uint16_t exponent; + uint16_t padding[3]; +} PAL_FPXREG; + +typedef struct { + uint32_t element[4]; +} PAL_XMMREG; + +typedef struct { + /* 64-bit FXSAVE format. */ + uint16_t cwd; + uint16_t swd; + uint16_t ftw; + uint16_t fop; + uint64_t rip; + uint64_t rdp; + uint32_t mxcsr; + uint32_t mxcr_mask; + PAL_FPXREG st[8]; + PAL_XMMREG xmm[16]; + union { + uint32_t padding[24]; + struct { + uint32_t padding2[12]; + PAL_FPX_SW_BYTES sw_reserved; + }; + }; +} PAL_FPSTATE; + +typedef struct { + uint64_t xfeatures; + uint64_t xcomp_bv; + uint64_t reserved[6]; +} __attribute__((packed)) PAL_XSTATE_HEADER; + +#define PAL_XSTATE_ALIGN 64 + +typedef struct { + PAL_FPSTATE fpstate; + PAL_XSTATE_HEADER header; +} __attribute__((packed, aligned(PAL_XSTATE_ALIGN))) PAL_XREGS_STATE; +#else +# error "Unsupported architecture" +#endif + typedef struct { #ifdef __x86_64__ PAL_NUM r8, r9, r10, r11, r12, r13, r14, r15; PAL_NUM rdi, rsi, rbp, rbx, rdx, rax, rcx; PAL_NUM rsp, rip; PAL_NUM efl, csgsfs, err, trapno, oldmask, cr2; + PAL_XREGS_STATE* fpregs; #else # error "Unsupported architecture" #endif