Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 62583
b: refs/heads/master
c: 39804b2
h: refs/heads/master
i:
  62581: 33f6f92
  62579: ee6859b
  62575: a79c558
v: v3
  • Loading branch information
Linus Torvalds committed Jul 22, 2007
1 parent f166f7e commit 695f425
Show file tree
Hide file tree
Showing 53 changed files with 312 additions and 260 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 17c50b4102b32842224824b30d9182af9f582b90
refs/heads/master: 39804b20f62532fa05c2a8c3e2d1ae551fd0327b
55 changes: 49 additions & 6 deletions trunk/arch/i386/kernel/alternative.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/kprobes.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <asm/alternative.h>
#include <asm/sections.h>
#include <asm/pgtable.h>
#include <asm/mce.h>
#include <asm/nmi.h>

#ifdef CONFIG_HOTPLUG_CPU
static int smp_alt_once;
Expand Down Expand Up @@ -150,7 +156,7 @@ static void nop_out(void *insns, unsigned int len)
unsigned int noplen = len;
if (noplen > ASM_NOP_MAX)
noplen = ASM_NOP_MAX;
memcpy(insns, noptable[noplen], noplen);
text_poke(insns, noptable[noplen], noplen);
insns += noplen;
len -= noplen;
}
Expand Down Expand Up @@ -202,7 +208,7 @@ static void alternatives_smp_lock(u8 **start, u8 **end, u8 *text, u8 *text_end)
continue;
if (*ptr > text_end)
continue;
**ptr = 0xf0; /* lock prefix */
text_poke(*ptr, ((unsigned char []){0xf0}), 1); /* add lock prefix */
};
}

Expand Down Expand Up @@ -360,10 +366,6 @@ void apply_paravirt(struct paravirt_patch_site *start,
/* Pad the rest with nops */
nop_out(p->instr + used, p->len - used);
}

/* Sync to be conservative, in case we patched following
* instructions */
sync_core();
}
extern struct paravirt_patch_site __start_parainstructions[],
__stop_parainstructions[];
Expand All @@ -373,6 +375,14 @@ void __init alternative_instructions(void)
{
unsigned long flags;

/* The patching is not fully atomic, so try to avoid local interruptions
that might execute the to be patched code.
Other CPUs are not running. */
stop_nmi();
#ifdef CONFIG_MCE
stop_mce();
#endif

local_irq_save(flags);
apply_alternatives(__alt_instructions, __alt_instructions_end);

Expand Down Expand Up @@ -405,4 +415,37 @@ void __init alternative_instructions(void)
#endif
apply_paravirt(__parainstructions, __parainstructions_end);
local_irq_restore(flags);

restart_nmi();
#ifdef CONFIG_MCE
restart_mce();
#endif
}

/*
* Warning:
* When you use this code to patch more than one byte of an instruction
* you need to make sure that other CPUs cannot execute this code in parallel.
* Also no thread must be currently preempted in the middle of these instructions.
* And on the local CPU you need to be protected again NMI or MCE handlers
* seeing an inconsistent instruction while you patch.
*/
void __kprobes text_poke(void *oaddr, unsigned char *opcode, int len)
{
u8 *addr = oaddr;
if (!pte_write(*lookup_address((unsigned long)addr))) {
struct page *p[2] = { virt_to_page(addr), virt_to_page(addr+PAGE_SIZE) };
addr = vmap(p, 2, VM_MAP, PAGE_KERNEL);
if (!addr)
return;
addr += ((unsigned long)oaddr) % PAGE_SIZE;
}
memcpy(addr, opcode, len);
sync_core();
/* Not strictly needed, but can speed CPU recovery up. Ignore cross cacheline
case. */
if (cpu_has_clflush)
asm("clflush (%0) " :: "r" (oaddr) : "memory");
if (addr != oaddr)
vunmap(addr);
}
3 changes: 3 additions & 0 deletions trunk/arch/i386/kernel/cpu/amd.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,9 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)

switch (c->x86) {
case 15:
/* Use K8 tuning for Fam10h and Fam11h */
case 0x10:
case 0x11:
set_bit(X86_FEATURE_K8, c->x86_capability);
break;
case 6:
Expand Down
2 changes: 1 addition & 1 deletion trunk/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
#include <linux/smp.h>
#include <linux/cpufreq.h>
#include <linux/pci.h>
#include <asm/processor.h>
#include <asm/processor-cyrix.h>
#include <asm/errno.h>

/* PCI config registers, all at F0 */
Expand Down
2 changes: 1 addition & 1 deletion trunk/arch/i386/kernel/cpu/cyrix.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <linux/pci.h>
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/processor-cyrix.h>
#include <asm/timer.h>
#include <asm/pci-direct.h>
#include <asm/tsc.h>
Expand Down
14 changes: 14 additions & 0 deletions trunk/arch/i386/kernel/cpu/mcheck/mce.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,20 @@ void mcheck_init(struct cpuinfo_x86 *c)
}
}

static unsigned long old_cr4 __initdata;

void __init stop_mce(void)
{
old_cr4 = read_cr4();
clear_in_cr4(X86_CR4_MCE);
}

void __init restart_mce(void)
{
if (old_cr4 & X86_CR4_MCE)
set_in_cr4(X86_CR4_MCE);
}

static int __init mcheck_disable(char *str)
{
mce_disabled = 1;
Expand Down
1 change: 1 addition & 0 deletions trunk/arch/i386/kernel/cpu/mtrr/cyrix.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <asm/mtrr.h>
#include <asm/msr.h>
#include <asm/io.h>
#include <asm/processor-cyrix.h>
#include "mtrr.h"

int arr3_protected;
Expand Down
1 change: 1 addition & 0 deletions trunk/arch/i386/kernel/cpu/mtrr/state.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <asm/io.h>
#include <asm/mtrr.h>
#include <asm/msr.h>
#include <asm-i386/processor-cyrix.h>
#include "mtrr.h"


Expand Down
6 changes: 4 additions & 2 deletions trunk/arch/i386/kernel/cpu/perfctr-watchdog.c
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ static struct wd_ops k7_wd_ops = {
.stop = single_msr_stop_watchdog,
.perfctr = MSR_K7_PERFCTR0,
.evntsel = MSR_K7_EVNTSEL0,
.checkbit = 1ULL<<63,
.checkbit = 1ULL<<47,
};

/* Intel Model 6 (PPro+,P2,P3,P-M,Core1) */
Expand All @@ -346,7 +346,9 @@ static int setup_p6_watchdog(unsigned nmi_hz)
perfctr_msr = MSR_P6_PERFCTR0;
evntsel_msr = MSR_P6_EVNTSEL0;

wrmsrl(perfctr_msr, 0UL);
/* KVM doesn't implement this MSR */
if (wrmsr_safe(perfctr_msr, 0, 0) < 0)
return 0;

evntsel = P6_EVNTSEL_INT
| P6_EVNTSEL_OS
Expand Down
9 changes: 3 additions & 6 deletions trunk/arch/i386/kernel/kprobes.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <asm/cacheflush.h>
#include <asm/desc.h>
#include <asm/uaccess.h>
#include <asm/alternative.h>

void jprobe_return_end(void);

Expand Down Expand Up @@ -169,16 +170,12 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)

void __kprobes arch_arm_kprobe(struct kprobe *p)
{
*p->addr = BREAKPOINT_INSTRUCTION;
flush_icache_range((unsigned long) p->addr,
(unsigned long) p->addr + sizeof(kprobe_opcode_t));
text_poke(p->addr, ((unsigned char []){BREAKPOINT_INSTRUCTION}), 1);
}

void __kprobes arch_disarm_kprobe(struct kprobe *p)
{
*p->addr = p->opcode;
flush_icache_range((unsigned long) p->addr,
(unsigned long) p->addr + sizeof(kprobe_opcode_t));
text_poke(p->addr, &p->opcode, 1);
}

void __kprobes arch_remove_kprobe(struct kprobe *p)
Expand Down
2 changes: 1 addition & 1 deletion trunk/arch/i386/kernel/nmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ __kprobes int nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
* Take the local apic timer and PIT/HPET into account. We don't
* know which one is active, when we have highres/dyntick on
*/
sum = per_cpu(irq_stat, cpu).apic_timer_irqs + kstat_irqs(0);
sum = per_cpu(irq_stat, cpu).apic_timer_irqs + kstat_cpu(cpu).irqs[0];

/* if the none of the timers isn't firing, this cpu isn't doing much */
if (!touched && last_irq_sums[cpu] == sum) {
Expand Down
17 changes: 13 additions & 4 deletions trunk/arch/i386/kernel/paravirt.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,20 +124,28 @@ unsigned paravirt_patch_ignore(unsigned len)
return len;
}

struct branch {
unsigned char opcode;
u32 delta;
} __attribute__((packed));

unsigned paravirt_patch_call(void *target, u16 tgt_clobbers,
void *site, u16 site_clobbers,
unsigned len)
{
unsigned char *call = site;
unsigned long delta = (unsigned long)target - (unsigned long)(call+5);
struct branch b;

if (tgt_clobbers & ~site_clobbers)
return len; /* target would clobber too much for this site */
if (len < 5)
return len; /* call too long for patch site */

*call++ = 0xe8; /* call */
*(unsigned long *)call = delta;
b.opcode = 0xe8; /* call */
b.delta = delta;
BUILD_BUG_ON(sizeof(b) != 5);
text_poke(call, (unsigned char *)&b, 5);

return 5;
}
Expand All @@ -150,8 +158,9 @@ unsigned paravirt_patch_jmp(void *target, void *site, unsigned len)
if (len < 5)
return len; /* call too long for patch site */

*jmp++ = 0xe9; /* jmp */
*(unsigned long *)jmp = delta;
b.opcode = 0xe9; /* jmp */
b.delta = delta;
text_poke(call, (unsigned char *)&b, 5);

return 5;
}
Expand Down
7 changes: 7 additions & 0 deletions trunk/arch/i386/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,13 @@ asmlinkage int sys_sigreturn(unsigned long __unused)
return eax;

badframe:
if (show_unhandled_signals && printk_ratelimit())
printk("%s%s[%d] bad frame in sigreturn frame:%p eip:%lx"
" esp:%lx oeax:%lx\n",
current->pid > 1 ? KERN_INFO : KERN_EMERG,
current->comm, current->pid, frame, regs->eip,
regs->esp, regs->orig_eax);

force_sig(SIGSEGV, current);
return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion trunk/arch/i386/kernel/smpboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ cpumask_t cpu_coregroup_map(int cpu)
/* representing cpus for which sibling maps can be computed */
static cpumask_t cpu_sibling_setup_map;

void set_cpu_sibling_map(int cpu)
void __cpuinit set_cpu_sibling_map(int cpu)
{
int i;
struct cpuinfo_x86 *c = cpu_data;
Expand Down
24 changes: 23 additions & 1 deletion trunk/arch/i386/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,13 @@ fastcall void __kprobes do_general_protection(struct pt_regs * regs,

current->thread.error_code = error_code;
current->thread.trap_no = 13;
if (show_unhandled_signals && unhandled_signal(current, SIGSEGV) &&
printk_ratelimit())
printk(KERN_INFO
"%s[%d] general protection eip:%lx esp:%lx error:%lx\n",
current->comm, current->pid,
regs->eip, regs->esp, error_code);

force_sig(SIGSEGV, current);
return;

Expand Down Expand Up @@ -768,6 +775,8 @@ static __kprobes void default_do_nmi(struct pt_regs * regs)
reassert_nmi();
}

static int ignore_nmis;

fastcall __kprobes void do_nmi(struct pt_regs * regs, long error_code)
{
int cpu;
Expand All @@ -778,11 +787,24 @@ fastcall __kprobes void do_nmi(struct pt_regs * regs, long error_code)

++nmi_count(cpu);

default_do_nmi(regs);
if (!ignore_nmis)
default_do_nmi(regs);

nmi_exit();
}

void stop_nmi(void)
{
acpi_nmi_disable();
ignore_nmis++;
}

void restart_nmi(void)
{
ignore_nmis--;
acpi_nmi_enable();
}

#ifdef CONFIG_KPROBES
fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code)
{
Expand Down
10 changes: 10 additions & 0 deletions trunk/arch/i386/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,8 @@ static inline int vmalloc_fault(unsigned long address)
return 0;
}

int show_unhandled_signals = 1;

/*
* This routine handles page faults. It determines the address,
* and the problem, and then passes it off to one of the appropriate
Expand Down Expand Up @@ -469,6 +471,14 @@ fastcall void __kprobes do_page_fault(struct pt_regs *regs,
if (is_prefetch(regs, address, error_code))
return;

if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
printk_ratelimit()) {
printk("%s%s[%d]: segfault at %08lx eip %08lx "
"esp %08lx error %lx\n",
tsk->pid > 1 ? KERN_INFO : KERN_EMERG,
tsk->comm, tsk->pid, address, regs->eip,
regs->esp, error_code);
}
tsk->thread.cr2 = address;
/* Kernel addresses are always protection faults */
tsk->thread.error_code = error_code | (address >= TASK_SIZE);
Expand Down
14 changes: 3 additions & 11 deletions trunk/arch/i386/mm/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -800,17 +800,9 @@ void mark_rodata_ro(void)
unsigned long start = PFN_ALIGN(_text);
unsigned long size = PFN_ALIGN(_etext) - start;

#ifndef CONFIG_KPROBES
#ifdef CONFIG_HOTPLUG_CPU
/* It must still be possible to apply SMP alternatives. */
if (num_possible_cpus() <= 1)
#endif
{
change_page_attr(virt_to_page(start),
size >> PAGE_SHIFT, PAGE_KERNEL_RX);
printk("Write protecting the kernel text: %luk\n", size >> 10);
}
#endif
change_page_attr(virt_to_page(start),
size >> PAGE_SHIFT, PAGE_KERNEL_RX);
printk("Write protecting the kernel text: %luk\n", size >> 10);
start += size;
size = (unsigned long)__end_rodata - start;
change_page_attr(virt_to_page(start),
Expand Down
Loading

0 comments on commit 695f425

Please sign in to comment.