aboutsummaryrefslogtreecommitdiffstats
path: root/arch/parisc/mm
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@HansenPartnership.com>2011-04-14 19:25:21 -0400
committerJames Bottomley <James.Bottomley@suse.de>2011-04-15 13:55:18 -0400
commitd7dd2ff11b7fcd425aca5a875983c862d19a67ae (patch)
tree6ad74d89d2355861b513eefb763ea6103a8d68e7 /arch/parisc/mm
parente38f5b745075828ac51b12c8c95c85a7be4a3ec7 (diff)
[PARISC] only make executable areas executable
Currently parisc has the whole kernel marked as RWX, meaning any kernel page at all is eligible to be executed. This can cause a theoretical problem on systems with combined I/D TLB because the act of referencing a page causes a TLB insertion with an executable bit. This TLB entry may be used by the CPU as the basis for speculating the page into the I-Cache. If this speculated page is subsequently used for a user process, there is the possibility we will get a stale I-cache line picked up as the binary executes. As a point of good practise, only mark actual kernel text pages as executable. The same has to be done for init_text pages, but they're converted to data pages (and the I-Cache flushed) when the init memory is released. Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'arch/parisc/mm')
-rw-r--r--arch/parisc/mm/init.c260
1 files changed, 143 insertions, 117 deletions
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
index b7ed8d7a9b33..7e6b4656f3d7 100644
--- a/arch/parisc/mm/init.c
+++ b/arch/parisc/mm/init.c
@@ -369,24 +369,158 @@ static void __init setup_bootmem(void)
369 request_resource(&sysram_resources[0], &pdcdata_resource); 369 request_resource(&sysram_resources[0], &pdcdata_resource);
370} 370}
371 371
372static void __init map_pages(unsigned long start_vaddr,
373 unsigned long start_paddr, unsigned long size,
374 pgprot_t pgprot, int force)
375{
376 pgd_t *pg_dir;
377 pmd_t *pmd;
378 pte_t *pg_table;
379 unsigned long end_paddr;
380 unsigned long start_pmd;
381 unsigned long start_pte;
382 unsigned long tmp1;
383 unsigned long tmp2;
384 unsigned long address;
385 unsigned long vaddr;
386 unsigned long ro_start;
387 unsigned long ro_end;
388 unsigned long fv_addr;
389 unsigned long gw_addr;
390 extern const unsigned long fault_vector_20;
391 extern void * const linux_gateway_page;
392
393 ro_start = __pa((unsigned long)_text);
394 ro_end = __pa((unsigned long)&data_start);
395 fv_addr = __pa((unsigned long)&fault_vector_20) & PAGE_MASK;
396 gw_addr = __pa((unsigned long)&linux_gateway_page) & PAGE_MASK;
397
398 end_paddr = start_paddr + size;
399
400 pg_dir = pgd_offset_k(start_vaddr);
401
402#if PTRS_PER_PMD == 1
403 start_pmd = 0;
404#else
405 start_pmd = ((start_vaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1));
406#endif
407 start_pte = ((start_vaddr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
408
409 address = start_paddr;
410 vaddr = start_vaddr;
411 while (address < end_paddr) {
412#if PTRS_PER_PMD == 1
413 pmd = (pmd_t *)__pa(pg_dir);
414#else
415 pmd = (pmd_t *)pgd_address(*pg_dir);
416
417 /*
418 * pmd is physical at this point
419 */
420
421 if (!pmd) {
422 pmd = (pmd_t *) alloc_bootmem_low_pages_node(NODE_DATA(0), PAGE_SIZE << PMD_ORDER);
423 pmd = (pmd_t *) __pa(pmd);
424 }
425
426 pgd_populate(NULL, pg_dir, __va(pmd));
427#endif
428 pg_dir++;
429
430 /* now change pmd to kernel virtual addresses */
431
432 pmd = (pmd_t *)__va(pmd) + start_pmd;
433 for (tmp1 = start_pmd; tmp1 < PTRS_PER_PMD; tmp1++, pmd++) {
434
435 /*
436 * pg_table is physical at this point
437 */
438
439 pg_table = (pte_t *)pmd_address(*pmd);
440 if (!pg_table) {
441 pg_table = (pte_t *)
442 alloc_bootmem_low_pages_node(NODE_DATA(0), PAGE_SIZE);
443 pg_table = (pte_t *) __pa(pg_table);
444 }
445
446 pmd_populate_kernel(NULL, pmd, __va(pg_table));
447
448 /* now change pg_table to kernel virtual addresses */
449
450 pg_table = (pte_t *) __va(pg_table) + start_pte;
451 for (tmp2 = start_pte; tmp2 < PTRS_PER_PTE; tmp2++, pg_table++) {
452 pte_t pte;
453
454 /*
455 * Map the fault vector writable so we can
456 * write the HPMC checksum.
457 */
458 if (force)
459 pte = __mk_pte(address, pgprot);
460 else if (core_kernel_text(vaddr) &&
461 address != fv_addr)
462 pte = __mk_pte(address, PAGE_KERNEL_EXEC);
463 else
464#if defined(CONFIG_PARISC_PAGE_SIZE_4KB)
465 if (address >= ro_start && address < ro_end
466 && address != fv_addr
467 && address != gw_addr)
468 pte = __mk_pte(address, PAGE_KERNEL_RO);
469 else
470#endif
471 pte = __mk_pte(address, pgprot);
472
473 if (address >= end_paddr) {
474 if (force)
475 break;
476 else
477 pte_val(pte) = 0;
478 }
479
480 set_pte(pg_table, pte);
481
482 address += PAGE_SIZE;
483 vaddr += PAGE_SIZE;
484 }
485 start_pte = 0;
486
487 if (address >= end_paddr)
488 break;
489 }
490 start_pmd = 0;
491 }
492}
493
372void free_initmem(void) 494void free_initmem(void)
373{ 495{
374 unsigned long addr; 496 unsigned long addr;
375 unsigned long init_begin = (unsigned long)__init_begin; 497 unsigned long init_begin = (unsigned long)__init_begin;
376 unsigned long init_end = (unsigned long)__init_end; 498 unsigned long init_end = (unsigned long)__init_end;
377 499
378#ifdef CONFIG_DEBUG_KERNEL 500 /* The init text pages are marked R-X. We have to
501 * flush the icache and mark them RW-
502 *
503 * This is tricky, because map_pages is in the init section.
504 * Do a dummy remap of the data section first (the data
505 * section is already PAGE_KERNEL) to pull in the TLB entries
506 * for map_kernel */
507 map_pages(init_begin, __pa(init_begin), init_end - init_begin,
508 PAGE_KERNEL_RWX, 1);
509 /* now remap at PAGE_KERNEL since the TLB is pre-primed to execute
510 * map_pages */
511 map_pages(init_begin, __pa(init_begin), init_end - init_begin,
512 PAGE_KERNEL, 1);
513
514 /* force the kernel to see the new TLB entries */
515 __flush_tlb_range(0, init_begin, init_end);
379 /* Attempt to catch anyone trying to execute code here 516 /* Attempt to catch anyone trying to execute code here
380 * by filling the page with BRK insns. 517 * by filling the page with BRK insns.
381 */ 518 */
382 memset((void *)init_begin, 0x00, init_end - init_begin); 519 memset((void *)init_begin, 0x00, init_end - init_begin);
520 /* finally dump all the instructions which were cached, since the
521 * pages are no-longer executable */
383 flush_icache_range(init_begin, init_end); 522 flush_icache_range(init_begin, init_end);
384#endif
385 523
386 /* align __init_begin and __init_end to page size,
387 ignoring linker script where we might have tried to save RAM */
388 init_begin = PAGE_ALIGN(init_begin);
389 init_end = PAGE_ALIGN(init_end);
390 for (addr = init_begin; addr < init_end; addr += PAGE_SIZE) { 524 for (addr = init_begin; addr < init_end; addr += PAGE_SIZE) {
391 ClearPageReserved(virt_to_page(addr)); 525 ClearPageReserved(virt_to_page(addr));
392 init_page_count(virt_to_page(addr)); 526 init_page_count(virt_to_page(addr));
@@ -616,114 +750,6 @@ void show_mem(unsigned int filter)
616#endif 750#endif
617} 751}
618 752
619
620static void __init map_pages(unsigned long start_vaddr, unsigned long start_paddr, unsigned long size, pgprot_t pgprot)
621{
622 pgd_t *pg_dir;
623 pmd_t *pmd;
624 pte_t *pg_table;
625 unsigned long end_paddr;
626 unsigned long start_pmd;
627 unsigned long start_pte;
628 unsigned long tmp1;
629 unsigned long tmp2;
630 unsigned long address;
631 unsigned long ro_start;
632 unsigned long ro_end;
633 unsigned long fv_addr;
634 unsigned long gw_addr;
635 extern const unsigned long fault_vector_20;
636 extern void * const linux_gateway_page;
637
638 ro_start = __pa((unsigned long)_text);
639 ro_end = __pa((unsigned long)&data_start);
640 fv_addr = __pa((unsigned long)&fault_vector_20) & PAGE_MASK;
641 gw_addr = __pa((unsigned long)&linux_gateway_page) & PAGE_MASK;
642
643 end_paddr = start_paddr + size;
644
645 pg_dir = pgd_offset_k(start_vaddr);
646
647#if PTRS_PER_PMD == 1
648 start_pmd = 0;
649#else
650 start_pmd = ((start_vaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1));
651#endif
652 start_pte = ((start_vaddr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
653
654 address = start_paddr;
655 while (address < end_paddr) {
656#if PTRS_PER_PMD == 1
657 pmd = (pmd_t *)__pa(pg_dir);
658#else
659 pmd = (pmd_t *)pgd_address(*pg_dir);
660
661 /*
662 * pmd is physical at this point
663 */
664
665 if (!pmd) {
666 pmd = (pmd_t *) alloc_bootmem_low_pages_node(NODE_DATA(0),PAGE_SIZE << PMD_ORDER);
667 pmd = (pmd_t *) __pa(pmd);
668 }
669
670 pgd_populate(NULL, pg_dir, __va(pmd));
671#endif
672 pg_dir++;
673
674 /* now change pmd to kernel virtual addresses */
675
676 pmd = (pmd_t *)__va(pmd) + start_pmd;
677 for (tmp1 = start_pmd; tmp1 < PTRS_PER_PMD; tmp1++,pmd++) {
678
679 /*
680 * pg_table is physical at this point
681 */
682
683 pg_table = (pte_t *)pmd_address(*pmd);
684 if (!pg_table) {
685 pg_table = (pte_t *)
686 alloc_bootmem_low_pages_node(NODE_DATA(0),PAGE_SIZE);
687 pg_table = (pte_t *) __pa(pg_table);
688 }
689
690 pmd_populate_kernel(NULL, pmd, __va(pg_table));
691
692 /* now change pg_table to kernel virtual addresses */
693
694 pg_table = (pte_t *) __va(pg_table) + start_pte;
695 for (tmp2 = start_pte; tmp2 < PTRS_PER_PTE; tmp2++,pg_table++) {
696 pte_t pte;
697
698 /*
699 * Map the fault vector writable so we can
700 * write the HPMC checksum.
701 */
702#if defined(CONFIG_PARISC_PAGE_SIZE_4KB)
703 if (address >= ro_start && address < ro_end
704 && address != fv_addr
705 && address != gw_addr)
706 pte = __mk_pte(address, PAGE_KERNEL_RO);
707 else
708#endif
709 pte = __mk_pte(address, pgprot);
710
711 if (address >= end_paddr)
712 pte_val(pte) = 0;
713
714 set_pte(pg_table, pte);
715
716 address += PAGE_SIZE;
717 }
718 start_pte = 0;
719
720 if (address >= end_paddr)
721 break;
722 }
723 start_pmd = 0;
724 }
725}
726
727/* 753/*
728 * pagetable_init() sets up the page tables 754 * pagetable_init() sets up the page tables
729 * 755 *
@@ -748,14 +774,14 @@ static void __init pagetable_init(void)
748 size = pmem_ranges[range].pages << PAGE_SHIFT; 774 size = pmem_ranges[range].pages << PAGE_SHIFT;
749 775
750 map_pages((unsigned long)__va(start_paddr), start_paddr, 776 map_pages((unsigned long)__va(start_paddr), start_paddr,
751 size, PAGE_KERNEL); 777 size, PAGE_KERNEL, 0);
752 } 778 }
753 779
754#ifdef CONFIG_BLK_DEV_INITRD 780#ifdef CONFIG_BLK_DEV_INITRD
755 if (initrd_end && initrd_end > mem_limit) { 781 if (initrd_end && initrd_end > mem_limit) {
756 printk(KERN_INFO "initrd: mapping %08lx-%08lx\n", initrd_start, initrd_end); 782 printk(KERN_INFO "initrd: mapping %08lx-%08lx\n", initrd_start, initrd_end);
757 map_pages(initrd_start, __pa(initrd_start), 783 map_pages(initrd_start, __pa(initrd_start),
758 initrd_end - initrd_start, PAGE_KERNEL); 784 initrd_end - initrd_start, PAGE_KERNEL, 0);
759 } 785 }
760#endif 786#endif
761 787
@@ -780,7 +806,7 @@ static void __init gateway_init(void)
780 */ 806 */
781 807
782 map_pages(linux_gateway_page_addr, __pa(&linux_gateway_page), 808 map_pages(linux_gateway_page_addr, __pa(&linux_gateway_page),
783 PAGE_SIZE, PAGE_GATEWAY); 809 PAGE_SIZE, PAGE_GATEWAY, 1);
784} 810}
785 811
786#ifdef CONFIG_HPUX 812#ifdef CONFIG_HPUX