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