1*acc4229cSAndra Paraschiv // SPDX-License-Identifier: GPL-2.0
2*acc4229cSAndra Paraschiv /*
3*acc4229cSAndra Paraschiv  * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4*acc4229cSAndra Paraschiv  */
5*acc4229cSAndra Paraschiv 
6*acc4229cSAndra Paraschiv /**
7*acc4229cSAndra Paraschiv  * DOC: Sample flow of using the ioctl interface provided by the Nitro Enclaves (NE)
8*acc4229cSAndra Paraschiv  * kernel driver.
9*acc4229cSAndra Paraschiv  *
10*acc4229cSAndra Paraschiv  * Usage
11*acc4229cSAndra Paraschiv  * -----
12*acc4229cSAndra Paraschiv  *
13*acc4229cSAndra Paraschiv  * Load the nitro_enclaves module, setting also the enclave CPU pool. The
14*acc4229cSAndra Paraschiv  * enclave CPUs need to be full cores from the same NUMA node. CPU 0 and its
15*acc4229cSAndra Paraschiv  * siblings have to remain available for the primary / parent VM, so they
16*acc4229cSAndra Paraschiv  * cannot be included in the enclave CPU pool.
17*acc4229cSAndra Paraschiv  *
18*acc4229cSAndra Paraschiv  * See the cpu list section from the kernel documentation.
19*acc4229cSAndra Paraschiv  * https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html#cpu-lists
20*acc4229cSAndra Paraschiv  *
21*acc4229cSAndra Paraschiv  *	insmod drivers/virt/nitro_enclaves/nitro_enclaves.ko
22*acc4229cSAndra Paraschiv  *	lsmod
23*acc4229cSAndra Paraschiv  *
24*acc4229cSAndra Paraschiv  *	The CPU pool can be set at runtime, after the kernel module is loaded.
25*acc4229cSAndra Paraschiv  *
26*acc4229cSAndra Paraschiv  *	echo <cpu-list> > /sys/module/nitro_enclaves/parameters/ne_cpus
27*acc4229cSAndra Paraschiv  *
28*acc4229cSAndra Paraschiv  *	NUMA and CPU siblings information can be found using:
29*acc4229cSAndra Paraschiv  *
30*acc4229cSAndra Paraschiv  *	lscpu
31*acc4229cSAndra Paraschiv  *	/proc/cpuinfo
32*acc4229cSAndra Paraschiv  *
33*acc4229cSAndra Paraschiv  * Check the online / offline CPU list. The CPUs from the pool should be
34*acc4229cSAndra Paraschiv  * offlined.
35*acc4229cSAndra Paraschiv  *
36*acc4229cSAndra Paraschiv  *	lscpu
37*acc4229cSAndra Paraschiv  *
38*acc4229cSAndra Paraschiv  * Check dmesg for any warnings / errors through the NE driver lifetime / usage.
39*acc4229cSAndra Paraschiv  * The NE logs contain the "nitro_enclaves" or "pci 0000:00:02.0" pattern.
40*acc4229cSAndra Paraschiv  *
41*acc4229cSAndra Paraschiv  *	dmesg
42*acc4229cSAndra Paraschiv  *
43*acc4229cSAndra Paraschiv  * Setup hugetlbfs huge pages. The memory needs to be from the same NUMA node as
44*acc4229cSAndra Paraschiv  * the enclave CPUs.
45*acc4229cSAndra Paraschiv  *
46*acc4229cSAndra Paraschiv  * https://www.kernel.org/doc/html/latest/admin-guide/mm/hugetlbpage.html
47*acc4229cSAndra Paraschiv  *
48*acc4229cSAndra Paraschiv  * By default, the allocation of hugetlb pages are distributed on all possible
49*acc4229cSAndra Paraschiv  * NUMA nodes. Use the following configuration files to set the number of huge
50*acc4229cSAndra Paraschiv  * pages from a NUMA node:
51*acc4229cSAndra Paraschiv  *
52*acc4229cSAndra Paraschiv  *	/sys/devices/system/node/node<X>/hugepages/hugepages-2048kB/nr_hugepages
53*acc4229cSAndra Paraschiv  *	/sys/devices/system/node/node<X>/hugepages/hugepages-1048576kB/nr_hugepages
54*acc4229cSAndra Paraschiv  *
55*acc4229cSAndra Paraschiv  *	or, if not on a system with multiple NUMA nodes, can also set the number
56*acc4229cSAndra Paraschiv  *	of 2 MiB / 1 GiB huge pages using
57*acc4229cSAndra Paraschiv  *
58*acc4229cSAndra Paraschiv  *	/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
59*acc4229cSAndra Paraschiv  *	/sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages
60*acc4229cSAndra Paraschiv  *
61*acc4229cSAndra Paraschiv  *	In this example 256 hugepages of 2 MiB are used.
62*acc4229cSAndra Paraschiv  *
63*acc4229cSAndra Paraschiv  * Build and run the NE sample.
64*acc4229cSAndra Paraschiv  *
65*acc4229cSAndra Paraschiv  *	make -C samples/nitro_enclaves clean
66*acc4229cSAndra Paraschiv  *	make -C samples/nitro_enclaves
67*acc4229cSAndra Paraschiv  *	./samples/nitro_enclaves/ne_ioctl_sample <path_to_enclave_image>
68*acc4229cSAndra Paraschiv  *
69*acc4229cSAndra Paraschiv  * Unload the nitro_enclaves module.
70*acc4229cSAndra Paraschiv  *
71*acc4229cSAndra Paraschiv  *	rmmod nitro_enclaves
72*acc4229cSAndra Paraschiv  *	lsmod
73*acc4229cSAndra Paraschiv  */
74*acc4229cSAndra Paraschiv 
75*acc4229cSAndra Paraschiv #include <stdio.h>
76*acc4229cSAndra Paraschiv #include <stdlib.h>
77*acc4229cSAndra Paraschiv #include <errno.h>
78*acc4229cSAndra Paraschiv #include <fcntl.h>
79*acc4229cSAndra Paraschiv #include <limits.h>
80*acc4229cSAndra Paraschiv #include <poll.h>
81*acc4229cSAndra Paraschiv #include <pthread.h>
82*acc4229cSAndra Paraschiv #include <string.h>
83*acc4229cSAndra Paraschiv #include <sys/eventfd.h>
84*acc4229cSAndra Paraschiv #include <sys/ioctl.h>
85*acc4229cSAndra Paraschiv #include <sys/mman.h>
86*acc4229cSAndra Paraschiv #include <sys/socket.h>
87*acc4229cSAndra Paraschiv #include <sys/stat.h>
88*acc4229cSAndra Paraschiv #include <sys/types.h>
89*acc4229cSAndra Paraschiv #include <unistd.h>
90*acc4229cSAndra Paraschiv 
91*acc4229cSAndra Paraschiv #include <linux/mman.h>
92*acc4229cSAndra Paraschiv #include <linux/nitro_enclaves.h>
93*acc4229cSAndra Paraschiv #include <linux/vm_sockets.h>
94*acc4229cSAndra Paraschiv 
95*acc4229cSAndra Paraschiv /**
96*acc4229cSAndra Paraschiv  * NE_DEV_NAME - Nitro Enclaves (NE) misc device that provides the ioctl interface.
97*acc4229cSAndra Paraschiv  */
98*acc4229cSAndra Paraschiv #define NE_DEV_NAME			"/dev/nitro_enclaves"
99*acc4229cSAndra Paraschiv 
100*acc4229cSAndra Paraschiv /**
101*acc4229cSAndra Paraschiv  * NE_POLL_WAIT_TIME - Timeout in seconds for each poll event.
102*acc4229cSAndra Paraschiv  */
103*acc4229cSAndra Paraschiv #define NE_POLL_WAIT_TIME		(60)
104*acc4229cSAndra Paraschiv /**
105*acc4229cSAndra Paraschiv  * NE_POLL_WAIT_TIME_MS - Timeout in milliseconds for each poll event.
106*acc4229cSAndra Paraschiv  */
107*acc4229cSAndra Paraschiv #define NE_POLL_WAIT_TIME_MS		(NE_POLL_WAIT_TIME * 1000)
108*acc4229cSAndra Paraschiv 
109*acc4229cSAndra Paraschiv /**
110*acc4229cSAndra Paraschiv  * NE_SLEEP_TIME - Amount of time in seconds for the process to keep the enclave alive.
111*acc4229cSAndra Paraschiv  */
112*acc4229cSAndra Paraschiv #define NE_SLEEP_TIME			(300)
113*acc4229cSAndra Paraschiv 
114*acc4229cSAndra Paraschiv /**
115*acc4229cSAndra Paraschiv  * NE_DEFAULT_NR_VCPUS - Default number of vCPUs set for an enclave.
116*acc4229cSAndra Paraschiv  */
117*acc4229cSAndra Paraschiv #define NE_DEFAULT_NR_VCPUS		(2)
118*acc4229cSAndra Paraschiv 
119*acc4229cSAndra Paraschiv /**
120*acc4229cSAndra Paraschiv  * NE_MIN_MEM_REGION_SIZE - Minimum size of a memory region - 2 MiB.
121*acc4229cSAndra Paraschiv  */
122*acc4229cSAndra Paraschiv #define NE_MIN_MEM_REGION_SIZE		(2 * 1024 * 1024)
123*acc4229cSAndra Paraschiv 
124*acc4229cSAndra Paraschiv /**
125*acc4229cSAndra Paraschiv  * NE_DEFAULT_NR_MEM_REGIONS - Default number of memory regions of 2 MiB set for
126*acc4229cSAndra Paraschiv  *			       an enclave.
127*acc4229cSAndra Paraschiv  */
128*acc4229cSAndra Paraschiv #define NE_DEFAULT_NR_MEM_REGIONS	(256)
129*acc4229cSAndra Paraschiv 
130*acc4229cSAndra Paraschiv /**
131*acc4229cSAndra Paraschiv  * NE_IMAGE_LOAD_HEARTBEAT_CID - Vsock CID for enclave image loading heartbeat logic.
132*acc4229cSAndra Paraschiv  */
133*acc4229cSAndra Paraschiv #define NE_IMAGE_LOAD_HEARTBEAT_CID	(3)
134*acc4229cSAndra Paraschiv /**
135*acc4229cSAndra Paraschiv  * NE_IMAGE_LOAD_HEARTBEAT_PORT - Vsock port for enclave image loading heartbeat logic.
136*acc4229cSAndra Paraschiv  */
137*acc4229cSAndra Paraschiv #define NE_IMAGE_LOAD_HEARTBEAT_PORT	(9000)
138*acc4229cSAndra Paraschiv /**
139*acc4229cSAndra Paraschiv  * NE_IMAGE_LOAD_HEARTBEAT_VALUE - Heartbeat value for enclave image loading.
140*acc4229cSAndra Paraschiv  */
141*acc4229cSAndra Paraschiv #define NE_IMAGE_LOAD_HEARTBEAT_VALUE	(0xb7)
142*acc4229cSAndra Paraschiv 
143*acc4229cSAndra Paraschiv /**
144*acc4229cSAndra Paraschiv  * struct ne_user_mem_region - User space memory region set for an enclave.
145*acc4229cSAndra Paraschiv  * @userspace_addr:	Address of the user space memory region.
146*acc4229cSAndra Paraschiv  * @memory_size:	Size of the user space memory region.
147*acc4229cSAndra Paraschiv  */
148*acc4229cSAndra Paraschiv struct ne_user_mem_region {
149*acc4229cSAndra Paraschiv 	void	*userspace_addr;
150*acc4229cSAndra Paraschiv 	size_t	memory_size;
151*acc4229cSAndra Paraschiv };
152*acc4229cSAndra Paraschiv 
153*acc4229cSAndra Paraschiv /**
154*acc4229cSAndra Paraschiv  * ne_create_vm() - Create a slot for the enclave VM.
155*acc4229cSAndra Paraschiv  * @ne_dev_fd:		The file descriptor of the NE misc device.
156*acc4229cSAndra Paraschiv  * @slot_uid:		The generated slot uid for the enclave.
157*acc4229cSAndra Paraschiv  * @enclave_fd :	The generated file descriptor for the enclave.
158*acc4229cSAndra Paraschiv  *
159*acc4229cSAndra Paraschiv  * Context: Process context.
160*acc4229cSAndra Paraschiv  * Return:
161*acc4229cSAndra Paraschiv  * * 0 on success.
162*acc4229cSAndra Paraschiv  * * Negative return value on failure.
163*acc4229cSAndra Paraschiv  */
164*acc4229cSAndra Paraschiv static int ne_create_vm(int ne_dev_fd, unsigned long *slot_uid, int *enclave_fd)
165*acc4229cSAndra Paraschiv {
166*acc4229cSAndra Paraschiv 	int rc = -EINVAL;
167*acc4229cSAndra Paraschiv 	*enclave_fd = ioctl(ne_dev_fd, NE_CREATE_VM, slot_uid);
168*acc4229cSAndra Paraschiv 
169*acc4229cSAndra Paraschiv 	if (*enclave_fd < 0) {
170*acc4229cSAndra Paraschiv 		rc = *enclave_fd;
171*acc4229cSAndra Paraschiv 		switch (errno) {
172*acc4229cSAndra Paraschiv 		case NE_ERR_NO_CPUS_AVAIL_IN_POOL: {
173*acc4229cSAndra Paraschiv 			printf("Error in create VM, no CPUs available in the NE CPU pool\n");
174*acc4229cSAndra Paraschiv 
175*acc4229cSAndra Paraschiv 			break;
176*acc4229cSAndra Paraschiv 		}
177*acc4229cSAndra Paraschiv 
178*acc4229cSAndra Paraschiv 		default:
179*acc4229cSAndra Paraschiv 			printf("Error in create VM [%m]\n");
180*acc4229cSAndra Paraschiv 		}
181*acc4229cSAndra Paraschiv 
182*acc4229cSAndra Paraschiv 		return rc;
183*acc4229cSAndra Paraschiv 	}
184*acc4229cSAndra Paraschiv 
185*acc4229cSAndra Paraschiv 	return 0;
186*acc4229cSAndra Paraschiv }
187*acc4229cSAndra Paraschiv 
188*acc4229cSAndra Paraschiv 
189*acc4229cSAndra Paraschiv /**
190*acc4229cSAndra Paraschiv  * ne_poll_enclave_fd() - Thread function for polling the enclave fd.
191*acc4229cSAndra Paraschiv  * @data:	Argument provided for the polling function.
192*acc4229cSAndra Paraschiv  *
193*acc4229cSAndra Paraschiv  * Context: Process context.
194*acc4229cSAndra Paraschiv  * Return:
195*acc4229cSAndra Paraschiv  * * NULL on success / failure.
196*acc4229cSAndra Paraschiv  */
197*acc4229cSAndra Paraschiv void *ne_poll_enclave_fd(void *data)
198*acc4229cSAndra Paraschiv {
199*acc4229cSAndra Paraschiv 	int enclave_fd = *(int *)data;
200*acc4229cSAndra Paraschiv 	struct pollfd fds[1] = {};
201*acc4229cSAndra Paraschiv 	int i = 0;
202*acc4229cSAndra Paraschiv 	int rc = -EINVAL;
203*acc4229cSAndra Paraschiv 
204*acc4229cSAndra Paraschiv 	printf("Running from poll thread, enclave fd %d\n", enclave_fd);
205*acc4229cSAndra Paraschiv 
206*acc4229cSAndra Paraschiv 	fds[0].fd = enclave_fd;
207*acc4229cSAndra Paraschiv 	fds[0].events = POLLIN | POLLERR | POLLHUP;
208*acc4229cSAndra Paraschiv 
209*acc4229cSAndra Paraschiv 	/* Keep on polling until the current process is terminated. */
210*acc4229cSAndra Paraschiv 	while (1) {
211*acc4229cSAndra Paraschiv 		printf("[iter %d] Polling ...\n", i);
212*acc4229cSAndra Paraschiv 
213*acc4229cSAndra Paraschiv 		rc = poll(fds, 1, NE_POLL_WAIT_TIME_MS);
214*acc4229cSAndra Paraschiv 		if (rc < 0) {
215*acc4229cSAndra Paraschiv 			printf("Error in poll [%m]\n");
216*acc4229cSAndra Paraschiv 
217*acc4229cSAndra Paraschiv 			return NULL;
218*acc4229cSAndra Paraschiv 		}
219*acc4229cSAndra Paraschiv 
220*acc4229cSAndra Paraschiv 		i++;
221*acc4229cSAndra Paraschiv 
222*acc4229cSAndra Paraschiv 		if (!rc) {
223*acc4229cSAndra Paraschiv 			printf("Poll: %d seconds elapsed\n",
224*acc4229cSAndra Paraschiv 			       i * NE_POLL_WAIT_TIME);
225*acc4229cSAndra Paraschiv 
226*acc4229cSAndra Paraschiv 			continue;
227*acc4229cSAndra Paraschiv 		}
228*acc4229cSAndra Paraschiv 
229*acc4229cSAndra Paraschiv 		printf("Poll received value 0x%x\n", fds[0].revents);
230*acc4229cSAndra Paraschiv 
231*acc4229cSAndra Paraschiv 		if (fds[0].revents & POLLHUP) {
232*acc4229cSAndra Paraschiv 			printf("Received POLLHUP\n");
233*acc4229cSAndra Paraschiv 
234*acc4229cSAndra Paraschiv 			return NULL;
235*acc4229cSAndra Paraschiv 		}
236*acc4229cSAndra Paraschiv 
237*acc4229cSAndra Paraschiv 		if (fds[0].revents & POLLNVAL) {
238*acc4229cSAndra Paraschiv 			printf("Received POLLNVAL\n");
239*acc4229cSAndra Paraschiv 
240*acc4229cSAndra Paraschiv 			return NULL;
241*acc4229cSAndra Paraschiv 		}
242*acc4229cSAndra Paraschiv 	}
243*acc4229cSAndra Paraschiv 
244*acc4229cSAndra Paraschiv 	return NULL;
245*acc4229cSAndra Paraschiv }
246*acc4229cSAndra Paraschiv 
247*acc4229cSAndra Paraschiv /**
248*acc4229cSAndra Paraschiv  * ne_alloc_user_mem_region() - Allocate a user space memory region for an enclave.
249*acc4229cSAndra Paraschiv  * @ne_user_mem_region:	User space memory region allocated using hugetlbfs.
250*acc4229cSAndra Paraschiv  *
251*acc4229cSAndra Paraschiv  * Context: Process context.
252*acc4229cSAndra Paraschiv  * Return:
253*acc4229cSAndra Paraschiv  * * 0 on success.
254*acc4229cSAndra Paraschiv  * * Negative return value on failure.
255*acc4229cSAndra Paraschiv  */
256*acc4229cSAndra Paraschiv static int ne_alloc_user_mem_region(struct ne_user_mem_region *ne_user_mem_region)
257*acc4229cSAndra Paraschiv {
258*acc4229cSAndra Paraschiv 	/**
259*acc4229cSAndra Paraschiv 	 * Check available hugetlb encodings for different huge page sizes in
260*acc4229cSAndra Paraschiv 	 * include/uapi/linux/mman.h.
261*acc4229cSAndra Paraschiv 	 */
262*acc4229cSAndra Paraschiv 	ne_user_mem_region->userspace_addr = mmap(NULL, ne_user_mem_region->memory_size,
263*acc4229cSAndra Paraschiv 						  PROT_READ | PROT_WRITE,
264*acc4229cSAndra Paraschiv 						  MAP_PRIVATE | MAP_ANONYMOUS |
265*acc4229cSAndra Paraschiv 						  MAP_HUGETLB | MAP_HUGE_2MB, -1, 0);
266*acc4229cSAndra Paraschiv 	if (ne_user_mem_region->userspace_addr == MAP_FAILED) {
267*acc4229cSAndra Paraschiv 		printf("Error in mmap memory [%m]\n");
268*acc4229cSAndra Paraschiv 
269*acc4229cSAndra Paraschiv 		return -1;
270*acc4229cSAndra Paraschiv 	}
271*acc4229cSAndra Paraschiv 
272*acc4229cSAndra Paraschiv 	return 0;
273*acc4229cSAndra Paraschiv }
274*acc4229cSAndra Paraschiv 
275*acc4229cSAndra Paraschiv /**
276*acc4229cSAndra Paraschiv  * ne_load_enclave_image() - Place the enclave image in the enclave memory.
277*acc4229cSAndra Paraschiv  * @enclave_fd :		The file descriptor associated with the enclave.
278*acc4229cSAndra Paraschiv  * @ne_user_mem_regions:	User space memory regions allocated for the enclave.
279*acc4229cSAndra Paraschiv  * @enclave_image_path :	The file path of the enclave image.
280*acc4229cSAndra Paraschiv  *
281*acc4229cSAndra Paraschiv  * Context: Process context.
282*acc4229cSAndra Paraschiv  * Return:
283*acc4229cSAndra Paraschiv  * * 0 on success.
284*acc4229cSAndra Paraschiv  * * Negative return value on failure.
285*acc4229cSAndra Paraschiv  */
286*acc4229cSAndra Paraschiv static int ne_load_enclave_image(int enclave_fd, struct ne_user_mem_region ne_user_mem_regions[],
287*acc4229cSAndra Paraschiv 				 char *enclave_image_path)
288*acc4229cSAndra Paraschiv {
289*acc4229cSAndra Paraschiv 	unsigned char *enclave_image = NULL;
290*acc4229cSAndra Paraschiv 	int enclave_image_fd = -1;
291*acc4229cSAndra Paraschiv 	size_t enclave_image_size = 0;
292*acc4229cSAndra Paraschiv 	size_t enclave_memory_size = 0;
293*acc4229cSAndra Paraschiv 	unsigned long i = 0;
294*acc4229cSAndra Paraschiv 	size_t image_written_bytes = 0;
295*acc4229cSAndra Paraschiv 	struct ne_image_load_info image_load_info = {
296*acc4229cSAndra Paraschiv 		.flags = NE_EIF_IMAGE,
297*acc4229cSAndra Paraschiv 	};
298*acc4229cSAndra Paraschiv 	struct stat image_stat_buf = {};
299*acc4229cSAndra Paraschiv 	int rc = -EINVAL;
300*acc4229cSAndra Paraschiv 	size_t temp_image_offset = 0;
301*acc4229cSAndra Paraschiv 
302*acc4229cSAndra Paraschiv 	for (i = 0; i < NE_DEFAULT_NR_MEM_REGIONS; i++)
303*acc4229cSAndra Paraschiv 		enclave_memory_size += ne_user_mem_regions[i].memory_size;
304*acc4229cSAndra Paraschiv 
305*acc4229cSAndra Paraschiv 	rc = stat(enclave_image_path, &image_stat_buf);
306*acc4229cSAndra Paraschiv 	if (rc < 0) {
307*acc4229cSAndra Paraschiv 		printf("Error in get image stat info [%m]\n");
308*acc4229cSAndra Paraschiv 
309*acc4229cSAndra Paraschiv 		return rc;
310*acc4229cSAndra Paraschiv 	}
311*acc4229cSAndra Paraschiv 
312*acc4229cSAndra Paraschiv 	enclave_image_size = image_stat_buf.st_size;
313*acc4229cSAndra Paraschiv 
314*acc4229cSAndra Paraschiv 	if (enclave_memory_size < enclave_image_size) {
315*acc4229cSAndra Paraschiv 		printf("The enclave memory is smaller than the enclave image size\n");
316*acc4229cSAndra Paraschiv 
317*acc4229cSAndra Paraschiv 		return -ENOMEM;
318*acc4229cSAndra Paraschiv 	}
319*acc4229cSAndra Paraschiv 
320*acc4229cSAndra Paraschiv 	rc = ioctl(enclave_fd, NE_GET_IMAGE_LOAD_INFO, &image_load_info);
321*acc4229cSAndra Paraschiv 	if (rc < 0) {
322*acc4229cSAndra Paraschiv 		switch (errno) {
323*acc4229cSAndra Paraschiv 		case NE_ERR_NOT_IN_INIT_STATE: {
324*acc4229cSAndra Paraschiv 			printf("Error in get image load info, enclave not in init state\n");
325*acc4229cSAndra Paraschiv 
326*acc4229cSAndra Paraschiv 			break;
327*acc4229cSAndra Paraschiv 		}
328*acc4229cSAndra Paraschiv 
329*acc4229cSAndra Paraschiv 		case NE_ERR_INVALID_FLAG_VALUE: {
330*acc4229cSAndra Paraschiv 			printf("Error in get image load info, provided invalid flag\n");
331*acc4229cSAndra Paraschiv 
332*acc4229cSAndra Paraschiv 			break;
333*acc4229cSAndra Paraschiv 		}
334*acc4229cSAndra Paraschiv 
335*acc4229cSAndra Paraschiv 		default:
336*acc4229cSAndra Paraschiv 			printf("Error in get image load info [%m]\n");
337*acc4229cSAndra Paraschiv 		}
338*acc4229cSAndra Paraschiv 
339*acc4229cSAndra Paraschiv 		return rc;
340*acc4229cSAndra Paraschiv 	}
341*acc4229cSAndra Paraschiv 
342*acc4229cSAndra Paraschiv 	printf("Enclave image offset in enclave memory is %lld\n",
343*acc4229cSAndra Paraschiv 	       image_load_info.memory_offset);
344*acc4229cSAndra Paraschiv 
345*acc4229cSAndra Paraschiv 	enclave_image_fd = open(enclave_image_path, O_RDONLY);
346*acc4229cSAndra Paraschiv 	if (enclave_image_fd < 0) {
347*acc4229cSAndra Paraschiv 		printf("Error in open enclave image file [%m]\n");
348*acc4229cSAndra Paraschiv 
349*acc4229cSAndra Paraschiv 		return enclave_image_fd;
350*acc4229cSAndra Paraschiv 	}
351*acc4229cSAndra Paraschiv 
352*acc4229cSAndra Paraschiv 	enclave_image = mmap(NULL, enclave_image_size, PROT_READ,
353*acc4229cSAndra Paraschiv 			     MAP_PRIVATE, enclave_image_fd, 0);
354*acc4229cSAndra Paraschiv 	if (enclave_image == MAP_FAILED) {
355*acc4229cSAndra Paraschiv 		printf("Error in mmap enclave image [%m]\n");
356*acc4229cSAndra Paraschiv 
357*acc4229cSAndra Paraschiv 		return -1;
358*acc4229cSAndra Paraschiv 	}
359*acc4229cSAndra Paraschiv 
360*acc4229cSAndra Paraschiv 	temp_image_offset = image_load_info.memory_offset;
361*acc4229cSAndra Paraschiv 
362*acc4229cSAndra Paraschiv 	for (i = 0; i < NE_DEFAULT_NR_MEM_REGIONS; i++) {
363*acc4229cSAndra Paraschiv 		size_t bytes_to_write = 0;
364*acc4229cSAndra Paraschiv 		size_t memory_offset = 0;
365*acc4229cSAndra Paraschiv 		size_t memory_size = ne_user_mem_regions[i].memory_size;
366*acc4229cSAndra Paraschiv 		size_t remaining_bytes = 0;
367*acc4229cSAndra Paraschiv 		void *userspace_addr = ne_user_mem_regions[i].userspace_addr;
368*acc4229cSAndra Paraschiv 
369*acc4229cSAndra Paraschiv 		if (temp_image_offset >= memory_size) {
370*acc4229cSAndra Paraschiv 			temp_image_offset -= memory_size;
371*acc4229cSAndra Paraschiv 
372*acc4229cSAndra Paraschiv 			continue;
373*acc4229cSAndra Paraschiv 		} else if (temp_image_offset != 0) {
374*acc4229cSAndra Paraschiv 			memory_offset = temp_image_offset;
375*acc4229cSAndra Paraschiv 			memory_size -= temp_image_offset;
376*acc4229cSAndra Paraschiv 			temp_image_offset = 0;
377*acc4229cSAndra Paraschiv 		}
378*acc4229cSAndra Paraschiv 
379*acc4229cSAndra Paraschiv 		remaining_bytes = enclave_image_size - image_written_bytes;
380*acc4229cSAndra Paraschiv 		bytes_to_write = memory_size < remaining_bytes ?
381*acc4229cSAndra Paraschiv 				 memory_size : remaining_bytes;
382*acc4229cSAndra Paraschiv 
383*acc4229cSAndra Paraschiv 		memcpy(userspace_addr + memory_offset,
384*acc4229cSAndra Paraschiv 		       enclave_image + image_written_bytes, bytes_to_write);
385*acc4229cSAndra Paraschiv 
386*acc4229cSAndra Paraschiv 		image_written_bytes += bytes_to_write;
387*acc4229cSAndra Paraschiv 
388*acc4229cSAndra Paraschiv 		if (image_written_bytes == enclave_image_size)
389*acc4229cSAndra Paraschiv 			break;
390*acc4229cSAndra Paraschiv 	}
391*acc4229cSAndra Paraschiv 
392*acc4229cSAndra Paraschiv 	munmap(enclave_image, enclave_image_size);
393*acc4229cSAndra Paraschiv 
394*acc4229cSAndra Paraschiv 	close(enclave_image_fd);
395*acc4229cSAndra Paraschiv 
396*acc4229cSAndra Paraschiv 	return 0;
397*acc4229cSAndra Paraschiv }
398*acc4229cSAndra Paraschiv 
399*acc4229cSAndra Paraschiv /**
400*acc4229cSAndra Paraschiv  * ne_set_user_mem_region() - Set a user space memory region for the given enclave.
401*acc4229cSAndra Paraschiv  * @enclave_fd :		The file descriptor associated with the enclave.
402*acc4229cSAndra Paraschiv  * @ne_user_mem_region :	User space memory region to be set for the enclave.
403*acc4229cSAndra Paraschiv  *
404*acc4229cSAndra Paraschiv  * Context: Process context.
405*acc4229cSAndra Paraschiv  * Return:
406*acc4229cSAndra Paraschiv  * * 0 on success.
407*acc4229cSAndra Paraschiv  * * Negative return value on failure.
408*acc4229cSAndra Paraschiv  */
409*acc4229cSAndra Paraschiv static int ne_set_user_mem_region(int enclave_fd, struct ne_user_mem_region ne_user_mem_region)
410*acc4229cSAndra Paraschiv {
411*acc4229cSAndra Paraschiv 	struct ne_user_memory_region mem_region = {
412*acc4229cSAndra Paraschiv 		.flags = NE_DEFAULT_MEMORY_REGION,
413*acc4229cSAndra Paraschiv 		.memory_size = ne_user_mem_region.memory_size,
414*acc4229cSAndra Paraschiv 		.userspace_addr = (__u64)ne_user_mem_region.userspace_addr,
415*acc4229cSAndra Paraschiv 	};
416*acc4229cSAndra Paraschiv 	int rc = -EINVAL;
417*acc4229cSAndra Paraschiv 
418*acc4229cSAndra Paraschiv 	rc = ioctl(enclave_fd, NE_SET_USER_MEMORY_REGION, &mem_region);
419*acc4229cSAndra Paraschiv 	if (rc < 0) {
420*acc4229cSAndra Paraschiv 		switch (errno) {
421*acc4229cSAndra Paraschiv 		case NE_ERR_NOT_IN_INIT_STATE: {
422*acc4229cSAndra Paraschiv 			printf("Error in set user memory region, enclave not in init state\n");
423*acc4229cSAndra Paraschiv 
424*acc4229cSAndra Paraschiv 			break;
425*acc4229cSAndra Paraschiv 		}
426*acc4229cSAndra Paraschiv 
427*acc4229cSAndra Paraschiv 		case NE_ERR_INVALID_MEM_REGION_SIZE: {
428*acc4229cSAndra Paraschiv 			printf("Error in set user memory region, mem size not multiple of 2 MiB\n");
429*acc4229cSAndra Paraschiv 
430*acc4229cSAndra Paraschiv 			break;
431*acc4229cSAndra Paraschiv 		}
432*acc4229cSAndra Paraschiv 
433*acc4229cSAndra Paraschiv 		case NE_ERR_INVALID_MEM_REGION_ADDR: {
434*acc4229cSAndra Paraschiv 			printf("Error in set user memory region, invalid user space address\n");
435*acc4229cSAndra Paraschiv 
436*acc4229cSAndra Paraschiv 			break;
437*acc4229cSAndra Paraschiv 		}
438*acc4229cSAndra Paraschiv 
439*acc4229cSAndra Paraschiv 		case NE_ERR_UNALIGNED_MEM_REGION_ADDR: {
440*acc4229cSAndra Paraschiv 			printf("Error in set user memory region, unaligned user space address\n");
441*acc4229cSAndra Paraschiv 
442*acc4229cSAndra Paraschiv 			break;
443*acc4229cSAndra Paraschiv 		}
444*acc4229cSAndra Paraschiv 
445*acc4229cSAndra Paraschiv 		case NE_ERR_MEM_REGION_ALREADY_USED: {
446*acc4229cSAndra Paraschiv 			printf("Error in set user memory region, memory region already used\n");
447*acc4229cSAndra Paraschiv 
448*acc4229cSAndra Paraschiv 			break;
449*acc4229cSAndra Paraschiv 		}
450*acc4229cSAndra Paraschiv 
451*acc4229cSAndra Paraschiv 		case NE_ERR_MEM_NOT_HUGE_PAGE: {
452*acc4229cSAndra Paraschiv 			printf("Error in set user memory region, not backed by huge pages\n");
453*acc4229cSAndra Paraschiv 
454*acc4229cSAndra Paraschiv 			break;
455*acc4229cSAndra Paraschiv 		}
456*acc4229cSAndra Paraschiv 
457*acc4229cSAndra Paraschiv 		case NE_ERR_MEM_DIFFERENT_NUMA_NODE: {
458*acc4229cSAndra Paraschiv 			printf("Error in set user memory region, different NUMA node than CPUs\n");
459*acc4229cSAndra Paraschiv 
460*acc4229cSAndra Paraschiv 			break;
461*acc4229cSAndra Paraschiv 		}
462*acc4229cSAndra Paraschiv 
463*acc4229cSAndra Paraschiv 		case NE_ERR_MEM_MAX_REGIONS: {
464*acc4229cSAndra Paraschiv 			printf("Error in set user memory region, max memory regions reached\n");
465*acc4229cSAndra Paraschiv 
466*acc4229cSAndra Paraschiv 			break;
467*acc4229cSAndra Paraschiv 		}
468*acc4229cSAndra Paraschiv 
469*acc4229cSAndra Paraschiv 		case NE_ERR_INVALID_PAGE_SIZE: {
470*acc4229cSAndra Paraschiv 			printf("Error in set user memory region, has page not multiple of 2 MiB\n");
471*acc4229cSAndra Paraschiv 
472*acc4229cSAndra Paraschiv 			break;
473*acc4229cSAndra Paraschiv 		}
474*acc4229cSAndra Paraschiv 
475*acc4229cSAndra Paraschiv 		case NE_ERR_INVALID_FLAG_VALUE: {
476*acc4229cSAndra Paraschiv 			printf("Error in set user memory region, provided invalid flag\n");
477*acc4229cSAndra Paraschiv 
478*acc4229cSAndra Paraschiv 			break;
479*acc4229cSAndra Paraschiv 		}
480*acc4229cSAndra Paraschiv 
481*acc4229cSAndra Paraschiv 		default:
482*acc4229cSAndra Paraschiv 			printf("Error in set user memory region [%m]\n");
483*acc4229cSAndra Paraschiv 		}
484*acc4229cSAndra Paraschiv 
485*acc4229cSAndra Paraschiv 		return rc;
486*acc4229cSAndra Paraschiv 	}
487*acc4229cSAndra Paraschiv 
488*acc4229cSAndra Paraschiv 	return 0;
489*acc4229cSAndra Paraschiv }
490*acc4229cSAndra Paraschiv 
491*acc4229cSAndra Paraschiv /**
492*acc4229cSAndra Paraschiv  * ne_free_mem_regions() - Unmap all the user space memory regions that were set
493*acc4229cSAndra Paraschiv  *			   aside for the enclave.
494*acc4229cSAndra Paraschiv  * @ne_user_mem_regions:	The user space memory regions associated with an enclave.
495*acc4229cSAndra Paraschiv  *
496*acc4229cSAndra Paraschiv  * Context: Process context.
497*acc4229cSAndra Paraschiv  */
498*acc4229cSAndra Paraschiv static void ne_free_mem_regions(struct ne_user_mem_region ne_user_mem_regions[])
499*acc4229cSAndra Paraschiv {
500*acc4229cSAndra Paraschiv 	unsigned int i = 0;
501*acc4229cSAndra Paraschiv 
502*acc4229cSAndra Paraschiv 	for (i = 0; i < NE_DEFAULT_NR_MEM_REGIONS; i++)
503*acc4229cSAndra Paraschiv 		munmap(ne_user_mem_regions[i].userspace_addr,
504*acc4229cSAndra Paraschiv 		       ne_user_mem_regions[i].memory_size);
505*acc4229cSAndra Paraschiv }
506*acc4229cSAndra Paraschiv 
507*acc4229cSAndra Paraschiv /**
508*acc4229cSAndra Paraschiv  * ne_add_vcpu() - Add a vCPU to the given enclave.
509*acc4229cSAndra Paraschiv  * @enclave_fd :	The file descriptor associated with the enclave.
510*acc4229cSAndra Paraschiv  * @vcpu_id:		vCPU id to be set for the enclave, either provided or
511*acc4229cSAndra Paraschiv  *			auto-generated (if provided vCPU id is 0).
512*acc4229cSAndra Paraschiv  *
513*acc4229cSAndra Paraschiv  * Context: Process context.
514*acc4229cSAndra Paraschiv  * Return:
515*acc4229cSAndra Paraschiv  * * 0 on success.
516*acc4229cSAndra Paraschiv  * * Negative return value on failure.
517*acc4229cSAndra Paraschiv  */
518*acc4229cSAndra Paraschiv static int ne_add_vcpu(int enclave_fd, unsigned int *vcpu_id)
519*acc4229cSAndra Paraschiv {
520*acc4229cSAndra Paraschiv 	int rc = -EINVAL;
521*acc4229cSAndra Paraschiv 
522*acc4229cSAndra Paraschiv 	rc = ioctl(enclave_fd, NE_ADD_VCPU, vcpu_id);
523*acc4229cSAndra Paraschiv 	if (rc < 0) {
524*acc4229cSAndra Paraschiv 		switch (errno) {
525*acc4229cSAndra Paraschiv 		case NE_ERR_NO_CPUS_AVAIL_IN_POOL: {
526*acc4229cSAndra Paraschiv 			printf("Error in add vcpu, no CPUs available in the NE CPU pool\n");
527*acc4229cSAndra Paraschiv 
528*acc4229cSAndra Paraschiv 			break;
529*acc4229cSAndra Paraschiv 		}
530*acc4229cSAndra Paraschiv 
531*acc4229cSAndra Paraschiv 		case NE_ERR_VCPU_ALREADY_USED: {
532*acc4229cSAndra Paraschiv 			printf("Error in add vcpu, the provided vCPU is already used\n");
533*acc4229cSAndra Paraschiv 
534*acc4229cSAndra Paraschiv 			break;
535*acc4229cSAndra Paraschiv 		}
536*acc4229cSAndra Paraschiv 
537*acc4229cSAndra Paraschiv 		case NE_ERR_VCPU_NOT_IN_CPU_POOL: {
538*acc4229cSAndra Paraschiv 			printf("Error in add vcpu, the provided vCPU is not in the NE CPU pool\n");
539*acc4229cSAndra Paraschiv 
540*acc4229cSAndra Paraschiv 			break;
541*acc4229cSAndra Paraschiv 		}
542*acc4229cSAndra Paraschiv 
543*acc4229cSAndra Paraschiv 		case NE_ERR_VCPU_INVALID_CPU_CORE: {
544*acc4229cSAndra Paraschiv 			printf("Error in add vcpu, the core id of the provided vCPU is invalid\n");
545*acc4229cSAndra Paraschiv 
546*acc4229cSAndra Paraschiv 			break;
547*acc4229cSAndra Paraschiv 		}
548*acc4229cSAndra Paraschiv 
549*acc4229cSAndra Paraschiv 		case NE_ERR_NOT_IN_INIT_STATE: {
550*acc4229cSAndra Paraschiv 			printf("Error in add vcpu, enclave not in init state\n");
551*acc4229cSAndra Paraschiv 
552*acc4229cSAndra Paraschiv 			break;
553*acc4229cSAndra Paraschiv 		}
554*acc4229cSAndra Paraschiv 
555*acc4229cSAndra Paraschiv 		case NE_ERR_INVALID_VCPU: {
556*acc4229cSAndra Paraschiv 			printf("Error in add vcpu, the provided vCPU is out of avail CPUs range\n");
557*acc4229cSAndra Paraschiv 
558*acc4229cSAndra Paraschiv 			break;
559*acc4229cSAndra Paraschiv 		}
560*acc4229cSAndra Paraschiv 
561*acc4229cSAndra Paraschiv 		default:
562*acc4229cSAndra Paraschiv 			printf("Error in add vcpu [%m]\n");
563*acc4229cSAndra Paraschiv 
564*acc4229cSAndra Paraschiv 		}
565*acc4229cSAndra Paraschiv 		return rc;
566*acc4229cSAndra Paraschiv 	}
567*acc4229cSAndra Paraschiv 
568*acc4229cSAndra Paraschiv 	return 0;
569*acc4229cSAndra Paraschiv }
570*acc4229cSAndra Paraschiv 
571*acc4229cSAndra Paraschiv /**
572*acc4229cSAndra Paraschiv  * ne_start_enclave() - Start the given enclave.
573*acc4229cSAndra Paraschiv  * @enclave_fd :		The file descriptor associated with the enclave.
574*acc4229cSAndra Paraschiv  * @enclave_start_info :	Enclave metadata used for starting e.g. vsock CID.
575*acc4229cSAndra Paraschiv  *
576*acc4229cSAndra Paraschiv  * Context: Process context.
577*acc4229cSAndra Paraschiv  * Return:
578*acc4229cSAndra Paraschiv  * * 0 on success.
579*acc4229cSAndra Paraschiv  * * Negative return value on failure.
580*acc4229cSAndra Paraschiv  */
581*acc4229cSAndra Paraschiv static int ne_start_enclave(int enclave_fd,  struct ne_enclave_start_info *enclave_start_info)
582*acc4229cSAndra Paraschiv {
583*acc4229cSAndra Paraschiv 	int rc = -EINVAL;
584*acc4229cSAndra Paraschiv 
585*acc4229cSAndra Paraschiv 	rc = ioctl(enclave_fd, NE_START_ENCLAVE, enclave_start_info);
586*acc4229cSAndra Paraschiv 	if (rc < 0) {
587*acc4229cSAndra Paraschiv 		switch (errno) {
588*acc4229cSAndra Paraschiv 		case NE_ERR_NOT_IN_INIT_STATE: {
589*acc4229cSAndra Paraschiv 			printf("Error in start enclave, enclave not in init state\n");
590*acc4229cSAndra Paraschiv 
591*acc4229cSAndra Paraschiv 			break;
592*acc4229cSAndra Paraschiv 		}
593*acc4229cSAndra Paraschiv 
594*acc4229cSAndra Paraschiv 		case NE_ERR_NO_MEM_REGIONS_ADDED: {
595*acc4229cSAndra Paraschiv 			printf("Error in start enclave, no memory regions have been added\n");
596*acc4229cSAndra Paraschiv 
597*acc4229cSAndra Paraschiv 			break;
598*acc4229cSAndra Paraschiv 		}
599*acc4229cSAndra Paraschiv 
600*acc4229cSAndra Paraschiv 		case NE_ERR_NO_VCPUS_ADDED: {
601*acc4229cSAndra Paraschiv 			printf("Error in start enclave, no vCPUs have been added\n");
602*acc4229cSAndra Paraschiv 
603*acc4229cSAndra Paraschiv 			break;
604*acc4229cSAndra Paraschiv 		}
605*acc4229cSAndra Paraschiv 
606*acc4229cSAndra Paraschiv 		case NE_ERR_FULL_CORES_NOT_USED: {
607*acc4229cSAndra Paraschiv 			printf("Error in start enclave, enclave has no full cores set\n");
608*acc4229cSAndra Paraschiv 
609*acc4229cSAndra Paraschiv 			break;
610*acc4229cSAndra Paraschiv 		}
611*acc4229cSAndra Paraschiv 
612*acc4229cSAndra Paraschiv 		case NE_ERR_ENCLAVE_MEM_MIN_SIZE: {
613*acc4229cSAndra Paraschiv 			printf("Error in start enclave, enclave memory is less than min size\n");
614*acc4229cSAndra Paraschiv 
615*acc4229cSAndra Paraschiv 			break;
616*acc4229cSAndra Paraschiv 		}
617*acc4229cSAndra Paraschiv 
618*acc4229cSAndra Paraschiv 		case NE_ERR_INVALID_FLAG_VALUE: {
619*acc4229cSAndra Paraschiv 			printf("Error in start enclave, provided invalid flag\n");
620*acc4229cSAndra Paraschiv 
621*acc4229cSAndra Paraschiv 			break;
622*acc4229cSAndra Paraschiv 		}
623*acc4229cSAndra Paraschiv 
624*acc4229cSAndra Paraschiv 		case NE_ERR_INVALID_ENCLAVE_CID: {
625*acc4229cSAndra Paraschiv 			printf("Error in start enclave, provided invalid enclave CID\n");
626*acc4229cSAndra Paraschiv 
627*acc4229cSAndra Paraschiv 			break;
628*acc4229cSAndra Paraschiv 		}
629*acc4229cSAndra Paraschiv 
630*acc4229cSAndra Paraschiv 		default:
631*acc4229cSAndra Paraschiv 			printf("Error in start enclave [%m]\n");
632*acc4229cSAndra Paraschiv 		}
633*acc4229cSAndra Paraschiv 
634*acc4229cSAndra Paraschiv 		return rc;
635*acc4229cSAndra Paraschiv 	}
636*acc4229cSAndra Paraschiv 
637*acc4229cSAndra Paraschiv 	return 0;
638*acc4229cSAndra Paraschiv }
639*acc4229cSAndra Paraschiv 
640*acc4229cSAndra Paraschiv /**
641*acc4229cSAndra Paraschiv  * ne_start_enclave_check_booted() - Start the enclave and wait for a hearbeat
642*acc4229cSAndra Paraschiv  *				     from it, on a newly created vsock channel,
643*acc4229cSAndra Paraschiv  *				     to check it has booted.
644*acc4229cSAndra Paraschiv  * @enclave_fd :	The file descriptor associated with the enclave.
645*acc4229cSAndra Paraschiv  *
646*acc4229cSAndra Paraschiv  * Context: Process context.
647*acc4229cSAndra Paraschiv  * Return:
648*acc4229cSAndra Paraschiv  * * 0 on success.
649*acc4229cSAndra Paraschiv  * * Negative return value on failure.
650*acc4229cSAndra Paraschiv  */
651*acc4229cSAndra Paraschiv static int ne_start_enclave_check_booted(int enclave_fd)
652*acc4229cSAndra Paraschiv {
653*acc4229cSAndra Paraschiv 	struct sockaddr_vm client_vsock_addr = {};
654*acc4229cSAndra Paraschiv 	int client_vsock_fd = -1;
655*acc4229cSAndra Paraschiv 	socklen_t client_vsock_len = sizeof(client_vsock_addr);
656*acc4229cSAndra Paraschiv 	struct ne_enclave_start_info enclave_start_info = {};
657*acc4229cSAndra Paraschiv 	struct pollfd fds[1] = {};
658*acc4229cSAndra Paraschiv 	int rc = -EINVAL;
659*acc4229cSAndra Paraschiv 	unsigned char recv_buf = 0;
660*acc4229cSAndra Paraschiv 	struct sockaddr_vm server_vsock_addr = {
661*acc4229cSAndra Paraschiv 		.svm_family = AF_VSOCK,
662*acc4229cSAndra Paraschiv 		.svm_cid = NE_IMAGE_LOAD_HEARTBEAT_CID,
663*acc4229cSAndra Paraschiv 		.svm_port = NE_IMAGE_LOAD_HEARTBEAT_PORT,
664*acc4229cSAndra Paraschiv 	};
665*acc4229cSAndra Paraschiv 	int server_vsock_fd = -1;
666*acc4229cSAndra Paraschiv 
667*acc4229cSAndra Paraschiv 	server_vsock_fd = socket(AF_VSOCK, SOCK_STREAM, 0);
668*acc4229cSAndra Paraschiv 	if (server_vsock_fd < 0) {
669*acc4229cSAndra Paraschiv 		rc = server_vsock_fd;
670*acc4229cSAndra Paraschiv 
671*acc4229cSAndra Paraschiv 		printf("Error in socket [%m]\n");
672*acc4229cSAndra Paraschiv 
673*acc4229cSAndra Paraschiv 		return rc;
674*acc4229cSAndra Paraschiv 	}
675*acc4229cSAndra Paraschiv 
676*acc4229cSAndra Paraschiv 	rc = bind(server_vsock_fd, (struct sockaddr *)&server_vsock_addr,
677*acc4229cSAndra Paraschiv 		  sizeof(server_vsock_addr));
678*acc4229cSAndra Paraschiv 	if (rc < 0) {
679*acc4229cSAndra Paraschiv 		printf("Error in bind [%m]\n");
680*acc4229cSAndra Paraschiv 
681*acc4229cSAndra Paraschiv 		goto out;
682*acc4229cSAndra Paraschiv 	}
683*acc4229cSAndra Paraschiv 
684*acc4229cSAndra Paraschiv 	rc = listen(server_vsock_fd, 1);
685*acc4229cSAndra Paraschiv 	if (rc < 0) {
686*acc4229cSAndra Paraschiv 		printf("Error in listen [%m]\n");
687*acc4229cSAndra Paraschiv 
688*acc4229cSAndra Paraschiv 		goto out;
689*acc4229cSAndra Paraschiv 	}
690*acc4229cSAndra Paraschiv 
691*acc4229cSAndra Paraschiv 	rc = ne_start_enclave(enclave_fd, &enclave_start_info);
692*acc4229cSAndra Paraschiv 	if (rc < 0)
693*acc4229cSAndra Paraschiv 		goto out;
694*acc4229cSAndra Paraschiv 
695*acc4229cSAndra Paraschiv 	printf("Enclave started, CID %llu\n", enclave_start_info.enclave_cid);
696*acc4229cSAndra Paraschiv 
697*acc4229cSAndra Paraschiv 	fds[0].fd = server_vsock_fd;
698*acc4229cSAndra Paraschiv 	fds[0].events = POLLIN;
699*acc4229cSAndra Paraschiv 
700*acc4229cSAndra Paraschiv 	rc = poll(fds, 1, NE_POLL_WAIT_TIME_MS);
701*acc4229cSAndra Paraschiv 	if (rc < 0) {
702*acc4229cSAndra Paraschiv 		printf("Error in poll [%m]\n");
703*acc4229cSAndra Paraschiv 
704*acc4229cSAndra Paraschiv 		goto out;
705*acc4229cSAndra Paraschiv 	}
706*acc4229cSAndra Paraschiv 
707*acc4229cSAndra Paraschiv 	if (!rc) {
708*acc4229cSAndra Paraschiv 		printf("Poll timeout, %d seconds elapsed\n", NE_POLL_WAIT_TIME);
709*acc4229cSAndra Paraschiv 
710*acc4229cSAndra Paraschiv 		rc = -ETIMEDOUT;
711*acc4229cSAndra Paraschiv 
712*acc4229cSAndra Paraschiv 		goto out;
713*acc4229cSAndra Paraschiv 	}
714*acc4229cSAndra Paraschiv 
715*acc4229cSAndra Paraschiv 	if ((fds[0].revents & POLLIN) == 0) {
716*acc4229cSAndra Paraschiv 		printf("Poll received value %d\n", fds[0].revents);
717*acc4229cSAndra Paraschiv 
718*acc4229cSAndra Paraschiv 		rc = -EINVAL;
719*acc4229cSAndra Paraschiv 
720*acc4229cSAndra Paraschiv 		goto out;
721*acc4229cSAndra Paraschiv 	}
722*acc4229cSAndra Paraschiv 
723*acc4229cSAndra Paraschiv 	rc = accept(server_vsock_fd, (struct sockaddr *)&client_vsock_addr,
724*acc4229cSAndra Paraschiv 		    &client_vsock_len);
725*acc4229cSAndra Paraschiv 	if (rc < 0) {
726*acc4229cSAndra Paraschiv 		printf("Error in accept [%m]\n");
727*acc4229cSAndra Paraschiv 
728*acc4229cSAndra Paraschiv 		goto out;
729*acc4229cSAndra Paraschiv 	}
730*acc4229cSAndra Paraschiv 
731*acc4229cSAndra Paraschiv 	client_vsock_fd = rc;
732*acc4229cSAndra Paraschiv 
733*acc4229cSAndra Paraschiv 	/*
734*acc4229cSAndra Paraschiv 	 * Read the heartbeat value that the init process in the enclave sends
735*acc4229cSAndra Paraschiv 	 * after vsock connect.
736*acc4229cSAndra Paraschiv 	 */
737*acc4229cSAndra Paraschiv 	rc = read(client_vsock_fd, &recv_buf, sizeof(recv_buf));
738*acc4229cSAndra Paraschiv 	if (rc < 0) {
739*acc4229cSAndra Paraschiv 		printf("Error in read [%m]\n");
740*acc4229cSAndra Paraschiv 
741*acc4229cSAndra Paraschiv 		goto out;
742*acc4229cSAndra Paraschiv 	}
743*acc4229cSAndra Paraschiv 
744*acc4229cSAndra Paraschiv 	if (rc != sizeof(recv_buf) || recv_buf != NE_IMAGE_LOAD_HEARTBEAT_VALUE) {
745*acc4229cSAndra Paraschiv 		printf("Read %d instead of %d\n", recv_buf,
746*acc4229cSAndra Paraschiv 		       NE_IMAGE_LOAD_HEARTBEAT_VALUE);
747*acc4229cSAndra Paraschiv 
748*acc4229cSAndra Paraschiv 		goto out;
749*acc4229cSAndra Paraschiv 	}
750*acc4229cSAndra Paraschiv 
751*acc4229cSAndra Paraschiv 	/* Write the heartbeat value back. */
752*acc4229cSAndra Paraschiv 	rc = write(client_vsock_fd, &recv_buf, sizeof(recv_buf));
753*acc4229cSAndra Paraschiv 	if (rc < 0) {
754*acc4229cSAndra Paraschiv 		printf("Error in write [%m]\n");
755*acc4229cSAndra Paraschiv 
756*acc4229cSAndra Paraschiv 		goto out;
757*acc4229cSAndra Paraschiv 	}
758*acc4229cSAndra Paraschiv 
759*acc4229cSAndra Paraschiv 	rc = 0;
760*acc4229cSAndra Paraschiv 
761*acc4229cSAndra Paraschiv out:
762*acc4229cSAndra Paraschiv 	close(server_vsock_fd);
763*acc4229cSAndra Paraschiv 
764*acc4229cSAndra Paraschiv 	return rc;
765*acc4229cSAndra Paraschiv }
766*acc4229cSAndra Paraschiv 
767*acc4229cSAndra Paraschiv int main(int argc, char *argv[])
768*acc4229cSAndra Paraschiv {
769*acc4229cSAndra Paraschiv 	int enclave_fd = -1;
770*acc4229cSAndra Paraschiv 	unsigned int i = 0;
771*acc4229cSAndra Paraschiv 	int ne_dev_fd = -1;
772*acc4229cSAndra Paraschiv 	struct ne_user_mem_region ne_user_mem_regions[NE_DEFAULT_NR_MEM_REGIONS] = {};
773*acc4229cSAndra Paraschiv 	unsigned int ne_vcpus[NE_DEFAULT_NR_VCPUS] = {};
774*acc4229cSAndra Paraschiv 	int rc = -EINVAL;
775*acc4229cSAndra Paraschiv 	pthread_t thread_id = 0;
776*acc4229cSAndra Paraschiv 	unsigned long slot_uid = 0;
777*acc4229cSAndra Paraschiv 
778*acc4229cSAndra Paraschiv 	if (argc != 2) {
779*acc4229cSAndra Paraschiv 		printf("Usage: %s <path_to_enclave_image>\n", argv[0]);
780*acc4229cSAndra Paraschiv 
781*acc4229cSAndra Paraschiv 		exit(EXIT_FAILURE);
782*acc4229cSAndra Paraschiv 	}
783*acc4229cSAndra Paraschiv 
784*acc4229cSAndra Paraschiv 	if (strlen(argv[1]) >= PATH_MAX) {
785*acc4229cSAndra Paraschiv 		printf("The size of the path to enclave image is higher than max path\n");
786*acc4229cSAndra Paraschiv 
787*acc4229cSAndra Paraschiv 		exit(EXIT_FAILURE);
788*acc4229cSAndra Paraschiv 	}
789*acc4229cSAndra Paraschiv 
790*acc4229cSAndra Paraschiv 	ne_dev_fd = open(NE_DEV_NAME, O_RDWR | O_CLOEXEC);
791*acc4229cSAndra Paraschiv 	if (ne_dev_fd < 0) {
792*acc4229cSAndra Paraschiv 		printf("Error in open NE device [%m]\n");
793*acc4229cSAndra Paraschiv 
794*acc4229cSAndra Paraschiv 		exit(EXIT_FAILURE);
795*acc4229cSAndra Paraschiv 	}
796*acc4229cSAndra Paraschiv 
797*acc4229cSAndra Paraschiv 	printf("Creating enclave slot ...\n");
798*acc4229cSAndra Paraschiv 
799*acc4229cSAndra Paraschiv 	rc = ne_create_vm(ne_dev_fd, &slot_uid, &enclave_fd);
800*acc4229cSAndra Paraschiv 
801*acc4229cSAndra Paraschiv 	close(ne_dev_fd);
802*acc4229cSAndra Paraschiv 
803*acc4229cSAndra Paraschiv 	if (rc < 0)
804*acc4229cSAndra Paraschiv 		exit(EXIT_FAILURE);
805*acc4229cSAndra Paraschiv 
806*acc4229cSAndra Paraschiv 	printf("Enclave fd %d\n", enclave_fd);
807*acc4229cSAndra Paraschiv 
808*acc4229cSAndra Paraschiv 	rc = pthread_create(&thread_id, NULL, ne_poll_enclave_fd, (void *)&enclave_fd);
809*acc4229cSAndra Paraschiv 	if (rc < 0) {
810*acc4229cSAndra Paraschiv 		printf("Error in thread create [%m]\n");
811*acc4229cSAndra Paraschiv 
812*acc4229cSAndra Paraschiv 		close(enclave_fd);
813*acc4229cSAndra Paraschiv 
814*acc4229cSAndra Paraschiv 		exit(EXIT_FAILURE);
815*acc4229cSAndra Paraschiv 	}
816*acc4229cSAndra Paraschiv 
817*acc4229cSAndra Paraschiv 	for (i = 0; i < NE_DEFAULT_NR_MEM_REGIONS; i++) {
818*acc4229cSAndra Paraschiv 		ne_user_mem_regions[i].memory_size = NE_MIN_MEM_REGION_SIZE;
819*acc4229cSAndra Paraschiv 
820*acc4229cSAndra Paraschiv 		rc = ne_alloc_user_mem_region(&ne_user_mem_regions[i]);
821*acc4229cSAndra Paraschiv 		if (rc < 0) {
822*acc4229cSAndra Paraschiv 			printf("Error in alloc userspace memory region, iter %d\n", i);
823*acc4229cSAndra Paraschiv 
824*acc4229cSAndra Paraschiv 			goto release_enclave_fd;
825*acc4229cSAndra Paraschiv 		}
826*acc4229cSAndra Paraschiv 	}
827*acc4229cSAndra Paraschiv 
828*acc4229cSAndra Paraschiv 	rc = ne_load_enclave_image(enclave_fd, ne_user_mem_regions, argv[1]);
829*acc4229cSAndra Paraschiv 	if (rc < 0)
830*acc4229cSAndra Paraschiv 		goto release_enclave_fd;
831*acc4229cSAndra Paraschiv 
832*acc4229cSAndra Paraschiv 	for (i = 0; i < NE_DEFAULT_NR_MEM_REGIONS; i++) {
833*acc4229cSAndra Paraschiv 		rc = ne_set_user_mem_region(enclave_fd, ne_user_mem_regions[i]);
834*acc4229cSAndra Paraschiv 		if (rc < 0) {
835*acc4229cSAndra Paraschiv 			printf("Error in set memory region, iter %d\n", i);
836*acc4229cSAndra Paraschiv 
837*acc4229cSAndra Paraschiv 			goto release_enclave_fd;
838*acc4229cSAndra Paraschiv 		}
839*acc4229cSAndra Paraschiv 	}
840*acc4229cSAndra Paraschiv 
841*acc4229cSAndra Paraschiv 	printf("Enclave memory regions were added\n");
842*acc4229cSAndra Paraschiv 
843*acc4229cSAndra Paraschiv 	for (i = 0; i < NE_DEFAULT_NR_VCPUS; i++) {
844*acc4229cSAndra Paraschiv 		/*
845*acc4229cSAndra Paraschiv 		 * The vCPU is chosen from the enclave vCPU pool, if the value
846*acc4229cSAndra Paraschiv 		 * of the vcpu_id is 0.
847*acc4229cSAndra Paraschiv 		 */
848*acc4229cSAndra Paraschiv 		ne_vcpus[i] = 0;
849*acc4229cSAndra Paraschiv 		rc = ne_add_vcpu(enclave_fd, &ne_vcpus[i]);
850*acc4229cSAndra Paraschiv 		if (rc < 0) {
851*acc4229cSAndra Paraschiv 			printf("Error in add vcpu, iter %d\n", i);
852*acc4229cSAndra Paraschiv 
853*acc4229cSAndra Paraschiv 			goto release_enclave_fd;
854*acc4229cSAndra Paraschiv 		}
855*acc4229cSAndra Paraschiv 
856*acc4229cSAndra Paraschiv 		printf("Added vCPU %d to the enclave\n", ne_vcpus[i]);
857*acc4229cSAndra Paraschiv 	}
858*acc4229cSAndra Paraschiv 
859*acc4229cSAndra Paraschiv 	printf("Enclave vCPUs were added\n");
860*acc4229cSAndra Paraschiv 
861*acc4229cSAndra Paraschiv 	rc = ne_start_enclave_check_booted(enclave_fd);
862*acc4229cSAndra Paraschiv 	if (rc < 0) {
863*acc4229cSAndra Paraschiv 		printf("Error in the enclave start / image loading heartbeat logic [rc=%d]\n", rc);
864*acc4229cSAndra Paraschiv 
865*acc4229cSAndra Paraschiv 		goto release_enclave_fd;
866*acc4229cSAndra Paraschiv 	}
867*acc4229cSAndra Paraschiv 
868*acc4229cSAndra Paraschiv 	printf("Entering sleep for %d seconds ...\n", NE_SLEEP_TIME);
869*acc4229cSAndra Paraschiv 
870*acc4229cSAndra Paraschiv 	sleep(NE_SLEEP_TIME);
871*acc4229cSAndra Paraschiv 
872*acc4229cSAndra Paraschiv 	close(enclave_fd);
873*acc4229cSAndra Paraschiv 
874*acc4229cSAndra Paraschiv 	ne_free_mem_regions(ne_user_mem_regions);
875*acc4229cSAndra Paraschiv 
876*acc4229cSAndra Paraschiv 	exit(EXIT_SUCCESS);
877*acc4229cSAndra Paraschiv 
878*acc4229cSAndra Paraschiv release_enclave_fd:
879*acc4229cSAndra Paraschiv 	close(enclave_fd);
880*acc4229cSAndra Paraschiv 	ne_free_mem_regions(ne_user_mem_regions);
881*acc4229cSAndra Paraschiv 
882*acc4229cSAndra Paraschiv 	exit(EXIT_FAILURE);
883*acc4229cSAndra Paraschiv }
884