SGX driver
#Intel SGX driver
##Overall Description
The intel SGX driver operates in the Ring0, it is responsible for issuing SGX Ring0 instructions. All the instructions that issued by SGX diver is defined in sgx_asm.h
75 enum sgx_commands {
76 ECREATE = 0x0,
77 EADD = 0x1,
78 EINIT = 0x2,
79 EREMOVE = 0x3,
80 EDGBRD = 0x4,
81 EDGBWR = 0x5,
82 EEXTEND = 0x6,
83 ELDU = 0x8,
84 EBLOCK = 0x9,
85 EPA = 0xA,
86 EWB = 0xB,
87 ETRACK = 0xC,
88 EAUG = 0xD,
89 EMODPR = 0xE,
90 EMODT = 0xF,
91 };
The two major questions are:
- How did SGX driver hook MMU with Enclave pages?
By a MMAP and FIND
- How to manage Enclave paging - what is the the algorithm?
It is a simplied version of LRU
##Driver init
The driver is registered in the Kernel module initialization routine.
360 static struct platform_driver sgx_drv = {
361 .probe = sgx_drv_probe,
362 .remove = sgx_drv_remove,
363 .driver = {
364 .name = "intel_sgx",
365 .pm = &sgx_drv_pm,
366 .acpi_match_table = ACPI_PTR(sgx_device_ids),
367 },
368 };
The .probe()
routine then will be called. The implementation of .probe()
routine is sgx_drv_probe()
. This routine ensures that the platform has SGX featured enabled and then calls sgx_dev_init()
function to init the SGX device.
###EPC bank
The sgx_dev_init()
reads the EPC banks configuation information and fills the data structure called sgx_epc_banks
, which is global array. Each item stores the one EPC banks physical address and length. For example, in my platform, the EPC bank’s information is like below. According to the value, we can see my platform has the EPC size of about 93.5MB
. The routine then calls ioremap()
to map the EPC memory to a virtual addres. The sgx_dev_int()
routine also inits a work queue calld intel_sgx-add-page-wq
. The sgx_add_epc_bank
initializes a free list of all EPC pages. Each has physical addresses.
intel_sgx INT0E0C:00: EPC bank 0x30200000-0x35f80000
###FILE operations
The sgx_fops
is defined as below. The sgx_mmap
and sgx_ioctl
is defined.
151 static const struct file_operations sgx_fops = {
152 .owner = THIS_MODULE,
153 .unlocked_ioctl = sgx_ioctl,
154 #ifdef CONFIG_COMPAT
155 .compat_ioctl = sgx_compat_ioctl,
156 #endif
157 .mmap = sgx_mmap,
158 .get_unmapped_area = sgx_get_unmapped_area,
159 };
The sgx_mmap()
registered sgx_vm_ops
defined as below.
238 const struct vm_operations_struct sgx_vm_ops = {
239 .close = sgx_vma_close,
240 .open = sgx_vma_open,
241 .fault = sgx_vma_fault,
242 .access = sgx_vma_access,
243 };
###SGX_IOCTL()
sgx_ioctl()
handles ENCLAVE_CREATE
, ENCLAVE_ADD_PAGE
and ENCLAVE_INIT
commands issued from the user space.
###SGX virtual memory operations
sgx_vma_open()
get a reference tosgx_encl
and increases its reference countsgx_vma_close()
sets the flag of asgx_encl
toSGX_ENCL_DEAD
, It also removes the page table entries that mapping to the vma area.sgx_vma_access()
is designed for DEBUG modesgx_vma_fault()
will forward the fault to thesgx_fault_page()
routine with theaddr
being the faulting address.
##Enclave create
The user creates enclave through IOTCL interface. The user passes the address of the a `sgx_secs” structure which is defined as
84 struct sgx_secs {
85 uint64_t size;
86 uint64_t base;
87 uint32_t ssaframesize;
88 uint32_t miscselect;
89 uint8_t reserved1[SGX_SECS_RESERVED1_SIZE];
90 uint64_t attributes;
91 uint64_t xfrm;
92 uint32_t mrenclave[8];
93 uint8_t reserved2[SGX_SECS_RESERVED2_SIZE];
94 uint32_t mrsigner[8];
95 uint8_t reserved3[SGX_SECS_RESERVED3_SIZE];
96 uint16_t isvvprodid;
97 uint16_t isvsvn;
98 uint8_t reserved4[SGX_SECS_RESERVED4_SIZE];
99 };
The SECS or the SGX Enclave Control Structure
is the metadata of a Enclave. It is a architecture defined data structure. The SECS is used to identify one enclave. The below is quoted from Intel SGX explained Section 5.1.3
by a MIT researcher
SGX stores per-enclave metadata in a SGX Enclave Control Structure (SECS) associated with each enclave. Each SECS is stored in a dedicated EPC page with the page type PT SECS. These pages are not intended to be mapped into any enclave’s address space, and are exclusively used by the CPU’s SGX implementation.
The size
and the base
in the SECS data structure defines ELRANGE
, which is the Enclave Linear Address Range. The virtual address that is in the ELRANGE
will be mapped into the EPC.
The sgx_encl_create()
function will call sgx_encl_alloc()
function to allocate an Enclave based on the secs information.
The sgx_encl_alloc()
will call shmem_file_setup()
to allocate a shared memory sized of secs->size
rounded by PAGE_SZIE
and set it to secs->backing
. So that this memory portion could be shared between kernel and user. The information of shared memory virtual filesystem could be foun here. The function also allocated a memory 32 times smaller than secs->size
and set it to encl->pcmd
. FIXME The function inits several list and fills in the encl
data structure as follows
543 INIT_LIST_HEAD(&encl->add_page_reqs);
544 INIT_LIST_HEAD(&encl->va_pages);
545 INIT_RADIX_TREE(&encl->page_tree, GFP_KERNEL);
546 INIT_LIST_HEAD(&encl->load_list);
547 INIT_LIST_HEAD(&encl->encl_list);
548 mutex_init(&encl->lock);
551 encl->mm = current->mm;
552 encl->base = secs->base;
553 encl->size = secs->size;
554 encl->ssaframesize = secs->ssaframesize;
555 encl->backing = backing;
556 encl->pcmd = pcmd;
The sgx_encl_create()
function then allocate a page from EPC. That page will hold the SECS information. That page will be populated by SGX hardware (ECREATE instrcution). The function then population a sgx_pageinfo
structure and use that structure to call __ecreate()
function which takes two arguments. A sgx_pageinfo
structure and a destination for the target secs page. In the sgx_pageinfo
structure, srcpge
should points to the source secs. secinfo
contains the meta-data about an enclave page.
122 struct sgx_pageinfo {
123 uint64_t linaddr;
124 uint64_t srcpge;
125 union {
126 uint64_t secinfo;
127 uint64_t pcmd;
128 };
129 uint64_t secs;
130 } __attribute__((aligned(32)));
Note that, the SECS used here is provided by the user and it is not the same with the architectural defined one. According to Intel SGX manual, SECS is immutable after EINIT is called and can be modified by EADD and EEXTEND. SECS is not accessible to software.
There are 2 main data structures associated with operating an enclave, the SGX Enclave Control Structure (SECS) and the Thread Control Structure (TCS). There is one SECS for each enclave. The SECS contains meta-data which is used by the hardware to protect the enclave. Included in the SECS is a field which stores the enclave build measurement value. This field, MRENCLAVE, is initialized by the ECREATE instruction and updated by every EADD and EEXTEND. It is locked by EINIT. The SECS cannot be accessed by software. Every enclave contains one or more TCSs. The TCS contains meta-data used by the hardware to save and restore thread specific information when entering/exiting the enclave. There is one field, FLAGS, which may be accessed by software. The SECS is created at the time ECREATE is executed. The TCS can be created using the EADD instruction or the SGX2 instructions.
###Enclave Page Initialization
The sgx_init_page
associates an Enclave page with a EPC page and a va page.
##Page Cache Handling
EPC pages can be categories into three kinds, Regluar, version array page or SECS page. One version array page can contain 512 versions.
###Page representation
There are three structures that represent a page, sgx_va_page
, sgx_epc_page
and sgx_encl_page
. They are defined as below. sgx_epc_page
has a physicall address associated with it. The sgx_va_page
presents a Version Array page. The sgx_encl_page
has a pointer to epc and va page (plus offset to indicate its version location). It also have associated virtual address and flags associated with it.
81 struct sgx_epc_page {
82 resource_size_t pa;
83 struct list_head list;
84 struct sgx_encl_page *encl_page;
85 };
91 struct sgx_va_page {
92 struct sgx_epc_page *epc_page;
93 DECLARE_BITMAP(slots, SGX_VA_SLOT_COUNT);
94 struct list_head list;
95 };
118 struct sgx_encl_page {
119 unsigned long addr;
120 unsigned int flags;
121 struct sgx_epc_page *epc_page;
122 struct sgx_va_page *va_page;
123 unsigned int va_offset;
124 };
###Alloc a page
An EPC page is allocated by grab a free page from the sgx_free_list
, which is a global list maintaining the free pages. *FIXME: complex logic about swapping
###Get a page
sgx_get_page()
returns the virtual address of page.