diff options
| author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-06 16:54:09 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-06 16:54:09 -0500 |
| commit | 3e6bdf473f489664dac4d7511d26c7ac3dfdc748 (patch) | |
| tree | 10cb2e928830b9de8bbc3f6dd47c18c24cd2affa /arch | |
| parent | 3d4d4582e5b3f67a68f2cf32fd5b70d8d80f119d (diff) | |
| parent | 58d5d0d8dd52cbca988af24b5692a20b00285543 (diff) | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86
* git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86:
x86: fix deadlock, make pgd_lock irq-safe
virtio: fix trivial build bug
x86: fix mttr trimming
x86: delay CPA self-test and repeat it
x86: fix 64-bit sections
generic: add __FINITDATA
x86: remove suprious ifdefs from pageattr.c
x86: mark the .rodata section also NX
x86: fix iret exception recovery on 64-bit
cpuidle: dubious one-bit signed bitfield in cpuidle.h
x86: fix sparse warnings in powernow-k8.c
x86: fix sparse error in traps_32.c
x86: trivial sparse/checkpatch in quirks.c
x86 ptrace: disallow null cs/ss
MAINTAINERS: RDC R-321x SoC maintainer
brk randomization: introduce CONFIG_COMPAT_BRK
brk: check the lower bound properly
x86: remove X2 workaround
x86: make spurious fault handler aware of large mappings
x86: make traps on entry code be debuggable in user space, 64-bit
Diffstat (limited to 'arch')
| -rw-r--r-- | arch/x86/Kconfig.debug | 4 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/cpufreq/powernow-k8.c | 1 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/mtrr/main.c | 19 | ||||
| -rw-r--r-- | arch/x86/kernel/entry_64.S | 24 | ||||
| -rw-r--r-- | arch/x86/kernel/head_64.S | 15 | ||||
| -rw-r--r-- | arch/x86/kernel/ptrace.c | 25 | ||||
| -rw-r--r-- | arch/x86/kernel/quirks.c | 26 | ||||
| -rw-r--r-- | arch/x86/kernel/test_nx.c | 2 | ||||
| -rw-r--r-- | arch/x86/kernel/traps_32.c | 15 | ||||
| -rw-r--r-- | arch/x86/mm/fault.c | 28 | ||||
| -rw-r--r-- | arch/x86/mm/init_64.c | 9 | ||||
| -rw-r--r-- | arch/x86/mm/pageattr-test.c | 65 | ||||
| -rw-r--r-- | arch/x86/mm/pageattr.c | 14 |
13 files changed, 153 insertions, 94 deletions
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index 2e1e3af28c3a..fa555148823d 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug | |||
| @@ -220,9 +220,9 @@ config DEBUG_BOOT_PARAMS | |||
| 220 | This option will cause struct boot_params to be exported via debugfs. | 220 | This option will cause struct boot_params to be exported via debugfs. |
| 221 | 221 | ||
| 222 | config CPA_DEBUG | 222 | config CPA_DEBUG |
| 223 | bool "CPA self test code" | 223 | bool "CPA self-test code" |
| 224 | depends on DEBUG_KERNEL | 224 | depends on DEBUG_KERNEL |
| 225 | help | 225 | help |
| 226 | Do change_page_attr self tests at boot. | 226 | Do change_page_attr() self-tests every 30 seconds. |
| 227 | 227 | ||
| 228 | endmenu | 228 | endmenu |
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c index a0522735dd9d..5affe91ca1e5 100644 --- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c +++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c | |||
| @@ -827,7 +827,6 @@ static int fill_powernow_table_pstate(struct powernow_k8_data *data, struct cpuf | |||
| 827 | 827 | ||
| 828 | for (i = 0; i < data->acpi_data.state_count; i++) { | 828 | for (i = 0; i < data->acpi_data.state_count; i++) { |
| 829 | u32 index; | 829 | u32 index; |
| 830 | u32 hi = 0, lo = 0; | ||
| 831 | 830 | ||
| 832 | index = data->acpi_data.states[i].control & HW_PSTATE_MASK; | 831 | index = data->acpi_data.states[i].control & HW_PSTATE_MASK; |
| 833 | if (index > data->max_hw_pstate) { | 832 | if (index > data->max_hw_pstate) { |
diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c index 1e27b69a7a0e..b6e136f23d3d 100644 --- a/arch/x86/kernel/cpu/mtrr/main.c +++ b/arch/x86/kernel/cpu/mtrr/main.c | |||
| @@ -659,7 +659,7 @@ static __init int amd_special_default_mtrr(void) | |||
| 659 | */ | 659 | */ |
| 660 | int __init mtrr_trim_uncached_memory(unsigned long end_pfn) | 660 | int __init mtrr_trim_uncached_memory(unsigned long end_pfn) |
| 661 | { | 661 | { |
| 662 | unsigned long i, base, size, highest_addr = 0, def, dummy; | 662 | unsigned long i, base, size, highest_pfn = 0, def, dummy; |
| 663 | mtrr_type type; | 663 | mtrr_type type; |
| 664 | u64 trim_start, trim_size; | 664 | u64 trim_start, trim_size; |
| 665 | 665 | ||
| @@ -682,28 +682,27 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn) | |||
| 682 | mtrr_if->get(i, &base, &size, &type); | 682 | mtrr_if->get(i, &base, &size, &type); |
| 683 | if (type != MTRR_TYPE_WRBACK) | 683 | if (type != MTRR_TYPE_WRBACK) |
| 684 | continue; | 684 | continue; |
| 685 | base <<= PAGE_SHIFT; | 685 | if (highest_pfn < base + size) |
| 686 | size <<= PAGE_SHIFT; | 686 | highest_pfn = base + size; |
| 687 | if (highest_addr < base + size) | ||
| 688 | highest_addr = base + size; | ||
| 689 | } | 687 | } |
| 690 | 688 | ||
| 691 | /* kvm/qemu doesn't have mtrr set right, don't trim them all */ | 689 | /* kvm/qemu doesn't have mtrr set right, don't trim them all */ |
| 692 | if (!highest_addr) { | 690 | if (!highest_pfn) { |
| 693 | printk(KERN_WARNING "WARNING: strange, CPU MTRRs all blank?\n"); | 691 | printk(KERN_WARNING "WARNING: strange, CPU MTRRs all blank?\n"); |
| 694 | WARN_ON(1); | 692 | WARN_ON(1); |
| 695 | return 0; | 693 | return 0; |
| 696 | } | 694 | } |
| 697 | 695 | ||
| 698 | if ((highest_addr >> PAGE_SHIFT) < end_pfn) { | 696 | if (highest_pfn < end_pfn) { |
| 699 | printk(KERN_WARNING "WARNING: BIOS bug: CPU MTRRs don't cover" | 697 | printk(KERN_WARNING "WARNING: BIOS bug: CPU MTRRs don't cover" |
| 700 | " all of memory, losing %LdMB of RAM.\n", | 698 | " all of memory, losing %luMB of RAM.\n", |
| 701 | (((u64)end_pfn << PAGE_SHIFT) - highest_addr) >> 20); | 699 | (end_pfn - highest_pfn) >> (20 - PAGE_SHIFT)); |
| 702 | 700 | ||
| 703 | WARN_ON(1); | 701 | WARN_ON(1); |
| 704 | 702 | ||
| 705 | printk(KERN_INFO "update e820 for mtrr\n"); | 703 | printk(KERN_INFO "update e820 for mtrr\n"); |
| 706 | trim_start = highest_addr; | 704 | trim_start = highest_pfn; |
| 705 | trim_start <<= PAGE_SHIFT; | ||
| 707 | trim_size = end_pfn; | 706 | trim_size = end_pfn; |
| 708 | trim_size <<= PAGE_SHIFT; | 707 | trim_size <<= PAGE_SHIFT; |
| 709 | trim_size -= trim_start; | 708 | trim_size -= trim_start; |
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index bea8474744ff..c7341e81941c 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S | |||
| @@ -582,7 +582,6 @@ retint_restore_args: /* return to kernel space */ | |||
| 582 | TRACE_IRQS_IRETQ | 582 | TRACE_IRQS_IRETQ |
| 583 | restore_args: | 583 | restore_args: |
| 584 | RESTORE_ARGS 0,8,0 | 584 | RESTORE_ARGS 0,8,0 |
| 585 | iret_label: | ||
| 586 | #ifdef CONFIG_PARAVIRT | 585 | #ifdef CONFIG_PARAVIRT |
| 587 | INTERRUPT_RETURN | 586 | INTERRUPT_RETURN |
| 588 | #endif | 587 | #endif |
| @@ -593,13 +592,22 @@ ENTRY(native_iret) | |||
| 593 | .quad native_iret, bad_iret | 592 | .quad native_iret, bad_iret |
| 594 | .previous | 593 | .previous |
| 595 | .section .fixup,"ax" | 594 | .section .fixup,"ax" |
| 596 | /* force a signal here? this matches i386 behaviour */ | ||
| 597 | /* running with kernel gs */ | ||
| 598 | bad_iret: | 595 | bad_iret: |
| 599 | movq $11,%rdi /* SIGSEGV */ | 596 | /* |
| 600 | TRACE_IRQS_ON | 597 | * The iret traps when the %cs or %ss being restored is bogus. |
| 601 | ENABLE_INTERRUPTS(CLBR_ANY | ~(CLBR_RDI)) | 598 | * We've lost the original trap vector and error code. |
| 602 | jmp do_exit | 599 | * #GPF is the most likely one to get for an invalid selector. |
| 600 | * So pretend we completed the iret and took the #GPF in user mode. | ||
| 601 | * | ||
| 602 | * We are now running with the kernel GS after exception recovery. | ||
| 603 | * But error_entry expects us to have user GS to match the user %cs, | ||
| 604 | * so swap back. | ||
| 605 | */ | ||
| 606 | pushq $0 | ||
| 607 | |||
| 608 | SWAPGS | ||
| 609 | jmp general_protection | ||
| 610 | |||
| 603 | .previous | 611 | .previous |
| 604 | 612 | ||
| 605 | /* edi: workmask, edx: work */ | 613 | /* edi: workmask, edx: work */ |
| @@ -911,7 +919,7 @@ error_kernelspace: | |||
| 911 | iret run with kernel gs again, so don't set the user space flag. | 919 | iret run with kernel gs again, so don't set the user space flag. |
| 912 | B stepping K8s sometimes report an truncated RIP for IRET | 920 | B stepping K8s sometimes report an truncated RIP for IRET |
| 913 | exceptions returning to compat mode. Check for these here too. */ | 921 | exceptions returning to compat mode. Check for these here too. */ |
| 914 | leaq iret_label(%rip),%rbp | 922 | leaq native_iret(%rip),%rbp |
| 915 | cmpq %rbp,RIP(%rsp) | 923 | cmpq %rbp,RIP(%rsp) |
| 916 | je error_swapgs | 924 | je error_swapgs |
| 917 | movl %ebp,%ebp /* zero extend */ | 925 | movl %ebp,%ebp /* zero extend */ |
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index 4f283ad215ec..09b38d539b09 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S | |||
| @@ -250,18 +250,13 @@ ENTRY(secondary_startup_64) | |||
| 250 | lretq | 250 | lretq |
| 251 | 251 | ||
| 252 | /* SMP bootup changes these two */ | 252 | /* SMP bootup changes these two */ |
| 253 | #ifndef CONFIG_HOTPLUG_CPU | 253 | __CPUINITDATA |
| 254 | .pushsection .init.data | ||
| 255 | #endif | ||
| 256 | .align 8 | 254 | .align 8 |
| 257 | .globl initial_code | 255 | ENTRY(initial_code) |
| 258 | initial_code: | ||
| 259 | .quad x86_64_start_kernel | 256 | .quad x86_64_start_kernel |
| 260 | #ifndef CONFIG_HOTPLUG_CPU | 257 | __FINITDATA |
| 261 | .popsection | 258 | |
| 262 | #endif | 259 | ENTRY(init_rsp) |
| 263 | .globl init_rsp | ||
| 264 | init_rsp: | ||
| 265 | .quad init_thread_union+THREAD_SIZE-8 | 260 | .quad init_thread_union+THREAD_SIZE-8 |
| 266 | 261 | ||
| 267 | bad_address: | 262 | bad_address: |
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 96286df1bb81..702c33efea84 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
| @@ -103,9 +103,26 @@ static int set_segment_reg(struct task_struct *task, | |||
| 103 | if (invalid_selector(value)) | 103 | if (invalid_selector(value)) |
| 104 | return -EIO; | 104 | return -EIO; |
| 105 | 105 | ||
| 106 | if (offset != offsetof(struct user_regs_struct, gs)) | 106 | /* |
| 107 | * For %cs and %ss we cannot permit a null selector. | ||
| 108 | * We can permit a bogus selector as long as it has USER_RPL. | ||
| 109 | * Null selectors are fine for other segment registers, but | ||
| 110 | * we will never get back to user mode with invalid %cs or %ss | ||
| 111 | * and will take the trap in iret instead. Much code relies | ||
| 112 | * on user_mode() to distinguish a user trap frame (which can | ||
| 113 | * safely use invalid selectors) from a kernel trap frame. | ||
| 114 | */ | ||
| 115 | switch (offset) { | ||
| 116 | case offsetof(struct user_regs_struct, cs): | ||
| 117 | case offsetof(struct user_regs_struct, ss): | ||
| 118 | if (unlikely(value == 0)) | ||
| 119 | return -EIO; | ||
| 120 | |||
| 121 | default: | ||
| 107 | *pt_regs_access(task_pt_regs(task), offset) = value; | 122 | *pt_regs_access(task_pt_regs(task), offset) = value; |
| 108 | else { | 123 | break; |
| 124 | |||
| 125 | case offsetof(struct user_regs_struct, gs): | ||
| 109 | task->thread.gs = value; | 126 | task->thread.gs = value; |
| 110 | if (task == current) | 127 | if (task == current) |
| 111 | /* | 128 | /* |
| @@ -227,12 +244,16 @@ static int set_segment_reg(struct task_struct *task, | |||
| 227 | * Can't actually change these in 64-bit mode. | 244 | * Can't actually change these in 64-bit mode. |
| 228 | */ | 245 | */ |
| 229 | case offsetof(struct user_regs_struct,cs): | 246 | case offsetof(struct user_regs_struct,cs): |
| 247 | if (unlikely(value == 0)) | ||
| 248 | return -EIO; | ||
| 230 | #ifdef CONFIG_IA32_EMULATION | 249 | #ifdef CONFIG_IA32_EMULATION |
| 231 | if (test_tsk_thread_flag(task, TIF_IA32)) | 250 | if (test_tsk_thread_flag(task, TIF_IA32)) |
| 232 | task_pt_regs(task)->cs = value; | 251 | task_pt_regs(task)->cs = value; |
| 233 | #endif | 252 | #endif |
| 234 | break; | 253 | break; |
| 235 | case offsetof(struct user_regs_struct,ss): | 254 | case offsetof(struct user_regs_struct,ss): |
| 255 | if (unlikely(value == 0)) | ||
| 256 | return -EIO; | ||
| 236 | #ifdef CONFIG_IA32_EMULATION | 257 | #ifdef CONFIG_IA32_EMULATION |
| 237 | if (test_tsk_thread_flag(task, TIF_IA32)) | 258 | if (test_tsk_thread_flag(task, TIF_IA32)) |
| 238 | task_pt_regs(task)->ss = value; | 259 | task_pt_regs(task)->ss = value; |
diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c index 3cd7a2dcd4fe..6ba33ca8715a 100644 --- a/arch/x86/kernel/quirks.c +++ b/arch/x86/kernel/quirks.c | |||
| @@ -380,19 +380,19 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, 0x0367, | |||
| 380 | void force_hpet_resume(void) | 380 | void force_hpet_resume(void) |
| 381 | { | 381 | { |
| 382 | switch (force_hpet_resume_type) { | 382 | switch (force_hpet_resume_type) { |
| 383 | case ICH_FORCE_HPET_RESUME: | 383 | case ICH_FORCE_HPET_RESUME: |
| 384 | return ich_force_hpet_resume(); | 384 | ich_force_hpet_resume(); |
| 385 | 385 | return; | |
| 386 | case OLD_ICH_FORCE_HPET_RESUME: | 386 | case OLD_ICH_FORCE_HPET_RESUME: |
| 387 | return old_ich_force_hpet_resume(); | 387 | old_ich_force_hpet_resume(); |
| 388 | 388 | return; | |
| 389 | case VT8237_FORCE_HPET_RESUME: | 389 | case VT8237_FORCE_HPET_RESUME: |
| 390 | return vt8237_force_hpet_resume(); | 390 | vt8237_force_hpet_resume(); |
| 391 | 391 | return; | |
| 392 | case NVIDIA_FORCE_HPET_RESUME: | 392 | case NVIDIA_FORCE_HPET_RESUME: |
| 393 | return nvidia_force_hpet_resume(); | 393 | nvidia_force_hpet_resume(); |
| 394 | 394 | return; | |
| 395 | default: | 395 | default: |
| 396 | break; | 396 | break; |
| 397 | } | 397 | } |
| 398 | } | 398 | } |
diff --git a/arch/x86/kernel/test_nx.c b/arch/x86/kernel/test_nx.c index 36c100c323aa..10b8a6f69f84 100644 --- a/arch/x86/kernel/test_nx.c +++ b/arch/x86/kernel/test_nx.c | |||
| @@ -139,7 +139,6 @@ static int test_NX(void) | |||
| 139 | * Until then, don't run them to avoid too many people getting scared | 139 | * Until then, don't run them to avoid too many people getting scared |
| 140 | * by the error message | 140 | * by the error message |
| 141 | */ | 141 | */ |
| 142 | #if 0 | ||
| 143 | 142 | ||
| 144 | #ifdef CONFIG_DEBUG_RODATA | 143 | #ifdef CONFIG_DEBUG_RODATA |
| 145 | /* Test 3: Check if the .rodata section is executable */ | 144 | /* Test 3: Check if the .rodata section is executable */ |
| @@ -152,6 +151,7 @@ static int test_NX(void) | |||
| 152 | } | 151 | } |
| 153 | #endif | 152 | #endif |
| 154 | 153 | ||
| 154 | #if 0 | ||
| 155 | /* Test 4: Check if the .data section of a module is executable */ | 155 | /* Test 4: Check if the .data section of a module is executable */ |
| 156 | if (test_address(&test_data)) { | 156 | if (test_address(&test_data)) { |
| 157 | printk(KERN_ERR "test_nx: .data section is executable\n"); | 157 | printk(KERN_ERR "test_nx: .data section is executable\n"); |
diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c index 3cf72977d012..b22c01e05a18 100644 --- a/arch/x86/kernel/traps_32.c +++ b/arch/x86/kernel/traps_32.c | |||
| @@ -1176,17 +1176,12 @@ void __init trap_init(void) | |||
| 1176 | #endif | 1176 | #endif |
| 1177 | set_trap_gate(19,&simd_coprocessor_error); | 1177 | set_trap_gate(19,&simd_coprocessor_error); |
| 1178 | 1178 | ||
| 1179 | /* | ||
| 1180 | * Verify that the FXSAVE/FXRSTOR data will be 16-byte aligned. | ||
| 1181 | * Generate a build-time error if the alignment is wrong. | ||
| 1182 | */ | ||
| 1183 | BUILD_BUG_ON(offsetof(struct task_struct, thread.i387.fxsave) & 15); | ||
| 1179 | if (cpu_has_fxsr) { | 1184 | if (cpu_has_fxsr) { |
| 1180 | /* | ||
| 1181 | * Verify that the FXSAVE/FXRSTOR data will be 16-byte aligned. | ||
| 1182 | * Generates a compile-time "error: zero width for bit-field" if | ||
| 1183 | * the alignment is wrong. | ||
| 1184 | */ | ||
| 1185 | struct fxsrAlignAssert { | ||
| 1186 | int _:!(offsetof(struct task_struct, | ||
| 1187 | thread.i387.fxsave) & 15); | ||
| 1188 | }; | ||
| 1189 | |||
| 1190 | printk(KERN_INFO "Enabling fast FPU save and restore... "); | 1185 | printk(KERN_INFO "Enabling fast FPU save and restore... "); |
| 1191 | set_in_cr4(X86_CR4_OSFXSR); | 1186 | set_in_cr4(X86_CR4_OSFXSR); |
| 1192 | printk("done.\n"); | 1187 | printk("done.\n"); |
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index ad8b9733d6b3..621afb6343dc 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c | |||
| @@ -428,6 +428,16 @@ static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs, | |||
| 428 | } | 428 | } |
| 429 | #endif | 429 | #endif |
| 430 | 430 | ||
| 431 | static int spurious_fault_check(unsigned long error_code, pte_t *pte) | ||
| 432 | { | ||
| 433 | if ((error_code & PF_WRITE) && !pte_write(*pte)) | ||
| 434 | return 0; | ||
| 435 | if ((error_code & PF_INSTR) && !pte_exec(*pte)) | ||
| 436 | return 0; | ||
| 437 | |||
| 438 | return 1; | ||
| 439 | } | ||
| 440 | |||
| 431 | /* | 441 | /* |
| 432 | * Handle a spurious fault caused by a stale TLB entry. This allows | 442 | * Handle a spurious fault caused by a stale TLB entry. This allows |
| 433 | * us to lazily refresh the TLB when increasing the permissions of a | 443 | * us to lazily refresh the TLB when increasing the permissions of a |
| @@ -457,20 +467,21 @@ static int spurious_fault(unsigned long address, | |||
| 457 | if (!pud_present(*pud)) | 467 | if (!pud_present(*pud)) |
| 458 | return 0; | 468 | return 0; |
| 459 | 469 | ||
| 470 | if (pud_large(*pud)) | ||
| 471 | return spurious_fault_check(error_code, (pte_t *) pud); | ||
| 472 | |||
| 460 | pmd = pmd_offset(pud, address); | 473 | pmd = pmd_offset(pud, address); |
| 461 | if (!pmd_present(*pmd)) | 474 | if (!pmd_present(*pmd)) |
| 462 | return 0; | 475 | return 0; |
| 463 | 476 | ||
| 477 | if (pmd_large(*pmd)) | ||
| 478 | return spurious_fault_check(error_code, (pte_t *) pmd); | ||
| 479 | |||
| 464 | pte = pte_offset_kernel(pmd, address); | 480 | pte = pte_offset_kernel(pmd, address); |
| 465 | if (!pte_present(*pte)) | 481 | if (!pte_present(*pte)) |
| 466 | return 0; | 482 | return 0; |
| 467 | 483 | ||
| 468 | if ((error_code & PF_WRITE) && !pte_write(*pte)) | 484 | return spurious_fault_check(error_code, pte); |
| 469 | return 0; | ||
| 470 | if ((error_code & PF_INSTR) && !pte_exec(*pte)) | ||
| 471 | return 0; | ||
| 472 | |||
| 473 | return 1; | ||
| 474 | } | 485 | } |
| 475 | 486 | ||
| 476 | /* | 487 | /* |
| @@ -947,11 +958,12 @@ void vmalloc_sync_all(void) | |||
| 947 | for (address = start; address <= VMALLOC_END; address += PGDIR_SIZE) { | 958 | for (address = start; address <= VMALLOC_END; address += PGDIR_SIZE) { |
| 948 | if (!test_bit(pgd_index(address), insync)) { | 959 | if (!test_bit(pgd_index(address), insync)) { |
| 949 | const pgd_t *pgd_ref = pgd_offset_k(address); | 960 | const pgd_t *pgd_ref = pgd_offset_k(address); |
| 961 | unsigned long flags; | ||
| 950 | struct page *page; | 962 | struct page *page; |
| 951 | 963 | ||
| 952 | if (pgd_none(*pgd_ref)) | 964 | if (pgd_none(*pgd_ref)) |
| 953 | continue; | 965 | continue; |
| 954 | spin_lock(&pgd_lock); | 966 | spin_lock_irqsave(&pgd_lock, flags); |
| 955 | list_for_each_entry(page, &pgd_list, lru) { | 967 | list_for_each_entry(page, &pgd_list, lru) { |
| 956 | pgd_t *pgd; | 968 | pgd_t *pgd; |
| 957 | pgd = (pgd_t *)page_address(page) + pgd_index(address); | 969 | pgd = (pgd_t *)page_address(page) + pgd_index(address); |
| @@ -960,7 +972,7 @@ void vmalloc_sync_all(void) | |||
| 960 | else | 972 | else |
| 961 | BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref)); | 973 | BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref)); |
| 962 | } | 974 | } |
| 963 | spin_unlock(&pgd_lock); | 975 | spin_unlock_irqrestore(&pgd_lock, flags); |
| 964 | set_bit(pgd_index(address), insync); | 976 | set_bit(pgd_index(address), insync); |
| 965 | } | 977 | } |
| 966 | if (address == start) | 978 | if (address == start) |
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 3a98d6f724ab..9b61c75a2355 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c | |||
| @@ -591,10 +591,17 @@ void mark_rodata_ro(void) | |||
| 591 | if (end <= start) | 591 | if (end <= start) |
| 592 | return; | 592 | return; |
| 593 | 593 | ||
| 594 | set_memory_ro(start, (end - start) >> PAGE_SHIFT); | ||
| 595 | 594 | ||
| 596 | printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n", | 595 | printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n", |
| 597 | (end - start) >> 10); | 596 | (end - start) >> 10); |
| 597 | set_memory_ro(start, (end - start) >> PAGE_SHIFT); | ||
| 598 | |||
| 599 | /* | ||
| 600 | * The rodata section (but not the kernel text!) should also be | ||
| 601 | * not-executable. | ||
| 602 | */ | ||
| 603 | start = ((unsigned long)__start_rodata + PAGE_SIZE - 1) & PAGE_MASK; | ||
| 604 | set_memory_nx(start, (end - start) >> PAGE_SHIFT); | ||
| 598 | 605 | ||
| 599 | rodata_test(); | 606 | rodata_test(); |
| 600 | 607 | ||
diff --git a/arch/x86/mm/pageattr-test.c b/arch/x86/mm/pageattr-test.c index 398f3a578dde..ed8201600354 100644 --- a/arch/x86/mm/pageattr-test.c +++ b/arch/x86/mm/pageattr-test.c | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | * and compares page tables forwards and afterwards. | 5 | * and compares page tables forwards and afterwards. |
| 6 | */ | 6 | */ |
| 7 | #include <linux/bootmem.h> | 7 | #include <linux/bootmem.h> |
| 8 | #include <linux/kthread.h> | ||
| 8 | #include <linux/random.h> | 9 | #include <linux/random.h> |
| 9 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
| 10 | #include <linux/init.h> | 11 | #include <linux/init.h> |
| @@ -14,8 +15,13 @@ | |||
| 14 | #include <asm/pgtable.h> | 15 | #include <asm/pgtable.h> |
| 15 | #include <asm/kdebug.h> | 16 | #include <asm/kdebug.h> |
| 16 | 17 | ||
| 18 | /* | ||
| 19 | * Only print the results of the first pass: | ||
| 20 | */ | ||
| 21 | static __read_mostly int print = 1; | ||
| 22 | |||
| 17 | enum { | 23 | enum { |
| 18 | NTEST = 4000, | 24 | NTEST = 400, |
| 19 | #ifdef CONFIG_X86_64 | 25 | #ifdef CONFIG_X86_64 |
| 20 | LPS = (1 << PMD_SHIFT), | 26 | LPS = (1 << PMD_SHIFT), |
| 21 | #elif defined(CONFIG_X86_PAE) | 27 | #elif defined(CONFIG_X86_PAE) |
| @@ -31,7 +37,7 @@ struct split_state { | |||
| 31 | long min_exec, max_exec; | 37 | long min_exec, max_exec; |
| 32 | }; | 38 | }; |
| 33 | 39 | ||
| 34 | static __init int print_split(struct split_state *s) | 40 | static int print_split(struct split_state *s) |
| 35 | { | 41 | { |
| 36 | long i, expected, missed = 0; | 42 | long i, expected, missed = 0; |
| 37 | int printed = 0; | 43 | int printed = 0; |
| @@ -82,10 +88,13 @@ static __init int print_split(struct split_state *s) | |||
| 82 | s->max_exec = addr; | 88 | s->max_exec = addr; |
| 83 | } | 89 | } |
| 84 | } | 90 | } |
| 85 | printk(KERN_INFO | 91 | if (print) { |
| 86 | "CPA mapping 4k %lu large %lu gb %lu x %lu[%lx-%lx] miss %lu\n", | 92 | printk(KERN_INFO |
| 87 | s->spg, s->lpg, s->gpg, s->exec, | 93 | " 4k %lu large %lu gb %lu x %lu[%lx-%lx] miss %lu\n", |
| 88 | s->min_exec != ~0UL ? s->min_exec : 0, s->max_exec, missed); | 94 | s->spg, s->lpg, s->gpg, s->exec, |
| 95 | s->min_exec != ~0UL ? s->min_exec : 0, | ||
| 96 | s->max_exec, missed); | ||
| 97 | } | ||
| 89 | 98 | ||
| 90 | expected = (s->gpg*GPS + s->lpg*LPS)/PAGE_SIZE + s->spg + missed; | 99 | expected = (s->gpg*GPS + s->lpg*LPS)/PAGE_SIZE + s->spg + missed; |
| 91 | if (expected != i) { | 100 | if (expected != i) { |
| @@ -96,11 +105,11 @@ static __init int print_split(struct split_state *s) | |||
| 96 | return err; | 105 | return err; |
| 97 | } | 106 | } |
| 98 | 107 | ||
| 99 | static unsigned long __initdata addr[NTEST]; | 108 | static unsigned long addr[NTEST]; |
| 100 | static unsigned int __initdata len[NTEST]; | 109 | static unsigned int len[NTEST]; |
| 101 | 110 | ||
| 102 | /* Change the global bit on random pages in the direct mapping */ | 111 | /* Change the global bit on random pages in the direct mapping */ |
| 103 | static __init int exercise_pageattr(void) | 112 | static int pageattr_test(void) |
| 104 | { | 113 | { |
| 105 | struct split_state sa, sb, sc; | 114 | struct split_state sa, sb, sc; |
| 106 | unsigned long *bm; | 115 | unsigned long *bm; |
| @@ -110,7 +119,8 @@ static __init int exercise_pageattr(void) | |||
| 110 | int i, k; | 119 | int i, k; |
| 111 | int err; | 120 | int err; |
| 112 | 121 | ||
| 113 | printk(KERN_INFO "CPA exercising pageattr\n"); | 122 | if (print) |
| 123 | printk(KERN_INFO "CPA self-test:\n"); | ||
| 114 | 124 | ||
| 115 | bm = vmalloc((max_pfn_mapped + 7) / 8); | 125 | bm = vmalloc((max_pfn_mapped + 7) / 8); |
| 116 | if (!bm) { | 126 | if (!bm) { |
| @@ -186,7 +196,6 @@ static __init int exercise_pageattr(void) | |||
| 186 | 196 | ||
| 187 | failed += print_split(&sb); | 197 | failed += print_split(&sb); |
| 188 | 198 | ||
| 189 | printk(KERN_INFO "CPA reverting everything\n"); | ||
| 190 | for (i = 0; i < NTEST; i++) { | 199 | for (i = 0; i < NTEST; i++) { |
| 191 | if (!addr[i]) | 200 | if (!addr[i]) |
| 192 | continue; | 201 | continue; |
| @@ -214,12 +223,40 @@ static __init int exercise_pageattr(void) | |||
| 214 | failed += print_split(&sc); | 223 | failed += print_split(&sc); |
| 215 | 224 | ||
| 216 | if (failed) { | 225 | if (failed) { |
| 217 | printk(KERN_ERR "CPA selftests NOT PASSED. Please report.\n"); | 226 | printk(KERN_ERR "NOT PASSED. Please report.\n"); |
| 218 | WARN_ON(1); | 227 | WARN_ON(1); |
| 228 | return -EINVAL; | ||
| 219 | } else { | 229 | } else { |
| 220 | printk(KERN_INFO "CPA selftests PASSED\n"); | 230 | if (print) |
| 231 | printk(KERN_INFO "ok.\n"); | ||
| 221 | } | 232 | } |
| 222 | 233 | ||
| 223 | return 0; | 234 | return 0; |
| 224 | } | 235 | } |
| 225 | module_init(exercise_pageattr); | 236 | |
| 237 | static int do_pageattr_test(void *__unused) | ||
| 238 | { | ||
| 239 | while (!kthread_should_stop()) { | ||
| 240 | schedule_timeout_interruptible(HZ*30); | ||
| 241 | if (pageattr_test() < 0) | ||
| 242 | break; | ||
| 243 | if (print) | ||
| 244 | print--; | ||
| 245 | } | ||
| 246 | return 0; | ||
| 247 | } | ||
| 248 | |||
| 249 | static int start_pageattr_test(void) | ||
| 250 | { | ||
| 251 | struct task_struct *p; | ||
| 252 | |||
| 253 | p = kthread_create(do_pageattr_test, NULL, "pageattr-test"); | ||
| 254 | if (!IS_ERR(p)) | ||
| 255 | wake_up_process(p); | ||
| 256 | else | ||
| 257 | WARN_ON(1); | ||
| 258 | |||
| 259 | return 0; | ||
| 260 | } | ||
| 261 | |||
| 262 | module_init(start_pageattr_test); | ||
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 16ce841f08d6..8493c855582b 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
| @@ -167,8 +167,6 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address) | |||
| 167 | if (within(address, virt_to_highmap(_text), virt_to_highmap(_etext))) | 167 | if (within(address, virt_to_highmap(_text), virt_to_highmap(_etext))) |
| 168 | pgprot_val(forbidden) |= _PAGE_NX; | 168 | pgprot_val(forbidden) |= _PAGE_NX; |
| 169 | 169 | ||
| 170 | |||
| 171 | #ifdef CONFIG_DEBUG_RODATA | ||
| 172 | /* The .rodata section needs to be read-only */ | 170 | /* The .rodata section needs to be read-only */ |
| 173 | if (within(address, (unsigned long)__start_rodata, | 171 | if (within(address, (unsigned long)__start_rodata, |
| 174 | (unsigned long)__end_rodata)) | 172 | (unsigned long)__end_rodata)) |
| @@ -179,7 +177,6 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address) | |||
| 179 | if (within(address, virt_to_highmap(__start_rodata), | 177 | if (within(address, virt_to_highmap(__start_rodata), |
| 180 | virt_to_highmap(__end_rodata))) | 178 | virt_to_highmap(__end_rodata))) |
| 181 | pgprot_val(forbidden) |= _PAGE_RW; | 179 | pgprot_val(forbidden) |= _PAGE_RW; |
| 182 | #endif | ||
| 183 | 180 | ||
| 184 | prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden)); | 181 | prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden)); |
| 185 | 182 | ||
| @@ -260,17 +257,6 @@ try_preserve_large_page(pte_t *kpte, unsigned long address, | |||
| 260 | pgprot_t old_prot, new_prot; | 257 | pgprot_t old_prot, new_prot; |
| 261 | int level, do_split = 1; | 258 | int level, do_split = 1; |
| 262 | 259 | ||
| 263 | /* | ||
| 264 | * An Athlon 64 X2 showed hard hangs if we tried to preserve | ||
| 265 | * largepages and changed the PSE entry from RW to RO. | ||
| 266 | * | ||
| 267 | * As AMD CPUs have a long series of erratas in this area, | ||
| 268 | * (and none of the known ones seem to explain this hang), | ||
| 269 | * disable this code until the hang can be debugged: | ||
| 270 | */ | ||
| 271 | if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) | ||
| 272 | return 1; | ||
| 273 | |||
| 274 | spin_lock_irqsave(&pgd_lock, flags); | 260 | spin_lock_irqsave(&pgd_lock, flags); |
| 275 | /* | 261 | /* |
| 276 | * Check for races, another CPU might have split this page | 262 | * Check for races, another CPU might have split this page |
