1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright(c) 2016-20 Intel Corporation. */ 3 4 #include <stddef.h> 5 #include "defines.h" 6 7 /* 8 * Data buffer spanning two pages that will be placed first in the .data 9 * segment. Even if not used internally the second page is needed by external 10 * test manipulating page permissions, so mark encl_buffer as "used" to make 11 * sure it is entirely preserved by the compiler. 12 */ 13 static uint8_t __used encl_buffer[8192] = { 1 }; 14 15 enum sgx_enclu_function { 16 EACCEPT = 0x5, 17 EMODPE = 0x6, 18 }; 19 20 static void do_encl_emodpe(void *_op) 21 { 22 struct sgx_secinfo secinfo __aligned(sizeof(struct sgx_secinfo)) = {0}; 23 struct encl_op_emodpe *op = _op; 24 25 secinfo.flags = op->flags; 26 27 asm volatile(".byte 0x0f, 0x01, 0xd7" 28 : /* no outputs */ 29 : "a" (EMODPE), 30 "b" (&secinfo), 31 "c" (op->epc_addr) 32 : "memory" /* read from secinfo pointer */); 33 } 34 35 static void do_encl_eaccept(void *_op) 36 { 37 struct sgx_secinfo secinfo __aligned(sizeof(struct sgx_secinfo)) = {0}; 38 struct encl_op_eaccept *op = _op; 39 int rax; 40 41 secinfo.flags = op->flags; 42 43 asm volatile(".byte 0x0f, 0x01, 0xd7" 44 : "=a" (rax) 45 : "a" (EACCEPT), 46 "b" (&secinfo), 47 "c" (op->epc_addr) 48 : "memory" /* read from secinfo pointer */); 49 50 op->ret = rax; 51 } 52 53 static void *memcpy(void *dest, const void *src, size_t n) 54 { 55 size_t i; 56 57 for (i = 0; i < n; i++) 58 ((char *)dest)[i] = ((char *)src)[i]; 59 60 return dest; 61 } 62 63 static void *memset(void *dest, int c, size_t n) 64 { 65 size_t i; 66 67 for (i = 0; i < n; i++) 68 ((char *)dest)[i] = c; 69 70 return dest; 71 } 72 73 static void do_encl_init_tcs_page(void *_op) 74 { 75 struct encl_op_init_tcs_page *op = _op; 76 void *tcs = (void *)op->tcs_page; 77 uint32_t val_32; 78 79 memset(tcs, 0, 16); /* STATE and FLAGS */ 80 memcpy(tcs + 16, &op->ssa, 8); /* OSSA */ 81 memset(tcs + 24, 0, 4); /* CSSA */ 82 val_32 = 1; 83 memcpy(tcs + 28, &val_32, 4); /* NSSA */ 84 memcpy(tcs + 32, &op->entry, 8); /* OENTRY */ 85 memset(tcs + 40, 0, 24); /* AEP, OFSBASE, OGSBASE */ 86 val_32 = 0xFFFFFFFF; 87 memcpy(tcs + 64, &val_32, 4); /* FSLIMIT */ 88 memcpy(tcs + 68, &val_32, 4); /* GSLIMIT */ 89 memset(tcs + 72, 0, 4024); /* Reserved */ 90 } 91 92 static void do_encl_op_put_to_buf(void *op) 93 { 94 struct encl_op_put_to_buf *op2 = op; 95 96 memcpy(&encl_buffer[0], &op2->value, 8); 97 } 98 99 static void do_encl_op_get_from_buf(void *op) 100 { 101 struct encl_op_get_from_buf *op2 = op; 102 103 memcpy(&op2->value, &encl_buffer[0], 8); 104 } 105 106 static void do_encl_op_put_to_addr(void *_op) 107 { 108 struct encl_op_put_to_addr *op = _op; 109 110 memcpy((void *)op->addr, &op->value, 8); 111 } 112 113 static void do_encl_op_get_from_addr(void *_op) 114 { 115 struct encl_op_get_from_addr *op = _op; 116 117 memcpy(&op->value, (void *)op->addr, 8); 118 } 119 120 static void do_encl_op_nop(void *_op) 121 { 122 123 } 124 125 /* 126 * Symbol placed at the start of the enclave image by the linker script. 127 * Declare this extern symbol with visibility "hidden" to ensure the compiler 128 * does not access it through the GOT and generates position-independent 129 * addressing as __encl_base(%rip), so we can get the actual enclave base 130 * during runtime. 131 */ 132 extern const uint8_t __attribute__((visibility("hidden"))) __encl_base; 133 134 typedef void (*encl_op_t)(void *); 135 static const encl_op_t encl_op_array[ENCL_OP_MAX] = { 136 do_encl_op_put_to_buf, 137 do_encl_op_get_from_buf, 138 do_encl_op_put_to_addr, 139 do_encl_op_get_from_addr, 140 do_encl_op_nop, 141 do_encl_eaccept, 142 do_encl_emodpe, 143 do_encl_init_tcs_page, 144 }; 145 146 void encl_body(void *rdi, void *rsi) 147 { 148 struct encl_op_header *header = (struct encl_op_header *)rdi; 149 encl_op_t op; 150 151 if (header->type >= ENCL_OP_MAX) 152 return; 153 154 /* 155 * The enclave base address needs to be added, as this call site 156 * *cannot be* made rip-relative by the compiler, or fixed up by 157 * any other possible means. 158 */ 159 op = ((uint64_t)&__encl_base) + encl_op_array[header->type]; 160 161 (*op)(header); 162 } 163