diff options
| -rw-r--r-- | arch/parisc/include/asm/cache.h | 3 | ||||
| -rw-r--r-- | arch/parisc/kernel/vmlinux.lds.S | 3 | ||||
| -rw-r--r-- | arch/parisc/mm/init.c | 67 |
3 files changed, 35 insertions, 38 deletions
diff --git a/arch/parisc/include/asm/cache.h b/arch/parisc/include/asm/cache.h index 4016fe1c65a9..73ca89a47f49 100644 --- a/arch/parisc/include/asm/cache.h +++ b/arch/parisc/include/asm/cache.h | |||
| @@ -24,9 +24,6 @@ | |||
| 24 | 24 | ||
| 25 | #define __read_mostly __attribute__((__section__(".data..read_mostly"))) | 25 | #define __read_mostly __attribute__((__section__(".data..read_mostly"))) |
| 26 | 26 | ||
| 27 | /* Read-only memory is marked before mark_rodata_ro() is called. */ | ||
| 28 | #define __ro_after_init __read_mostly | ||
| 29 | |||
| 30 | void parisc_cache_init(void); /* initializes cache-flushing */ | 27 | void parisc_cache_init(void); /* initializes cache-flushing */ |
| 31 | void disable_sr_hashing_asm(int); /* low level support for above */ | 28 | void disable_sr_hashing_asm(int); /* low level support for above */ |
| 32 | void disable_sr_hashing(void); /* turns off space register hashing */ | 29 | void disable_sr_hashing(void); /* turns off space register hashing */ |
diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S index a8be7a47fcc0..c3b1b9c24ede 100644 --- a/arch/parisc/kernel/vmlinux.lds.S +++ b/arch/parisc/kernel/vmlinux.lds.S | |||
| @@ -18,9 +18,6 @@ | |||
| 18 | *(.data..vm0.pgd) \ | 18 | *(.data..vm0.pgd) \ |
| 19 | *(.data..vm0.pte) | 19 | *(.data..vm0.pte) |
| 20 | 20 | ||
| 21 | /* No __ro_after_init data in the .rodata section - which will always be ro */ | ||
| 22 | #define RO_AFTER_INIT_DATA | ||
| 23 | |||
| 24 | #include <asm-generic/vmlinux.lds.h> | 21 | #include <asm-generic/vmlinux.lds.h> |
| 25 | 22 | ||
| 26 | /* needed for the processor specific cache alignment size */ | 23 | /* needed for the processor specific cache alignment size */ |
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c index 3b0f9eab7f2c..b99bcbf1ecdb 100644 --- a/arch/parisc/mm/init.c +++ b/arch/parisc/mm/init.c | |||
| @@ -345,16 +345,7 @@ static void __init setup_bootmem(void) | |||
| 345 | memblock_dump_all(); | 345 | memblock_dump_all(); |
| 346 | } | 346 | } |
| 347 | 347 | ||
| 348 | static int __init parisc_text_address(unsigned long vaddr) | 348 | static bool kernel_set_to_readonly; |
| 349 | { | ||
| 350 | static unsigned long head_ptr __initdata; | ||
| 351 | |||
| 352 | if (!head_ptr) | ||
| 353 | head_ptr = PAGE_MASK & (unsigned long) | ||
| 354 | dereference_function_descriptor(&parisc_kernel_start); | ||
| 355 | |||
| 356 | return core_kernel_text(vaddr) || vaddr == head_ptr; | ||
| 357 | } | ||
| 358 | 349 | ||
| 359 | static void __init map_pages(unsigned long start_vaddr, | 350 | static void __init map_pages(unsigned long start_vaddr, |
| 360 | unsigned long start_paddr, unsigned long size, | 351 | unsigned long start_paddr, unsigned long size, |
| @@ -372,10 +363,11 @@ static void __init map_pages(unsigned long start_vaddr, | |||
| 372 | unsigned long vaddr; | 363 | unsigned long vaddr; |
| 373 | unsigned long ro_start; | 364 | unsigned long ro_start; |
| 374 | unsigned long ro_end; | 365 | unsigned long ro_end; |
| 375 | unsigned long kernel_end; | 366 | unsigned long kernel_start, kernel_end; |
| 376 | 367 | ||
| 377 | ro_start = __pa((unsigned long)_text); | 368 | ro_start = __pa((unsigned long)_text); |
| 378 | ro_end = __pa((unsigned long)&data_start); | 369 | ro_end = __pa((unsigned long)&data_start); |
| 370 | kernel_start = __pa((unsigned long)&__init_begin); | ||
| 379 | kernel_end = __pa((unsigned long)&_end); | 371 | kernel_end = __pa((unsigned long)&_end); |
| 380 | 372 | ||
| 381 | end_paddr = start_paddr + size; | 373 | end_paddr = start_paddr + size; |
| @@ -438,26 +430,30 @@ static void __init map_pages(unsigned long start_vaddr, | |||
| 438 | pg_table = (pte_t *) __va(pg_table) + start_pte; | 430 | pg_table = (pte_t *) __va(pg_table) + start_pte; |
| 439 | for (tmp2 = start_pte; tmp2 < PTRS_PER_PTE; tmp2++, pg_table++) { | 431 | for (tmp2 = start_pte; tmp2 < PTRS_PER_PTE; tmp2++, pg_table++) { |
| 440 | pte_t pte; | 432 | pte_t pte; |
| 441 | 433 | pgprot_t prot; | |
| 442 | if (force) | 434 | bool huge = false; |
| 443 | pte = __mk_pte(address, pgprot); | 435 | |
| 444 | else if (parisc_text_address(vaddr)) { | 436 | if (force) { |
| 445 | pte = __mk_pte(address, PAGE_KERNEL_EXEC); | 437 | prot = pgprot; |
| 446 | if (address >= ro_start && address < kernel_end) | 438 | } else if (address < kernel_start || address >= kernel_end) { |
| 447 | pte = pte_mkhuge(pte); | 439 | /* outside kernel memory */ |
| 440 | prot = PAGE_KERNEL; | ||
| 441 | } else if (!kernel_set_to_readonly) { | ||
| 442 | /* still initializing, allow writing to RO memory */ | ||
| 443 | prot = PAGE_KERNEL_RWX; | ||
| 444 | huge = true; | ||
| 445 | } else if (address >= ro_start) { | ||
| 446 | /* Code (ro) and Data areas */ | ||
| 447 | prot = (address < ro_end) ? | ||
| 448 | PAGE_KERNEL_EXEC : PAGE_KERNEL; | ||
| 449 | huge = true; | ||
| 450 | } else { | ||
| 451 | prot = PAGE_KERNEL; | ||
| 448 | } | 452 | } |
| 449 | else | 453 | |
| 450 | #if defined(CONFIG_PARISC_PAGE_SIZE_4KB) | 454 | pte = __mk_pte(address, prot); |
| 451 | if (address >= ro_start && address < ro_end) { | 455 | if (huge) |
| 452 | pte = __mk_pte(address, PAGE_KERNEL_EXEC); | ||
| 453 | pte = pte_mkhuge(pte); | 456 | pte = pte_mkhuge(pte); |
| 454 | } else | ||
| 455 | #endif | ||
| 456 | { | ||
| 457 | pte = __mk_pte(address, pgprot); | ||
| 458 | if (address >= ro_start && address < kernel_end) | ||
| 459 | pte = pte_mkhuge(pte); | ||
| 460 | } | ||
| 461 | 457 | ||
| 462 | if (address >= end_paddr) | 458 | if (address >= end_paddr) |
| 463 | break; | 459 | break; |
| @@ -493,6 +489,12 @@ void __ref free_initmem(void) | |||
| 493 | { | 489 | { |
| 494 | unsigned long init_begin = (unsigned long)__init_begin; | 490 | unsigned long init_begin = (unsigned long)__init_begin; |
| 495 | unsigned long init_end = (unsigned long)__init_end; | 491 | unsigned long init_end = (unsigned long)__init_end; |
| 492 | unsigned long kernel_end = (unsigned long)&_end; | ||
| 493 | |||
| 494 | /* Remap kernel text and data, but do not touch init section yet. */ | ||
| 495 | kernel_set_to_readonly = true; | ||
| 496 | map_pages(init_end, __pa(init_end), kernel_end - init_end, | ||
| 497 | PAGE_KERNEL, 0); | ||
| 496 | 498 | ||
| 497 | /* The init text pages are marked R-X. We have to | 499 | /* The init text pages are marked R-X. We have to |
| 498 | * flush the icache and mark them RW- | 500 | * flush the icache and mark them RW- |
| @@ -509,7 +511,7 @@ void __ref free_initmem(void) | |||
| 509 | PAGE_KERNEL, 1); | 511 | PAGE_KERNEL, 1); |
| 510 | 512 | ||
| 511 | /* force the kernel to see the new TLB entries */ | 513 | /* force the kernel to see the new TLB entries */ |
| 512 | __flush_tlb_range(0, init_begin, init_end); | 514 | __flush_tlb_range(0, init_begin, kernel_end); |
| 513 | 515 | ||
| 514 | /* finally dump all the instructions which were cached, since the | 516 | /* finally dump all the instructions which were cached, since the |
| 515 | * pages are no-longer executable */ | 517 | * pages are no-longer executable */ |
| @@ -527,8 +529,9 @@ void mark_rodata_ro(void) | |||
| 527 | { | 529 | { |
| 528 | /* rodata memory was already mapped with KERNEL_RO access rights by | 530 | /* rodata memory was already mapped with KERNEL_RO access rights by |
| 529 | pagetable_init() and map_pages(). No need to do additional stuff here */ | 531 | pagetable_init() and map_pages(). No need to do additional stuff here */ |
| 530 | printk (KERN_INFO "Write protecting the kernel read-only data: %luk\n", | 532 | unsigned long roai_size = __end_ro_after_init - __start_ro_after_init; |
| 531 | (unsigned long)(__end_rodata - __start_rodata) >> 10); | 533 | |
| 534 | pr_info("Write protected read-only-after-init data: %luk\n", roai_size >> 10); | ||
| 532 | } | 535 | } |
| 533 | #endif | 536 | #endif |
| 534 | 537 | ||
