@@ -183,19 +183,9 @@ int arch_hibernation_header_restore(void *addr)
EXPORT_SYMBOL(arch_hibernation_header_restore);
/*
- * Copies length bytes, starting at src_start into an new page,
- * perform cache maintentance, then maps it at the specified address low
- * address as executable.
- *
- * This is used by hibernate to copy the code it needs to execute when
- * overwriting the kernel text. This function generates a new set of page
- * tables, which it loads into ttbr0.
- *
- * Length is provided as we probably only want 4K of data, even on a 64K
- * page system.
+ * Create a set of page tables that map page to dst_addr.
*/
-static int create_safe_exec_page(void *src_start, size_t length,
- unsigned long dst_addr,
+static int create_single_mapping(unsigned long page, unsigned long dst_addr,
phys_addr_t *phys_dst_addr,
void *(*allocator)(gfp_t mask),
gfp_t mask)
@@ -206,15 +196,6 @@ static int create_safe_exec_page(void *src_start, size_t length,
pud_t *pudp;
pmd_t *pmdp;
pte_t *ptep;
- unsigned long dst = (unsigned long)allocator(mask);
-
- if (!dst) {
- rc = -ENOMEM;
- goto out;
- }
-
- memcpy((void *)dst, src_start, length);
- __flush_icache_range(dst, dst + length);
trans_pgd = allocator(mask);
if (!trans_pgd) {
@@ -253,7 +234,7 @@ static int create_safe_exec_page(void *src_start, size_t length,
}
ptep = pte_offset_kernel(pmdp, dst_addr);
- set_pte(ptep, pfn_pte(virt_to_pfn(dst), PAGE_KERNEL_EXEC));
+ set_pte(ptep, pfn_pte(virt_to_pfn(page), PAGE_KERNEL_EXEC));
/*
* Load our new page tables. A strict BBM approach requires that we
@@ -272,12 +253,42 @@ static int create_safe_exec_page(void *src_start, size_t length,
write_sysreg(phys_to_ttbr(virt_to_phys(pgdp)), ttbr0_el1);
isb();
- *phys_dst_addr = virt_to_phys((void *)dst);
+ *phys_dst_addr = virt_to_phys((void *)page);
out:
return rc;
}
+/*
+ * Copies length bytes, starting at src_start into an new page,
+ * perform cache maintentance, then maps it at the specified address low
+ * address as executable.
+ *
+ * This is used by hibernate to copy the code it needs to execute when
+ * overwriting the kernel text. This function generates a new set of page
+ * tables, which it loads into ttbr0.
+ *
+ * Length is provided as we probably only want 4K of data, even on a 64K
+ * page system.
+ */
+static int create_safe_exec_page(void *src_start, size_t length,
+ unsigned long dst_addr,
+ phys_addr_t *phys_dst_addr,
+ void *(*allocator)(gfp_t mask),
+ gfp_t mask)
+{
+ unsigned long page = (unsigned long)allocator(mask);
+
+ if (!page)
+ return -ENOMEM;
+
+ memcpy((void *)page, src_start, length);
+ __flush_icache_range(page, page + length);
+
+ return create_single_mapping(page, dst_addr, phys_dst_addr,
+ allocator, gfp_t mask)
+}
+
#define dcache_clean_range(start, end) __flush_dcache_area(start, (end - start))
int swsusp_arch_suspend(void)
Kexec wants to share hibernate's page table setup code, but needs its memory-copy buffer idmapped as it also has to turn the MMU off. Split the copy of this buffer from the code that maps it. Signed-off-by: James Morse <james.morse@arm.com> --- arch/arm64/kernel/hibernate.c | 57 +++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 23 deletions(-)