aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/cpu/sgx/encl.h
blob: fec43ca65065b0caecf5e05dd261c62cf045494e (plain) (blame)
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
/* SPDX-License-Identifier: GPL-2.0 */
/**
 * Copyright(c) 2016-20 Intel Corporation.
 *
 * Contains the software defined data structures for enclaves.
 */
#ifndef _X86_ENCL_H
#define _X86_ENCL_H

#include <linux/cpumask.h>
#include <linux/kref.h>
#include <linux/list.h>
#include <linux/mm_types.h>
#include <linux/mmu_notifier.h>
#include <linux/mutex.h>
#include <linux/notifier.h>
#include <linux/srcu.h>
#include <linux/workqueue.h>
#include <linux/xarray.h>
#include "sgx.h"

/* 'desc' bits holding the offset in the VA (version array) page. */
#define SGX_ENCL_PAGE_VA_OFFSET_MASK	GENMASK_ULL(11, 3)

/* 'desc' bit marking that the page is being reclaimed. */
#define SGX_ENCL_PAGE_BEING_RECLAIMED	BIT(3)

struct sgx_encl_page {
	unsigned long desc;
	unsigned long vm_max_prot_bits;
	struct sgx_epc_page *epc_page;
	struct sgx_encl *encl;
	struct sgx_va_page *va_page;
};

enum sgx_encl_flags {
	SGX_ENCL_IOCTL		= BIT(0),
	SGX_ENCL_DEBUG		= BIT(1),
	SGX_ENCL_CREATED	= BIT(2),
	SGX_ENCL_INITIALIZED	= BIT(3),
};

struct sgx_encl_mm {
	struct sgx_encl *encl;
	struct mm_struct *mm;
	struct list_head list;
	struct mmu_notifier mmu_notifier;
};

struct sgx_encl {
	unsigned long base;
	unsigned long size;
	unsigned long flags;
	unsigned int page_cnt;
	unsigned int secs_child_cnt;
	struct mutex lock;
	struct xarray page_array;
	struct sgx_encl_page secs;
	unsigned long attributes;
	unsigned long attributes_mask;

	cpumask_t cpumask;
	struct file *backing;
	struct kref refcount;
	struct list_head va_pages;
	unsigned long mm_list_version;
	struct list_head mm_list;
	spinlock_t mm_lock;
	struct srcu_struct srcu;
};

#define SGX_VA_SLOT_COUNT 512

struct sgx_va_page {
	struct sgx_epc_page *epc_page;
	DECLARE_BITMAP(slots, SGX_VA_SLOT_COUNT);
	struct list_head list;
};

struct sgx_backing {
	pgoff_t page_index;
	struct page *contents;
	struct page *pcmd;
	unsigned long pcmd_offset;
};

extern const struct vm_operations_struct sgx_vm_ops;

static inline int sgx_encl_find(struct mm_struct *mm, unsigned long addr,
				struct vm_area_struct **vma)
{
	struct vm_area_struct *result;

	result = vma_lookup(mm, addr);
	if (!result || result->vm_ops != &sgx_vm_ops)
		return -EINVAL;

	*vma = result;

	return 0;
}

int sgx_encl_may_map(struct sgx_encl *encl, unsigned long start,
		     unsigned long end, unsigned long vm_flags);

void sgx_encl_release(struct kref *ref);
int sgx_encl_mm_add(struct sgx_encl *encl, struct mm_struct *mm);
int sgx_encl_get_backing(struct sgx_encl *encl, unsigned long page_index,
			 struct sgx_backing *backing);
void sgx_encl_put_backing(struct sgx_backing *backing, bool do_write);
int sgx_encl_test_and_clear_young(struct mm_struct *mm,
				  struct sgx_encl_page *page);

struct sgx_epc_page *sgx_alloc_va_page(void);
unsigned int sgx_alloc_va_slot(struct sgx_va_page *va_page);
void sgx_free_va_slot(struct sgx_va_page *va_page, unsigned int offset);
bool sgx_va_page_full(struct sgx_va_page *va_page);
void sgx_encl_free_epc_page(struct sgx_epc_page *page);

#endif /* _X86_ENCL_H */