Skip to content

Commit

Permalink
keystone-linux-driver: fix CMA physical address handling (#398)
Browse files Browse the repository at this point in the history
This commit changes the EPM physical address attribute to be set to the
`dma_addr_t dma_handle` returned by `dma_alloc_coherent`, instead of the
virtual to physical address mapping of the returned virtual address. The
__pa macro used for the virtual to physical translation can be used to
map addresses within the contiguous kernel virtual to physical mapping.
However, this operation appears to overflow if the allocation in the CMA
memory region is outside this range (e.g., before
kernel_map.va_pa_offset) and instead returns an address outside of any
physical memory mapping (e.g. 0xff20000111b01000 on a system with RAM
mapped from 0x080000000 to 0x880000000).

When this happens, the Enclave initialization routine is stuck in the
EnclavePhysicalMemory::writeMem's memcpy routine while copying the
loader binary. Trying to debug this in GDB has the program freeze on the
first memory write instruction (sd), and the debugger is unable to move
past this instruction. While I have not traced the exact behavior,
presumably this is because the Keystone kernel driver sets up the
userspace-virtual address mapping to this (unmapped) physical range. A
write to this memory then causes a hardware fault. However, because this
virtual access is backed by a valid userspace-virtual mapping, which is
further not paged out, it will return to the userspace application and
attempt to reexecute the faulting instruction.

For buddy-allocator based EPM memory, `pa` is simply set to
`__pa(epm_vaddr)`. This change replaces remaining virtual-physical
mappings with usage of the dedicated `pa` attribute. Both
`root_page_table` and `ptr` still contain the kernel-virtual
`epm_vaddr`.

With this change, I can successfully initialize Enclaves with a large
amount of freemem (>= 64MB) on a Linux 6.1.66 #1-NixOS SMP system
running on a (patched) QEMU 8.1.3 riscv64 virt machine with 32GB RAM and
a 1GB CMA reservation as a kernel parameter.

Co-authored-by: Gongqi Huang <[email protected]>
  • Loading branch information
lschuermann and cherrypiejam authored Dec 20, 2023
1 parent a06b054 commit 033ccc6
Show file tree
Hide file tree
Showing 3 changed files with 3 additions and 3 deletions.
2 changes: 1 addition & 1 deletion linux-keystone-driver/keystone-ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ int keystone_create_enclave(struct file *filep, unsigned long arg)
}

/* Pass base page table */
enclp->pt_ptr = __pa(enclave->epm->root_page_table);
enclp->pt_ptr = enclave->epm->pa;
enclp->epm_size = enclave->epm->size;

/* allocate UID */
Expand Down
2 changes: 1 addition & 1 deletion linux-keystone-driver/keystone-page.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ int epm_init(struct epm* epm, unsigned int min_pages)
memset((void*)epm_vaddr, 0, PAGE_SIZE*count);

epm->root_page_table = (void*)epm_vaddr;
epm->pa = __pa(epm_vaddr);
epm->pa = (epm->is_cma) ? device_phys_addr : __pa(epm_vaddr);
epm->order = order;
epm->size = count << PAGE_SHIFT;
epm->ptr = epm_vaddr;
Expand Down
2 changes: 1 addition & 1 deletion linux-keystone-driver/keystone.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ int keystone_mmap(struct file* filp, struct vm_area_struct *vma)
if(enclave->is_init){
if (vsize > PAGE_SIZE)
return -EINVAL;
paddr = __pa(epm->root_page_table) + (vma->vm_pgoff << PAGE_SHIFT);
paddr = epm->pa + (vma->vm_pgoff << PAGE_SHIFT);
remap_pfn_range(vma,
vma->vm_start,
paddr >> PAGE_SHIFT,
Expand Down

0 comments on commit 033ccc6

Please sign in to comment.