[RFC PATCH 2/3] arm64: hibernate: Split create_safe_exec_page() and its mapping code
From: James Morse <james.morse@arm.com>
Date: 2020-01-15 14:34:21
Subsystem:
arm64 port (aarch64 architecture), the rest · Maintainers:
Catalin Marinas, Will Deacon, Linus Torvalds
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(-)
diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c
index a96b2921d22c..7f8cb7596f9e 100644
--- a/arch/arm64/kernel/hibernate.c
+++ b/arch/arm64/kernel/hibernate.c@@ -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)
--
2.24.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel