aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKirill A. Shutemov <kirill.shutemov@linux.intel.com>2018-02-26 13:04:51 -0500
committerIngo Molnar <mingo@kernel.org>2018-03-12 04:37:26 -0400
commite9d0e6330eb81ca49bdd8849cc52b3b0f70ed5cb (patch)
treea449919525b7cbc3b756085b0efccca9f36b78c8
parent32fcefa2bfc8961987e91d1daeb00624b4176d2e (diff)
x86/boot/compressed/64: Prepare new top-level page table for trampoline
If trampoline code would need to switch between 4- and 5-level paging modes, we have to use a page table in trampoline memory. Having it in trampoline memory guarantees that it's below 4G and we can point CR3 to it from 32-bit trampoline code. We only use the page table if the desired paging mode doesn't match the mode we are in. Otherwise the page table is unused and trampoline code wouldn't touch CR3. For 4- to 5-level paging transition, we set up current (4-level paging) CR3 as the first and the only entry in a new top-level page table. For 5- to 4-level paging transition, copy page table pointed by first entry in the current top-level page table as our new top-level page table. If the page table is used by trampoline we would need to copy it to new page table outside trampoline and update CR3 before restoring trampoline memory. Tested-by: Borislav Petkov <bp@suse.de> Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Andy Shevchenko <andy.shevchenko@gmail.com> Cc: Cyrill Gorcunov <gorcunov@openvz.org> Cc: Eric Biederman <ebiederm@xmission.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Juergen Gross <jgross@suse.com> Cc: Kees Cook <keescook@chromium.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Matthew Wilcox <willy@infradead.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: linux-mm@kvack.org Link: http://lkml.kernel.org/r/20180226180451.86788-6-kirill.shutemov@linux.intel.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/boot/compressed/pgtable_64.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/arch/x86/boot/compressed/pgtable_64.c b/arch/x86/boot/compressed/pgtable_64.c
index 810c2c32d98e..32af1cbcd903 100644
--- a/arch/x86/boot/compressed/pgtable_64.c
+++ b/arch/x86/boot/compressed/pgtable_64.c
@@ -23,6 +23,14 @@ struct paging_config {
23static char trampoline_save[TRAMPOLINE_32BIT_SIZE]; 23static char trampoline_save[TRAMPOLINE_32BIT_SIZE];
24 24
25/* 25/*
26 * The page table is going to be used instead of page table in the trampoline
27 * memory.
28 *
29 * It must not be in BSS as BSS is cleared after cleanup_trampoline().
30 */
31static char top_pgtable[PAGE_SIZE] __aligned(PAGE_SIZE) __section(.data);
32
33/*
26 * Trampoline address will be printed by extract_kernel() for debugging 34 * Trampoline address will be printed by extract_kernel() for debugging
27 * purposes. 35 * purposes.
28 * 36 *
@@ -83,11 +91,64 @@ struct paging_config paging_prepare(void)
83 memcpy(trampoline_32bit + TRAMPOLINE_32BIT_CODE_OFFSET / sizeof(unsigned long), 91 memcpy(trampoline_32bit + TRAMPOLINE_32BIT_CODE_OFFSET / sizeof(unsigned long),
84 &trampoline_32bit_src, TRAMPOLINE_32BIT_CODE_SIZE); 92 &trampoline_32bit_src, TRAMPOLINE_32BIT_CODE_SIZE);
85 93
94 /*
95 * The code below prepares page table in trampoline memory.
96 *
97 * The new page table will be used by trampoline code for switching
98 * from 4- to 5-level paging or vice versa.
99 *
100 * If switching is not required, the page table is unused: trampoline
101 * code wouldn't touch CR3.
102 */
103
104 /*
105 * We are not going to use the page table in trampoline memory if we
106 * are already in the desired paging mode.
107 */
108 if (paging_config.l5_required == !!(native_read_cr4() & X86_CR4_LA57))
109 goto out;
110
111 if (paging_config.l5_required) {
112 /*
113 * For 4- to 5-level paging transition, set up current CR3 as
114 * the first and the only entry in a new top-level page table.
115 */
116 trampoline_32bit[TRAMPOLINE_32BIT_PGTABLE_OFFSET] = __native_read_cr3() | _PAGE_TABLE_NOENC;
117 } else {
118 unsigned long src;
119
120 /*
121 * For 5- to 4-level paging transition, copy page table pointed
122 * by first entry in the current top-level page table as our
123 * new top-level page table.
124 *
125 * We cannot just point to the page table from trampoline as it
126 * may be above 4G.
127 */
128 src = *(unsigned long *)__native_read_cr3() & PAGE_MASK;
129 memcpy(trampoline_32bit + TRAMPOLINE_32BIT_PGTABLE_OFFSET / sizeof(unsigned long),
130 (void *)src, PAGE_SIZE);
131 }
132
133out:
86 return paging_config; 134 return paging_config;
87} 135}
88 136
89void cleanup_trampoline(void) 137void cleanup_trampoline(void)
90{ 138{
139 void *trampoline_pgtable;
140
141 trampoline_pgtable = trampoline_32bit + TRAMPOLINE_32BIT_PGTABLE_OFFSET;
142
143 /*
144 * Move the top level page table out of trampoline memory,
145 * if it's there.
146 */
147 if ((void *)__native_read_cr3() == trampoline_pgtable) {
148 memcpy(top_pgtable, trampoline_pgtable, PAGE_SIZE);
149 native_write_cr3((unsigned long)top_pgtable);
150 }
151
91 /* Restore trampoline memory */ 152 /* Restore trampoline memory */
92 memcpy(trampoline_32bit, trampoline_save, TRAMPOLINE_32BIT_SIZE); 153 memcpy(trampoline_32bit, trampoline_save, TRAMPOLINE_32BIT_SIZE);
93} 154}