~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/power/hibernate_64.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 #include <linux/pgtable.h>
 16 
 17 #include <crypto/hash.h>
 18 
 19 #include <asm/e820/api.h>
 20 #include <asm/init.h>
 21 #include <asm/proto.h>
 22 #include <asm/page.h>
 23 #include <asm/mtrr.h>
 24 #include <asm/sections.h>
 25 #include <asm/suspend.h>
 26 #include <asm/tlbflush.h>
 27 
 28 static int set_up_temporary_text_mapping(pgd_t *pgd)
 29 {
 30         pmd_t *pmd;
 31         pud_t *pud;
 32         p4d_t *p4d = NULL;
 33         pgprot_t pgtable_prot = __pgprot(_KERNPG_TABLE);
 34         pgprot_t pmd_text_prot = __pgprot(__PAGE_KERNEL_LARGE_EXEC);
 35 
 36         /* Filter out unsupported __PAGE_KERNEL* bits: */
 37         pgprot_val(pmd_text_prot) &= __default_kernel_pte_mask;
 38         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         if (pgtable_l5_enabled()) {
 55                 p4d = (p4d_t *)get_safe_page(GFP_ATOMIC);
 56                 if (!p4d)
 57                         return -ENOMEM;
 58         }
 59 
 60         pud = (pud_t *)get_safe_page(GFP_ATOMIC);
 61         if (!pud)
 62                 return -ENOMEM;
 63 
 64         pmd = (pmd_t *)get_safe_page(GFP_ATOMIC);
 65         if (!pmd)
 66                 return -ENOMEM;
 67 
 68         set_pmd(pmd + pmd_index(restore_jump_address),
 69                 __pmd((jump_address_phys & PMD_MASK) | pgprot_val(pmd_text_prot)));
 70         set_pud(pud + pud_index(restore_jump_address),
 71                 __pud(__pa(pmd) | pgprot_val(pgtable_prot)));
 72         if (p4d) {
 73                 p4d_t new_p4d = __p4d(__pa(pud) | pgprot_val(pgtable_prot));
 74                 pgd_t new_pgd = __pgd(__pa(p4d) | pgprot_val(pgtable_prot));
 75 
 76                 set_p4d(p4d + p4d_index(restore_jump_address), new_p4d);
 77                 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                 pgd_t new_pgd = __pgd(__pa(pud) | pgprot_val(pgtable_prot));
 81                 set_pgd(pgd + pgd_index(restore_jump_address), new_pgd);
 82         }
 83 
 84         return 0;
 85 }
 86 
 87 static void *alloc_pgt_page(void *context)
 88 {
 89         return (void *)get_safe_page(GFP_ATOMIC);
 90 }
 91 
 92 static int set_up_temporary_mappings(void)
 93 {
 94         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         unsigned long mstart, mend;
100         pgd_t *pgd;
101         int result;
102         int i;
103 
104         pgd = (pgd_t *)get_safe_page(GFP_ATOMIC);
105         if (!pgd)
106                 return -ENOMEM;
107 
108         /* Prepare a temporary mapping for the kernel text */
109         result = set_up_temporary_text_mapping(pgd);
110         if (result)
111                 return result;
112 
113         /* Set up the direct mapping from scratch */
114         for (i = 0; i < nr_pfn_mapped; i++) {
115                 mstart = pfn_mapped[i].start << PAGE_SHIFT;
116                 mend   = pfn_mapped[i].end << PAGE_SHIFT;
117 
118                 result = kernel_ident_mapping_init(&info, pgd, mstart, mend);
119                 if (result)
120                         return result;
121         }
122 
123         temp_pgt = __pa(pgd);
124         return 0;
125 }
126 
127 asmlinkage int swsusp_arch_resume(void)
128 {
129         int error;
130 
131         /* We have got enough memory and from now on we cannot recover */
132         error = set_up_temporary_mappings();
133         if (error)
134                 return error;
135 
136         error = relocate_restore_code();
137         if (error)
138                 return error;
139 
140         restore_image();
141         return 0;
142 }
143 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php