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