12adcba79SJarkko Sakkinen // SPDX-License-Identifier: GPL-2.0
22adcba79SJarkko Sakkinen /*  Copyright(c) 2016-20 Intel Corporation. */
32adcba79SJarkko Sakkinen 
42adcba79SJarkko Sakkinen #include <stddef.h>
52adcba79SJarkko Sakkinen #include "defines.h"
62adcba79SJarkko Sakkinen 
7abc5cec4SReinette Chatre /*
8abc5cec4SReinette Chatre  * Data buffer spanning two pages that will be placed first in .data
9abc5cec4SReinette Chatre  * segment. Even if not used internally the second page is needed by
10abc5cec4SReinette Chatre  * external test manipulating page permissions.
11abc5cec4SReinette Chatre  */
1222118ce1SJarkko Sakkinen static uint8_t encl_buffer[8192] = { 1 };
1322118ce1SJarkko Sakkinen 
1420404a80SReinette Chatre enum sgx_enclu_function {
1520404a80SReinette Chatre 	EACCEPT = 0x5,
1620404a80SReinette Chatre 	EMODPE = 0x6,
1720404a80SReinette Chatre };
1820404a80SReinette Chatre 
do_encl_emodpe(void * _op)1920404a80SReinette Chatre static void do_encl_emodpe(void *_op)
2020404a80SReinette Chatre {
2120404a80SReinette Chatre 	struct sgx_secinfo secinfo __aligned(sizeof(struct sgx_secinfo)) = {0};
2220404a80SReinette Chatre 	struct encl_op_emodpe *op = _op;
2320404a80SReinette Chatre 
2420404a80SReinette Chatre 	secinfo.flags = op->flags;
2520404a80SReinette Chatre 
2620404a80SReinette Chatre 	asm volatile(".byte 0x0f, 0x01, 0xd7"
27*88fe67d4SJo Van Bulck 				: /* no outputs */
2820404a80SReinette Chatre 				: "a" (EMODPE),
2920404a80SReinette Chatre 				  "b" (&secinfo),
30*88fe67d4SJo Van Bulck 				  "c" (op->epc_addr)
31*88fe67d4SJo Van Bulck 				: "memory" /* read from secinfo pointer */);
3220404a80SReinette Chatre }
3320404a80SReinette Chatre 
do_encl_eaccept(void * _op)3420404a80SReinette Chatre static void do_encl_eaccept(void *_op)
3520404a80SReinette Chatre {
3620404a80SReinette Chatre 	struct sgx_secinfo secinfo __aligned(sizeof(struct sgx_secinfo)) = {0};
3720404a80SReinette Chatre 	struct encl_op_eaccept *op = _op;
3820404a80SReinette Chatre 	int rax;
3920404a80SReinette Chatre 
4020404a80SReinette Chatre 	secinfo.flags = op->flags;
4120404a80SReinette Chatre 
4220404a80SReinette Chatre 	asm volatile(".byte 0x0f, 0x01, 0xd7"
4320404a80SReinette Chatre 				: "=a" (rax)
4420404a80SReinette Chatre 				: "a" (EACCEPT),
4520404a80SReinette Chatre 				  "b" (&secinfo),
46*88fe67d4SJo Van Bulck 				  "c" (op->epc_addr)
47*88fe67d4SJo Van Bulck 				: "memory" /* read from secinfo pointer */);
4820404a80SReinette Chatre 
4920404a80SReinette Chatre 	op->ret = rax;
5020404a80SReinette Chatre }
5120404a80SReinette Chatre 
memcpy(void * dest,const void * src,size_t n)522adcba79SJarkko Sakkinen static void *memcpy(void *dest, const void *src, size_t n)
532adcba79SJarkko Sakkinen {
542adcba79SJarkko Sakkinen 	size_t i;
552adcba79SJarkko Sakkinen 
562adcba79SJarkko Sakkinen 	for (i = 0; i < n; i++)
572adcba79SJarkko Sakkinen 		((char *)dest)[i] = ((char *)src)[i];
582adcba79SJarkko Sakkinen 
592adcba79SJarkko Sakkinen 	return dest;
602adcba79SJarkko Sakkinen }
612adcba79SJarkko Sakkinen 
memset(void * dest,int c,size_t n)62b564982fSReinette Chatre static void *memset(void *dest, int c, size_t n)
63b564982fSReinette Chatre {
64b564982fSReinette Chatre 	size_t i;
65b564982fSReinette Chatre 
66b564982fSReinette Chatre 	for (i = 0; i < n; i++)
67b564982fSReinette Chatre 		((char *)dest)[i] = c;
68b564982fSReinette Chatre 
69b564982fSReinette Chatre 	return dest;
70b564982fSReinette Chatre }
71b564982fSReinette Chatre 
do_encl_init_tcs_page(void * _op)72b564982fSReinette Chatre static void do_encl_init_tcs_page(void *_op)
73b564982fSReinette Chatre {
74b564982fSReinette Chatre 	struct encl_op_init_tcs_page *op = _op;
75b564982fSReinette Chatre 	void *tcs = (void *)op->tcs_page;
76b564982fSReinette Chatre 	uint32_t val_32;
77b564982fSReinette Chatre 
78b564982fSReinette Chatre 	memset(tcs, 0, 16);			/* STATE and FLAGS */
79b564982fSReinette Chatre 	memcpy(tcs + 16, &op->ssa, 8);		/* OSSA */
80b564982fSReinette Chatre 	memset(tcs + 24, 0, 4);			/* CSSA */
81b564982fSReinette Chatre 	val_32 = 1;
82b564982fSReinette Chatre 	memcpy(tcs + 28, &val_32, 4);		/* NSSA */
83b564982fSReinette Chatre 	memcpy(tcs + 32, &op->entry, 8);	/* OENTRY */
84b564982fSReinette Chatre 	memset(tcs + 40, 0, 24);		/* AEP, OFSBASE, OGSBASE */
85b564982fSReinette Chatre 	val_32 = 0xFFFFFFFF;
86b564982fSReinette Chatre 	memcpy(tcs + 64, &val_32, 4);		/* FSLIMIT */
87b564982fSReinette Chatre 	memcpy(tcs + 68, &val_32, 4);		/* GSLIMIT */
88b564982fSReinette Chatre 	memset(tcs + 72, 0, 4024);		/* Reserved */
89b564982fSReinette Chatre }
90b564982fSReinette Chatre 
do_encl_op_put_to_buf(void * op)91c085dfc7SReinette Chatre static void do_encl_op_put_to_buf(void *op)
9241493a09SJarkko Sakkinen {
93c085dfc7SReinette Chatre 	struct encl_op_put_to_buf *op2 = op;
9441493a09SJarkko Sakkinen 
9541493a09SJarkko Sakkinen 	memcpy(&encl_buffer[0], &op2->value, 8);
9641493a09SJarkko Sakkinen }
9741493a09SJarkko Sakkinen 
do_encl_op_get_from_buf(void * op)98c085dfc7SReinette Chatre static void do_encl_op_get_from_buf(void *op)
9941493a09SJarkko Sakkinen {
100c085dfc7SReinette Chatre 	struct encl_op_get_from_buf *op2 = op;
10141493a09SJarkko Sakkinen 
10241493a09SJarkko Sakkinen 	memcpy(&op2->value, &encl_buffer[0], 8);
10341493a09SJarkko Sakkinen }
10441493a09SJarkko Sakkinen 
do_encl_op_put_to_addr(void * _op)105abc5cec4SReinette Chatre static void do_encl_op_put_to_addr(void *_op)
106abc5cec4SReinette Chatre {
107abc5cec4SReinette Chatre 	struct encl_op_put_to_addr *op = _op;
108abc5cec4SReinette Chatre 
109abc5cec4SReinette Chatre 	memcpy((void *)op->addr, &op->value, 8);
110abc5cec4SReinette Chatre }
111abc5cec4SReinette Chatre 
do_encl_op_get_from_addr(void * _op)112abc5cec4SReinette Chatre static void do_encl_op_get_from_addr(void *_op)
113abc5cec4SReinette Chatre {
114abc5cec4SReinette Chatre 	struct encl_op_get_from_addr *op = _op;
115abc5cec4SReinette Chatre 
116abc5cec4SReinette Chatre 	memcpy(&op->value, (void *)op->addr, 8);
117abc5cec4SReinette Chatre }
118abc5cec4SReinette Chatre 
do_encl_op_nop(void * _op)119688542e2SReinette Chatre static void do_encl_op_nop(void *_op)
120688542e2SReinette Chatre {
121688542e2SReinette Chatre 
122688542e2SReinette Chatre }
123688542e2SReinette Chatre 
encl_body(void * rdi,void * rsi)1242adcba79SJarkko Sakkinen void encl_body(void *rdi,  void *rsi)
1252adcba79SJarkko Sakkinen {
12641493a09SJarkko Sakkinen 	const void (*encl_op_array[ENCL_OP_MAX])(void *) = {
127c085dfc7SReinette Chatre 		do_encl_op_put_to_buf,
128c085dfc7SReinette Chatre 		do_encl_op_get_from_buf,
129abc5cec4SReinette Chatre 		do_encl_op_put_to_addr,
130abc5cec4SReinette Chatre 		do_encl_op_get_from_addr,
131688542e2SReinette Chatre 		do_encl_op_nop,
13220404a80SReinette Chatre 		do_encl_eaccept,
13320404a80SReinette Chatre 		do_encl_emodpe,
134b564982fSReinette Chatre 		do_encl_init_tcs_page,
13541493a09SJarkko Sakkinen 	};
13622118ce1SJarkko Sakkinen 
13741493a09SJarkko Sakkinen 	struct encl_op_header *op = (struct encl_op_header *)rdi;
13822118ce1SJarkko Sakkinen 
13941493a09SJarkko Sakkinen 	if (op->type < ENCL_OP_MAX)
14041493a09SJarkko Sakkinen 		(*encl_op_array[op->type])(op);
1412adcba79SJarkko Sakkinen }
142