aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKirill A. Shutemov <kirill.shutemov@linux.intel.com>2017-06-06 07:31:26 -0400
committerIngo Molnar <mingo@kernel.org>2017-06-13 02:56:54 -0400
commitc88d71508e36b514413464bd2e01f96f34583a0e (patch)
treec9200c17794c779470adc6a0c664e3a3e2079d75
parent34bbb0009f3b7a5eef1ab34f14e5dbf7b8fc389c (diff)
x86/boot/64: Rewrite startup_64() in C
The patch write most of startup_64 logic in C. This is preparation for 5-level paging enabling. Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Andy Lutomirski <luto@kernel.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Brian Gerst <brgerst@gmail.com> Cc: Dave Hansen <dave.hansen@intel.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: linux-arch@vger.kernel.org Cc: linux-mm@kvack.org Link: http://lkml.kernel.org/r/20170606113133.22974-8-kirill.shutemov@linux.intel.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/kernel/head64.c85
-rw-r--r--arch/x86/kernel/head_64.S95
2 files changed, 87 insertions, 93 deletions
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index 794e8f517a81..1f2a499929c3 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -35,9 +35,92 @@
35 */ 35 */
36extern pgd_t early_level4_pgt[PTRS_PER_PGD]; 36extern pgd_t early_level4_pgt[PTRS_PER_PGD];
37extern pmd_t early_dynamic_pgts[EARLY_DYNAMIC_PAGE_TABLES][PTRS_PER_PMD]; 37extern pmd_t early_dynamic_pgts[EARLY_DYNAMIC_PAGE_TABLES][PTRS_PER_PMD];
38static unsigned int __initdata next_early_pgt = 2; 38static unsigned int __initdata next_early_pgt;
39pmdval_t early_pmd_flags = __PAGE_KERNEL_LARGE & ~(_PAGE_GLOBAL | _PAGE_NX); 39pmdval_t early_pmd_flags = __PAGE_KERNEL_LARGE & ~(_PAGE_GLOBAL | _PAGE_NX);
40 40
41static void __init *fixup_pointer(void *ptr, unsigned long physaddr)
42{
43 return ptr - (void *)_text + (void *)physaddr;
44}
45
46void __init __startup_64(unsigned long physaddr)
47{
48 unsigned long load_delta, *p;
49 pgdval_t *pgd;
50 pudval_t *pud;
51 pmdval_t *pmd, pmd_entry;
52 int i;
53
54 /* Is the address too large? */
55 if (physaddr >> MAX_PHYSMEM_BITS)
56 for (;;);
57
58 /*
59 * Compute the delta between the address I am compiled to run at
60 * and the address I am actually running at.
61 */
62 load_delta = physaddr - (unsigned long)(_text - __START_KERNEL_map);
63
64 /* Is the address not 2M aligned? */
65 if (load_delta & ~PMD_PAGE_MASK)
66 for (;;);
67
68 /* Fixup the physical addresses in the page table */
69
70 pgd = fixup_pointer(&early_level4_pgt, physaddr);
71 pgd[pgd_index(__START_KERNEL_map)] += load_delta;
72
73 pud = fixup_pointer(&level3_kernel_pgt, physaddr);
74 pud[510] += load_delta;
75 pud[511] += load_delta;
76
77 pmd = fixup_pointer(level2_fixmap_pgt, physaddr);
78 pmd[506] += load_delta;
79
80 /*
81 * Set up the identity mapping for the switchover. These
82 * entries should *NOT* have the global bit set! This also
83 * creates a bunch of nonsense entries but that is fine --
84 * it avoids problems around wraparound.
85 */
86
87 pud = fixup_pointer(early_dynamic_pgts[next_early_pgt++], physaddr);
88 pmd = fixup_pointer(early_dynamic_pgts[next_early_pgt++], physaddr);
89
90 i = (physaddr >> PGDIR_SHIFT) % PTRS_PER_PGD;
91 pgd[i + 0] = (pgdval_t)pud + _KERNPG_TABLE;
92 pgd[i + 1] = (pgdval_t)pud + _KERNPG_TABLE;
93
94 i = (physaddr >> PUD_SHIFT) % PTRS_PER_PUD;
95 pud[i + 0] = (pudval_t)pmd + _KERNPG_TABLE;
96 pud[i + 1] = (pudval_t)pmd + _KERNPG_TABLE;
97
98 pmd_entry = __PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL;
99 pmd_entry += physaddr;
100
101 for (i = 0; i < DIV_ROUND_UP(_end - _text, PMD_SIZE); i++) {
102 int idx = i + (physaddr >> PMD_SHIFT) % PTRS_PER_PMD;
103 pmd[idx] = pmd_entry + i * PMD_SIZE;
104 }
105
106 /*
107 * Fixup the kernel text+data virtual addresses. Note that
108 * we might write invalid pmds, when the kernel is relocated
109 * cleanup_highmap() fixes this up along with the mappings
110 * beyond _end.
111 */
112
113 pmd = fixup_pointer(level2_kernel_pgt, physaddr);
114 for (i = 0; i < PTRS_PER_PMD; i++) {
115 if (pmd[i] & _PAGE_PRESENT)
116 pmd[i] += load_delta;
117 }
118
119 /* Fixup phys_base */
120 p = fixup_pointer(&phys_base, physaddr);
121 *p += load_delta;
122}
123
41/* Wipe all early page tables except for the kernel symbol map */ 124/* Wipe all early page tables except for the kernel symbol map */
42static void __init reset_early_page_tables(void) 125static void __init reset_early_page_tables(void)
43{ 126{
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index ac9d327d2e42..1432d530fa35 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -72,100 +72,11 @@ startup_64:
72 /* Sanitize CPU configuration */ 72 /* Sanitize CPU configuration */
73 call verify_cpu 73 call verify_cpu
74 74
75 /*
76 * Compute the delta between the address I am compiled to run at and the
77 * address I am actually running at.
78 */
79 leaq _text(%rip), %rbp
80 subq $_text - __START_KERNEL_map, %rbp
81
82 /* Is the address not 2M aligned? */
83 testl $~PMD_PAGE_MASK, %ebp
84 jnz bad_address
85
86 /*
87 * Is the address too large?
88 */
89 leaq _text(%rip), %rax
90 shrq $MAX_PHYSMEM_BITS, %rax
91 jnz bad_address
92
93 /*
94 * Fixup the physical addresses in the page table
95 */
96 addq %rbp, early_level4_pgt + (L4_START_KERNEL*8)(%rip)
97
98 addq %rbp, level3_kernel_pgt + (510*8)(%rip)
99 addq %rbp, level3_kernel_pgt + (511*8)(%rip)
100
101 addq %rbp, level2_fixmap_pgt + (506*8)(%rip)
102
103 /*
104 * Set up the identity mapping for the switchover. These
105 * entries should *NOT* have the global bit set! This also
106 * creates a bunch of nonsense entries but that is fine --
107 * it avoids problems around wraparound.
108 */
109 leaq _text(%rip), %rdi 75 leaq _text(%rip), %rdi
110 leaq early_level4_pgt(%rip), %rbx 76 pushq %rsi
111 77 call __startup_64
112 movq %rdi, %rax 78 popq %rsi
113 shrq $PGDIR_SHIFT, %rax
114
115 leaq (PAGE_SIZE + _KERNPG_TABLE)(%rbx), %rdx
116 movq %rdx, 0(%rbx,%rax,8)
117 movq %rdx, 8(%rbx,%rax,8)
118
119 addq $PAGE_SIZE, %rdx
120 movq %rdi, %rax
121 shrq $PUD_SHIFT, %rax
122 andl $(PTRS_PER_PUD-1), %eax
123 movq %rdx, PAGE_SIZE(%rbx,%rax,8)
124 incl %eax
125 andl $(PTRS_PER_PUD-1), %eax
126 movq %rdx, PAGE_SIZE(%rbx,%rax,8)
127
128 addq $PAGE_SIZE * 2, %rbx
129 movq %rdi, %rax
130 shrq $PMD_SHIFT, %rdi
131 addq $(__PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL), %rax
132 leaq (_end - 1)(%rip), %rcx
133 shrq $PMD_SHIFT, %rcx
134 subq %rdi, %rcx
135 incl %ecx
136 79
1371:
138 andq $(PTRS_PER_PMD - 1), %rdi
139 movq %rax, (%rbx,%rdi,8)
140 incq %rdi
141 addq $PMD_SIZE, %rax
142 decl %ecx
143 jnz 1b
144
145 test %rbp, %rbp
146 jz .Lskip_fixup
147
148 /*
149 * Fixup the kernel text+data virtual addresses. Note that
150 * we might write invalid pmds, when the kernel is relocated
151 * cleanup_highmap() fixes this up along with the mappings
152 * beyond _end.
153 */
154 leaq level2_kernel_pgt(%rip), %rdi
155 leaq PAGE_SIZE(%rdi), %r8
156 /* See if it is a valid page table entry */
1571: testb $_PAGE_PRESENT, 0(%rdi)
158 jz 2f
159 addq %rbp, 0(%rdi)
160 /* Go to the next page */
1612: addq $8, %rdi
162 cmp %r8, %rdi
163 jne 1b
164
165 /* Fixup phys_base */
166 addq %rbp, phys_base(%rip)
167
168.Lskip_fixup:
169 movq $(early_level4_pgt - __START_KERNEL_map), %rax 80 movq $(early_level4_pgt - __START_KERNEL_map), %rax
170 jmp 1f 81 jmp 1f
171ENTRY(secondary_startup_64) 82ENTRY(secondary_startup_64)