b564982fda
The Thread Control Structure (TCS) contains meta-data used by the hardware to save and restore thread specific information when entering/exiting the enclave. A TCS can be added to an initialized enclave by first adding a new regular enclave page, initializing the content of the new page from within the enclave, and then changing that page's type to a TCS. Support the initialization of a TCS from within the enclave. The variable information needed that should be provided from outside the enclave is the address of the TCS, address of the State Save Area (SSA), and the entry point that the thread should use to enter the enclave. With this information provided all needed fields of a TCS can be initialized. Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Acked-by: Jarkko Sakkinen <jarkko@kernel.org> Link: https://lkml.kernel.org/r/bad6052056188bde753a54313da1ac8f1e29088a.1652137848.git.reinette.chatre@intel.com
140 lines
2.8 KiB
C
140 lines
2.8 KiB
C
// 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 .data
|
|
* segment. Even if not used internally the second page is needed by
|
|
* external test manipulating page permissions.
|
|
*/
|
|
static uint8_t 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"
|
|
:
|
|
: "a" (EMODPE),
|
|
"b" (&secinfo),
|
|
"c" (op->epc_addr));
|
|
}
|
|
|
|
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));
|
|
|
|
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)
|
|
{
|
|
|
|
}
|
|
|
|
void encl_body(void *rdi, void *rsi)
|
|
{
|
|
const void (*encl_op_array[ENCL_OP_MAX])(void *) = {
|
|
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,
|
|
};
|
|
|
|
struct encl_op_header *op = (struct encl_op_header *)rdi;
|
|
|
|
if (op->type < ENCL_OP_MAX)
|
|
(*encl_op_array[op->type])(op);
|
|
}
|