aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/mm/init_64.c
diff options
context:
space:
mode:
authorSuresh Siddha <suresh.b.siddha@intel.com>2008-09-23 17:00:38 -0400
committerIngo Molnar <mingo@elte.hu>2008-10-10 13:29:13 -0400
commita2699e477b8e6b17d4da64916f766dd5a2576c9c (patch)
tree44d9c0840cec212070a94f4097442c7cc7957522 /arch/x86/mm/init_64.c
parent3a85e770aa77e4f1a4096275c97b64c10cd7323e (diff)
x86, cpa: make the kernel physical mapping initialization a two pass sequence
In the first pass, kernel physical mapping will be setup using large or small pages but uses the same PTE attributes as that of the early PTE attributes setup by early boot code in head_[32|64].S After flushing TLB's, we go through the second pass, which setups the direct mapped PTE's with the appropriate attributes (like NX, GLOBAL etc) which are runtime detectable. This two pass mechanism conforms to the TLB app note which says: "Software should not write to a paging-structure entry in a way that would change, for any linear address, both the page size and either the page frame or attributes." Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com> Cc: Suresh Siddha <suresh.b.siddha@intel.com> Cc: arjan@linux.intel.com Cc: venkatesh.pallipadi@intel.com Cc: jeremy@goop.org Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/mm/init_64.c')
-rw-r--r--arch/x86/mm/init_64.c99
1 files changed, 84 insertions, 15 deletions
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index d3746efb060d..1ba945eb6282 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -270,6 +270,8 @@ static __ref void unmap_low_page(void *adr)
270 early_iounmap(adr, PAGE_SIZE); 270 early_iounmap(adr, PAGE_SIZE);
271} 271}
272 272
273static int physical_mapping_iter;
274
273static unsigned long __meminit 275static unsigned long __meminit
274phys_pte_init(pte_t *pte_page, unsigned long addr, unsigned long end) 276phys_pte_init(pte_t *pte_page, unsigned long addr, unsigned long end)
275{ 277{
@@ -290,16 +292,19 @@ phys_pte_init(pte_t *pte_page, unsigned long addr, unsigned long end)
290 } 292 }
291 293
292 if (pte_val(*pte)) 294 if (pte_val(*pte))
293 continue; 295 goto repeat_set_pte;
294 296
295 if (0) 297 if (0)
296 printk(" pte=%p addr=%lx pte=%016lx\n", 298 printk(" pte=%p addr=%lx pte=%016lx\n",
297 pte, addr, pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL).pte); 299 pte, addr, pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL).pte);
300 pages++;
301repeat_set_pte:
298 set_pte(pte, pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL)); 302 set_pte(pte, pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL));
299 last_map_addr = (addr & PAGE_MASK) + PAGE_SIZE; 303 last_map_addr = (addr & PAGE_MASK) + PAGE_SIZE;
300 pages++;
301 } 304 }
302 update_page_count(PG_LEVEL_4K, pages); 305
306 if (physical_mapping_iter == 1)
307 update_page_count(PG_LEVEL_4K, pages);
303 308
304 return last_map_addr; 309 return last_map_addr;
305} 310}
@@ -318,7 +323,6 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
318{ 323{
319 unsigned long pages = 0; 324 unsigned long pages = 0;
320 unsigned long last_map_addr = end; 325 unsigned long last_map_addr = end;
321 unsigned long start = address;
322 326
323 int i = pmd_index(address); 327 int i = pmd_index(address);
324 328
@@ -341,15 +345,14 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
341 last_map_addr = phys_pte_update(pmd, address, 345 last_map_addr = phys_pte_update(pmd, address,
342 end); 346 end);
343 spin_unlock(&init_mm.page_table_lock); 347 spin_unlock(&init_mm.page_table_lock);
348 continue;
344 } 349 }
345 /* Count entries we're using from level2_ident_pgt */ 350 goto repeat_set_pte;
346 if (start == 0)
347 pages++;
348 continue;
349 } 351 }
350 352
351 if (page_size_mask & (1<<PG_LEVEL_2M)) { 353 if (page_size_mask & (1<<PG_LEVEL_2M)) {
352 pages++; 354 pages++;
355repeat_set_pte:
353 spin_lock(&init_mm.page_table_lock); 356 spin_lock(&init_mm.page_table_lock);
354 set_pte((pte_t *)pmd, 357 set_pte((pte_t *)pmd,
355 pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL_LARGE)); 358 pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL_LARGE));
@@ -366,7 +369,8 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
366 pmd_populate_kernel(&init_mm, pmd, __va(pte_phys)); 369 pmd_populate_kernel(&init_mm, pmd, __va(pte_phys));
367 spin_unlock(&init_mm.page_table_lock); 370 spin_unlock(&init_mm.page_table_lock);
368 } 371 }
369 update_page_count(PG_LEVEL_2M, pages); 372 if (physical_mapping_iter == 1)
373 update_page_count(PG_LEVEL_2M, pages);
370 return last_map_addr; 374 return last_map_addr;
371} 375}
372 376
@@ -405,14 +409,18 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,
405 } 409 }
406 410
407 if (pud_val(*pud)) { 411 if (pud_val(*pud)) {
408 if (!pud_large(*pud)) 412 if (!pud_large(*pud)) {
409 last_map_addr = phys_pmd_update(pud, addr, end, 413 last_map_addr = phys_pmd_update(pud, addr, end,
410 page_size_mask); 414 page_size_mask);
411 continue; 415 continue;
416 }
417
418 goto repeat_set_pte;
412 } 419 }
413 420
414 if (page_size_mask & (1<<PG_LEVEL_1G)) { 421 if (page_size_mask & (1<<PG_LEVEL_1G)) {
415 pages++; 422 pages++;
423repeat_set_pte:
416 spin_lock(&init_mm.page_table_lock); 424 spin_lock(&init_mm.page_table_lock);
417 set_pte((pte_t *)pud, 425 set_pte((pte_t *)pud,
418 pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL_LARGE)); 426 pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL_LARGE));
@@ -430,7 +438,9 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,
430 spin_unlock(&init_mm.page_table_lock); 438 spin_unlock(&init_mm.page_table_lock);
431 } 439 }
432 __flush_tlb_all(); 440 __flush_tlb_all();
433 update_page_count(PG_LEVEL_1G, pages); 441
442 if (physical_mapping_iter == 1)
443 update_page_count(PG_LEVEL_1G, pages);
434 444
435 return last_map_addr; 445 return last_map_addr;
436} 446}
@@ -494,15 +504,54 @@ static void __init init_gbpages(void)
494 direct_gbpages = 0; 504 direct_gbpages = 0;
495} 505}
496 506
507static int is_kernel(unsigned long pfn)
508{
509 unsigned long pg_addresss = pfn << PAGE_SHIFT;
510
511 if (pg_addresss >= (unsigned long) __pa(_text) &&
512 pg_addresss <= (unsigned long) __pa(_end))
513 return 1;
514
515 return 0;
516}
517
497static unsigned long __init kernel_physical_mapping_init(unsigned long start, 518static unsigned long __init kernel_physical_mapping_init(unsigned long start,
498 unsigned long end, 519 unsigned long end,
499 unsigned long page_size_mask) 520 unsigned long page_size_mask)
500{ 521{
501 522
502 unsigned long next, last_map_addr = end; 523 unsigned long next, last_map_addr;
524 u64 cached_supported_pte_mask = __supported_pte_mask;
525 unsigned long cache_start = start;
526 unsigned long cache_end = end;
527
528 /*
529 * First iteration will setup identity mapping using large/small pages
530 * based on page_size_mask, with other attributes same as set by
531 * the early code in head_64.S
532 *
533 * Second iteration will setup the appropriate attributes
534 * as desired for the kernel identity mapping.
535 *
536 * This two pass mechanism conforms to the TLB app note which says:
537 *
538 * "Software should not write to a paging-structure entry in a way
539 * that would change, for any linear address, both the page size
540 * and either the page frame or attributes."
541 *
542 * For now, only difference between very early PTE attributes used in
543 * head_64.S and here is _PAGE_NX.
544 */
545 BUILD_BUG_ON((__PAGE_KERNEL_LARGE & ~__PAGE_KERNEL_IDENT_LARGE_EXEC)
546 != _PAGE_NX);
547 __supported_pte_mask &= ~(_PAGE_NX);
548 physical_mapping_iter = 1;
503 549
504 start = (unsigned long)__va(start); 550repeat:
505 end = (unsigned long)__va(end); 551 last_map_addr = cache_end;
552
553 start = (unsigned long)__va(cache_start);
554 end = (unsigned long)__va(cache_end);
506 555
507 for (; start < end; start = next) { 556 for (; start < end; start = next) {
508 pgd_t *pgd = pgd_offset_k(start); 557 pgd_t *pgd = pgd_offset_k(start);
@@ -514,11 +563,21 @@ static unsigned long __init kernel_physical_mapping_init(unsigned long start,
514 next = end; 563 next = end;
515 564
516 if (pgd_val(*pgd)) { 565 if (pgd_val(*pgd)) {
566 /*
567 * Static identity mappings will be overwritten
568 * with run-time mappings. For example, this allows
569 * the static 0-1GB identity mapping to be mapped
570 * non-executable with this.
571 */
572 if (is_kernel(pte_pfn(*((pte_t *) pgd))))
573 goto realloc;
574
517 last_map_addr = phys_pud_update(pgd, __pa(start), 575 last_map_addr = phys_pud_update(pgd, __pa(start),
518 __pa(end), page_size_mask); 576 __pa(end), page_size_mask);
519 continue; 577 continue;
520 } 578 }
521 579
580realloc:
522 pud = alloc_low_page(&pud_phys); 581 pud = alloc_low_page(&pud_phys);
523 last_map_addr = phys_pud_init(pud, __pa(start), __pa(next), 582 last_map_addr = phys_pud_init(pud, __pa(start), __pa(next),
524 page_size_mask); 583 page_size_mask);
@@ -528,6 +587,16 @@ static unsigned long __init kernel_physical_mapping_init(unsigned long start,
528 pgd_populate(&init_mm, pgd, __va(pud_phys)); 587 pgd_populate(&init_mm, pgd, __va(pud_phys));
529 spin_unlock(&init_mm.page_table_lock); 588 spin_unlock(&init_mm.page_table_lock);
530 } 589 }
590 __flush_tlb_all();
591
592 if (physical_mapping_iter == 1) {
593 physical_mapping_iter = 2;
594 /*
595 * Second iteration will set the actual desired PTE attributes.
596 */
597 __supported_pte_mask = cached_supported_pte_mask;
598 goto repeat;
599 }
531 600
532 return last_map_addr; 601 return last_map_addr;
533} 602}