Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only 2 : : /* 3 : : * Hibernation support for x86-64 4 : : * 5 : : * Copyright (c) 2007 Rafael J. Wysocki <rjw@sisk.pl> 6 : : * Copyright (c) 2002 Pavel Machek <pavel@ucw.cz> 7 : : * Copyright (c) 2001 Patrick Mochel <mochel@osdl.org> 8 : : */ 9 : : 10 : : #include <linux/gfp.h> 11 : : #include <linux/smp.h> 12 : : #include <linux/suspend.h> 13 : : #include <linux/scatterlist.h> 14 : : #include <linux/kdebug.h> 15 : : 16 : : #include <crypto/hash.h> 17 : : 18 : : #include <asm/e820/api.h> 19 : : #include <asm/init.h> 20 : : #include <asm/proto.h> 21 : : #include <asm/page.h> 22 : : #include <asm/pgtable.h> 23 : : #include <asm/mtrr.h> 24 : : #include <asm/sections.h> 25 : : #include <asm/suspend.h> 26 : : #include <asm/tlbflush.h> 27 : : 28 : 0 : static int set_up_temporary_text_mapping(pgd_t *pgd) 29 : : { 30 : 0 : pmd_t *pmd; 31 : 0 : pud_t *pud; 32 : 0 : p4d_t *p4d = NULL; 33 : 0 : pgprot_t pgtable_prot = __pgprot(_KERNPG_TABLE); 34 : 0 : pgprot_t pmd_text_prot = __pgprot(__PAGE_KERNEL_LARGE_EXEC); 35 : : 36 : : /* Filter out unsupported __PAGE_KERNEL* bits: */ 37 : 0 : pgprot_val(pmd_text_prot) &= __default_kernel_pte_mask; 38 : 0 : pgprot_val(pgtable_prot) &= __default_kernel_pte_mask; 39 : : 40 : : /* 41 : : * The new mapping only has to cover the page containing the image 42 : : * kernel's entry point (jump_address_phys), because the switch over to 43 : : * it is carried out by relocated code running from a page allocated 44 : : * specifically for this purpose and covered by the identity mapping, so 45 : : * the temporary kernel text mapping is only needed for the final jump. 46 : : * Moreover, in that mapping the virtual address of the image kernel's 47 : : * entry point must be the same as its virtual address in the image 48 : : * kernel (restore_jump_address), so the image kernel's 49 : : * restore_registers() code doesn't find itself in a different area of 50 : : * the virtual address space after switching over to the original page 51 : : * tables used by the image kernel. 52 : : */ 53 : : 54 [ # # # ]: 0 : if (pgtable_l5_enabled()) { 55 : 0 : p4d = (p4d_t *)get_safe_page(GFP_ATOMIC); 56 [ # # ]: 0 : if (!p4d) 57 : : return -ENOMEM; 58 : : } 59 : : 60 : 0 : pud = (pud_t *)get_safe_page(GFP_ATOMIC); 61 [ # # ]: 0 : if (!pud) 62 : : return -ENOMEM; 63 : : 64 : 0 : pmd = (pmd_t *)get_safe_page(GFP_ATOMIC); 65 [ # # ]: 0 : if (!pmd) 66 : : return -ENOMEM; 67 : : 68 [ # # ]: 0 : set_pmd(pmd + pmd_index(restore_jump_address), 69 : : __pmd((jump_address_phys & PMD_MASK) | pgprot_val(pmd_text_prot))); 70 [ # # # # ]: 0 : set_pud(pud + pud_index(restore_jump_address), 71 : : __pud(__pa(pmd) | pgprot_val(pgtable_prot))); 72 [ # # ]: 0 : if (p4d) { 73 [ # # # # ]: 0 : p4d_t new_p4d = __p4d(__pa(pud) | pgprot_val(pgtable_prot)); 74 [ # # ]: 0 : pgd_t new_pgd = __pgd(__pa(p4d) | pgprot_val(pgtable_prot)); 75 : : 76 : 0 : set_p4d(p4d + p4d_index(restore_jump_address), new_p4d); 77 : 0 : set_pgd(pgd + pgd_index(restore_jump_address), new_pgd); 78 : : } else { 79 : : /* No p4d for 4-level paging: point the pgd to the pud page table */ 80 [ # # ]: 0 : pgd_t new_pgd = __pgd(__pa(pud) | pgprot_val(pgtable_prot)); 81 : 0 : set_pgd(pgd + pgd_index(restore_jump_address), new_pgd); 82 : : } 83 : : 84 : : return 0; 85 : : } 86 : : 87 : 0 : static void *alloc_pgt_page(void *context) 88 : : { 89 : 0 : return (void *)get_safe_page(GFP_ATOMIC); 90 : : } 91 : : 92 : 0 : static int set_up_temporary_mappings(void) 93 : : { 94 : 0 : struct x86_mapping_info info = { 95 : : .alloc_pgt_page = alloc_pgt_page, 96 : : .page_flag = __PAGE_KERNEL_LARGE_EXEC, 97 : : .offset = __PAGE_OFFSET, 98 : : }; 99 : 0 : unsigned long mstart, mend; 100 : 0 : pgd_t *pgd; 101 : 0 : int result; 102 : 0 : int i; 103 : : 104 : 0 : pgd = (pgd_t *)get_safe_page(GFP_ATOMIC); 105 [ # # ]: 0 : if (!pgd) 106 : : return -ENOMEM; 107 : : 108 : : /* Prepare a temporary mapping for the kernel text */ 109 : 0 : result = set_up_temporary_text_mapping(pgd); 110 [ # # ]: 0 : if (result) 111 : : return result; 112 : : 113 : : /* Set up the direct mapping from scratch */ 114 [ # # ]: 0 : for (i = 0; i < nr_pfn_mapped; i++) { 115 : 0 : mstart = pfn_mapped[i].start << PAGE_SHIFT; 116 : 0 : mend = pfn_mapped[i].end << PAGE_SHIFT; 117 : : 118 : 0 : result = kernel_ident_mapping_init(&info, pgd, mstart, mend); 119 [ # # ]: 0 : if (result) 120 : 0 : return result; 121 : : } 122 : : 123 [ # # ]: 0 : temp_pgt = __pa(pgd); 124 : 0 : return 0; 125 : : } 126 : : 127 : 0 : asmlinkage int swsusp_arch_resume(void) 128 : : { 129 : 0 : int error; 130 : : 131 : : /* We have got enough memory and from now on we cannot recover */ 132 : 0 : error = set_up_temporary_mappings(); 133 [ # # ]: 0 : if (error) 134 : : return error; 135 : : 136 : 0 : error = relocate_restore_code(); 137 [ # # ]: 0 : if (error) 138 : : return error; 139 : : 140 : 0 : restore_image(); 141 : 0 : return 0; 142 : : }