diff options
author | Boris Ostrovsky <boris.ostrovsky@oracle.com> | 2017-02-03 16:57:22 -0500 |
---|---|---|
committer | Boris Ostrovsky <boris.ostrovsky@oracle.com> | 2017-02-07 08:07:01 -0500 |
commit | 5a7670ee23f2c07a639c263b70140eaf1da9f68f (patch) | |
tree | c757539174ba4cde79f9d2eb1ae6e17da531ef50 | |
parent | 4fed1b125eb6252bde478665fc05d4819f774fa8 (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.h | 32 | ||||
-rw-r--r-- | arch/x86/kernel/head32.c | 62 | ||||
-rw-r--r-- | arch/x86/kernel/head_32.S | 121 |
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 | ||
28 | extern pgd_t swapper_pg_dir[1024]; | 28 | extern pgd_t swapper_pg_dir[1024]; |
29 | extern pgd_t initial_page_table[1024]; | 29 | extern pgd_t initial_page_table[1024]; |
30 | extern pmd_t initial_pg_pmd[]; | ||
30 | 31 | ||
31 | static inline void pgtable_cache_init(void) { } | 32 | static inline void pgtable_cache_init(void) { } |
32 | static inline void check_pgt_cache(void) { } | 33 | static 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 | */ | ||
66 | void __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 | */ | ||
76 | LOWMEM_PAGES = (((2<<31) - __PAGE_OFFSET) >> PAGE_SHIFT) | ||
77 | |||
78 | /* Enough space to fit pagetables for the low memory linear map */ | ||
79 | MAPPING_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 | ||
188 | 10: | ||
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 | ||
194 | 11: | ||
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 | ||
208 | 1: | ||
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 | |||
219 | page_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 | ||
224 | 10: | ||
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 | ||
230 | 11: | ||
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 | ||
669 | initial_pg_pmd: | 562 | initial_pg_pmd: |
670 | .fill 1024*KPMDS,4,0 | 563 | .fill 1024*KPMDS,4,0 |
671 | #else | 564 | #else |