aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBoris Ostrovsky <boris.ostrovsky@oracle.com>2017-02-03 16:57:22 -0500
committerBoris Ostrovsky <boris.ostrovsky@oracle.com>2017-02-07 08:07:01 -0500
commit5a7670ee23f2c07a639c263b70140eaf1da9f68f (patch)
treec757539174ba4cde79f9d2eb1ae6e17da531ef50
parent4fed1b125eb6252bde478665fc05d4819f774fa8 (diff)
x86/boot/32: Convert the 32-bit pgtable setup code from assembly to C
The new Xen PVH entry point requires page tables to be setup by the kernel since it is entered with paging disabled. Pull the common code out of head_32.S so that mk_early_pgtbl_32() can be invoked from both the new Xen entry point and the existing startup_32() code. Convert resulting common code to C. Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com> Cc: Andy Lutomirski <luto@kernel.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Brian Gerst <brgerst@gmail.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: matt@codeblueprint.co.uk Cc: xen-devel@lists.xenproject.org Link: http://lkml.kernel.org/r/1481215471-9639-1-git-send-email-boris.ostrovsky@oracle.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/include/asm/pgtable_32.h32
-rw-r--r--arch/x86/kernel/head32.c62
-rw-r--r--arch/x86/kernel/head_32.S121
3 files changed, 101 insertions, 114 deletions
diff --git a/arch/x86/include/asm/pgtable_32.h b/arch/x86/include/asm/pgtable_32.h
index b6c0b404898a..fbc73360aea0 100644
--- a/arch/x86/include/asm/pgtable_32.h
+++ b/arch/x86/include/asm/pgtable_32.h
@@ -27,6 +27,7 @@ struct vm_area_struct;
27 27
28extern pgd_t swapper_pg_dir[1024]; 28extern pgd_t swapper_pg_dir[1024];
29extern pgd_t initial_page_table[1024]; 29extern pgd_t initial_page_table[1024];
30extern pmd_t initial_pg_pmd[];
30 31
31static inline void pgtable_cache_init(void) { } 32static inline void pgtable_cache_init(void) { }
32static inline void check_pgt_cache(void) { } 33static inline void check_pgt_cache(void) { }
@@ -75,4 +76,35 @@ do { \
75#define kern_addr_valid(kaddr) (0) 76#define kern_addr_valid(kaddr) (0)
76#endif 77#endif
77 78
79/*
80 * This is how much memory in addition to the memory covered up to
81 * and including _end we need mapped initially.
82 * We need:
83 * (KERNEL_IMAGE_SIZE/4096) / 1024 pages (worst case, non PAE)
84 * (KERNEL_IMAGE_SIZE/4096) / 512 + 4 pages (worst case for PAE)
85 *
86 * Modulo rounding, each megabyte assigned here requires a kilobyte of
87 * memory, which is currently unreclaimed.
88 *
89 * This should be a multiple of a page.
90 *
91 * KERNEL_IMAGE_SIZE should be greater than pa(_end)
92 * and small than max_low_pfn, otherwise will waste some page table entries
93 */
94#if PTRS_PER_PMD > 1
95#define PAGE_TABLE_SIZE(pages) (((pages) / PTRS_PER_PMD) + PTRS_PER_PGD)
96#else
97#define PAGE_TABLE_SIZE(pages) ((pages) / PTRS_PER_PGD)
98#endif
99
100/*
101 * Number of possible pages in the lowmem region.
102 *
103 * We shift 2 by 31 instead of 1 by 32 to the left in order to avoid a
104 * gas warning about overflowing shift count when gas has been compiled
105 * with only a host target support using a 32-bit type for internal
106 * representation.
107 */
108#define LOWMEM_PAGES ((((2<<31) - __PAGE_OFFSET) >> PAGE_SHIFT))
109
78#endif /* _ASM_X86_PGTABLE_32_H */ 110#endif /* _ASM_X86_PGTABLE_32_H */
diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c
index f16c55bfc090..e5fb436a6548 100644
--- a/arch/x86/kernel/head32.c
+++ b/arch/x86/kernel/head32.c
@@ -49,3 +49,65 @@ asmlinkage __visible void __init i386_start_kernel(void)
49 49
50 start_kernel(); 50 start_kernel();
51} 51}
52
53/*
54 * Initialize page tables. This creates a PDE and a set of page
55 * tables, which are located immediately beyond __brk_base. The variable
56 * _brk_end is set up to point to the first "safe" location.
57 * Mappings are created both at virtual address 0 (identity mapping)
58 * and PAGE_OFFSET for up to _end.
59 *
60 * In PAE mode initial_page_table is statically defined to contain
61 * enough entries to cover the VMSPLIT option (that is the top 1, 2 or 3
62 * entries). The identity mapping is handled by pointing two PGD entries
63 * to the first kernel PMD. Note the upper half of each PMD or PTE are
64 * always zero at this stage.
65 */
66void __init mk_early_pgtbl_32(void)
67{
68#ifdef __pa
69#undef __pa
70#endif
71#define __pa(x) ((unsigned long)(x) - PAGE_OFFSET)
72 pte_t pte, *ptep;
73 int i;
74 unsigned long *ptr;
75 /* Enough space to fit pagetables for the low memory linear map */
76 const unsigned long limit = __pa(_end) +
77 (PAGE_TABLE_SIZE(LOWMEM_PAGES) << PAGE_SHIFT);
78#ifdef CONFIG_X86_PAE
79 pmd_t pl2, *pl2p = (pmd_t *)__pa(initial_pg_pmd);
80#define SET_PL2(pl2, val) { (pl2).pmd = (val); }
81#else
82 pgd_t pl2, *pl2p = (pgd_t *)__pa(initial_page_table);
83#define SET_PL2(pl2, val) { (pl2).pgd = (val); }
84#endif
85
86 ptep = (pte_t *)__pa(__brk_base);
87 pte.pte = PTE_IDENT_ATTR;
88
89 while ((pte.pte & PTE_PFN_MASK) < limit) {
90
91 SET_PL2(pl2, (unsigned long)ptep | PDE_IDENT_ATTR);
92 *pl2p = pl2;
93#ifndef CONFIG_X86_PAE
94 /* Kernel PDE entry */
95 *(pl2p + ((PAGE_OFFSET >> PGDIR_SHIFT))) = pl2;
96#endif
97 for (i = 0; i < PTRS_PER_PTE; i++) {
98 *ptep = pte;
99 pte.pte += PAGE_SIZE;
100 ptep++;
101 }
102
103 pl2p++;
104 }
105
106 ptr = (unsigned long *)__pa(&max_pfn_mapped);
107 /* Can't use pte_pfn() since it's a call with CONFIG_PARAVIRT */
108 *ptr = (pte.pte & PTE_PFN_MASK) >> PAGE_SHIFT;
109
110 ptr = (unsigned long *)__pa(&_brk_end);
111 *ptr = (unsigned long)ptep + PAGE_OFFSET;
112}
113
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index 4e8577d03372..1f85ee8f9439 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -24,6 +24,7 @@
24#include <asm/nops.h> 24#include <asm/nops.h>
25#include <asm/bootparam.h> 25#include <asm/bootparam.h>
26#include <asm/export.h> 26#include <asm/export.h>
27#include <asm/pgtable_32.h>
27 28
28/* Physical address */ 29/* Physical address */
29#define pa(X) ((X) - __PAGE_OFFSET) 30#define pa(X) ((X) - __PAGE_OFFSET)
@@ -41,44 +42,10 @@
41#define X86_CAPABILITY new_cpu_data+CPUINFO_x86_capability 42#define X86_CAPABILITY new_cpu_data+CPUINFO_x86_capability
42#define X86_VENDOR_ID new_cpu_data+CPUINFO_x86_vendor_id 43#define X86_VENDOR_ID new_cpu_data+CPUINFO_x86_vendor_id
43 44
44/*
45 * This is how much memory in addition to the memory covered up to
46 * and including _end we need mapped initially.
47 * We need:
48 * (KERNEL_IMAGE_SIZE/4096) / 1024 pages (worst case, non PAE)
49 * (KERNEL_IMAGE_SIZE/4096) / 512 + 4 pages (worst case for PAE)
50 *
51 * Modulo rounding, each megabyte assigned here requires a kilobyte of
52 * memory, which is currently unreclaimed.
53 *
54 * This should be a multiple of a page.
55 *
56 * KERNEL_IMAGE_SIZE should be greater than pa(_end)
57 * and small than max_low_pfn, otherwise will waste some page table entries
58 */
59
60#if PTRS_PER_PMD > 1
61#define PAGE_TABLE_SIZE(pages) (((pages) / PTRS_PER_PMD) + PTRS_PER_PGD)
62#else
63#define PAGE_TABLE_SIZE(pages) ((pages) / PTRS_PER_PGD)
64#endif
65 45
66#define SIZEOF_PTREGS 17*4 46#define SIZEOF_PTREGS 17*4
67 47
68/* 48/*
69 * Number of possible pages in the lowmem region.
70 *
71 * We shift 2 by 31 instead of 1 by 32 to the left in order to avoid a
72 * gas warning about overflowing shift count when gas has been compiled
73 * with only a host target support using a 32-bit type for internal
74 * representation.
75 */
76LOWMEM_PAGES = (((2<<31) - __PAGE_OFFSET) >> PAGE_SHIFT)
77
78/* Enough space to fit pagetables for the low memory linear map */
79MAPPING_BEYOND_END = PAGE_TABLE_SIZE(LOWMEM_PAGES) << PAGE_SHIFT
80
81/*
82 * Worst-case size of the kernel mapping we need to make: 49 * Worst-case size of the kernel mapping we need to make:
83 * a relocatable kernel can live anywhere in lowmem, so we need to be able 50 * a relocatable kernel can live anywhere in lowmem, so we need to be able
84 * to map all of lowmem. 51 * to map all of lowmem.
@@ -160,90 +127,15 @@ ENTRY(startup_32)
160 call load_ucode_bsp 127 call load_ucode_bsp
161#endif 128#endif
162 129
163/* 130 /* Create early pagetables. */
164 * Initialize page tables. This creates a PDE and a set of page 131 call mk_early_pgtbl_32
165 * tables, which are located immediately beyond __brk_base. The variable
166 * _brk_end is set up to point to the first "safe" location.
167 * Mappings are created both at virtual address 0 (identity mapping)
168 * and PAGE_OFFSET for up to _end.
169 */
170#ifdef CONFIG_X86_PAE
171
172 /*
173 * In PAE mode initial_page_table is statically defined to contain
174 * enough entries to cover the VMSPLIT option (that is the top 1, 2 or 3
175 * entries). The identity mapping is handled by pointing two PGD entries
176 * to the first kernel PMD.
177 *
178 * Note the upper half of each PMD or PTE are always zero at this stage.
179 */
180
181#define KPMDS (((-__PAGE_OFFSET) >> 30) & 3) /* Number of kernel PMDs */
182
183 xorl %ebx,%ebx /* %ebx is kept at zero */
184
185 movl $pa(__brk_base), %edi
186 movl $pa(initial_pg_pmd), %edx
187 movl $PTE_IDENT_ATTR, %eax
18810:
189 leal PDE_IDENT_ATTR(%edi),%ecx /* Create PMD entry */
190 movl %ecx,(%edx) /* Store PMD entry */
191 /* Upper half already zero */
192 addl $8,%edx
193 movl $512,%ecx
19411:
195 stosl
196 xchgl %eax,%ebx
197 stosl
198 xchgl %eax,%ebx
199 addl $0x1000,%eax
200 loop 11b
201
202 /*
203 * End condition: we must map up to the end + MAPPING_BEYOND_END.
204 */
205 movl $pa(_end) + MAPPING_BEYOND_END + PTE_IDENT_ATTR, %ebp
206 cmpl %ebp,%eax
207 jb 10b
2081:
209 addl $__PAGE_OFFSET, %edi
210 movl %edi, pa(_brk_end)
211 shrl $12, %eax
212 movl %eax, pa(max_pfn_mapped)
213 132
214 /* Do early initialization of the fixmap area */ 133 /* Do early initialization of the fixmap area */
215 movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,%eax 134 movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,%eax
135#ifdef CONFIG_X86_PAE
136#define KPMDS (((-__PAGE_OFFSET) >> 30) & 3) /* Number of kernel PMDs */
216 movl %eax,pa(initial_pg_pmd+0x1000*KPMDS-8) 137 movl %eax,pa(initial_pg_pmd+0x1000*KPMDS-8)
217#else /* Not PAE */ 138#else
218
219page_pde_offset = (__PAGE_OFFSET >> 20);
220
221 movl $pa(__brk_base), %edi
222 movl $pa(initial_page_table), %edx
223 movl $PTE_IDENT_ATTR, %eax
22410:
225 leal PDE_IDENT_ATTR(%edi),%ecx /* Create PDE entry */
226 movl %ecx,(%edx) /* Store identity PDE entry */
227 movl %ecx,page_pde_offset(%edx) /* Store kernel PDE entry */
228 addl $4,%edx
229 movl $1024, %ecx
23011:
231 stosl
232 addl $0x1000,%eax
233 loop 11b
234 /*
235 * End condition: we must map up to the end + MAPPING_BEYOND_END.
236 */
237 movl $pa(_end) + MAPPING_BEYOND_END + PTE_IDENT_ATTR, %ebp
238 cmpl %ebp,%eax
239 jb 10b
240 addl $__PAGE_OFFSET, %edi
241 movl %edi, pa(_brk_end)
242 shrl $12, %eax
243 movl %eax, pa(max_pfn_mapped)
244
245 /* Do early initialization of the fixmap area */
246 movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,%eax
247 movl %eax,pa(initial_page_table+0xffc) 139 movl %eax,pa(initial_page_table+0xffc)
248#endif 140#endif
249 141
@@ -666,6 +558,7 @@ ENTRY(setup_once_ref)
666__PAGE_ALIGNED_BSS 558__PAGE_ALIGNED_BSS
667 .align PAGE_SIZE 559 .align PAGE_SIZE
668#ifdef CONFIG_X86_PAE 560#ifdef CONFIG_X86_PAE
561.globl initial_pg_pmd
669initial_pg_pmd: 562initial_pg_pmd:
670 .fill 1024*KPMDS,4,0 563 .fill 1024*KPMDS,4,0
671#else 564#else