Commit 445722f9 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6

* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6:
  [IA64] kprobe clears qp bits for special instructions
  [IA64] enable trap code on slot 1
  [IA64] Take defensive stance on ia64_pal_get_brand_info()
  [IA64] fix possible XPC deadlock when disconnecting
  [IA64] - Reduce overhead of FP exception logging messages
  [IA64] fix arch/ia64/mm/contig.c:235: warning: unused variable `nid'
  [IA64] s/termios/ktermios/ in simserial.c
  [IA64] kexec/kdump: tidy up declaration of relocate_new_kernel_t
  [IA64] Kexec/Kdump: honour non-zero crashkernel offset.
  [IA64] CONFIG_KEXEC/CONFIG_CRASH_DUMP permutations
  [IA64] Do not call SN_SAL_SET_CPU_NUMBER twice on cpu 0
parents 3641b536 df3e0d1c
...@@ -488,7 +488,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, ...@@ -488,7 +488,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{ {
unsigned int cflag = tty->termios->c_cflag; unsigned int cflag = tty->termios->c_cflag;
......
...@@ -29,6 +29,7 @@ obj-$(CONFIG_CPU_FREQ) += cpufreq/ ...@@ -29,6 +29,7 @@ obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o
obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
obj-$(CONFIG_AUDIT) += audit.o obj-$(CONFIG_AUDIT) += audit.o
obj-$(CONFIG_PCI_MSI) += msi_ia64.o obj-$(CONFIG_PCI_MSI) += msi_ia64.o
......
...@@ -19,29 +19,11 @@ ...@@ -19,29 +19,11 @@
#include <asm/kdebug.h> #include <asm/kdebug.h>
#include <asm/mca.h> #include <asm/mca.h>
#include <asm/uaccess.h>
int kdump_status[NR_CPUS]; int kdump_status[NR_CPUS];
atomic_t kdump_cpu_freezed; atomic_t kdump_cpu_freezed;
atomic_t kdump_in_progress; atomic_t kdump_in_progress;
int kdump_on_init = 1; int kdump_on_init = 1;
ssize_t
copy_oldmem_page(unsigned long pfn, char *buf,
size_t csize, unsigned long offset, int userbuf)
{
void *vaddr;
if (!csize)
return 0;
vaddr = __va(pfn<<PAGE_SHIFT);
if (userbuf) {
if (copy_to_user(buf, (vaddr + offset), csize)) {
return -EFAULT;
}
} else
memcpy(buf, (vaddr + offset), csize);
return csize;
}
static inline Elf64_Word static inline Elf64_Word
*append_elf_note(Elf64_Word *buf, char *name, unsigned type, void *data, *append_elf_note(Elf64_Word *buf, char *name, unsigned type, void *data,
...@@ -225,14 +207,10 @@ static ctl_table sys_table[] = { ...@@ -225,14 +207,10 @@ static ctl_table sys_table[] = {
static int static int
machine_crash_setup(void) machine_crash_setup(void)
{ {
char *from = strstr(saved_command_line, "elfcorehdr=");
static struct notifier_block kdump_init_notifier_nb = { static struct notifier_block kdump_init_notifier_nb = {
.notifier_call = kdump_init_notifier, .notifier_call = kdump_init_notifier,
}; };
int ret; int ret;
if (from)
elfcorehdr_addr = memparse(from+11, &from);
saved_max_pfn = (unsigned long)-1;
if((ret = register_die_notifier(&kdump_init_notifier_nb)) != 0) if((ret = register_die_notifier(&kdump_init_notifier_nb)) != 0)
return ret; return ret;
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
......
/*
* kernel/crash_dump.c - Memory preserving reboot related code.
*
* Created by: Simon Horman <horms@verge.net.au>
* Original code moved from kernel/crash.c
* Original code comment copied from the i386 version of this file
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/uaccess.h>
/**
* copy_oldmem_page - copy one page from "oldmem"
* @pfn: page frame number to be copied
* @buf: target memory address for the copy; this can be in kernel address
* space or user address space (see @userbuf)
* @csize: number of bytes to copy
* @offset: offset in bytes into the page (based on pfn) to begin the copy
* @userbuf: if set, @buf is in user address space, use copy_to_user(),
* otherwise @buf is in kernel address space, use memcpy().
*
* Copy a page from "oldmem". For this page, there is no pte mapped
* in the current kernel. We stitch up a pte, similar to kmap_atomic.
*
* Calling copy_to_user() in atomic context is not desirable. Hence first
* copying the data to a pre-allocated kernel page and then copying to user
* space in non-atomic context.
*/
ssize_t
copy_oldmem_page(unsigned long pfn, char *buf,
size_t csize, unsigned long offset, int userbuf)
{
void *vaddr;
if (!csize)
return 0;
vaddr = __va(pfn<<PAGE_SHIFT);
if (userbuf) {
if (copy_to_user(buf, (vaddr + offset), csize)) {
return -EFAULT;
}
} else
memcpy(buf, (vaddr + offset), csize);
return csize;
}
...@@ -45,13 +45,14 @@ ...@@ -45,13 +45,14 @@
* to the correct location. * to the correct location.
*/ */
#include <asm/asmmacro.h> #include <asm/asmmacro.h>
#include <asm-ia64/break.h>
/* /*
* void jprobe_break(void) * void jprobe_break(void)
*/ */
.section .kprobes.text, "ax" .section .kprobes.text, "ax"
ENTRY(jprobe_break) ENTRY(jprobe_break)
break.m 0x80300 break.m __IA64_BREAK_JPROBE
END(jprobe_break) END(jprobe_break)
/* /*
......
...@@ -88,6 +88,7 @@ static void __kprobes update_kprobe_inst_flag(uint template, uint slot, ...@@ -88,6 +88,7 @@ static void __kprobes update_kprobe_inst_flag(uint template, uint slot,
{ {
p->ainsn.inst_flag = 0; p->ainsn.inst_flag = 0;
p->ainsn.target_br_reg = 0; p->ainsn.target_br_reg = 0;
p->ainsn.slot = slot;
/* Check for Break instruction /* Check for Break instruction
* Bits 37:40 Major opcode to be zero * Bits 37:40 Major opcode to be zero
...@@ -127,10 +128,46 @@ static void __kprobes update_kprobe_inst_flag(uint template, uint slot, ...@@ -127,10 +128,46 @@ static void __kprobes update_kprobe_inst_flag(uint template, uint slot,
return; return;
} }
/*
* In this function we check to see if the instruction
* (qp) cmpx.crel.ctype p1,p2=r2,r3
* on which we are inserting kprobe is cmp instruction
* with ctype as unc.
*/
static uint __kprobes is_cmp_ctype_unc_inst(uint template, uint slot,
uint major_opcode,
unsigned long kprobe_inst)
{
cmp_inst_t cmp_inst;
uint ctype_unc = 0;
if (!((bundle_encoding[template][slot] == I) ||
(bundle_encoding[template][slot] == M)))
goto out;
if (!((major_opcode == 0xC) || (major_opcode == 0xD) ||
(major_opcode == 0xE)))
goto out;
cmp_inst.l = kprobe_inst;
if ((cmp_inst.f.x2 == 0) || (cmp_inst.f.x2 == 1)) {
/* Integere compare - Register Register (A6 type)*/
if ((cmp_inst.f.tb == 0) && (cmp_inst.f.ta == 0)
&&(cmp_inst.f.c == 1))
ctype_unc = 1;
} else if ((cmp_inst.f.x2 == 2)||(cmp_inst.f.x2 == 3)) {
/* Integere compare - Immediate Register (A8 type)*/
if ((cmp_inst.f.ta == 0) &&(cmp_inst.f.c == 1))
ctype_unc = 1;
}
out:
return ctype_unc;
}
/* /*
* In this function we check to see if the instruction * In this function we check to see if the instruction
* on which we are inserting kprobe is supported. * on which we are inserting kprobe is supported.
* Returns 0 if supported * Returns qp value if supported
* Returns -EINVAL if unsupported * Returns -EINVAL if unsupported
*/ */
static int __kprobes unsupported_inst(uint template, uint slot, static int __kprobes unsupported_inst(uint template, uint slot,
...@@ -138,9 +175,21 @@ static int __kprobes unsupported_inst(uint template, uint slot, ...@@ -138,9 +175,21 @@ static int __kprobes unsupported_inst(uint template, uint slot,
unsigned long kprobe_inst, unsigned long kprobe_inst,
unsigned long addr) unsigned long addr)
{ {
if (bundle_encoding[template][slot] == I) { int qp;
switch (major_opcode) {
case 0x0: //I_UNIT_MISC_OPCODE: qp = kprobe_inst & 0x3f;
if (is_cmp_ctype_unc_inst(template, slot, major_opcode, kprobe_inst)) {
if (slot == 1 && qp) {
printk(KERN_WARNING "Kprobes on cmp unc"
"instruction on slot 1 at <0x%lx>"
"is not supported\n", addr);
return -EINVAL;
}
qp = 0;
}
else if (bundle_encoding[template][slot] == I) {
if (major_opcode == 0) {
/* /*
* Check for Integer speculation instruction * Check for Integer speculation instruction
* - Bit 33-35 to be equal to 0x1 * - Bit 33-35 to be equal to 0x1
...@@ -151,7 +200,6 @@ static int __kprobes unsupported_inst(uint template, uint slot, ...@@ -151,7 +200,6 @@ static int __kprobes unsupported_inst(uint template, uint slot,
addr); addr);
return -EINVAL; return -EINVAL;
} }
/* /*
* IP relative mov instruction * IP relative mov instruction
* - Bit 27-35 to be equal to 0x30 * - Bit 27-35 to be equal to 0x30
...@@ -164,45 +212,69 @@ static int __kprobes unsupported_inst(uint template, uint slot, ...@@ -164,45 +212,69 @@ static int __kprobes unsupported_inst(uint template, uint slot,
} }
} }
else if ((major_opcode == 5) && !(kprobe_inst & (0xFUl << 33)) &&
(kprobe_inst & (0x1UL << 12))) {
/* test bit instructions, tbit,tnat,tf
* bit 33-36 to be equal to 0
* bit 12 to be equal to 1
*/
if (slot == 1 && qp) {
printk(KERN_WARNING "Kprobes on test bit"
"instruction on slot at <0x%lx>"
"is not supported\n", addr);
return -EINVAL;
} }
return 0; qp = 0;
} }
}
else if (bundle_encoding[template][slot] == B) {
/* if (major_opcode == 7) {
* In this function we check to see if the instruction /* IP-Relative Predict major code is 7 */
* (qp) cmpx.crel.ctype p1,p2=r2,r3 printk(KERN_WARNING "Kprobes on IP-Relative"
* on which we are inserting kprobe is cmp instruction "Predict is not supported\n");
* with ctype as unc. return -EINVAL;
}
else if (major_opcode == 2) {
/* Indirect Predict, major code is 2
* bit 27-32 to be equal to 10 or 11
*/ */
static uint __kprobes is_cmp_ctype_unc_inst(uint template, uint slot, int x6=(kprobe_inst >> 27) & 0x3F;
uint major_opcode, if ((x6 == 0x10) || (x6 == 0x11)) {
unsigned long kprobe_inst) printk(KERN_WARNING "Kprobes on"
{ "Indirect Predict is not supported\n");
cmp_inst_t cmp_inst; return -EINVAL;
uint ctype_unc = 0; }
}
if (!((bundle_encoding[template][slot] == I) || }
(bundle_encoding[template][slot] == M))) /* kernel does not use float instruction, here for safety kprobe
goto out; * will judge whether it is fcmp/flass/float approximation instruction
*/
if (!((major_opcode == 0xC) || (major_opcode == 0xD) || else if (unlikely(bundle_encoding[template][slot] == F)) {
(major_opcode == 0xE))) if ((major_opcode == 4 || major_opcode == 5) &&
goto out; (kprobe_inst & (0x1 << 12))) {
/* fcmp/fclass unc instruction */
if (slot == 1 && qp) {
printk(KERN_WARNING "Kprobes on fcmp/fclass "
"instruction on slot at <0x%lx> "
"is not supported\n", addr);
return -EINVAL;
cmp_inst.l = kprobe_inst;
if ((cmp_inst.f.x2 == 0) || (cmp_inst.f.x2 == 1)) {
/* Integere compare - Register Register (A6 type)*/
if ((cmp_inst.f.tb == 0) && (cmp_inst.f.ta == 0)
&&(cmp_inst.f.c == 1))
ctype_unc = 1;
} else if ((cmp_inst.f.x2 == 2)||(cmp_inst.f.x2 == 3)) {
/* Integere compare - Immediate Register (A8 type)*/
if ((cmp_inst.f.ta == 0) &&(cmp_inst.f.c == 1))
ctype_unc = 1;
} }
out: qp = 0;
return ctype_unc; }
if ((major_opcode == 0 || major_opcode == 1) &&
(kprobe_inst & (0x1UL << 33))) {
/* float Approximation instruction */
if (slot == 1 && qp) {
printk(KERN_WARNING "Kprobes on float Approx "
"instr at <0x%lx> is not supported\n",
addr);
return -EINVAL;
}
qp = 0;
}
}
return qp;
} }
/* /*
...@@ -212,20 +284,17 @@ out: ...@@ -212,20 +284,17 @@ out:
static void __kprobes prepare_break_inst(uint template, uint slot, static void __kprobes prepare_break_inst(uint template, uint slot,
uint major_opcode, uint major_opcode,
unsigned long kprobe_inst, unsigned long kprobe_inst,
struct kprobe *p) struct kprobe *p,
int qp)
{ {
unsigned long break_inst = BREAK_INST; unsigned long break_inst = BREAK_INST;
bundle_t *bundle = &p->opcode.bundle; bundle_t *bundle = &p->opcode.bundle;
/* /*
* Copy the original kprobe_inst qualifying predicate(qp) * Copy the original kprobe_inst qualifying predicate(qp)
* to the break instruction iff !is_cmp_ctype_unc_inst * to the break instruction
* because for cmp instruction with ctype equal to unc,
* which is a special instruction always needs to be
* executed regradless of qp
*/ */
if (!is_cmp_ctype_unc_inst(template, slot, major_opcode, kprobe_inst)) break_inst |= qp;
break_inst |= (0x3f & kprobe_inst);
switch (slot) { switch (slot) {
case 0: case 0:
...@@ -296,12 +365,6 @@ static int __kprobes valid_kprobe_addr(int template, int slot, ...@@ -296,12 +365,6 @@ static int __kprobes valid_kprobe_addr(int template, int slot,
return -EINVAL; return -EINVAL;
} }
if (slot == 1 && bundle_encoding[template][1] != L) {
printk(KERN_WARNING "Inserting kprobes on slot #1 "
"is not supported\n");
return -EINVAL;
}
return 0; return 0;
} }
...@@ -427,6 +490,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) ...@@ -427,6 +490,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
unsigned long kprobe_inst=0; unsigned long kprobe_inst=0;
unsigned int slot = addr & 0xf, template, major_opcode = 0; unsigned int slot = addr & 0xf, template, major_opcode = 0;
bundle_t *bundle; bundle_t *bundle;
int qp;
bundle = &((kprobe_opcode_t *)kprobe_addr)->bundle; bundle = &((kprobe_opcode_t *)kprobe_addr)->bundle;
template = bundle->quad0.template; template = bundle->quad0.template;
...@@ -441,40 +505,66 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) ...@@ -441,40 +505,66 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
/* Get kprobe_inst and major_opcode from the bundle */ /* Get kprobe_inst and major_opcode from the bundle */
get_kprobe_inst(bundle, slot, &kprobe_inst, &major_opcode); get_kprobe_inst(bundle, slot, &kprobe_inst, &major_opcode);
if (unsupported_inst(template, slot, major_opcode, kprobe_inst, addr)) qp = unsupported_inst(template, slot, major_opcode, kprobe_inst, addr);
if (qp < 0)
return -EINVAL; return -EINVAL;
p->ainsn.insn = get_insn_slot(); p->ainsn.insn = get_insn_slot();
if (!p->ainsn.insn) if (!p->ainsn.insn)
return -ENOMEM; return -ENOMEM;
memcpy(&p->opcode, kprobe_addr, sizeof(kprobe_opcode_t)); memcpy(&p->opcode, kprobe_addr, sizeof(kprobe_opcode_t));
memcpy(p->ainsn.insn, kprobe_addr, sizeof(kprobe_opcode_t)); memcpy(p->ainsn.insn, kprobe_addr, sizeof(kprobe_opcode_t));
prepare_break_inst(template, slot, major_opcode, kprobe_inst, p); prepare_break_inst(template, slot, major_opcode, kprobe_inst, p, qp);
return 0; return 0;
} }
void __kprobes arch_arm_kprobe(struct kprobe *p) void __kprobes arch_arm_kprobe(struct kprobe *p)
{ {
unsigned long addr = (unsigned long)p->addr; unsigned long arm_addr;
unsigned long arm_addr = addr & ~0xFULL; bundle_t *src, *dest;
arm_addr = ((unsigned long)p->addr) & ~0xFUL;
dest = &((kprobe_opcode_t *)arm_addr)->bundle;
src = &p->opcode.bundle;
flush_icache_range((unsigned long)p->ainsn.insn, flush_icache_range((unsigned long)p->ainsn.insn,
(unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t)); (unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t));
memcpy((char *)arm_addr, &p->opcode, sizeof(kprobe_opcode_t)); switch (p->ainsn.slot) {
case 0:
dest->quad0.slot0 = src->quad0.slot0;
break;
case 1:
dest->quad1.slot1_p1 = src->quad1.slot1_p1;
break;
case 2:
dest->quad1.slot2 = src->quad1.slot2;
break;
}
flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t)); flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t));
} }
void __kprobes arch_disarm_kprobe(struct kprobe *p) void __kprobes arch_disarm_kprobe(struct kprobe *p)
{ {
unsigned long addr = (unsigned long)p->addr; unsigned long arm_addr;
unsigned long arm_addr = addr & ~0xFULL; bundle_t *src, *dest;
arm_addr = ((unsigned long)p->addr) & ~0xFUL;
dest = &((kprobe_opcode_t *)arm_addr)->bundle;
/* p->ainsn.insn contains the original unaltered kprobe_opcode_t */ /* p->ainsn.insn contains the original unaltered kprobe_opcode_t */
memcpy((char *) arm_addr, (char *) p->ainsn.insn, src = &p->ainsn.insn->bundle;
sizeof(kprobe_opcode_t)); switch (p->ainsn.slot) {
case 0:
dest->quad0.slot0 = src->quad0.slot0;
break;
case 1:
dest->quad1.slot1_p1 = src->quad1.slot1_p1;
break;
case 2:
dest->quad1.slot2 = src->quad1.slot2;
break;
}
flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t)); flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t));
} }
...@@ -807,7 +897,9 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, ...@@ -807,7 +897,9 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
switch(val) { switch(val) {
case DIE_BREAK: case DIE_BREAK:
/* err is break number from ia64_bad_break() */ /* err is break number from ia64_bad_break() */
if (args->err == 0x80200 || args->err == 0x80300 || args->err == 0) if ((args->err >> 12) == (__IA64_BREAK_KPROBE >> 12)
|| args->err == __IA64_BREAK_JPROBE
|| args->err == 0)
if (pre_kprobes_handler(args)) if (pre_kprobes_handler(args))
ret = NOTIFY_STOP; ret = NOTIFY_STOP;
break; break;
......
...@@ -19,8 +19,11 @@ ...@@ -19,8 +19,11 @@
#include <asm/delay.h> #include <asm/delay.h>
#include <asm/meminit.h> #include <asm/meminit.h>
typedef void (*relocate_new_kernel_t)(unsigned long, unsigned long, typedef NORET_TYPE void (*relocate_new_kernel_t)(
struct ia64_boot_param *, unsigned long); unsigned long indirection_page,
unsigned long start_address,
struct ia64_boot_param *boot_param,
unsigned long pal_addr) ATTRIB_NORET;
struct kimage *ia64_kimage; struct kimage *ia64_kimage;
......
...@@ -1239,7 +1239,7 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, ...@@ -1239,7 +1239,7 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw,
} else { } else {
/* Dump buffered message to console */ /* Dump buffered message to console */
ia64_mlogbuf_finish(1); ia64_mlogbuf_finish(1);
#ifdef CONFIG_CRASH_DUMP #ifdef CONFIG_KEXEC
atomic_set(&kdump_in_progress, 1); atomic_set(&kdump_in_progress, 1);
monarch_cpu = -1; monarch_cpu = -1;
#endif #endif
......
...@@ -256,7 +256,7 @@ reserve_memory (void) ...@@ -256,7 +256,7 @@ reserve_memory (void)
#ifdef CONFIG_KEXEC #ifdef CONFIG_KEXEC
/* crashkernel=size@offset specifies the size to reserve for a crash /* crashkernel=size@offset specifies the size to reserve for a crash
* kernel.(offset is ingored for keep compatibility with other archs) * kernel. If offset is 0, then it is determined automatically.
* By reserving this memory we guarantee that linux never set's it * By reserving this memory we guarantee that linux never set's it
* up as a DMA target.Useful for holding code to do something * up as a DMA target.Useful for holding code to do something
* appropriate after a kernel panic. * appropriate after a kernel panic.
...@@ -266,10 +266,16 @@ reserve_memory (void) ...@@ -266,10 +266,16 @@ reserve_memory (void)
unsigned long base, size; unsigned long base, size;
if (from) { if (from) {
size = memparse(from + 12, &from); size = memparse(from + 12, &from);
if (*from == '@')
base = memparse(from+1, &from);
else
base = 0;
if (size) { if (size) {
if (!base) {
sort_regions(rsvd_region, n); sort_regions(rsvd_region, n);
base = kdump_find_rsvd_region(size, base = kdump_find_rsvd_region(size,
rsvd_region, n); rsvd_region, n);
}
if (base != ~0UL) { if (base != ~0UL) {
rsvd_region[n].start = rsvd_region[n].start =
(unsigned long)__va(base); (unsigned long)__va(base);
...@@ -434,6 +440,21 @@ static __init int setup_nomca(char *s) ...@@ -434,6 +440,21 @@ static __init int setup_nomca(char *s)
} }
early_param("nomca", setup_nomca); early_param("nomca", setup_nomca);
#ifdef CONFIG_PROC_VMCORE
/* elfcorehdr= specifies the location of elf core header
* stored by the crashed kernel.
*/
static int __init parse_elfcorehdr(char *arg)
{
if (!arg)
return -EINVAL;
elfcorehdr_addr = memparse(arg, &arg);
return 0;
}
early_param("elfcorehdr", parse_elfcorehdr);
#endif /* CONFIG_PROC_VMCORE */
void __init void __init
setup_arch (char **cmdline_p) setup_arch (char **cmdline_p)
{ {
...@@ -653,6 +674,7 @@ get_model_name(__u8 family, __u8 model) ...@@ -653,6 +674,7 @@ get_model_name(__u8 family, __u8 model)
{ {
char brand[128]; char brand[128];
memcpy(brand, "Unknown", 8);
if (ia64_pal_get_brand_info(brand)) { if (ia64_pal_get_brand_info(brand)) {
if (family == 0x7) if (family == 0x7)
memcpy(brand, "Merced", 7); memcpy(brand, "Merced", 7);
...@@ -660,8 +682,7 @@ get_model_name(__u8 family, __u8 model) ...@@ -660,8 +682,7 @@ get_model_name(__u8 family, __u8 model)
case 0: memcpy(brand, "McKinley", 9); break; case 0: memcpy(brand, "McKinley", 9); break;
case 1: memcpy(brand, "Madison", 8); break; case 1: memcpy(brand, "Madison", 8); break;
case 2: memcpy(brand, "Madison up to 9M cache", 23); break; case 2: memcpy(brand, "Madison up to 9M cache", 23); break;
} else }
memcpy(brand, "Unknown", 8);
} }
if (brandname[0] == '\0') if (brandname[0] == '\0')
return strcpy(brandname, brand); return strcpy(brandname, brand);
......
...@@ -157,7 +157,7 @@ handle_IPI (int irq, void *dev_id) ...@@ -157,7 +157,7 @@ handle_IPI (int irq, void *dev_id)
case IPI_CPU_STOP: case IPI_CPU_STOP:
stop_this_cpu(); stop_this_cpu();
break; break;
#ifdef CONFIG_CRASH_DUMP #ifdef CONFIG_KEXEC
case IPI_KDUMP_CPU_STOP: case IPI_KDUMP_CPU_STOP:
unw_init_running(kdump_cpu_freeze, NULL); unw_init_running(kdump_cpu_freeze, NULL);
break; break;
...@@ -219,7 +219,7 @@ send_IPI_self (int op) ...@@ -219,7 +219,7 @@ send_IPI_self (int op)
send_IPI_single(smp_processor_id(), op); send_IPI_single(smp_processor_id(), op);
} }
#ifdef CONFIG_CRASH_DUMP #ifdef CONFIG_KEXEC
void void
kdump_smp_send_stop() kdump_smp_send_stop()
{ {
......
...@@ -307,6 +307,15 @@ fp_emulate (int fp_fault, void *bundle, long *ipsr, long *fpsr, long *isr, long ...@@ -307,6 +307,15 @@ fp_emulate (int fp_fault, void *bundle, long *ipsr, long *fpsr, long *isr, long
return ret.status; return ret.status;
} }
struct fpu_swa_msg {
unsigned long count;
unsigned long time;
};
static DEFINE_PER_CPU(struct fpu_swa_msg, cpulast);
DECLARE_PER_CPU(struct fpu_swa_msg, cpulast);
static struct fpu_swa_msg last __cacheline_aligned;
/* /*
* Handle floating-point assist faults and traps. * Handle floating-point assist faults and traps.
*/ */
...@@ -316,8 +325,6 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr) ...@@ -316,8 +325,6 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr)
long exception, bundle[2]; long exception, bundle[2];
unsigned long fault_ip; unsigned long fault_ip;
struct siginfo siginfo; struct siginfo siginfo;
static int fpu_swa_count = 0;
static unsigned long last_time;
fault_ip = regs->cr_iip; fault_ip = regs->cr_iip;
if (!fp_fault && (ia64_psr(regs)->ri == 0)) if (!fp_fault && (ia64_psr(regs)->ri == 0))
...@@ -325,15 +332,38 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr) ...@@ -325,15 +332,38 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr)
if (copy_from_user(bundle, (void __user *) fault_ip, sizeof(bundle))) if (copy_from_user(bundle, (void __user *) fault_ip, sizeof(bundle)))
return -1; return -1;
if (jiffies - last_time > 5*HZ) if (!(current->thread.flags & IA64_THREAD_FPEMU_NOPRINT)) {
fpu_swa_count = 0; unsigned long count, current_jiffies = jiffies;
if ((fpu_swa_count < 4) && !(current->thread.flags & IA64_THREAD_FPEMU_NOPRINT)) { struct fpu_swa_msg *cp = &__get_cpu_var(cpulast);
last_time = jiffies;
++fpu_swa_count; if (unlikely(current_jiffies > cp->time))
cp->count = 0;
if (unlikely(cp->count < 5)) {
cp->count++;
cp->time = current_jiffies + 5 * HZ;
/* minimize races by grabbing a copy of count BEFORE checking last.time. */
count = last.count;
barrier();
/*
* Lower 4 bits are used as a count. Upper bits are a sequence
* number that is updated when count is reset. The cmpxchg will
* fail is seqno has changed. This minimizes mutiple cpus
* reseting the count.
*/
if (current_jiffies > last.time)
(void) cmpxchg_acq(&last.count, count, 16 + (count & ~15));
/* used fetchadd to atomically update the count */
if ((last.count & 15) < 5 && (ia64_fetchadd(1, &last.count, acq) & 15) < 5) {
last.time = current_jiffies + 5 * HZ;
printk(KERN_WARNING printk(KERN_WARNING
"%s(%d): floating-point assist fault at ip %016lx, isr %016lx\n", "%s(%d): floating-point assist fault at ip %016lx, isr %016lx\n",
current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri, isr); current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri, isr);
} }
}
}
exception = fp_emulate(fp_fault, bundle, &regs->cr_ipsr, &regs->ar_fpsr, &isr, &regs->pr, exception = fp_emulate(fp_fault, bundle, &regs->cr_ipsr, &regs->ar_fpsr, &isr, &regs->pr,
&regs->cr_ifs, regs); &regs->cr_ifs, regs);
......
...@@ -174,6 +174,12 @@ find_memory (void) ...@@ -174,6 +174,12 @@ find_memory (void)
reserve_bootmem(bootmap_start, bootmap_size); reserve_bootmem(bootmap_start, bootmap_size);
find_initrd(); find_initrd();
#ifdef CONFIG_CRASH_DUMP
/* If we are doing a crash dump, we still need to know the real mem
* size before original memory map is * reset. */
saved_max_pfn = max_pfn;
#endif
} }
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
...@@ -226,7 +232,6 @@ void __init ...@@ -226,7 +232,6 @@ void __init
paging_init (void) paging_init (void)
{ {
unsigned long max_dma; unsigned long max_dma;
unsigned long nid = 0;
unsigned long max_zone_pfns[MAX_NR_ZONES]; unsigned long max_zone_pfns[MAX_NR_ZONES];
num_physpages = 0; num_physpages = 0;
...@@ -238,7 +243,7 @@ paging_init (void) ...@@ -238,7 +243,7 @@ paging_init (void)
max_zone_pfns[ZONE_NORMAL] = max_low_pfn; max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
#ifdef CONFIG_VIRTUAL_MEM_MAP #ifdef CONFIG_VIRTUAL_MEM_MAP
efi_memmap_walk(register_active_ranges, &nid); efi_memmap_walk(register_active_ranges, NULL);
efi_memmap_walk(find_largest_hole, (u64 *)&max_gap); efi_memmap_walk(find_largest_hole, (u64 *)&max_gap);
if (max_gap < LARGE_GAP) { if (max_gap < LARGE_GAP) {
vmem_map = (struct page *) 0; vmem_map = (struct page *) 0;
......
...@@ -595,14 +595,9 @@ find_largest_hole (u64 start, u64 end, void *arg) ...@@ -595,14 +595,9 @@ find_largest_hole (u64 start, u64 end, void *arg)
} }
int __init int __init
register_active_ranges(u64 start, u64 end, void *nid) register_active_ranges(u64 start, u64 end, void *arg)
{ {
BUG_ON(nid == NULL); add_active_range(0, __pa(start) >> PAGE_SHIFT, __pa(end) >> PAGE_SHIFT);
BUG_ON(*(unsigned long *)nid >= MAX_NUMNODES);
add_active_range(*(unsigned long *)nid,
__pa(start) >> PAGE_SHIFT,
__pa(end) >> PAGE_SHIFT);
return 0; return 0;
} }
#endif /* CONFIG_VIRTUAL_MEM_MAP */ #endif /* CONFIG_VIRTUAL_MEM_MAP */
......
...@@ -580,7 +580,7 @@ void __cpuinit sn_cpu_init(void) ...@@ -580,7 +580,7 @@ void __cpuinit sn_cpu_init(void)
int slice; int slice;
int cnode; int cnode;
int i; int i;
static int wars_have_been_checked; static int wars_have_been_checked, set_cpu0_number;
cpuid = smp_processor_id(); cpuid = smp_processor_id();
if (cpuid == 0 && IS_MEDUSA()) { if (cpuid == 0 && IS_MEDUSA()) {
...@@ -605,7 +605,15 @@ void __cpuinit sn_cpu_init(void) ...@@ -605,7 +605,15 @@ void __cpuinit sn_cpu_init(void)
/* /*
* Don't check status. The SAL call is not supported on all PROMs * Don't check status. The SAL call is not supported on all PROMs
* but a failure is harmless. * but a failure is harmless.
* Architechtuallly, cpu_init is always called twice on cpu 0. We
* should set cpu_number on cpu 0 once.
*/ */
if (cpuid == 0) {
if (!set_cpu0_number) {
(void) ia64_sn_set_cpu_number(cpuid);
set_cpu0_number = 1;
}
} else
(void) ia64_sn_set_cpu_number(cpuid); (void) ia64_sn_set_cpu_number(cpuid);
/* /*
......
...@@ -632,7 +632,7 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags) ...@@ -632,7 +632,7 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags)
ch->number, ch->partid); ch->number, ch->partid);
spin_unlock_irqrestore(&ch->lock, *irq_flags); spin_unlock_irqrestore(&ch->lock, *irq_flags);
xpc_create_kthreads(ch, 1); xpc_create_kthreads(ch, 1, 0);
spin_lock_irqsave(&ch->lock, *irq_flags); spin_lock_irqsave(&ch->lock, *irq_flags);
} }
...@@ -754,12 +754,12 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) ...@@ -754,12 +754,12 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags)
/* make sure all activity has settled down first */ /* make sure all activity has settled down first */
if (atomic_read(&ch->references) > 0 || if (atomic_read(&ch->kthreads_assigned) > 0 ||
((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) && atomic_read(&ch->references) > 0) {
!(ch->flags & XPC_C_DISCONNECTINGCALLOUT_MADE))) {
return; return;
} }
DBUG_ON(atomic_read(&ch->kthreads_assigned) != 0); DBUG_ON((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
!(ch->flags & XPC_C_DISCONNECTINGCALLOUT_MADE));
if (part->act_state == XPC_P_DEACTIVATING) { if (part->act_state == XPC_P_DEACTIVATING) {
/* can't proceed until the other side disengages from us */ /* can't proceed until the other side disengages from us */
...@@ -1651,6 +1651,11 @@ xpc_disconnect_channel(const int line, struct xpc_channel *ch, ...@@ -1651,6 +1651,11 @@ xpc_disconnect_channel(const int line, struct xpc_channel *ch,
/* wake all idle kthreads so they can exit */ /* wake all idle kthreads so they can exit */
if (atomic_read(&ch->kthreads_idle) > 0) { if (atomic_read(&ch->kthreads_idle) > 0) {
wake_up_all(&ch->idle_wq); wake_up_all(&ch->idle_wq);
} else if ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
!(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) {
/* start a kthread that will do the xpcDisconnecting callout */
xpc_create_kthreads(ch, 1, 1);
} }
/* wake those waiting to allocate an entry from the local msg queue */ /* wake those waiting to allocate an entry from the local msg queue */
......
...@@ -681,7 +681,7 @@ xpc_activate_kthreads(struct xpc_channel *ch, int needed) ...@@ -681,7 +681,7 @@ xpc_activate_kthreads(struct xpc_channel *ch, int needed)
dev_dbg(xpc_chan, "create %d new kthreads, partid=%d, channel=%d\n", dev_dbg(xpc_chan, "create %d new kthreads, partid=%d, channel=%d\n",
needed, ch->partid, ch->number); needed, ch->partid, ch->number);
xpc_create_kthreads(ch, needed); xpc_create_kthreads(ch, needed, 0);
} }
...@@ -775,7 +775,8 @@ xpc_daemonize_kthread(void *args) ...@@ -775,7 +775,8 @@ xpc_daemonize_kthread(void *args)
xpc_kthread_waitmsgs(part, ch); xpc_kthread_waitmsgs(part, ch);
} }
if (atomic_dec_return(&ch->kthreads_assigned) == 0) { /* let registerer know that connection is disconnecting */
spin_lock_irqsave(&ch->lock, irq_flags); spin_lock_irqsave(&ch->lock, irq_flags);
if ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) && if ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
!(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) { !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) {
...@@ -788,13 +789,14 @@ xpc_daemonize_kthread(void *args) ...@@ -788,13 +789,14 @@ xpc_daemonize_kthread(void *args)
ch->flags |= XPC_C_DISCONNECTINGCALLOUT_MADE; ch->flags |= XPC_C_DISCONNECTINGCALLOUT_MADE;
} }
spin_unlock_irqrestore(&ch->lock, irq_flags); spin_unlock_irqrestore(&ch->lock, irq_flags);
if (atomic_dec_return(&ch->kthreads_assigned) == 0) {
if (atomic_dec_return(&part->nchannels_engaged) == 0) { if (atomic_dec_return(&part->nchannels_engaged) == 0) {
xpc_mark_partition_disengaged(part); xpc_mark_partition_disengaged(part);
xpc_IPI_send_disengage(part); xpc_IPI_send_disengage(part);
} }
} }
xpc_msgqueue_deref(ch); xpc_msgqueue_deref(ch);
dev_dbg(xpc_chan, "kthread exiting, partid=%d, channel=%d\n", dev_dbg(xpc_chan, "kthread exiting, partid=%d, channel=%d\n",
...@@ -818,7 +820,8 @@ xpc_daemonize_kthread(void *args) ...@@ -818,7 +820,8 @@ xpc_daemonize_kthread(void *args)
* partition. * partition.
*/ */
void void
xpc_create_kthreads(struct xpc_channel *ch, int needed) xpc_create_kthreads(struct xpc_channel *ch, int needed,
int ignore_disconnecting)
{ {
unsigned long irq_flags; unsigned long irq_flags;
pid_t pid; pid_t pid;
...@@ -833,16 +836,38 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed) ...@@ -833,16 +836,38 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed)
* kthread. That kthread is responsible for doing the * kthread. That kthread is responsible for doing the
* counterpart to the following before it exits. * counterpart to the following before it exits.
*/ */
(void) xpc_part_ref(part); if (ignore_disconnecting) {
xpc_msgqueue_ref(ch); if (!atomic_inc_not_zero(&ch->kthreads_assigned)) {
if (atomic_inc_return(&ch->kthreads_assigned) == 1 && /* kthreads assigned had gone to zero */
atomic_inc_return(&part->nchannels_engaged) == 1) { BUG_ON(!(ch->flags &
XPC_C_DISCONNECTINGCALLOUT_MADE));
break;
}
} else if (ch->flags & XPC_C_DISCONNECTING) {
break;
} else if (atomic_inc_return(&ch->kthreads_assigned) == 1) {
if (atomic_inc_return(&part->nchannels_engaged) == 1)
xpc_mark_partition_engaged(part); xpc_mark_partition_engaged(part);
} }
(void) xpc_part_ref(part);
xpc_msgqueue_ref(ch);
pid = kernel_thread(xpc_daemonize_kthread, (void *) args, 0); pid = kernel_thread(xpc_daemonize_kthread, (void *) args, 0);
if (pid < 0) { if (pid < 0) {
/* the fork failed */ /* the fork failed */
/*
* NOTE: if (ignore_disconnecting &&
* !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) is true,
* then we'll deadlock if all other kthreads assigned
* to this channel are blocked in the channel's
* registerer, because the only thing that will unblock
* them is the xpcDisconnecting callout that this
* failed kernel_thread would have made.
*/
if (atomic_dec_return(&ch->kthreads_assigned) == 0 && if (atomic_dec_return(&ch->kthreads_assigned) == 0 &&
atomic_dec_return(&part->nchannels_engaged) == 0) { atomic_dec_return(&part->nchannels_engaged) == 0) {
xpc_mark_partition_disengaged(part); xpc_mark_partition_disengaged(part);
...@@ -857,9 +882,6 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed) ...@@ -857,9 +882,6 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed)
* Flag this as an error only if we have an * Flag this as an error only if we have an
* insufficient #of kthreads for the channel * insufficient #of kthreads for the channel
* to function. * to function.
*
* No xpc_msgqueue_ref() is needed here since
* the channel mgr is doing this.
*/ */
spin_lock_irqsave(&ch->lock, irq_flags); spin_lock_irqsave(&ch->lock, irq_flags);
XPC_DISCONNECT_CHANNEL(ch, xpcLackOfResources, XPC_DISCONNECT_CHANNEL(ch, xpcLackOfResources,
......
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
* OS-specific debug break numbers: * OS-specific debug break numbers:
*/ */
#define __IA64_BREAK_KDB 0x80100 #define __IA64_BREAK_KDB 0x80100
#define __IA64_BREAK_KPROBE 0x80200 #define __IA64_BREAK_KPROBE 0x81000 /* .. 0x81fff */
#define __IA64_BREAK_JPROBE 0x80300 #define __IA64_BREAK_JPROBE 0x82000
/* /*
* OS-specific break numbers: * OS-specific break numbers:
......
...@@ -115,6 +115,7 @@ struct arch_specific_insn { ...@@ -115,6 +115,7 @@ struct arch_specific_insn {
#define INST_FLAG_BREAK_INST 4 #define INST_FLAG_BREAK_INST 4
unsigned long inst_flag; unsigned long inst_flag;
unsigned short target_br_reg; unsigned short target_br_reg;
unsigned short slot;
}; };
extern int kprobe_exceptions_notify(struct notifier_block *self, extern int kprobe_exceptions_notify(struct notifier_block *self,
......
...@@ -673,7 +673,7 @@ extern irqreturn_t xpc_notify_IRQ_handler(int, void *); ...@@ -673,7 +673,7 @@ extern irqreturn_t xpc_notify_IRQ_handler(int, void *);
extern void xpc_dropped_IPI_check(struct xpc_partition *); extern void xpc_dropped_IPI_check(struct xpc_partition *);
extern void xpc_activate_partition(struct xpc_partition *); extern void xpc_activate_partition(struct xpc_partition *);
extern void xpc_activate_kthreads(struct xpc_channel *, int); extern void xpc_activate_kthreads(struct xpc_channel *, int);
extern void xpc_create_kthreads(struct xpc_channel *, int); extern void xpc_create_kthreads(struct xpc_channel *, int, int);
extern void xpc_disconnect_wait(int); extern void xpc_disconnect_wait(int);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment