@@ -674,6 +674,8 @@ int arch_memory_failure(unsigned long pfn, int flags)
struct sgx_epc_page *page = sgx_paddr_to_page(pfn << PAGE_SHIFT);
struct sgx_epc_section *section;
struct sgx_numa_node *node;
+ void __user * vaddr;
+ int ret;
/*
* mm/memory-failure.c calls this routine for all errors
@@ -690,8 +692,26 @@ int arch_memory_failure(unsigned long pfn, int flags)
* error. The signal may help the task understand why the
* enclave is broken.
*/
- if (flags & MF_ACTION_REQUIRED)
- force_sig(SIGBUS);
+ if (flags & MF_ACTION_REQUIRED) {
+ /*
+ * Provide extra info to the task so that it can make further
+ * decision but not simply kill it. This is quite useful for
+ * virtualization case.
+ */
+ if (page->flags & SGX_EPC_PAGE_KVM_GUEST) {
+ /*
+ * The 'encl_owner' field is repurposed, when allocating EPC
+ * page it was assigned to the virtual address of virtual EPC
+ * page.
+ */
+ vaddr = (unsigned long)page->vepc_vaddr & PAGE_MASK;
+ ret = force_sig_mceerr(BUS_MCEERR_AR, vaddr, PAGE_SHIFT);
+ if (ret < 0)
+ pr_err("Memory failure: Error sending signal to %s:%d: %d\n",
+ current->comm, current->pid, ret);
+ } else
+ force_sig(SIGBUS);
+ }
section = &sgx_epc_sections[page->section];
node = section->node;