* [PATCH 2/2] kdump shutdown hook support @ 2007-12-12 5:45 Michael Neuling 2007-12-12 7:01 ` Olof Johansson ` (2 more replies) 0 siblings, 3 replies; 27+ messages in thread From: Michael Neuling @ 2007-12-12 5:45 UTC (permalink / raw) To: Paul Mackerras; +Cc: linuxppc-dev, Michael Neuling, RAISCH, THEMANN This adds hooks into the default_machine_crash_shutdown so drivers can register a function to be run in the first kernel before we hand off to the second kernel. This should only be used in exceptional circumstances, like where the device can't be reset in the second kernel alone (as is the case with eHEA). To emphasize this, the number of handles allowed to be registered is currently #def to 1. This uses the setjmp/longjmp code to call out to the registered hooks, so any bogus exceptions we encounter will hopefully be recoverable. I've tested with bogus data and instruction exceptions. Signed-off-by: Michael Neuling <mikey@neuling.org> --- arch/powerpc/kernel/crash.c | 90 +++++++++++++++++++++++++++++++++++++++++--- include/asm-powerpc/kexec.h | 3 + 2 files changed, 88 insertions(+), 5 deletions(-) Index: linux-2.6-ozlabs/arch/powerpc/kernel/crash.c =================================================================== --- linux-2.6-ozlabs.orig/arch/powerpc/kernel/crash.c +++ linux-2.6-ozlabs/arch/powerpc/kernel/crash.c @@ -32,6 +32,8 @@ #include <asm/lmb.h> #include <asm/firmware.h> #include <asm/smp.h> +#include <asm/system.h> +#include <asm/setjmp.h> #ifdef DEBUG #include <asm/udbg.h> @@ -45,6 +47,11 @@ int crashing_cpu = -1; static cpumask_t cpus_in_crash = CPU_MASK_NONE; cpumask_t cpus_in_sr = CPU_MASK_NONE; +#define CRASH_SHUTDOWN_HANDLES_NUM 1 +/* NULL terminated list of shutdown handles */ +static crash_shutdown_t crash_shutdown_handles[CRASH_SHUTDOWN_HANDLES_NUM+1]; +static DEFINE_SPINLOCK(crash_handles_lock); + #ifdef CONFIG_SMP static atomic_t enter_on_soft_reset = ATOMIC_INIT(0); @@ -285,9 +292,69 @@ static inline void crash_kexec_stop_spus } #endif /* CONFIG_SPU_BASE */ +/* + * Register a function to be called on shutdown. Only use this if you + * can't reset your device in the second kernel. + */ +int crash_shutdown_register(crash_shutdown_t handler) +{ + unsigned int i; + + spin_lock(&crash_handles_lock); + for(i = 0 ; i <= CRASH_SHUTDOWN_HANDLES_NUM; i++) + if (!crash_shutdown_handles[i]) + break; + + if (i == CRASH_SHUTDOWN_HANDLES_NUM){ + printk(KERN_ERR "Crash shutdown handles full, " + "not registered.\n"); + spin_unlock(&crash_handles_lock); + return 1; + } + + /* Insert handle at end */ + crash_shutdown_handles[i] = handler; + spin_unlock(&crash_handles_lock); + return 0; +} +EXPORT_SYMBOL(crash_shutdown_register); + +int crash_shutdown_unregister(crash_shutdown_t handler) +{ + unsigned int i; + + spin_lock(&crash_handles_lock); + for(i = 0 ; i <= CRASH_SHUTDOWN_HANDLES_NUM; i++) + if (crash_shutdown_handles[i] == handler) + break; + + if (i == CRASH_SHUTDOWN_HANDLES_NUM){ + printk(KERN_ERR "Crash shutdown handle not found\n"); + spin_unlock(&crash_handles_lock); + return 1; + } + + /* Shift handles down */ + while(crash_shutdown_handles[i]) { + crash_shutdown_handles[i] = crash_shutdown_handles[i+1]; + i++; + } + spin_unlock(&crash_handles_lock); + return 0; +} +EXPORT_SYMBOL(crash_shutdown_unregister); + +static long crash_shutdown_buf[SETJMP_BUF_LEN]; + +static int handle_fault(struct pt_regs *regs) +{ + longjmp(crash_shutdown_buf, 1); + return 0; +} + void default_machine_crash_shutdown(struct pt_regs *regs) { - unsigned int irq; + unsigned int i; /* * This function is only called after the system @@ -301,14 +368,27 @@ void default_machine_crash_shutdown(stru */ hard_irq_disable(); - for_each_irq(irq) { - struct irq_desc *desc = irq_desc + irq; + for_each_irq(i) { + struct irq_desc *desc = irq_desc + i; if (desc->status & IRQ_INPROGRESS) - desc->chip->eoi(irq); + desc->chip->eoi(i); if (!(desc->status & IRQ_DISABLED)) - desc->chip->disable(irq); + desc->chip->disable(i); + } + + /* Call registered shutdown routines */ + __debugger_fault_handler = handle_fault; + i = 0; + while(crash_shutdown_handles[i]){ + if (setjmp(crash_shutdown_buf) == 0) { + asm volatile("sync; isync"); + crash_shutdown_handles[i](); + asm volatile("sync; isync"); + __delay(200); + } + i++; } /* Index: linux-2.6-ozlabs/include/asm-powerpc/kexec.h =================================================================== --- linux-2.6-ozlabs.orig/include/asm-powerpc/kexec.h +++ linux-2.6-ozlabs/include/asm-powerpc/kexec.h @@ -123,6 +123,9 @@ struct pt_regs; extern void default_machine_kexec(struct kimage *image); extern int default_machine_kexec_prepare(struct kimage *image); extern void default_machine_crash_shutdown(struct pt_regs *regs); +typedef void (*crash_shutdown_t)(void); +extern int crash_shutdown_register(crash_shutdown_t handler); +extern int crash_shutdown_unregister(crash_shutdown_t handler); extern void machine_kexec_simple(struct kimage *image); extern void crash_kexec_secondary(struct pt_regs *regs); ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 2/2] kdump shutdown hook support 2007-12-12 5:45 [PATCH 2/2] kdump shutdown hook support Michael Neuling @ 2007-12-12 7:01 ` Olof Johansson 2007-12-13 0:53 ` Michael Neuling 2007-12-12 23:07 ` Michael Ellerman 2007-12-13 3:16 ` [PATCH 0/2] Add crashdump shutdown hooks Michael Neuling 2 siblings, 1 reply; 27+ messages in thread From: Olof Johansson @ 2007-12-12 7:01 UTC (permalink / raw) To: Michael Neuling; +Cc: linuxppc-dev, RAISCH, Paul Mackerras, THEMANN Hi, A couple of comments below. -Olof On Wed, Dec 12, 2007 at 04:45:12PM +1100, Michael Neuling wrote: > Index: linux-2.6-ozlabs/arch/powerpc/kernel/crash.c > =================================================================== > --- linux-2.6-ozlabs.orig/arch/powerpc/kernel/crash.c > +++ linux-2.6-ozlabs/arch/powerpc/kernel/crash.c > @@ -32,6 +32,8 @@ > #include <asm/lmb.h> > #include <asm/firmware.h> > #include <asm/smp.h> > +#include <asm/system.h> > +#include <asm/setjmp.h> > > #ifdef DEBUG > #include <asm/udbg.h> > @@ -45,6 +47,11 @@ int crashing_cpu = -1; > static cpumask_t cpus_in_crash = CPU_MASK_NONE; > cpumask_t cpus_in_sr = CPU_MASK_NONE; > > +#define CRASH_SHUTDOWN_HANDLES_NUM 1 > +/* NULL terminated list of shutdown handles */ > +static crash_shutdown_t crash_shutdown_handles[CRASH_SHUTDOWN_HANDLES_NUM+1]; > +static DEFINE_SPINLOCK(crash_handles_lock); Not 'handlers'? > + > #ifdef CONFIG_SMP > static atomic_t enter_on_soft_reset = ATOMIC_INIT(0); > > @@ -285,9 +292,69 @@ static inline void crash_kexec_stop_spus > } > #endif /* CONFIG_SPU_BASE */ > > +/* > + * Register a function to be called on shutdown. Only use this if you > + * can't reset your device in the second kernel. > + */ > +int crash_shutdown_register(crash_shutdown_t handler) > +{ > + unsigned int i; > + > + spin_lock(&crash_handles_lock); > + for(i = 0 ; i <= CRASH_SHUTDOWN_HANDLES_NUM; i++) Missing space after for. There's a handful more of these through the patch. > + if (!crash_shutdown_handles[i]) > + break; > + > + if (i == CRASH_SHUTDOWN_HANDLES_NUM){ > + printk(KERN_ERR "Crash shutdown handles full, " > + "not registered.\n"); > + spin_unlock(&crash_handles_lock); > + return 1; > + } > + > + /* Insert handle at end */ > + crash_shutdown_handles[i] = handler; > + spin_unlock(&crash_handles_lock); > + return 0; > +} > +EXPORT_SYMBOL(crash_shutdown_register); > + > +int crash_shutdown_unregister(crash_shutdown_t handler) > +{ > + unsigned int i; > + > + spin_lock(&crash_handles_lock); > + for(i = 0 ; i <= CRASH_SHUTDOWN_HANDLES_NUM; i++) > + if (crash_shutdown_handles[i] == handler) > + break; > + > + if (i == CRASH_SHUTDOWN_HANDLES_NUM){ > + printk(KERN_ERR "Crash shutdown handle not found\n"); > + spin_unlock(&crash_handles_lock); > + return 1; > + } > + > + /* Shift handles down */ > + while(crash_shutdown_handles[i]) { > + crash_shutdown_handles[i] = crash_shutdown_handles[i+1]; > + i++; > + } > + spin_unlock(&crash_handles_lock); > + return 0; > +} > +EXPORT_SYMBOL(crash_shutdown_unregister); > + > +static long crash_shutdown_buf[SETJMP_BUF_LEN]; > + > +static int handle_fault(struct pt_regs *regs) > +{ > + longjmp(crash_shutdown_buf, 1); > + return 0; > +} > + > void default_machine_crash_shutdown(struct pt_regs *regs) > { > - unsigned int irq; > + unsigned int i; > > /* > * This function is only called after the system > @@ -301,14 +368,27 @@ void default_machine_crash_shutdown(stru > */ > hard_irq_disable(); > > - for_each_irq(irq) { > - struct irq_desc *desc = irq_desc + irq; > + for_each_irq(i) { > + struct irq_desc *desc = irq_desc + i; > > if (desc->status & IRQ_INPROGRESS) > - desc->chip->eoi(irq); > + desc->chip->eoi(i); > > if (!(desc->status & IRQ_DISABLED)) > - desc->chip->disable(irq); > + desc->chip->disable(i); > + } > + > + /* Call registered shutdown routines */ > + __debugger_fault_handler = handle_fault; > + i = 0; > + while(crash_shutdown_handles[i]){ This could do nicely as a for loop instead: for (i = 0; crash_shutdown_handles[i]; i++) { > + if (setjmp(crash_shutdown_buf) == 0) { > + asm volatile("sync; isync"); > + crash_shutdown_handles[i](); > + asm volatile("sync; isync"); > + __delay(200); This looks a bit random. Why the handcoded barriers, and why the delay? At least comment why the delay is needed (and why just 200 is sufficient). I don't see a need for the barriers at all here? > + } > + i++; > } > > /* > Index: linux-2.6-ozlabs/include/asm-powerpc/kexec.h > =================================================================== > --- linux-2.6-ozlabs.orig/include/asm-powerpc/kexec.h > +++ linux-2.6-ozlabs/include/asm-powerpc/kexec.h > @@ -123,6 +123,9 @@ struct pt_regs; > extern void default_machine_kexec(struct kimage *image); > extern int default_machine_kexec_prepare(struct kimage *image); > extern void default_machine_crash_shutdown(struct pt_regs *regs); > +typedef void (*crash_shutdown_t)(void); > +extern int crash_shutdown_register(crash_shutdown_t handler); > +extern int crash_shutdown_unregister(crash_shutdown_t handler); > > extern void machine_kexec_simple(struct kimage *image); > extern void crash_kexec_secondary(struct pt_regs *regs); > _______________________________________________ > Linuxppc-dev mailing list > Linuxppc-dev@ozlabs.org > https://ozlabs.org/mailman/listinfo/linuxppc-dev ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 2/2] kdump shutdown hook support 2007-12-12 7:01 ` Olof Johansson @ 2007-12-13 0:53 ` Michael Neuling 0 siblings, 0 replies; 27+ messages in thread From: Michael Neuling @ 2007-12-13 0:53 UTC (permalink / raw) To: Olof Johansson; +Cc: linuxppc-dev, RAISCH, Paul Mackerras, THEMANN > > > + if (setjmp(crash_shutdown_buf) == 0) { > > + asm volatile("sync; isync"); > > + crash_shutdown_handles[i](); > > + asm volatile("sync; isync"); > > + __delay(200); > > This looks a bit random. Why the handcoded barriers, and why the delay? > I don't see a need for the barriers at all here? I was following the bouncing ball here from the xmon code. We don't want the hardware executing any of potentially dangerous hooks before we've setup the setjmp save buffer. Similar, any code past the dangerous hooks shouldn't be executed before we take a machine check. It's definitely not a fast path so.... :-) > At least comment why the delay is needed (and why just 200 is > sufficient). xmon.c says: /* wait a little while to see if we get a machine check */ I'll update the "200" with a #define SETJMP_MACHINE_CHECK_DELAY and push the same change into the xmon code. This delay in the machine check is apparently required on 601 machines. All you other comments I agree with. Mikey ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 2/2] kdump shutdown hook support 2007-12-12 5:45 [PATCH 2/2] kdump shutdown hook support Michael Neuling 2007-12-12 7:01 ` Olof Johansson @ 2007-12-12 23:07 ` Michael Ellerman 2007-12-13 0:04 ` Michael Neuling 2007-12-13 3:16 ` [PATCH 0/2] Add crashdump shutdown hooks Michael Neuling 2 siblings, 1 reply; 27+ messages in thread From: Michael Ellerman @ 2007-12-12 23:07 UTC (permalink / raw) To: Michael Neuling; +Cc: linuxppc-dev, RAISCH, Paul Mackerras, THEMANN [-- Attachment #1: Type: text/plain, Size: 4958 bytes --] On Wed, 2007-12-12 at 16:45 +1100, Michael Neuling wrote: > This adds hooks into the default_machine_crash_shutdown so drivers can > register a function to be run in the first kernel before we hand off > to the second kernel. This should only be used in exceptional > circumstances, like where the device can't be reset in the second > kernel alone (as is the case with eHEA). To emphasize this, the > number of handles allowed to be registered is currently #def to 1. > > This uses the setjmp/longjmp code to call out to the registered hooks, > so any bogus exceptions we encounter will hopefully be recoverable. > > I've tested with bogus data and instruction exceptions. > > Signed-off-by: Michael Neuling <mikey@neuling.org> > --- > > arch/powerpc/kernel/crash.c | 90 +++++++++++++++++++++++++++++++++++++++++--- > include/asm-powerpc/kexec.h | 3 + > 2 files changed, 88 insertions(+), 5 deletions(-) > > Index: linux-2.6-ozlabs/arch/powerpc/kernel/crash.c > =================================================================== > --- linux-2.6-ozlabs.orig/arch/powerpc/kernel/crash.c > +++ linux-2.6-ozlabs/arch/powerpc/kernel/crash.c > @@ -32,6 +32,8 @@ > #include <asm/lmb.h> > #include <asm/firmware.h> > #include <asm/smp.h> > +#include <asm/system.h> > +#include <asm/setjmp.h> > > #ifdef DEBUG > #include <asm/udbg.h> > @@ -45,6 +47,11 @@ int crashing_cpu = -1; > static cpumask_t cpus_in_crash = CPU_MASK_NONE; > cpumask_t cpus_in_sr = CPU_MASK_NONE; > > +#define CRASH_SHUTDOWN_HANDLES_NUM 1 CRASH_HANDLER_MAX ? > +/* NULL terminated list of shutdown handles */ > +static crash_shutdown_t crash_shutdown_handles[CRASH_SHUTDOWN_HANDLES_NUM+1]; > +static DEFINE_SPINLOCK(crash_handles_lock); > + > #ifdef CONFIG_SMP > static atomic_t enter_on_soft_reset = ATOMIC_INIT(0); > > @@ -285,9 +292,69 @@ static inline void crash_kexec_stop_spus > } > #endif /* CONFIG_SPU_BASE */ > > +/* > + * Register a function to be called on shutdown. Only use this if you > + * can't reset your device in the second kernel. > + */ > +int crash_shutdown_register(crash_shutdown_t handler) > +{ > + unsigned int i, rc; > + > + spin_lock(&crash_handles_lock); > + for(i = 0 ; i <= CRASH_SHUTDOWN_HANDLES_NUM; i++) { > + if (!crash_shutdown_handles[i]) { > + /* Insert handle at end */ > + crash_shutdown_handles[i] = handler; > + rc = 0; > + break; > + } > + } > > + if (i == CRASH_SHUTDOWN_HANDLES_NUM){ > + printk(KERN_ERR "Crash shutdown handles full, " > + "not registered.\n"); > + rc = 1; > + } > + > + spin_unlock(&crash_handles_lock); Perhaps? > + return rc; > +} > +EXPORT_SYMBOL(crash_shutdown_register); > + > +int crash_shutdown_unregister(crash_shutdown_t handler) > +{ > + unsigned int i; > + > + spin_lock(&crash_handles_lock); > + for(i = 0 ; i <= CRASH_SHUTDOWN_HANDLES_NUM; i++) > + if (crash_shutdown_handles[i] == handler) > + break; > + > + if (i == CRASH_SHUTDOWN_HANDLES_NUM){ > + printk(KERN_ERR "Crash shutdown handle not found\n"); > + spin_unlock(&crash_handles_lock); > + return 1; > + } > + > + /* Shift handles down */ > + while(crash_shutdown_handles[i]) { > + crash_shutdown_handles[i] = crash_shutdown_handles[i+1]; > + i++; > + } > + spin_unlock(&crash_handles_lock); > + return 0; > +} > +EXPORT_SYMBOL(crash_shutdown_unregister); > + > +static long crash_shutdown_buf[SETJMP_BUF_LEN]; unsigned long? > + > +static int handle_fault(struct pt_regs *regs) > +{ > + longjmp(crash_shutdown_buf, 1); > + return 0; > +} > + > void default_machine_crash_shutdown(struct pt_regs *regs) > { > - unsigned int irq; > + unsigned int i; > > /* > * This function is only called after the system > @@ -301,14 +368,27 @@ void default_machine_crash_shutdown(stru > */ > hard_irq_disable(); > > - for_each_irq(irq) { > - struct irq_desc *desc = irq_desc + irq; > + for_each_irq(i) { > + struct irq_desc *desc = irq_desc + i; > > if (desc->status & IRQ_INPROGRESS) > - desc->chip->eoi(irq); > + desc->chip->eoi(i); > > if (!(desc->status & IRQ_DISABLED)) > - desc->chip->disable(irq); > + desc->chip->disable(i); > + } > + > + /* Call registered shutdown routines */ > + __debugger_fault_handler = handle_fault; > + i = 0; > + while(crash_shutdown_handles[i]){ > + if (setjmp(crash_shutdown_buf) == 0) { > + asm volatile("sync; isync"); > + crash_shutdown_handles[i](); > + asm volatile("sync; isync"); > + __delay(200); > + } > + i++; > } You should probably reset __debugger_fault_handler, just to be safe. cheers -- Michael Ellerman OzLabs, IBM Australia Development Lab wwweb: http://michael.ellerman.id.au phone: +61 2 6212 1183 (tie line 70 21183) We do not inherit the earth from our ancestors, we borrow it from our children. - S.M.A.R.T Person [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 2/2] kdump shutdown hook support 2007-12-12 23:07 ` Michael Ellerman @ 2007-12-13 0:04 ` Michael Neuling 0 siblings, 0 replies; 27+ messages in thread From: Michael Neuling @ 2007-12-13 0:04 UTC (permalink / raw) To: michael; +Cc: linuxppc-dev, RAISCH, Paul Mackerras, THEMANN In message <1197500839.7695.19.camel@concordia> you wrote: > > --=-Kza0KCx0MG8nsjfq7kOz > Content-Type: text/plain > Content-Transfer-Encoding: quoted-printable > > On Wed, 2007-12-12 at 16:45 +1100, Michael Neuling wrote: > > This adds hooks into the default_machine_crash_shutdown so drivers can > > register a function to be run in the first kernel before we hand off > > to the second kernel. This should only be used in exceptional > > circumstances, like where the device can't be reset in the second > > kernel alone (as is the case with eHEA). To emphasize this, the > > number of handles allowed to be registered is currently #def to 1. > >=20 > > This uses the setjmp/longjmp code to call out to the registered hooks, > > so any bogus exceptions we encounter will hopefully be recoverable. =20 > >=20 > > I've tested with bogus data and instruction exceptions. > >=20 > > Signed-off-by: Michael Neuling <mikey@neuling.org> > > --- > >=20 > > arch/powerpc/kernel/crash.c | 90 +++++++++++++++++++++++++++++++++++++= > ++++--- > > include/asm-powerpc/kexec.h | 3 + > > 2 files changed, 88 insertions(+), 5 deletions(-) > >=20 > > Index: linux-2.6-ozlabs/arch/powerpc/kernel/crash.c > > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > > --- linux-2.6-ozlabs.orig/arch/powerpc/kernel/crash.c > > +++ linux-2.6-ozlabs/arch/powerpc/kernel/crash.c > > @@ -32,6 +32,8 @@ > > #include <asm/lmb.h> > > #include <asm/firmware.h> > > #include <asm/smp.h> > > +#include <asm/system.h> > > +#include <asm/setjmp.h> > > =20 > > #ifdef DEBUG > > #include <asm/udbg.h> > > @@ -45,6 +47,11 @@ int crashing_cpu =3D -1; > > static cpumask_t cpus_in_crash =3D CPU_MASK_NONE; > > cpumask_t cpus_in_sr =3D CPU_MASK_NONE; > > =20 > > +#define CRASH_SHUTDOWN_HANDLES_NUM 1 > > CRASH_HANDLER_MAX ? yep, MAX is probably a more representative name > > > +/* NULL terminated list of shutdown handles */ > > +static crash_shutdown_t crash_shutdown_handles[CRASH_SHUTDOWN_HANDLES_NU= > M+1]; > > +static DEFINE_SPINLOCK(crash_handles_lock); > > + > > #ifdef CONFIG_SMP > > static atomic_t enter_on_soft_reset =3D ATOMIC_INIT(0); > > =20 > > @@ -285,9 +292,69 @@ static inline void crash_kexec_stop_spus > > } > > #endif /* CONFIG_SPU_BASE */ > > =20 > > +/*=20 > > + * Register a function to be called on shutdown. Only use this if you > > + * can't reset your device in the second kernel. > > + */ > > +int crash_shutdown_register(crash_shutdown_t handler) > > +{ > > + unsigned int i, rc; > > + > > + spin_lock(&crash_handles_lock); > > > + for(i =3D 0 ; i <=3D CRASH_SHUTDOWN_HANDLES_NUM; i++) { > > + if (!crash_shutdown_handles[i]) { > > + /* Insert handle at end */ > > + crash_shutdown_handles[i] =3D handler; > > + rc =3D 0; > > + break; > > + } > > + } > >=20 > > + if (i =3D=3D CRASH_SHUTDOWN_HANDLES_NUM){ > > + printk(KERN_ERR "Crash shutdown handles full, " > > + "not registered.\n"); > > + rc =3D 1; > > + } > > + > > + spin_unlock(&crash_handles_lock); > > Perhaps? Yep, looks nicer. I'll fix the one below too. > > > + return rc; > > +} > > +EXPORT_SYMBOL(crash_shutdown_register); > > + > > +int crash_shutdown_unregister(crash_shutdown_t handler) > > +{ > > + unsigned int i; > > + > > + spin_lock(&crash_handles_lock); > > + for(i =3D 0 ; i <=3D CRASH_SHUTDOWN_HANDLES_NUM; i++) > > + if (crash_shutdown_handles[i] =3D=3D handler) > > + break; > > + > > + if (i =3D=3D CRASH_SHUTDOWN_HANDLES_NUM){ > > + printk(KERN_ERR "Crash shutdown handle not found\n"); > > + spin_unlock(&crash_handles_lock); > > + return 1; > > + } > > + > > + /* Shift handles down */ > > + while(crash_shutdown_handles[i]) { > > + crash_shutdown_handles[i] =3D crash_shutdown_handles[i+1]; > > + i++; > > + } > > + spin_unlock(&crash_handles_lock); > > + return 0; > > +} > > +EXPORT_SYMBOL(crash_shutdown_unregister); > > + > > +static long crash_shutdown_buf[SETJMP_BUF_LEN]; > > unsigned long? yep > > > + > > +static int handle_fault(struct pt_regs *regs) > > +{ > > + longjmp(crash_shutdown_buf, 1); > > + return 0; > > +} > > + > > void default_machine_crash_shutdown(struct pt_regs *regs) > > { > > - unsigned int irq; > > + unsigned int i; > > =20 > > /* > > * This function is only called after the system > > @@ -301,14 +368,27 @@ void default_machine_crash_shutdown(stru > > */ > > hard_irq_disable(); > > =20 > > - for_each_irq(irq) { > > - struct irq_desc *desc =3D irq_desc + irq; > > + for_each_irq(i) { > > + struct irq_desc *desc =3D irq_desc + i; > > =20 > > if (desc->status & IRQ_INPROGRESS) > > - desc->chip->eoi(irq); > > + desc->chip->eoi(i); > > =20 > > if (!(desc->status & IRQ_DISABLED)) > > - desc->chip->disable(irq); > > + desc->chip->disable(i); > > + } > > + > > + /* Call registered shutdown routines */ > > + __debugger_fault_handler =3D handle_fault; > > + i =3D 0; > > + while(crash_shutdown_handles[i]){ > > + if (setjmp(crash_shutdown_buf) =3D=3D 0) { > > + asm volatile("sync; isync"); > > + crash_shutdown_handles[i](); > > + asm volatile("sync; isync"); > > + __delay(200); > > + } > > + i++; > > } > > You should probably reset __debugger_fault_handler, just to be safe. Agreed. Mikey ^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 0/2] Add crashdump shutdown hooks 2007-12-12 5:45 [PATCH 2/2] kdump shutdown hook support Michael Neuling 2007-12-12 7:01 ` Olof Johansson 2007-12-12 23:07 ` Michael Ellerman @ 2007-12-13 3:16 ` Michael Neuling 2007-12-13 3:16 ` [PATCH 2/2] kdump shutdown hook support Michael Neuling 2007-12-13 3:16 ` Michael Neuling 2 siblings, 2 replies; 27+ messages in thread From: Michael Neuling @ 2007-12-13 3:16 UTC (permalink / raw) To: Paul Mackerras; +Cc: linuxppc-dev, Michael Neuling, RAISCH, THEMANN The following patches add crashdump shutdown hooks for POWERPC. Signed-off-by: Michael Neuling <mikey@neuling.org> --- This is an updated series following comments from the first post. Adds some documentation, better code flow, fixes 32 bit compiles and other updates based on feedback Again these are based on paulus' for 2.6.25 tree. ^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 2/2] kdump shutdown hook support 2007-12-13 3:16 ` [PATCH 0/2] Add crashdump shutdown hooks Michael Neuling @ 2007-12-13 3:16 ` Michael Neuling 2007-12-13 5:12 ` Olof Johansson 2007-12-13 3:16 ` Michael Neuling 1 sibling, 1 reply; 27+ messages in thread From: Michael Neuling @ 2007-12-13 3:16 UTC (permalink / raw) To: Paul Mackerras; +Cc: linuxppc-dev, Michael Neuling, RAISCH, THEMANN This adds hooks into the default_machine_crash_shutdown so drivers can register a function to be run in the first kernel before we hand off to the second kernel. This should only be used in exceptional circumstances, like where the device can't be reset in the second kernel alone (as is the case with eHEA). To emphasize this, the number of handles allowed to be registered is currently #def to 1. This uses the setjmp/longjmp code to call out to the registered hooks, so any bogus exceptions we encounter will hopefully be recoverable. Tested with bogus data and instruction exceptions. Signed-off-by: Michael Neuling <mikey@neuling.org> --- arch/powerpc/kernel/crash.c | 102 +++++++++++++++++++++++++++++++++++++++++--- include/asm-powerpc/kexec.h | 3 + 2 files changed, 100 insertions(+), 5 deletions(-) Index: clone3/arch/powerpc/kernel/crash.c =================================================================== --- clone3.orig/arch/powerpc/kernel/crash.c +++ clone3/arch/powerpc/kernel/crash.c @@ -32,6 +32,8 @@ #include <asm/lmb.h> #include <asm/firmware.h> #include <asm/smp.h> +#include <asm/system.h> +#include <asm/setjmp.h> #ifdef DEBUG #include <asm/udbg.h> @@ -45,6 +47,11 @@ int crashing_cpu = -1; static cpumask_t cpus_in_crash = CPU_MASK_NONE; cpumask_t cpus_in_sr = CPU_MASK_NONE; +#define CRASH_HANDLER_MAX 1 +/* NULL terminated list of shutdown handles */ +static crash_shutdown_t crash_shutdown_handles[CRASH_HANDLER_MAX+1]; +static DEFINE_SPINLOCK(crash_handers_lock); + #ifdef CONFIG_SMP static atomic_t enter_on_soft_reset = ATOMIC_INIT(0); @@ -285,9 +292,72 @@ static inline void crash_kexec_stop_spus } #endif /* CONFIG_SPU_BASE */ +/* + * Register a function to be called on shutdown. Only use this if you + * can't reset your device in the second kernel. + */ +int crash_shutdown_register(crash_shutdown_t handler) +{ + unsigned int i, rc; + + spin_lock(&crash_handers_lock); + for (i = 0 ; i < CRASH_HANDLER_MAX; i++) + if (!crash_shutdown_handles[i]) { + /* Insert handle at first empty entry */ + crash_shutdown_handles[i] = handler; + rc = 0; + break; + } + + if (i == CRASH_HANDLER_MAX) { + printk(KERN_ERR "Crash shutdown handles full, " + "not registered.\n"); + rc = 1; + } + + spin_unlock(&crash_handers_lock); + return rc; +} +EXPORT_SYMBOL(crash_shutdown_register); + +int crash_shutdown_unregister(crash_shutdown_t handler) +{ + unsigned int i, rc; + + spin_lock(&crash_handers_lock); + for (i = 0 ; i < CRASH_HANDLER_MAX; i++) + if (crash_shutdown_handles[i] == handler) + break; + + if (i == CRASH_HANDLER_MAX) { + printk(KERN_ERR "Crash shutdown handle not found\n"); + rc = 1; + } else { + /* Shift handles down */ + for (; crash_shutdown_handles[i]; i++) + crash_shutdown_handles[i] = + crash_shutdown_handles[i+1]; + rc = 0; + } + + spin_unlock(&crash_handers_lock); + return rc; +} +EXPORT_SYMBOL(crash_shutdown_unregister); + +static unsigned long crash_shutdown_buf[SETJMP_BUF_LEN]; + +static int handle_fault(struct pt_regs *regs) +{ + longjmp(crash_shutdown_buf, 1); + return 0; +} + void default_machine_crash_shutdown(struct pt_regs *regs) { - unsigned int irq; + unsigned int i; + int (*old_handler)(struct pt_regs *regs); + /* * This function is only called after the system @@ -301,15 +371,37 @@ void default_machine_crash_shutdown(stru */ hard_irq_disable(); - for_each_irq(irq) { - struct irq_desc *desc = irq_desc + irq; + for_each_irq(i) { + struct irq_desc *desc = irq_desc + i; if (desc->status & IRQ_INPROGRESS) - desc->chip->eoi(irq); + desc->chip->eoi(i); if (!(desc->status & IRQ_DISABLED)) - desc->chip->disable(irq); + desc->chip->disable(i); + } + + /* + * Call registered shutdown routines savely. Swap out + * __debugger_fault_handler, and replace on exit. + */ + old_handler = __debugger_fault_handler; + __debugger_fault_handler = handle_fault; + for (i = 0; crash_shutdown_handles[i]; i++) { + if (setjmp(crash_shutdown_buf) == 0) { + /* + * Insert syncs and delay to ensure + * instructions in the dangerous region don't + * leak away from this protected region. + */ + asm volatile("sync; isync"); + /* dangerous region */ + crash_shutdown_handles[i](); + asm volatile("sync; isync"); + __delay(SETJMP_MACHINE_CHECK_DELAY); + } } + __debugger_fault_handler = old_handler; /* * Make a note of crashing cpu. Will be used in machine_kexec Index: clone3/include/asm-powerpc/kexec.h =================================================================== --- clone3.orig/include/asm-powerpc/kexec.h +++ clone3/include/asm-powerpc/kexec.h @@ -123,6 +123,9 @@ struct pt_regs; extern void default_machine_kexec(struct kimage *image); extern int default_machine_kexec_prepare(struct kimage *image); extern void default_machine_crash_shutdown(struct pt_regs *regs); +typedef void (*crash_shutdown_t)(void); +extern int crash_shutdown_register(crash_shutdown_t handler); +extern int crash_shutdown_unregister(crash_shutdown_t handler); extern void machine_kexec_simple(struct kimage *image); extern void crash_kexec_secondary(struct pt_regs *regs); ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 2/2] kdump shutdown hook support 2007-12-13 3:16 ` [PATCH 2/2] kdump shutdown hook support Michael Neuling @ 2007-12-13 5:12 ` Olof Johansson 2007-12-13 5:13 ` Olof Johansson 2007-12-13 9:59 ` [PATCH 0/2] Add crashdump shutdown hooks Michael Neuling 0 siblings, 2 replies; 27+ messages in thread From: Olof Johansson @ 2007-12-13 5:12 UTC (permalink / raw) To: Michael Neuling; +Cc: linuxppc-dev, RAISCH, Paul Mackerras, THEMANN Hi, On Thu, Dec 13, 2007 at 02:16:18PM +1100, Michael Neuling wrote: > Index: clone3/arch/powerpc/kernel/crash.c > =================================================================== > --- clone3.orig/arch/powerpc/kernel/crash.c > +++ clone3/arch/powerpc/kernel/crash.c > @@ -32,6 +32,8 @@ > #include <asm/lmb.h> > #include <asm/firmware.h> > #include <asm/smp.h> > +#include <asm/system.h> > +#include <asm/setjmp.h> > > #ifdef DEBUG > #include <asm/udbg.h> > @@ -45,6 +47,11 @@ int crashing_cpu = -1; > static cpumask_t cpus_in_crash = CPU_MASK_NONE; > cpumask_t cpus_in_sr = CPU_MASK_NONE; > > +#define CRASH_HANDLER_MAX 1 > +/* NULL terminated list of shutdown handles */ > +static crash_shutdown_t crash_shutdown_handles[CRASH_HANDLER_MAX+1]; > +static DEFINE_SPINLOCK(crash_handers_lock); How about just using 'handlers' instead of 'handers' and 'handles'? :) > static atomic_t enter_on_soft_reset = ATOMIC_INIT(0); > > @@ -285,9 +292,72 @@ static inline void crash_kexec_stop_spus > } > #endif /* CONFIG_SPU_BASE */ > > +/* > + * Register a function to be called on shutdown. Only use this if you > + * can't reset your device in the second kernel. > + */ > +int crash_shutdown_register(crash_shutdown_t handler) > +{ > + unsigned int i, rc; > + > + spin_lock(&crash_handers_lock); > + for (i = 0 ; i < CRASH_HANDLER_MAX; i++) > + if (!crash_shutdown_handles[i]) { > + /* Insert handle at first empty entry */ > + crash_shutdown_handles[i] = handler; > + rc = 0; > + break; > + } > + > + if (i == CRASH_HANDLER_MAX) { > + printk(KERN_ERR "Crash shutdown handles full, " > + "not registered.\n"); > + rc = 1; > + } > + > + spin_unlock(&crash_handers_lock); > + return rc; > +} > +EXPORT_SYMBOL(crash_shutdown_register); > + > +int crash_shutdown_unregister(crash_shutdown_t handler) > +{ > + unsigned int i, rc; > + > + spin_lock(&crash_handers_lock); > + for (i = 0 ; i < CRASH_HANDLER_MAX; i++) > + if (crash_shutdown_handles[i] == handler) > + break; > + > + if (i == CRASH_HANDLER_MAX) { > + printk(KERN_ERR "Crash shutdown handle not found\n"); > + rc = 1; > + } else { > + /* Shift handles down */ > + for (; crash_shutdown_handles[i]; i++) > + crash_shutdown_handles[i] = > + crash_shutdown_handles[i+1]; > + rc = 0; > + } > + > + spin_unlock(&crash_handers_lock); > + return rc; > +} > +EXPORT_SYMBOL(crash_shutdown_unregister); > + > +static unsigned long crash_shutdown_buf[SETJMP_BUF_LEN]; > + > +static int handle_fault(struct pt_regs *regs) > +{ > + longjmp(crash_shutdown_buf, 1); > + return 0; > +} > + > void default_machine_crash_shutdown(struct pt_regs *regs) > { > - unsigned int irq; > + unsigned int i; > + int (*old_handler)(struct pt_regs *regs); > + > > /* > * This function is only called after the system > @@ -301,15 +371,37 @@ void default_machine_crash_shutdown(stru > */ > hard_irq_disable(); > > - for_each_irq(irq) { > - struct irq_desc *desc = irq_desc + irq; > + for_each_irq(i) { > + struct irq_desc *desc = irq_desc + i; > > if (desc->status & IRQ_INPROGRESS) > - desc->chip->eoi(irq); > + desc->chip->eoi(i); > > if (!(desc->status & IRQ_DISABLED)) > - desc->chip->disable(irq); > + desc->chip->disable(i); > + } > + > + /* > + * Call registered shutdown routines savely. Swap out > + * __debugger_fault_handler, and replace on exit. > + */ > + old_handler = __debugger_fault_handler; > + __debugger_fault_handler = handle_fault; > + for (i = 0; crash_shutdown_handles[i]; i++) { > + if (setjmp(crash_shutdown_buf) == 0) { > + /* > + * Insert syncs and delay to ensure > + * instructions in the dangerous region don't > + * leak away from this protected region. > + */ > + asm volatile("sync; isync"); > + /* dangerous region */ > + crash_shutdown_handles[i](); > + asm volatile("sync; isync"); > + __delay(SETJMP_MACHINE_CHECK_DELAY); Where is this defined? > + } > } > + __debugger_fault_handler = old_handler; > > /* > * Make a note of crashing cpu. Will be used in machine_kexec > Index: clone3/include/asm-powerpc/kexec.h > =================================================================== > --- clone3.orig/include/asm-powerpc/kexec.h > +++ clone3/include/asm-powerpc/kexec.h > @@ -123,6 +123,9 @@ struct pt_regs; > extern void default_machine_kexec(struct kimage *image); > extern int default_machine_kexec_prepare(struct kimage *image); > extern void default_machine_crash_shutdown(struct pt_regs *regs); > +typedef void (*crash_shutdown_t)(void); > +extern int crash_shutdown_register(crash_shutdown_t handler); > +extern int crash_shutdown_unregister(crash_shutdown_t handler); > > extern void machine_kexec_simple(struct kimage *image); > extern void crash_kexec_secondary(struct pt_regs *regs); > _______________________________________________ > Linuxppc-dev mailing list > Linuxppc-dev@ozlabs.org > https://ozlabs.org/mailman/listinfo/linuxppc-dev ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 2/2] kdump shutdown hook support 2007-12-13 5:12 ` Olof Johansson @ 2007-12-13 5:13 ` Olof Johansson 2007-12-13 9:59 ` [PATCH 0/2] Add crashdump shutdown hooks Michael Neuling 1 sibling, 0 replies; 27+ messages in thread From: Olof Johansson @ 2007-12-13 5:13 UTC (permalink / raw) To: Michael Neuling; +Cc: linuxppc-dev, RAISCH, Paul Mackerras, THEMANN On Wed, Dec 12, 2007 at 11:12:24PM -0600, Olof Johansson wrote: > Hi, > > + __delay(SETJMP_MACHINE_CHECK_DELAY); > > Where is this defined? Oops, nevermind. In 1/2, of course. :-) -Olof ^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 0/2] Add crashdump shutdown hooks 2007-12-13 5:12 ` Olof Johansson 2007-12-13 5:13 ` Olof Johansson @ 2007-12-13 9:59 ` Michael Neuling 2007-12-13 9:59 ` [PATCH 2/2] kdump shutdown hook support Michael Neuling ` (2 more replies) 1 sibling, 3 replies; 27+ messages in thread From: Michael Neuling @ 2007-12-13 9:59 UTC (permalink / raw) To: Paul Mackerras; +Cc: linuxppc-dev, RAISCH, THEMANN The following patches add crashdump shutdown hooks for POWERPC. Signed-off-by: Michael Neuling <mikey@neuling.org> --- Fixes stupid variable name noticed by Olof. ^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 2/2] kdump shutdown hook support 2007-12-13 9:59 ` [PATCH 0/2] Add crashdump shutdown hooks Michael Neuling @ 2007-12-13 9:59 ` Michael Neuling 2007-12-13 9:59 ` [PATCH 1/2] Make setjmp/longjmp code generic Michael Neuling 2008-01-17 4:45 ` [PATCH 0/2] Add crashdump shutdown hooks Michael Neuling 2 siblings, 0 replies; 27+ messages in thread From: Michael Neuling @ 2007-12-13 9:59 UTC (permalink / raw) To: Paul Mackerras; +Cc: linuxppc-dev, RAISCH, THEMANN This adds hooks into the default_machine_crash_shutdown so drivers can register a function to be run in the first kernel before we hand off to the second kernel. This should only be used in exceptional circumstances, like where the device can't be reset in the second kernel alone (as is the case with eHEA). To emphasize this, the number of handles allowed to be registered is currently #def to 1. This uses the setjmp/longjmp code to call out to the registered hooks, so any bogus exceptions we encounter will hopefully be recoverable. Tested with bogus data and instruction exceptions. Signed-off-by: Michael Neuling <mikey@neuling.org> --- arch/powerpc/kernel/crash.c | 102 +++++++++++++++++++++++++++++++++++++++++--- include/asm-powerpc/kexec.h | 3 + 2 files changed, 100 insertions(+), 5 deletions(-) Index: clone3/arch/powerpc/kernel/crash.c =================================================================== --- clone3.orig/arch/powerpc/kernel/crash.c +++ clone3/arch/powerpc/kernel/crash.c @@ -32,6 +32,8 @@ #include <asm/lmb.h> #include <asm/firmware.h> #include <asm/smp.h> +#include <asm/system.h> +#include <asm/setjmp.h> #ifdef DEBUG #include <asm/udbg.h> @@ -45,6 +47,11 @@ int crashing_cpu = -1; static cpumask_t cpus_in_crash = CPU_MASK_NONE; cpumask_t cpus_in_sr = CPU_MASK_NONE; +#define CRASH_HANDLER_MAX 1 +/* NULL terminated list of shutdown handles */ +static crash_shutdown_t crash_shutdown_handles[CRASH_HANDLER_MAX+1]; +static DEFINE_SPINLOCK(crash_handlers_lock); + #ifdef CONFIG_SMP static atomic_t enter_on_soft_reset = ATOMIC_INIT(0); @@ -285,9 +292,72 @@ static inline void crash_kexec_stop_spus } #endif /* CONFIG_SPU_BASE */ +/* + * Register a function to be called on shutdown. Only use this if you + * can't reset your device in the second kernel. + */ +int crash_shutdown_register(crash_shutdown_t handler) +{ + unsigned int i, rc; + + spin_lock(&crash_handlers_lock); + for (i = 0 ; i < CRASH_HANDLER_MAX; i++) + if (!crash_shutdown_handles[i]) { + /* Insert handle at first empty entry */ + crash_shutdown_handles[i] = handler; + rc = 0; + break; + } + + if (i == CRASH_HANDLER_MAX) { + printk(KERN_ERR "Crash shutdown handles full, " + "not registered.\n"); + rc = 1; + } + + spin_unlock(&crash_handlers_lock); + return rc; +} +EXPORT_SYMBOL(crash_shutdown_register); + +int crash_shutdown_unregister(crash_shutdown_t handler) +{ + unsigned int i, rc; + + spin_lock(&crash_handlers_lock); + for (i = 0 ; i < CRASH_HANDLER_MAX; i++) + if (crash_shutdown_handles[i] == handler) + break; + + if (i == CRASH_HANDLER_MAX) { + printk(KERN_ERR "Crash shutdown handle not found\n"); + rc = 1; + } else { + /* Shift handles down */ + for (; crash_shutdown_handles[i]; i++) + crash_shutdown_handles[i] = + crash_shutdown_handles[i+1]; + rc = 0; + } + + spin_unlock(&crash_handlers_lock); + return rc; +} +EXPORT_SYMBOL(crash_shutdown_unregister); + +static unsigned long crash_shutdown_buf[SETJMP_BUF_LEN]; + +static int handle_fault(struct pt_regs *regs) +{ + longjmp(crash_shutdown_buf, 1); + return 0; +} + void default_machine_crash_shutdown(struct pt_regs *regs) { - unsigned int irq; + unsigned int i; + int (*old_handler)(struct pt_regs *regs); + /* * This function is only called after the system @@ -301,15 +371,37 @@ void default_machine_crash_shutdown(stru */ hard_irq_disable(); - for_each_irq(irq) { - struct irq_desc *desc = irq_desc + irq; + for_each_irq(i) { + struct irq_desc *desc = irq_desc + i; if (desc->status & IRQ_INPROGRESS) - desc->chip->eoi(irq); + desc->chip->eoi(i); if (!(desc->status & IRQ_DISABLED)) - desc->chip->disable(irq); + desc->chip->disable(i); + } + + /* + * Call registered shutdown routines savely. Swap out + * __debugger_fault_handler, and replace on exit. + */ + old_handler = __debugger_fault_handler; + __debugger_fault_handler = handle_fault; + for (i = 0; crash_shutdown_handles[i]; i++) { + if (setjmp(crash_shutdown_buf) == 0) { + /* + * Insert syncs and delay to ensure + * instructions in the dangerous region don't + * leak away from this protected region. + */ + asm volatile("sync; isync"); + /* dangerous region */ + crash_shutdown_handles[i](); + asm volatile("sync; isync"); + __delay(SETJMP_MACHINE_CHECK_DELAY); + } } + __debugger_fault_handler = old_handler; /* * Make a note of crashing cpu. Will be used in machine_kexec Index: clone3/include/asm-powerpc/kexec.h =================================================================== --- clone3.orig/include/asm-powerpc/kexec.h +++ clone3/include/asm-powerpc/kexec.h @@ -123,6 +123,9 @@ struct pt_regs; extern void default_machine_kexec(struct kimage *image); extern int default_machine_kexec_prepare(struct kimage *image); extern void default_machine_crash_shutdown(struct pt_regs *regs); +typedef void (*crash_shutdown_t)(void); +extern int crash_shutdown_register(crash_shutdown_t handler); +extern int crash_shutdown_unregister(crash_shutdown_t handler); extern void machine_kexec_simple(struct kimage *image); extern void crash_kexec_secondary(struct pt_regs *regs); ^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 1/2] Make setjmp/longjmp code generic 2007-12-13 9:59 ` [PATCH 0/2] Add crashdump shutdown hooks Michael Neuling 2007-12-13 9:59 ` [PATCH 2/2] kdump shutdown hook support Michael Neuling @ 2007-12-13 9:59 ` Michael Neuling 2008-01-17 4:45 ` [PATCH 0/2] Add crashdump shutdown hooks Michael Neuling 2 siblings, 0 replies; 27+ messages in thread From: Michael Neuling @ 2007-12-13 9:59 UTC (permalink / raw) To: Paul Mackerras; +Cc: linuxppc-dev, RAISCH, THEMANN This makes the setjmp/longjmp code used by xmon, generically available to other code. It also removes the requirement for debugger hooks to be only called on 0x300 (data storage) exception and adds some documentation. Signed-off-by: Michael Neuling <mikey@neuling.org> --- arch/powerpc/kernel/misc.S | 128 ++++++++++++++++++++++++++++++++++++++++ arch/powerpc/mm/fault.c | 6 - arch/powerpc/xmon/Makefile | 2 arch/powerpc/xmon/setjmp.S | 135 ------------------------------------------- arch/powerpc/xmon/xmon.c | 38 ++++-------- include/asm-powerpc/setjmp.h | 19 ++++++ 6 files changed, 164 insertions(+), 164 deletions(-) Index: clone3/arch/powerpc/kernel/misc.S =================================================================== --- clone3.orig/arch/powerpc/kernel/misc.S +++ clone3/arch/powerpc/kernel/misc.S @@ -8,6 +8,8 @@ * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com) * + * setjmp/longjmp and xmon_save_regs code by Paul Mackerras. + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version @@ -15,6 +17,8 @@ */ #include <asm/ppc_asm.h> #include <asm/unistd.h> +#include <asm/asm-compat.h> +#include <asm/asm-offsets.h> .text @@ -51,3 +55,127 @@ _GLOBAL(kernel_execve) bnslr neg r3,r3 blr + +_GLOBAL(setjmp) + mflr r0 + PPC_STL r0,0(r3) + PPC_STL r1,SZL(r3) + PPC_STL r2,2*SZL(r3) + mfcr r0 + PPC_STL r0,3*SZL(r3) + PPC_STL r13,4*SZL(r3) + PPC_STL r14,5*SZL(r3) + PPC_STL r15,6*SZL(r3) + PPC_STL r16,7*SZL(r3) + PPC_STL r17,8*SZL(r3) + PPC_STL r18,9*SZL(r3) + PPC_STL r19,10*SZL(r3) + PPC_STL r20,11*SZL(r3) + PPC_STL r21,12*SZL(r3) + PPC_STL r22,13*SZL(r3) + PPC_STL r23,14*SZL(r3) + PPC_STL r24,15*SZL(r3) + PPC_STL r25,16*SZL(r3) + PPC_STL r26,17*SZL(r3) + PPC_STL r27,18*SZL(r3) + PPC_STL r28,19*SZL(r3) + PPC_STL r29,20*SZL(r3) + PPC_STL r30,21*SZL(r3) + PPC_STL r31,22*SZL(r3) + li r3,0 + blr + +_GLOBAL(longjmp) + PPC_LCMPI r4,0 + bne 1f + li r4,1 +1: PPC_LL r13,4*SZL(r3) + PPC_LL r14,5*SZL(r3) + PPC_LL r15,6*SZL(r3) + PPC_LL r16,7*SZL(r3) + PPC_LL r17,8*SZL(r3) + PPC_LL r18,9*SZL(r3) + PPC_LL r19,10*SZL(r3) + PPC_LL r20,11*SZL(r3) + PPC_LL r21,12*SZL(r3) + PPC_LL r22,13*SZL(r3) + PPC_LL r23,14*SZL(r3) + PPC_LL r24,15*SZL(r3) + PPC_LL r25,16*SZL(r3) + PPC_LL r26,17*SZL(r3) + PPC_LL r27,18*SZL(r3) + PPC_LL r28,19*SZL(r3) + PPC_LL r29,20*SZL(r3) + PPC_LL r30,21*SZL(r3) + PPC_LL r31,22*SZL(r3) + PPC_LL r0,3*SZL(r3) + mtcrf 0x38,r0 + PPC_LL r0,0(r3) + PPC_LL r1,SZL(r3) + PPC_LL r2,2*SZL(r3) + mtlr r0 + mr r3,r4 + blr + +#ifdef CONFIG_XMON +/* + * Grab the register values as they are now. + * This won't do a particularily good job because we really + * want our caller's caller's registers, and our caller has + * already executed its prologue. + * ToDo: We could reach back into the caller's save area to do + * a better job of representing the caller's state (note that + * that will be different for 32-bit and 64-bit, because of the + * different ABIs, though). + */ +_GLOBAL(xmon_save_regs) + PPC_STL r0,0*SZL(r3) + PPC_STL r2,2*SZL(r3) + PPC_STL r3,3*SZL(r3) + PPC_STL r4,4*SZL(r3) + PPC_STL r5,5*SZL(r3) + PPC_STL r6,6*SZL(r3) + PPC_STL r7,7*SZL(r3) + PPC_STL r8,8*SZL(r3) + PPC_STL r9,9*SZL(r3) + PPC_STL r10,10*SZL(r3) + PPC_STL r11,11*SZL(r3) + PPC_STL r12,12*SZL(r3) + PPC_STL r13,13*SZL(r3) + PPC_STL r14,14*SZL(r3) + PPC_STL r15,15*SZL(r3) + PPC_STL r16,16*SZL(r3) + PPC_STL r17,17*SZL(r3) + PPC_STL r18,18*SZL(r3) + PPC_STL r19,19*SZL(r3) + PPC_STL r20,20*SZL(r3) + PPC_STL r21,21*SZL(r3) + PPC_STL r22,22*SZL(r3) + PPC_STL r23,23*SZL(r3) + PPC_STL r24,24*SZL(r3) + PPC_STL r25,25*SZL(r3) + PPC_STL r26,26*SZL(r3) + PPC_STL r27,27*SZL(r3) + PPC_STL r28,28*SZL(r3) + PPC_STL r29,29*SZL(r3) + PPC_STL r30,30*SZL(r3) + PPC_STL r31,31*SZL(r3) + /* go up one stack frame for SP */ + PPC_LL r4,0(r1) + PPC_STL r4,1*SZL(r3) + /* get caller's LR */ + PPC_LL r0,LRSAVE(r4) + PPC_STL r0,_NIP-STACK_FRAME_OVERHEAD(r3) + PPC_STL r0,_LINK-STACK_FRAME_OVERHEAD(r3) + mfmsr r0 + PPC_STL r0,_MSR-STACK_FRAME_OVERHEAD(r3) + mfctr r0 + PPC_STL r0,_CTR-STACK_FRAME_OVERHEAD(r3) + mfxer r0 + PPC_STL r0,_XER-STACK_FRAME_OVERHEAD(r3) + mfcr r0 + PPC_STL r0,_CCR-STACK_FRAME_OVERHEAD(r3) + li r0,0 + PPC_STL r0,_TRAP-STACK_FRAME_OVERHEAD(r3) + blr +#endif Index: clone3/arch/powerpc/mm/fault.c =================================================================== --- clone3.orig/arch/powerpc/mm/fault.c +++ clone3/arch/powerpc/mm/fault.c @@ -167,10 +167,8 @@ int __kprobes do_page_fault(struct pt_re if (notify_page_fault(regs)) return 0; - if (trap == 0x300) { - if (debugger_fault_handler(regs)) - return 0; - } + if (unlikely(debugger_fault_handler(regs))) + return 0; /* On a kernel SLB miss we can only check for a valid exception entry */ if (!user_mode(regs) && (address >= TASK_SIZE)) Index: clone3/arch/powerpc/xmon/Makefile =================================================================== --- clone3.orig/arch/powerpc/xmon/Makefile +++ clone3/arch/powerpc/xmon/Makefile @@ -4,7 +4,7 @@ ifdef CONFIG_PPC64 EXTRA_CFLAGS += -mno-minimal-toc endif -obj-y += xmon.o setjmp.o start.o nonstdio.o +obj-y += xmon.o start.o nonstdio.o ifdef CONFIG_XMON_DISASSEMBLY obj-y += ppc-dis.o ppc-opc.o Index: clone3/arch/powerpc/xmon/setjmp.S =================================================================== --- clone3.orig/arch/powerpc/xmon/setjmp.S +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 1996 Paul Mackerras. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * NOTE: assert(sizeof(buf) > 23 * sizeof(long)) - */ -#include <asm/processor.h> -#include <asm/ppc_asm.h> -#include <asm/asm-offsets.h> - -_GLOBAL(xmon_setjmp) - mflr r0 - PPC_STL r0,0(r3) - PPC_STL r1,SZL(r3) - PPC_STL r2,2*SZL(r3) - mfcr r0 - PPC_STL r0,3*SZL(r3) - PPC_STL r13,4*SZL(r3) - PPC_STL r14,5*SZL(r3) - PPC_STL r15,6*SZL(r3) - PPC_STL r16,7*SZL(r3) - PPC_STL r17,8*SZL(r3) - PPC_STL r18,9*SZL(r3) - PPC_STL r19,10*SZL(r3) - PPC_STL r20,11*SZL(r3) - PPC_STL r21,12*SZL(r3) - PPC_STL r22,13*SZL(r3) - PPC_STL r23,14*SZL(r3) - PPC_STL r24,15*SZL(r3) - PPC_STL r25,16*SZL(r3) - PPC_STL r26,17*SZL(r3) - PPC_STL r27,18*SZL(r3) - PPC_STL r28,19*SZL(r3) - PPC_STL r29,20*SZL(r3) - PPC_STL r30,21*SZL(r3) - PPC_STL r31,22*SZL(r3) - li r3,0 - blr - -_GLOBAL(xmon_longjmp) - PPC_LCMPI r4,0 - bne 1f - li r4,1 -1: PPC_LL r13,4*SZL(r3) - PPC_LL r14,5*SZL(r3) - PPC_LL r15,6*SZL(r3) - PPC_LL r16,7*SZL(r3) - PPC_LL r17,8*SZL(r3) - PPC_LL r18,9*SZL(r3) - PPC_LL r19,10*SZL(r3) - PPC_LL r20,11*SZL(r3) - PPC_LL r21,12*SZL(r3) - PPC_LL r22,13*SZL(r3) - PPC_LL r23,14*SZL(r3) - PPC_LL r24,15*SZL(r3) - PPC_LL r25,16*SZL(r3) - PPC_LL r26,17*SZL(r3) - PPC_LL r27,18*SZL(r3) - PPC_LL r28,19*SZL(r3) - PPC_LL r29,20*SZL(r3) - PPC_LL r30,21*SZL(r3) - PPC_LL r31,22*SZL(r3) - PPC_LL r0,3*SZL(r3) - mtcrf 0x38,r0 - PPC_LL r0,0(r3) - PPC_LL r1,SZL(r3) - PPC_LL r2,2*SZL(r3) - mtlr r0 - mr r3,r4 - blr - -/* - * Grab the register values as they are now. - * This won't do a particularily good job because we really - * want our caller's caller's registers, and our caller has - * already executed its prologue. - * ToDo: We could reach back into the caller's save area to do - * a better job of representing the caller's state (note that - * that will be different for 32-bit and 64-bit, because of the - * different ABIs, though). - */ -_GLOBAL(xmon_save_regs) - PPC_STL r0,0*SZL(r3) - PPC_STL r2,2*SZL(r3) - PPC_STL r3,3*SZL(r3) - PPC_STL r4,4*SZL(r3) - PPC_STL r5,5*SZL(r3) - PPC_STL r6,6*SZL(r3) - PPC_STL r7,7*SZL(r3) - PPC_STL r8,8*SZL(r3) - PPC_STL r9,9*SZL(r3) - PPC_STL r10,10*SZL(r3) - PPC_STL r11,11*SZL(r3) - PPC_STL r12,12*SZL(r3) - PPC_STL r13,13*SZL(r3) - PPC_STL r14,14*SZL(r3) - PPC_STL r15,15*SZL(r3) - PPC_STL r16,16*SZL(r3) - PPC_STL r17,17*SZL(r3) - PPC_STL r18,18*SZL(r3) - PPC_STL r19,19*SZL(r3) - PPC_STL r20,20*SZL(r3) - PPC_STL r21,21*SZL(r3) - PPC_STL r22,22*SZL(r3) - PPC_STL r23,23*SZL(r3) - PPC_STL r24,24*SZL(r3) - PPC_STL r25,25*SZL(r3) - PPC_STL r26,26*SZL(r3) - PPC_STL r27,27*SZL(r3) - PPC_STL r28,28*SZL(r3) - PPC_STL r29,29*SZL(r3) - PPC_STL r30,30*SZL(r3) - PPC_STL r31,31*SZL(r3) - /* go up one stack frame for SP */ - PPC_LL r4,0(r1) - PPC_STL r4,1*SZL(r3) - /* get caller's LR */ - PPC_LL r0,LRSAVE(r4) - PPC_STL r0,_NIP-STACK_FRAME_OVERHEAD(r3) - PPC_STL r0,_LINK-STACK_FRAME_OVERHEAD(r3) - mfmsr r0 - PPC_STL r0,_MSR-STACK_FRAME_OVERHEAD(r3) - mfctr r0 - PPC_STL r0,_CTR-STACK_FRAME_OVERHEAD(r3) - mfxer r0 - PPC_STL r0,_XER-STACK_FRAME_OVERHEAD(r3) - mfcr r0 - PPC_STL r0,_CCR-STACK_FRAME_OVERHEAD(r3) - li r0,0 - PPC_STL r0,_TRAP-STACK_FRAME_OVERHEAD(r3) - blr Index: clone3/arch/powerpc/xmon/xmon.c =================================================================== --- clone3.orig/arch/powerpc/xmon/xmon.c +++ clone3/arch/powerpc/xmon/xmon.c @@ -40,6 +40,7 @@ #include <asm/spu.h> #include <asm/spu_priv1.h> #include <asm/firmware.h> +#include <asm/setjmp.h> #ifdef CONFIG_PPC64 #include <asm/hvcall.h> @@ -71,12 +72,9 @@ static unsigned long ncsum = 4096; static int termch; static char tmpstr[128]; -#define JMP_BUF_LEN 23 -static long bus_error_jmp[JMP_BUF_LEN]; +static long bus_error_jmp[SETJMP_BUF_LEN]; static int catch_memory_errors; static long *xmon_fault_jmp[NR_CPUS]; -#define setjmp xmon_setjmp -#define longjmp xmon_longjmp /* Breakpoint stuff */ struct bpt { @@ -162,8 +160,6 @@ int xmon_no_auto_backtrace; extern void xmon_enter(void); extern void xmon_leave(void); -extern long setjmp(long *); -extern void longjmp(long *, long); extern void xmon_save_regs(struct pt_regs *); #ifdef CONFIG_PPC64 @@ -338,7 +334,7 @@ static int xmon_core(struct pt_regs *reg { int cmd = 0; struct bpt *bp; - long recurse_jmp[JMP_BUF_LEN]; + long recurse_jmp[SETJMP_BUF_LEN]; unsigned long offset; unsigned long flags; #ifdef CONFIG_SMP @@ -1428,7 +1424,7 @@ void prregs(struct pt_regs *fp) sync(); regs = *(struct pt_regs *)base; sync(); - __delay(200); + __delay(SETJMP_MACHINE_CHECK_DELAY); } else { catch_memory_errors = 0; printf("*** Error reading registers from "REG"\n", @@ -1497,8 +1493,7 @@ void cacheflush(void) cinval((void *) adrs); } sync(); - /* wait a little while to see if we get a machine check */ - __delay(200); + __delay(SETJMP_MACHINE_CHECK_DELAY); } catch_memory_errors = 0; } @@ -1533,8 +1528,7 @@ read_spr(int n) ret = code(); sync(); - /* wait a little while to see if we get a machine check */ - __delay(200); + __delay(SETJMP_MACHINE_CHECK_DELAY); n = size; } @@ -1569,8 +1563,7 @@ write_spr(int n, unsigned long val) code(val); sync(); - /* wait a little while to see if we get a machine check */ - __delay(200); + __delay(SETJMP_MACHINE_CHECK_DELAY); n = size; } } @@ -1676,8 +1669,7 @@ mread(unsigned long adrs, void *buf, int } } sync(); - /* wait a little while to see if we get a machine check */ - __delay(200); + __delay(SETJMP_MACHINE_CHECK_DELAY); n = size; } catch_memory_errors = 0; @@ -1713,8 +1705,7 @@ mwrite(unsigned long adrs, void *buf, in } } sync(); - /* wait a little while to see if we get a machine check */ - __delay(200); + __delay(SETJMP_MACHINE_CHECK_DELAY); n = size; } else { printf("*** Error writing address %x\n", adrs + n); @@ -2521,8 +2512,7 @@ static void xmon_print_symbol(unsigned l name = kallsyms_lookup(address, &size, &offset, &modname, tmpstr); sync(); - /* wait a little while to see if we get a machine check */ - __delay(200); + __delay(SETJMP_MACHINE_CHECK_DELAY); } catch_memory_errors = 0; @@ -2777,7 +2767,7 @@ static void stop_spus(void) spu_mfc_sr1_set(spu, tmp); sync(); - __delay(200); + __delay(SETJMP_MACHINE_CHECK_DELAY); spu_info[i].stopped_ok = 1; @@ -2817,7 +2807,7 @@ static void restart_spus(void) spu_info[i].saved_spu_runcntl_RW); sync(); - __delay(200); + __delay(SETJMP_MACHINE_CHECK_DELAY); printf("Restarted spu %.2d\n", i); } else { @@ -2837,7 +2827,7 @@ do { \ printf(" %-*s = "format"\n", DUMP_WIDTH, \ #field, value); \ sync(); \ - __delay(200); \ + __delay(SETJMP_MACHINE_CHECK_DELAY); \ } else { \ catch_memory_errors = 0; \ printf(" %-*s = *** Error reading field.\n", \ @@ -2899,7 +2889,7 @@ static void dump_spu_ls(unsigned long nu sync(); ls_addr = (unsigned long)spu_info[num].spu->local_store; sync(); - __delay(200); + __delay(SETJMP_MACHINE_CHECK_DELAY); } else { catch_memory_errors = 0; printf("*** Error: accessing spu info for spu %d\n", num); Index: clone3/include/asm-powerpc/setjmp.h =================================================================== --- /dev/null +++ clone3/include/asm-powerpc/setjmp.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2007 Michael Neuling + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ +#ifndef _ASM_POWERPC_SETJMP_H +#define _ASM_POWERPC_SETJMP_H + +#define SETJMP_BUF_LEN 23 +#define SETJMP_MACHINE_CHECK_DELAY 200 + +extern long setjmp(long *); +extern void longjmp(long *, long); + +#endif /* _ASM_POWERPC_SETJMP_H */ ^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 0/2] Add crashdump shutdown hooks 2007-12-13 9:59 ` [PATCH 0/2] Add crashdump shutdown hooks Michael Neuling 2007-12-13 9:59 ` [PATCH 2/2] kdump shutdown hook support Michael Neuling 2007-12-13 9:59 ` [PATCH 1/2] Make setjmp/longjmp code generic Michael Neuling @ 2008-01-17 4:45 ` Michael Neuling 2008-01-17 4:45 ` [PATCH 2/2] kdump shutdown hook support Michael Neuling 2008-01-17 4:45 ` [PATCH 1/2] Make setjmp/longjmp code generic Michael Neuling 2 siblings, 2 replies; 27+ messages in thread From: Michael Neuling @ 2008-01-17 4:45 UTC (permalink / raw) To: Paul Mackerras; +Cc: linuxppc-dev, RAISCH, THEMANN The following patches add crashdump shutdown hooks for POWERPC. Signed-off-by: Michael Neuling <mikey@neuling.org> --- Updated for suggests made by Paulus ^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 2/2] kdump shutdown hook support 2008-01-17 4:45 ` [PATCH 0/2] Add crashdump shutdown hooks Michael Neuling @ 2008-01-17 4:45 ` Michael Neuling 2008-01-17 4:45 ` [PATCH 1/2] Make setjmp/longjmp code generic Michael Neuling 1 sibling, 0 replies; 27+ messages in thread From: Michael Neuling @ 2008-01-17 4:45 UTC (permalink / raw) To: Paul Mackerras; +Cc: linuxppc-dev, RAISCH, THEMANN This adds hooks into the default_machine_crash_shutdown so drivers can register a function to be run in the first kernel before we hand off to the second kernel. This should only be used in exceptional circumstances, like where the device can't be reset in the second kernel alone (as is the case with eHEA). To emphasize this, the number of handles allowed to be registered is currently #def to 1. This uses the setjmp/longjmp code to call out to the registered hooks, so any bogus exceptions we encounter will hopefully be recoverable. Tested with bogus data and instruction exceptions. Signed-off-by: Michael Neuling <mikey@neuling.org> --- arch/powerpc/kernel/crash.c | 106 +++++++++++++++++++++++++++++++++++++++++--- include/asm-powerpc/kexec.h | 3 + 2 files changed, 104 insertions(+), 5 deletions(-) Index: linux-2.6-ozlabs/arch/powerpc/kernel/crash.c =================================================================== --- linux-2.6-ozlabs.orig/arch/powerpc/kernel/crash.c +++ linux-2.6-ozlabs/arch/powerpc/kernel/crash.c @@ -32,6 +32,8 @@ #include <asm/lmb.h> #include <asm/firmware.h> #include <asm/smp.h> +#include <asm/system.h> +#include <asm/setjmp.h> #ifdef DEBUG #include <asm/udbg.h> @@ -45,6 +47,11 @@ int crashing_cpu = -1; static cpumask_t cpus_in_crash = CPU_MASK_NONE; cpumask_t cpus_in_sr = CPU_MASK_NONE; +#define CRASH_HANDLER_MAX 1 +/* NULL terminated list of shutdown handles */ +static crash_shutdown_t crash_shutdown_handles[CRASH_HANDLER_MAX+1]; +static DEFINE_SPINLOCK(crash_handlers_lock); + #ifdef CONFIG_SMP static atomic_t enter_on_soft_reset = ATOMIC_INIT(0); @@ -285,9 +292,72 @@ static inline void crash_kexec_stop_spus } #endif /* CONFIG_SPU_BASE */ +/* + * Register a function to be called on shutdown. Only use this if you + * can't reset your device in the second kernel. + */ +int crash_shutdown_register(crash_shutdown_t handler) +{ + unsigned int i, rc; + + spin_lock(&crash_handlers_lock); + for (i = 0 ; i < CRASH_HANDLER_MAX; i++) + if (!crash_shutdown_handles[i]) { + /* Insert handle at first empty entry */ + crash_shutdown_handles[i] = handler; + rc = 0; + break; + } + + if (i == CRASH_HANDLER_MAX) { + printk(KERN_ERR "Crash shutdown handles full, " + "not registered.\n"); + rc = 1; + } + + spin_unlock(&crash_handlers_lock); + return rc; +} +EXPORT_SYMBOL(crash_shutdown_register); + +int crash_shutdown_unregister(crash_shutdown_t handler) +{ + unsigned int i, rc; + + spin_lock(&crash_handlers_lock); + for (i = 0 ; i < CRASH_HANDLER_MAX; i++) + if (crash_shutdown_handles[i] == handler) + break; + + if (i == CRASH_HANDLER_MAX) { + printk(KERN_ERR "Crash shutdown handle not found\n"); + rc = 1; + } else { + /* Shift handles down */ + for (; crash_shutdown_handles[i]; i++) + crash_shutdown_handles[i] = + crash_shutdown_handles[i+1]; + rc = 0; + } + + spin_unlock(&crash_handlers_lock); + return rc; +} +EXPORT_SYMBOL(crash_shutdown_unregister); + +static unsigned long crash_shutdown_buf[JMP_BUF_LEN]; + +static int handle_fault(struct pt_regs *regs) +{ + longjmp(crash_shutdown_buf, 1); + return 0; +} + void default_machine_crash_shutdown(struct pt_regs *regs) { - unsigned int irq; + unsigned int i; + int (*old_handler)(struct pt_regs *regs); + /* * This function is only called after the system @@ -301,15 +371,41 @@ void default_machine_crash_shutdown(stru */ hard_irq_disable(); - for_each_irq(irq) { - struct irq_desc *desc = irq_desc + irq; + for_each_irq(i) { + struct irq_desc *desc = irq_desc + i; if (desc->status & IRQ_INPROGRESS) - desc->chip->eoi(irq); + desc->chip->eoi(i); if (!(desc->status & IRQ_DISABLED)) - desc->chip->disable(irq); + desc->chip->disable(i); + } + + /* + * Call registered shutdown routines savely. Swap out + * __debugger_fault_handler, and replace on exit. + */ + old_handler = __debugger_fault_handler; + __debugger_fault_handler = handle_fault; + for (i = 0; crash_shutdown_handles[i]; i++) { + if (setjmp(crash_shutdown_buf) == 0) { + /* + * Insert syncs and delay to ensure + * instructions in the dangerous region don't + * leak away from this protected region. + */ + asm volatile("sync; isync"); + /* dangerous region */ + crash_shutdown_handles[i](); + asm volatile("sync; isync"); + /* + * wait a little while to see if we get a + * machine check + */ + __delay(200); + } } + __debugger_fault_handler = old_handler; /* * Make a note of crashing cpu. Will be used in machine_kexec Index: linux-2.6-ozlabs/include/asm-powerpc/kexec.h =================================================================== --- linux-2.6-ozlabs.orig/include/asm-powerpc/kexec.h +++ linux-2.6-ozlabs/include/asm-powerpc/kexec.h @@ -123,6 +123,9 @@ struct pt_regs; extern void default_machine_kexec(struct kimage *image); extern int default_machine_kexec_prepare(struct kimage *image); extern void default_machine_crash_shutdown(struct pt_regs *regs); +typedef void (*crash_shutdown_t)(void); +extern int crash_shutdown_register(crash_shutdown_t handler); +extern int crash_shutdown_unregister(crash_shutdown_t handler); extern void machine_kexec_simple(struct kimage *image); extern void crash_kexec_secondary(struct pt_regs *regs); ^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 1/2] Make setjmp/longjmp code generic 2008-01-17 4:45 ` [PATCH 0/2] Add crashdump shutdown hooks Michael Neuling 2008-01-17 4:45 ` [PATCH 2/2] kdump shutdown hook support Michael Neuling @ 2008-01-17 4:45 ` Michael Neuling 2008-01-17 5:38 ` Olof Johansson 2008-01-17 6:39 ` [PATCH 1/2] Make setjmp/longjmp code generic Stephen Rothwell 1 sibling, 2 replies; 27+ messages in thread From: Michael Neuling @ 2008-01-17 4:45 UTC (permalink / raw) To: Paul Mackerras; +Cc: linuxppc-dev, RAISCH, THEMANN This makes the setjmp/longjmp code used by xmon, generically available to other code. It also removes the requirement for debugger hooks to be only called on 0x300 (data storage) exception. Signed-off-by: Michael Neuling <mikey@neuling.org> --- arch/powerpc/kernel/misc.S | 65 +++++++++++++++++++++++++++++++++++++++++++ arch/powerpc/mm/fault.c | 6 +-- arch/powerpc/xmon/setjmp.S | 61 ---------------------------------------- arch/powerpc/xmon/xmon.c | 6 --- include/asm-powerpc/setjmp.h | 18 +++++++++++ 5 files changed, 86 insertions(+), 70 deletions(-) Index: linux-2.6-ozlabs/arch/powerpc/kernel/misc.S =================================================================== --- linux-2.6-ozlabs.orig/arch/powerpc/kernel/misc.S +++ linux-2.6-ozlabs/arch/powerpc/kernel/misc.S @@ -8,6 +8,8 @@ * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com) * + * setjmp/longjmp and xmon_save_regs code by Paul Mackerras. + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version @@ -15,6 +17,8 @@ */ #include <asm/ppc_asm.h> #include <asm/unistd.h> +#include <asm/asm-compat.h> +#include <asm/asm-offsets.h> .text @@ -51,3 +55,64 @@ _GLOBAL(kernel_execve) bnslr neg r3,r3 blr + +_GLOBAL(setjmp) + mflr r0 + PPC_STL r0,0(r3) + PPC_STL r1,SZL(r3) + PPC_STL r2,2*SZL(r3) + mfcr r0 + PPC_STL r0,3*SZL(r3) + PPC_STL r13,4*SZL(r3) + PPC_STL r14,5*SZL(r3) + PPC_STL r15,6*SZL(r3) + PPC_STL r16,7*SZL(r3) + PPC_STL r17,8*SZL(r3) + PPC_STL r18,9*SZL(r3) + PPC_STL r19,10*SZL(r3) + PPC_STL r20,11*SZL(r3) + PPC_STL r21,12*SZL(r3) + PPC_STL r22,13*SZL(r3) + PPC_STL r23,14*SZL(r3) + PPC_STL r24,15*SZL(r3) + PPC_STL r25,16*SZL(r3) + PPC_STL r26,17*SZL(r3) + PPC_STL r27,18*SZL(r3) + PPC_STL r28,19*SZL(r3) + PPC_STL r29,20*SZL(r3) + PPC_STL r30,21*SZL(r3) + PPC_STL r31,22*SZL(r3) + li r3,0 + blr + +_GLOBAL(longjmp) + PPC_LCMPI r4,0 + bne 1f + li r4,1 +1: PPC_LL r13,4*SZL(r3) + PPC_LL r14,5*SZL(r3) + PPC_LL r15,6*SZL(r3) + PPC_LL r16,7*SZL(r3) + PPC_LL r17,8*SZL(r3) + PPC_LL r18,9*SZL(r3) + PPC_LL r19,10*SZL(r3) + PPC_LL r20,11*SZL(r3) + PPC_LL r21,12*SZL(r3) + PPC_LL r22,13*SZL(r3) + PPC_LL r23,14*SZL(r3) + PPC_LL r24,15*SZL(r3) + PPC_LL r25,16*SZL(r3) + PPC_LL r26,17*SZL(r3) + PPC_LL r27,18*SZL(r3) + PPC_LL r28,19*SZL(r3) + PPC_LL r29,20*SZL(r3) + PPC_LL r30,21*SZL(r3) + PPC_LL r31,22*SZL(r3) + PPC_LL r0,3*SZL(r3) + mtcrf 0x38,r0 + PPC_LL r0,0(r3) + PPC_LL r1,SZL(r3) + PPC_LL r2,2*SZL(r3) + mtlr r0 + mr r3,r4 + blr Index: linux-2.6-ozlabs/arch/powerpc/mm/fault.c =================================================================== --- linux-2.6-ozlabs.orig/arch/powerpc/mm/fault.c +++ linux-2.6-ozlabs/arch/powerpc/mm/fault.c @@ -167,10 +167,8 @@ int __kprobes do_page_fault(struct pt_re if (notify_page_fault(regs)) return 0; - if (trap == 0x300) { - if (debugger_fault_handler(regs)) - return 0; - } + if (unlikely(debugger_fault_handler(regs))) + return 0; /* On a kernel SLB miss we can only check for a valid exception entry */ if (!user_mode(regs) && (address >= TASK_SIZE)) Index: linux-2.6-ozlabs/arch/powerpc/xmon/setjmp.S =================================================================== --- linux-2.6-ozlabs.orig/arch/powerpc/xmon/setjmp.S +++ linux-2.6-ozlabs/arch/powerpc/xmon/setjmp.S @@ -12,67 +12,6 @@ #include <asm/ppc_asm.h> #include <asm/asm-offsets.h> -_GLOBAL(xmon_setjmp) - mflr r0 - PPC_STL r0,0(r3) - PPC_STL r1,SZL(r3) - PPC_STL r2,2*SZL(r3) - mfcr r0 - PPC_STL r0,3*SZL(r3) - PPC_STL r13,4*SZL(r3) - PPC_STL r14,5*SZL(r3) - PPC_STL r15,6*SZL(r3) - PPC_STL r16,7*SZL(r3) - PPC_STL r17,8*SZL(r3) - PPC_STL r18,9*SZL(r3) - PPC_STL r19,10*SZL(r3) - PPC_STL r20,11*SZL(r3) - PPC_STL r21,12*SZL(r3) - PPC_STL r22,13*SZL(r3) - PPC_STL r23,14*SZL(r3) - PPC_STL r24,15*SZL(r3) - PPC_STL r25,16*SZL(r3) - PPC_STL r26,17*SZL(r3) - PPC_STL r27,18*SZL(r3) - PPC_STL r28,19*SZL(r3) - PPC_STL r29,20*SZL(r3) - PPC_STL r30,21*SZL(r3) - PPC_STL r31,22*SZL(r3) - li r3,0 - blr - -_GLOBAL(xmon_longjmp) - PPC_LCMPI r4,0 - bne 1f - li r4,1 -1: PPC_LL r13,4*SZL(r3) - PPC_LL r14,5*SZL(r3) - PPC_LL r15,6*SZL(r3) - PPC_LL r16,7*SZL(r3) - PPC_LL r17,8*SZL(r3) - PPC_LL r18,9*SZL(r3) - PPC_LL r19,10*SZL(r3) - PPC_LL r20,11*SZL(r3) - PPC_LL r21,12*SZL(r3) - PPC_LL r22,13*SZL(r3) - PPC_LL r23,14*SZL(r3) - PPC_LL r24,15*SZL(r3) - PPC_LL r25,16*SZL(r3) - PPC_LL r26,17*SZL(r3) - PPC_LL r27,18*SZL(r3) - PPC_LL r28,19*SZL(r3) - PPC_LL r29,20*SZL(r3) - PPC_LL r30,21*SZL(r3) - PPC_LL r31,22*SZL(r3) - PPC_LL r0,3*SZL(r3) - mtcrf 0x38,r0 - PPC_LL r0,0(r3) - PPC_LL r1,SZL(r3) - PPC_LL r2,2*SZL(r3) - mtlr r0 - mr r3,r4 - blr - /* * Grab the register values as they are now. * This won't do a particularily good job because we really Index: linux-2.6-ozlabs/arch/powerpc/xmon/xmon.c =================================================================== --- linux-2.6-ozlabs.orig/arch/powerpc/xmon/xmon.c +++ linux-2.6-ozlabs/arch/powerpc/xmon/xmon.c @@ -40,6 +40,7 @@ #include <asm/spu.h> #include <asm/spu_priv1.h> #include <asm/firmware.h> +#include <asm/setjmp.h> #ifdef CONFIG_PPC64 #include <asm/hvcall.h> @@ -71,12 +72,9 @@ static unsigned long ncsum = 4096; static int termch; static char tmpstr[128]; -#define JMP_BUF_LEN 23 static long bus_error_jmp[JMP_BUF_LEN]; static int catch_memory_errors; static long *xmon_fault_jmp[NR_CPUS]; -#define setjmp xmon_setjmp -#define longjmp xmon_longjmp /* Breakpoint stuff */ struct bpt { @@ -162,8 +160,6 @@ int xmon_no_auto_backtrace; extern void xmon_enter(void); extern void xmon_leave(void); -extern long setjmp(long *); -extern void longjmp(long *, long); extern void xmon_save_regs(struct pt_regs *); #ifdef CONFIG_PPC64 Index: linux-2.6-ozlabs/include/asm-powerpc/setjmp.h =================================================================== --- /dev/null +++ linux-2.6-ozlabs/include/asm-powerpc/setjmp.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2007 Michael Neuling + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ +#ifndef _ASM_POWERPC_SETJMP_H +#define _ASM_POWERPC_SETJMP_H + +#define JMP_BUF_LEN 23 + +extern long setjmp(long *); +extern void longjmp(long *, long); + +#endif /* _ASM_POWERPC_SETJMP_H */ ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 1/2] Make setjmp/longjmp code generic 2008-01-17 4:45 ` [PATCH 1/2] Make setjmp/longjmp code generic Michael Neuling @ 2008-01-17 5:38 ` Olof Johansson 2008-01-17 5:36 ` Michael Neuling 2008-01-17 6:39 ` [PATCH 1/2] Make setjmp/longjmp code generic Stephen Rothwell 1 sibling, 1 reply; 27+ messages in thread From: Olof Johansson @ 2008-01-17 5:38 UTC (permalink / raw) To: Michael Neuling; +Cc: linuxppc-dev, RAISCH, Paul Mackerras, THEMANN Hi, On Thu, Jan 17, 2008 at 03:45:42PM +1100, Michael Neuling wrote: > Index: linux-2.6-ozlabs/include/asm-powerpc/setjmp.h > =================================================================== > --- /dev/null > +++ linux-2.6-ozlabs/include/asm-powerpc/setjmp.h > @@ -0,0 +1,18 @@ > +/* > + * Copyright (C) 2007 Michael Neuling > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * as published by the Free Software Foundation; either version > + * 2 of the License, or (at your option) any later version. > + * > + */ > +#ifndef _ASM_POWERPC_SETJMP_H > +#define _ASM_POWERPC_SETJMP_H > + > +#define JMP_BUF_LEN 23 > + > +extern long setjmp(long *); > +extern void longjmp(long *, long); > + > +#endif /* _ASM_POWERPC_SETJMP_H */ Should the above be inside #ifdef __KERNEL__? -Olof ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 1/2] Make setjmp/longjmp code generic 2008-01-17 5:38 ` Olof Johansson @ 2008-01-17 5:36 ` Michael Neuling 2008-01-17 6:36 ` Stephen Rothwell ` (2 more replies) 0 siblings, 3 replies; 27+ messages in thread From: Michael Neuling @ 2008-01-17 5:36 UTC (permalink / raw) To: Olof Johansson; +Cc: linuxppc-dev, RAISCH, Paul Mackerras, THEMANN In message <20080117053857.GA29035@lixom.net> you wrote: > Hi, > > On Thu, Jan 17, 2008 at 03:45:42PM +1100, Michael Neuling wrote: > > > Index: linux-2.6-ozlabs/include/asm-powerpc/setjmp.h > > =================================================================== > > --- /dev/null > > +++ linux-2.6-ozlabs/include/asm-powerpc/setjmp.h > > @@ -0,0 +1,18 @@ > > +/* > > + * Copyright (C) 2007 Michael Neuling ^^^^^^ > > + * > > + * This program is free software; you can redistribute it and/or > > + * modify it under the terms of the GNU General Public License > > + * as published by the Free Software Foundation; either version > > + * 2 of the License, or (at your option) any later version. > > + * > > + */ > > +#ifndef _ASM_POWERPC_SETJMP_H > > +#define _ASM_POWERPC_SETJMP_H > > + > > +#define JMP_BUF_LEN 23 > > + > > +extern long setjmp(long *); > > +extern void longjmp(long *, long); > > + > > +#endif /* _ASM_POWERPC_SETJMP_H */ > > Should the above be inside #ifdef __KERNEL__? Yep... _and_ it's 2008 now! I'll update. Mikey ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 1/2] Make setjmp/longjmp code generic 2008-01-17 5:36 ` Michael Neuling @ 2008-01-17 6:36 ` Stephen Rothwell 2008-01-17 12:45 ` Josh Boyer 2008-01-17 22:16 ` [PATCH] Add crashdump shutdown hooks Michael Neuling 2 siblings, 0 replies; 27+ messages in thread From: Stephen Rothwell @ 2008-01-17 6:36 UTC (permalink / raw) To: Michael Neuling Cc: Olof Johansson, linuxppc-dev, RAISCH, Paul Mackerras, THEMANN [-- Attachment #1: Type: text/plain, Size: 459 bytes --] On Thu, 17 Jan 2008 16:36:49 +1100 Michael Neuling <mikey@neuling.org> wrote: > > > > > Should the above be inside #ifdef __KERNEL__? > > Yep... _and_ it's 2008 now! I think that if you don't list the file for exporting to user mode (in the Kbuild file), then you shouldn't need the __KERNEL__ protectors. But it is, indeed, 2008. :-) -- Cheers, Stephen Rothwell sfr@canb.auug.org.au http://www.canb.auug.org.au/~sfr/ [-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 1/2] Make setjmp/longjmp code generic 2008-01-17 5:36 ` Michael Neuling 2008-01-17 6:36 ` Stephen Rothwell @ 2008-01-17 12:45 ` Josh Boyer 2008-01-17 21:49 ` Michael Ellerman 2008-01-17 22:16 ` [PATCH] Add crashdump shutdown hooks Michael Neuling 2 siblings, 1 reply; 27+ messages in thread From: Josh Boyer @ 2008-01-17 12:45 UTC (permalink / raw) To: Michael Neuling Cc: Olof Johansson, linuxppc-dev, RAISCH, Paul Mackerras, THEMANN On Thu, 17 Jan 2008 16:36:49 +1100 Michael Neuling <mikey@neuling.org> wrote: > > > In message <20080117053857.GA29035@lixom.net> you wrote: > > Hi, > > > > On Thu, Jan 17, 2008 at 03:45:42PM +1100, Michael Neuling wrote: > > > > > Index: linux-2.6-ozlabs/include/asm-powerpc/setjmp.h > > > =================================================================== > > > --- /dev/null > > > +++ linux-2.6-ozlabs/include/asm-powerpc/setjmp.h > > > @@ -0,0 +1,18 @@ > > > +/* > > > + * Copyright (C) 2007 Michael Neuling > ^^^^^^ > > > > + * > > > + * This program is free software; you can redistribute it and/or > > > + * modify it under the terms of the GNU General Public License > > > + * as published by the Free Software Foundation; either version > > > + * 2 of the License, or (at your option) any later version. > > > + * > > > + */ > > > +#ifndef _ASM_POWERPC_SETJMP_H > > > +#define _ASM_POWERPC_SETJMP_H > > > + > > > +#define JMP_BUF_LEN 23 > > > + > > > +extern long setjmp(long *); > > > +extern void longjmp(long *, long); > > > + > > > +#endif /* _ASM_POWERPC_SETJMP_H */ > > > > Should the above be inside #ifdef __KERNEL__? > > Yep... _and_ it's 2008 now! > > I'll update. While you're off updating it, remove the (C). It's bogus and shouldn't be there. josh ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 1/2] Make setjmp/longjmp code generic 2008-01-17 12:45 ` Josh Boyer @ 2008-01-17 21:49 ` Michael Ellerman 0 siblings, 0 replies; 27+ messages in thread From: Michael Ellerman @ 2008-01-17 21:49 UTC (permalink / raw) To: Josh Boyer Cc: Michael Neuling, THEMANN, linuxppc-dev, RAISCH, Paul Mackerras, Olof Johansson [-- Attachment #1: Type: text/plain, Size: 1837 bytes --] On Thu, 2008-01-17 at 06:45 -0600, Josh Boyer wrote: > On Thu, 17 Jan 2008 16:36:49 +1100 > Michael Neuling <mikey@neuling.org> wrote: > > In message <20080117053857.GA29035@lixom.net> you wrote: > > > Hi, > > > > > > On Thu, Jan 17, 2008 at 03:45:42PM +1100, Michael Neuling wrote: > > > > > > > Index: linux-2.6-ozlabs/include/asm-powerpc/setjmp.h > > > > =================================================================== > > > > --- /dev/null > > > > +++ linux-2.6-ozlabs/include/asm-powerpc/setjmp.h > > > > @@ -0,0 +1,18 @@ > > > > +/* > > > > + * Copyright (C) 2007 Michael Neuling > > ^^^^^^ > > > > > > + * > > > > + * This program is free software; you can redistribute it and/or > > > > + * modify it under the terms of the GNU General Public License > > > > + * as published by the Free Software Foundation; either version > > > > + * 2 of the License, or (at your option) any later version. > > > > + * > > > > + */ > > > > +#ifndef _ASM_POWERPC_SETJMP_H > > > > +#define _ASM_POWERPC_SETJMP_H > > > > + > > > > +#define JMP_BUF_LEN 23 > > > > + > > > > +extern long setjmp(long *); > > > > +extern void longjmp(long *, long); > > > > + > > > > +#endif /* _ASM_POWERPC_SETJMP_H */ > > > > > > Should the above be inside #ifdef __KERNEL__? > > > > Yep... _and_ it's 2008 now! > > > > I'll update. > > While you're off updating it, remove the (C). It's bogus and shouldn't > be there. And it should say IBM corp too. Oh and my car needs a wash when you're free .. cheers -- Michael Ellerman OzLabs, IBM Australia Development Lab wwweb: http://michael.ellerman.id.au phone: +61 2 6212 1183 (tie line 70 21183) We do not inherit the earth from our ancestors, we borrow it from our children. - S.M.A.R.T Person [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH] Add crashdump shutdown hooks 2008-01-17 5:36 ` Michael Neuling 2008-01-17 6:36 ` Stephen Rothwell 2008-01-17 12:45 ` Josh Boyer @ 2008-01-17 22:16 ` Michael Neuling 2008-01-17 22:16 ` [PATCH] Make setjmp/longjmp code generic Michael Neuling 2008-01-18 4:50 ` [PATCH 0/2] Add crashdump shutdown hooks Michael Neuling 2 siblings, 2 replies; 27+ messages in thread From: Michael Neuling @ 2008-01-17 22:16 UTC (permalink / raw) To: Paul Mackerras; +Cc: linuxppc-dev, RAISCH, Stephen Rothwell, THEMANN The following patches add crashdump shutdown hooks for POWERPC. Signed-off-by: Michael Neuling <mikey@neuling.org> --- Updated some comments in the code, as noticed by sfr, Josh Boyer and a dirty car owner. ^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH] Make setjmp/longjmp code generic 2008-01-17 22:16 ` [PATCH] Add crashdump shutdown hooks Michael Neuling @ 2008-01-17 22:16 ` Michael Neuling 2008-01-18 4:50 ` [PATCH 0/2] Add crashdump shutdown hooks Michael Neuling 1 sibling, 0 replies; 27+ messages in thread From: Michael Neuling @ 2008-01-17 22:16 UTC (permalink / raw) To: Paul Mackerras; +Cc: linuxppc-dev, RAISCH, Stephen Rothwell, THEMANN [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain, Size: 6605 bytes --] This makes the setjmp/longjmp code used by xmon, generically available to other code. It also removes the requirement for debugger hooks to be only called on 0x300 (data storage) exception. Signed-off-by: Michael Neuling <mikey@neuling.org> --- arch/powerpc/kernel/misc.S | 65 +++++++++++++++++++++++++++++++++++++++++++ arch/powerpc/mm/fault.c | 6 +-- arch/powerpc/xmon/setjmp.S | 61 ---------------------------------------- arch/powerpc/xmon/xmon.c | 6 --- include/asm-powerpc/setjmp.h | 18 +++++++++++ 5 files changed, 86 insertions(+), 70 deletions(-) Index: linux-2.6-ozlabs/arch/powerpc/kernel/misc.S =================================================================== --- linux-2.6-ozlabs.orig/arch/powerpc/kernel/misc.S +++ linux-2.6-ozlabs/arch/powerpc/kernel/misc.S @@ -8,6 +8,8 @@ * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com) * + * setjmp/longjmp code by Paul Mackerras. + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version @@ -15,6 +17,8 @@ */ #include <asm/ppc_asm.h> #include <asm/unistd.h> +#include <asm/asm-compat.h> +#include <asm/asm-offsets.h> .text @@ -51,3 +55,64 @@ _GLOBAL(kernel_execve) bnslr neg r3,r3 blr + +_GLOBAL(setjmp) + mflr r0 + PPC_STL r0,0(r3) + PPC_STL r1,SZL(r3) + PPC_STL r2,2*SZL(r3) + mfcr r0 + PPC_STL r0,3*SZL(r3) + PPC_STL r13,4*SZL(r3) + PPC_STL r14,5*SZL(r3) + PPC_STL r15,6*SZL(r3) + PPC_STL r16,7*SZL(r3) + PPC_STL r17,8*SZL(r3) + PPC_STL r18,9*SZL(r3) + PPC_STL r19,10*SZL(r3) + PPC_STL r20,11*SZL(r3) + PPC_STL r21,12*SZL(r3) + PPC_STL r22,13*SZL(r3) + PPC_STL r23,14*SZL(r3) + PPC_STL r24,15*SZL(r3) + PPC_STL r25,16*SZL(r3) + PPC_STL r26,17*SZL(r3) + PPC_STL r27,18*SZL(r3) + PPC_STL r28,19*SZL(r3) + PPC_STL r29,20*SZL(r3) + PPC_STL r30,21*SZL(r3) + PPC_STL r31,22*SZL(r3) + li r3,0 + blr + +_GLOBAL(longjmp) + PPC_LCMPI r4,0 + bne 1f + li r4,1 +1: PPC_LL r13,4*SZL(r3) + PPC_LL r14,5*SZL(r3) + PPC_LL r15,6*SZL(r3) + PPC_LL r16,7*SZL(r3) + PPC_LL r17,8*SZL(r3) + PPC_LL r18,9*SZL(r3) + PPC_LL r19,10*SZL(r3) + PPC_LL r20,11*SZL(r3) + PPC_LL r21,12*SZL(r3) + PPC_LL r22,13*SZL(r3) + PPC_LL r23,14*SZL(r3) + PPC_LL r24,15*SZL(r3) + PPC_LL r25,16*SZL(r3) + PPC_LL r26,17*SZL(r3) + PPC_LL r27,18*SZL(r3) + PPC_LL r28,19*SZL(r3) + PPC_LL r29,20*SZL(r3) + PPC_LL r30,21*SZL(r3) + PPC_LL r31,22*SZL(r3) + PPC_LL r0,3*SZL(r3) + mtcrf 0x38,r0 + PPC_LL r0,0(r3) + PPC_LL r1,SZL(r3) + PPC_LL r2,2*SZL(r3) + mtlr r0 + mr r3,r4 + blr Index: linux-2.6-ozlabs/arch/powerpc/mm/fault.c =================================================================== --- linux-2.6-ozlabs.orig/arch/powerpc/mm/fault.c +++ linux-2.6-ozlabs/arch/powerpc/mm/fault.c @@ -167,10 +167,8 @@ int __kprobes do_page_fault(struct pt_re if (notify_page_fault(regs)) return 0; - if (trap == 0x300) { - if (debugger_fault_handler(regs)) - return 0; - } + if (unlikely(debugger_fault_handler(regs))) + return 0; /* On a kernel SLB miss we can only check for a valid exception entry */ if (!user_mode(regs) && (address >= TASK_SIZE)) Index: linux-2.6-ozlabs/arch/powerpc/xmon/setjmp.S =================================================================== --- linux-2.6-ozlabs.orig/arch/powerpc/xmon/setjmp.S +++ linux-2.6-ozlabs/arch/powerpc/xmon/setjmp.S @@ -12,67 +12,6 @@ #include <asm/ppc_asm.h> #include <asm/asm-offsets.h> -_GLOBAL(xmon_setjmp) - mflr r0 - PPC_STL r0,0(r3) - PPC_STL r1,SZL(r3) - PPC_STL r2,2*SZL(r3) - mfcr r0 - PPC_STL r0,3*SZL(r3) - PPC_STL r13,4*SZL(r3) - PPC_STL r14,5*SZL(r3) - PPC_STL r15,6*SZL(r3) - PPC_STL r16,7*SZL(r3) - PPC_STL r17,8*SZL(r3) - PPC_STL r18,9*SZL(r3) - PPC_STL r19,10*SZL(r3) - PPC_STL r20,11*SZL(r3) - PPC_STL r21,12*SZL(r3) - PPC_STL r22,13*SZL(r3) - PPC_STL r23,14*SZL(r3) - PPC_STL r24,15*SZL(r3) - PPC_STL r25,16*SZL(r3) - PPC_STL r26,17*SZL(r3) - PPC_STL r27,18*SZL(r3) - PPC_STL r28,19*SZL(r3) - PPC_STL r29,20*SZL(r3) - PPC_STL r30,21*SZL(r3) - PPC_STL r31,22*SZL(r3) - li r3,0 - blr - -_GLOBAL(xmon_longjmp) - PPC_LCMPI r4,0 - bne 1f - li r4,1 -1: PPC_LL r13,4*SZL(r3) - PPC_LL r14,5*SZL(r3) - PPC_LL r15,6*SZL(r3) - PPC_LL r16,7*SZL(r3) - PPC_LL r17,8*SZL(r3) - PPC_LL r18,9*SZL(r3) - PPC_LL r19,10*SZL(r3) - PPC_LL r20,11*SZL(r3) - PPC_LL r21,12*SZL(r3) - PPC_LL r22,13*SZL(r3) - PPC_LL r23,14*SZL(r3) - PPC_LL r24,15*SZL(r3) - PPC_LL r25,16*SZL(r3) - PPC_LL r26,17*SZL(r3) - PPC_LL r27,18*SZL(r3) - PPC_LL r28,19*SZL(r3) - PPC_LL r29,20*SZL(r3) - PPC_LL r30,21*SZL(r3) - PPC_LL r31,22*SZL(r3) - PPC_LL r0,3*SZL(r3) - mtcrf 0x38,r0 - PPC_LL r0,0(r3) - PPC_LL r1,SZL(r3) - PPC_LL r2,2*SZL(r3) - mtlr r0 - mr r3,r4 - blr - /* * Grab the register values as they are now. * This won't do a particularily good job because we really Index: linux-2.6-ozlabs/arch/powerpc/xmon/xmon.c =================================================================== --- linux-2.6-ozlabs.orig/arch/powerpc/xmon/xmon.c +++ linux-2.6-ozlabs/arch/powerpc/xmon/xmon.c @@ -40,6 +40,7 @@ #include <asm/spu.h> #include <asm/spu_priv1.h> #include <asm/firmware.h> +#include <asm/setjmp.h> #ifdef CONFIG_PPC64 #include <asm/hvcall.h> @@ -71,12 +72,9 @@ static unsigned long ncsum = 4096; static int termch; static char tmpstr[128]; -#define JMP_BUF_LEN 23 static long bus_error_jmp[JMP_BUF_LEN]; static int catch_memory_errors; static long *xmon_fault_jmp[NR_CPUS]; -#define setjmp xmon_setjmp -#define longjmp xmon_longjmp /* Breakpoint stuff */ struct bpt { @@ -162,8 +160,6 @@ int xmon_no_auto_backtrace; extern void xmon_enter(void); extern void xmon_leave(void); -extern long setjmp(long *); -extern void longjmp(long *, long); extern void xmon_save_regs(struct pt_regs *); #ifdef CONFIG_PPC64 Index: linux-2.6-ozlabs/include/asm-powerpc/setjmp.h =================================================================== --- /dev/null +++ linux-2.6-ozlabs/include/asm-powerpc/setjmp.h @@ -0,0 +1,18 @@ +/* + * Copyright © 2008 Michael Neuling IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ +#ifndef _ASM_POWERPC_SETJMP_H +#define _ASM_POWERPC_SETJMP_H + +#define JMP_BUF_LEN 23 + +extern long setjmp(long *); +extern void longjmp(long *, long); + +#endif /* _ASM_POWERPC_SETJMP_H */ ^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 0/2] Add crashdump shutdown hooks 2008-01-17 22:16 ` [PATCH] Add crashdump shutdown hooks Michael Neuling 2008-01-17 22:16 ` [PATCH] Make setjmp/longjmp code generic Michael Neuling @ 2008-01-18 4:50 ` Michael Neuling 2008-01-18 4:50 ` [PATCH 1/2] Make setjmp/longjmp code generic Michael Neuling 2008-01-18 4:50 ` [PATCH 2/2] kdump shutdown hook support Michael Neuling 1 sibling, 2 replies; 27+ messages in thread From: Michael Neuling @ 2008-01-18 4:50 UTC (permalink / raw) To: Paul Mackerras; +Cc: linuxppc-dev The following patches add crashdump shutdown hooks for POWERPC. Signed-off-by: Michael Neuling <mikey@neuling.org> --- Sorry, last update didn't include both patches. ^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 1/2] Make setjmp/longjmp code generic 2008-01-18 4:50 ` [PATCH 0/2] Add crashdump shutdown hooks Michael Neuling @ 2008-01-18 4:50 ` Michael Neuling 2008-01-18 4:50 ` [PATCH 2/2] kdump shutdown hook support Michael Neuling 1 sibling, 0 replies; 27+ messages in thread From: Michael Neuling @ 2008-01-18 4:50 UTC (permalink / raw) To: Paul Mackerras; +Cc: linuxppc-dev [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain, Size: 6605 bytes --] This makes the setjmp/longjmp code used by xmon, generically available to other code. It also removes the requirement for debugger hooks to be only called on 0x300 (data storage) exception. Signed-off-by: Michael Neuling <mikey@neuling.org> --- arch/powerpc/kernel/misc.S | 65 +++++++++++++++++++++++++++++++++++++++++++ arch/powerpc/mm/fault.c | 6 +-- arch/powerpc/xmon/setjmp.S | 61 ---------------------------------------- arch/powerpc/xmon/xmon.c | 6 --- include/asm-powerpc/setjmp.h | 18 +++++++++++ 5 files changed, 86 insertions(+), 70 deletions(-) Index: linux-2.6-ozlabs/arch/powerpc/kernel/misc.S =================================================================== --- linux-2.6-ozlabs.orig/arch/powerpc/kernel/misc.S +++ linux-2.6-ozlabs/arch/powerpc/kernel/misc.S @@ -8,6 +8,8 @@ * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com) * + * setjmp/longjmp code by Paul Mackerras. + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version @@ -15,6 +17,8 @@ */ #include <asm/ppc_asm.h> #include <asm/unistd.h> +#include <asm/asm-compat.h> +#include <asm/asm-offsets.h> .text @@ -51,3 +55,64 @@ _GLOBAL(kernel_execve) bnslr neg r3,r3 blr + +_GLOBAL(setjmp) + mflr r0 + PPC_STL r0,0(r3) + PPC_STL r1,SZL(r3) + PPC_STL r2,2*SZL(r3) + mfcr r0 + PPC_STL r0,3*SZL(r3) + PPC_STL r13,4*SZL(r3) + PPC_STL r14,5*SZL(r3) + PPC_STL r15,6*SZL(r3) + PPC_STL r16,7*SZL(r3) + PPC_STL r17,8*SZL(r3) + PPC_STL r18,9*SZL(r3) + PPC_STL r19,10*SZL(r3) + PPC_STL r20,11*SZL(r3) + PPC_STL r21,12*SZL(r3) + PPC_STL r22,13*SZL(r3) + PPC_STL r23,14*SZL(r3) + PPC_STL r24,15*SZL(r3) + PPC_STL r25,16*SZL(r3) + PPC_STL r26,17*SZL(r3) + PPC_STL r27,18*SZL(r3) + PPC_STL r28,19*SZL(r3) + PPC_STL r29,20*SZL(r3) + PPC_STL r30,21*SZL(r3) + PPC_STL r31,22*SZL(r3) + li r3,0 + blr + +_GLOBAL(longjmp) + PPC_LCMPI r4,0 + bne 1f + li r4,1 +1: PPC_LL r13,4*SZL(r3) + PPC_LL r14,5*SZL(r3) + PPC_LL r15,6*SZL(r3) + PPC_LL r16,7*SZL(r3) + PPC_LL r17,8*SZL(r3) + PPC_LL r18,9*SZL(r3) + PPC_LL r19,10*SZL(r3) + PPC_LL r20,11*SZL(r3) + PPC_LL r21,12*SZL(r3) + PPC_LL r22,13*SZL(r3) + PPC_LL r23,14*SZL(r3) + PPC_LL r24,15*SZL(r3) + PPC_LL r25,16*SZL(r3) + PPC_LL r26,17*SZL(r3) + PPC_LL r27,18*SZL(r3) + PPC_LL r28,19*SZL(r3) + PPC_LL r29,20*SZL(r3) + PPC_LL r30,21*SZL(r3) + PPC_LL r31,22*SZL(r3) + PPC_LL r0,3*SZL(r3) + mtcrf 0x38,r0 + PPC_LL r0,0(r3) + PPC_LL r1,SZL(r3) + PPC_LL r2,2*SZL(r3) + mtlr r0 + mr r3,r4 + blr Index: linux-2.6-ozlabs/arch/powerpc/mm/fault.c =================================================================== --- linux-2.6-ozlabs.orig/arch/powerpc/mm/fault.c +++ linux-2.6-ozlabs/arch/powerpc/mm/fault.c @@ -167,10 +167,8 @@ int __kprobes do_page_fault(struct pt_re if (notify_page_fault(regs)) return 0; - if (trap == 0x300) { - if (debugger_fault_handler(regs)) - return 0; - } + if (unlikely(debugger_fault_handler(regs))) + return 0; /* On a kernel SLB miss we can only check for a valid exception entry */ if (!user_mode(regs) && (address >= TASK_SIZE)) Index: linux-2.6-ozlabs/arch/powerpc/xmon/setjmp.S =================================================================== --- linux-2.6-ozlabs.orig/arch/powerpc/xmon/setjmp.S +++ linux-2.6-ozlabs/arch/powerpc/xmon/setjmp.S @@ -12,67 +12,6 @@ #include <asm/ppc_asm.h> #include <asm/asm-offsets.h> -_GLOBAL(xmon_setjmp) - mflr r0 - PPC_STL r0,0(r3) - PPC_STL r1,SZL(r3) - PPC_STL r2,2*SZL(r3) - mfcr r0 - PPC_STL r0,3*SZL(r3) - PPC_STL r13,4*SZL(r3) - PPC_STL r14,5*SZL(r3) - PPC_STL r15,6*SZL(r3) - PPC_STL r16,7*SZL(r3) - PPC_STL r17,8*SZL(r3) - PPC_STL r18,9*SZL(r3) - PPC_STL r19,10*SZL(r3) - PPC_STL r20,11*SZL(r3) - PPC_STL r21,12*SZL(r3) - PPC_STL r22,13*SZL(r3) - PPC_STL r23,14*SZL(r3) - PPC_STL r24,15*SZL(r3) - PPC_STL r25,16*SZL(r3) - PPC_STL r26,17*SZL(r3) - PPC_STL r27,18*SZL(r3) - PPC_STL r28,19*SZL(r3) - PPC_STL r29,20*SZL(r3) - PPC_STL r30,21*SZL(r3) - PPC_STL r31,22*SZL(r3) - li r3,0 - blr - -_GLOBAL(xmon_longjmp) - PPC_LCMPI r4,0 - bne 1f - li r4,1 -1: PPC_LL r13,4*SZL(r3) - PPC_LL r14,5*SZL(r3) - PPC_LL r15,6*SZL(r3) - PPC_LL r16,7*SZL(r3) - PPC_LL r17,8*SZL(r3) - PPC_LL r18,9*SZL(r3) - PPC_LL r19,10*SZL(r3) - PPC_LL r20,11*SZL(r3) - PPC_LL r21,12*SZL(r3) - PPC_LL r22,13*SZL(r3) - PPC_LL r23,14*SZL(r3) - PPC_LL r24,15*SZL(r3) - PPC_LL r25,16*SZL(r3) - PPC_LL r26,17*SZL(r3) - PPC_LL r27,18*SZL(r3) - PPC_LL r28,19*SZL(r3) - PPC_LL r29,20*SZL(r3) - PPC_LL r30,21*SZL(r3) - PPC_LL r31,22*SZL(r3) - PPC_LL r0,3*SZL(r3) - mtcrf 0x38,r0 - PPC_LL r0,0(r3) - PPC_LL r1,SZL(r3) - PPC_LL r2,2*SZL(r3) - mtlr r0 - mr r3,r4 - blr - /* * Grab the register values as they are now. * This won't do a particularily good job because we really Index: linux-2.6-ozlabs/arch/powerpc/xmon/xmon.c =================================================================== --- linux-2.6-ozlabs.orig/arch/powerpc/xmon/xmon.c +++ linux-2.6-ozlabs/arch/powerpc/xmon/xmon.c @@ -40,6 +40,7 @@ #include <asm/spu.h> #include <asm/spu_priv1.h> #include <asm/firmware.h> +#include <asm/setjmp.h> #ifdef CONFIG_PPC64 #include <asm/hvcall.h> @@ -71,12 +72,9 @@ static unsigned long ncsum = 4096; static int termch; static char tmpstr[128]; -#define JMP_BUF_LEN 23 static long bus_error_jmp[JMP_BUF_LEN]; static int catch_memory_errors; static long *xmon_fault_jmp[NR_CPUS]; -#define setjmp xmon_setjmp -#define longjmp xmon_longjmp /* Breakpoint stuff */ struct bpt { @@ -162,8 +160,6 @@ int xmon_no_auto_backtrace; extern void xmon_enter(void); extern void xmon_leave(void); -extern long setjmp(long *); -extern void longjmp(long *, long); extern void xmon_save_regs(struct pt_regs *); #ifdef CONFIG_PPC64 Index: linux-2.6-ozlabs/include/asm-powerpc/setjmp.h =================================================================== --- /dev/null +++ linux-2.6-ozlabs/include/asm-powerpc/setjmp.h @@ -0,0 +1,18 @@ +/* + * Copyright © 2008 Michael Neuling IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ +#ifndef _ASM_POWERPC_SETJMP_H +#define _ASM_POWERPC_SETJMP_H + +#define JMP_BUF_LEN 23 + +extern long setjmp(long *); +extern void longjmp(long *, long); + +#endif /* _ASM_POWERPC_SETJMP_H */ ^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 2/2] kdump shutdown hook support 2008-01-18 4:50 ` [PATCH 0/2] Add crashdump shutdown hooks Michael Neuling 2008-01-18 4:50 ` [PATCH 1/2] Make setjmp/longjmp code generic Michael Neuling @ 2008-01-18 4:50 ` Michael Neuling 1 sibling, 0 replies; 27+ messages in thread From: Michael Neuling @ 2008-01-18 4:50 UTC (permalink / raw) To: Paul Mackerras; +Cc: linuxppc-dev This adds hooks into the default_machine_crash_shutdown so drivers can register a function to be run in the first kernel before we hand off to the second kernel. This should only be used in exceptional circumstances, like where the device can't be reset in the second kernel alone (as is the case with eHEA). To emphasize this, the number of handles allowed to be registered is currently #def to 1. This uses the setjmp/longjmp code to call out to the registered hooks, so any bogus exceptions we encounter will hopefully be recoverable. Tested with bogus data and instruction exceptions. Signed-off-by: Michael Neuling <mikey@neuling.org> --- arch/powerpc/kernel/crash.c | 106 +++++++++++++++++++++++++++++++++++++++++--- include/asm-powerpc/kexec.h | 3 + 2 files changed, 104 insertions(+), 5 deletions(-) Index: linux-2.6-ozlabs/arch/powerpc/kernel/crash.c =================================================================== --- linux-2.6-ozlabs.orig/arch/powerpc/kernel/crash.c +++ linux-2.6-ozlabs/arch/powerpc/kernel/crash.c @@ -32,6 +32,8 @@ #include <asm/lmb.h> #include <asm/firmware.h> #include <asm/smp.h> +#include <asm/system.h> +#include <asm/setjmp.h> #ifdef DEBUG #include <asm/udbg.h> @@ -45,6 +47,11 @@ int crashing_cpu = -1; static cpumask_t cpus_in_crash = CPU_MASK_NONE; cpumask_t cpus_in_sr = CPU_MASK_NONE; +#define CRASH_HANDLER_MAX 1 +/* NULL terminated list of shutdown handles */ +static crash_shutdown_t crash_shutdown_handles[CRASH_HANDLER_MAX+1]; +static DEFINE_SPINLOCK(crash_handlers_lock); + #ifdef CONFIG_SMP static atomic_t enter_on_soft_reset = ATOMIC_INIT(0); @@ -285,9 +292,72 @@ static inline void crash_kexec_stop_spus } #endif /* CONFIG_SPU_BASE */ +/* + * Register a function to be called on shutdown. Only use this if you + * can't reset your device in the second kernel. + */ +int crash_shutdown_register(crash_shutdown_t handler) +{ + unsigned int i, rc; + + spin_lock(&crash_handlers_lock); + for (i = 0 ; i < CRASH_HANDLER_MAX; i++) + if (!crash_shutdown_handles[i]) { + /* Insert handle at first empty entry */ + crash_shutdown_handles[i] = handler; + rc = 0; + break; + } + + if (i == CRASH_HANDLER_MAX) { + printk(KERN_ERR "Crash shutdown handles full, " + "not registered.\n"); + rc = 1; + } + + spin_unlock(&crash_handlers_lock); + return rc; +} +EXPORT_SYMBOL(crash_shutdown_register); + +int crash_shutdown_unregister(crash_shutdown_t handler) +{ + unsigned int i, rc; + + spin_lock(&crash_handlers_lock); + for (i = 0 ; i < CRASH_HANDLER_MAX; i++) + if (crash_shutdown_handles[i] == handler) + break; + + if (i == CRASH_HANDLER_MAX) { + printk(KERN_ERR "Crash shutdown handle not found\n"); + rc = 1; + } else { + /* Shift handles down */ + for (; crash_shutdown_handles[i]; i++) + crash_shutdown_handles[i] = + crash_shutdown_handles[i+1]; + rc = 0; + } + + spin_unlock(&crash_handlers_lock); + return rc; +} +EXPORT_SYMBOL(crash_shutdown_unregister); + +static unsigned long crash_shutdown_buf[JMP_BUF_LEN]; + +static int handle_fault(struct pt_regs *regs) +{ + longjmp(crash_shutdown_buf, 1); + return 0; +} + void default_machine_crash_shutdown(struct pt_regs *regs) { - unsigned int irq; + unsigned int i; + int (*old_handler)(struct pt_regs *regs); + /* * This function is only called after the system @@ -301,15 +371,41 @@ void default_machine_crash_shutdown(stru */ hard_irq_disable(); - for_each_irq(irq) { - struct irq_desc *desc = irq_desc + irq; + for_each_irq(i) { + struct irq_desc *desc = irq_desc + i; if (desc->status & IRQ_INPROGRESS) - desc->chip->eoi(irq); + desc->chip->eoi(i); if (!(desc->status & IRQ_DISABLED)) - desc->chip->disable(irq); + desc->chip->disable(i); + } + + /* + * Call registered shutdown routines savely. Swap out + * __debugger_fault_handler, and replace on exit. + */ + old_handler = __debugger_fault_handler; + __debugger_fault_handler = handle_fault; + for (i = 0; crash_shutdown_handles[i]; i++) { + if (setjmp(crash_shutdown_buf) == 0) { + /* + * Insert syncs and delay to ensure + * instructions in the dangerous region don't + * leak away from this protected region. + */ + asm volatile("sync; isync"); + /* dangerous region */ + crash_shutdown_handles[i](); + asm volatile("sync; isync"); + /* + * wait a little while to see if we get a + * machine check + */ + __delay(200); + } } + __debugger_fault_handler = old_handler; /* * Make a note of crashing cpu. Will be used in machine_kexec Index: linux-2.6-ozlabs/include/asm-powerpc/kexec.h =================================================================== --- linux-2.6-ozlabs.orig/include/asm-powerpc/kexec.h +++ linux-2.6-ozlabs/include/asm-powerpc/kexec.h @@ -123,6 +123,9 @@ struct pt_regs; extern void default_machine_kexec(struct kimage *image); extern int default_machine_kexec_prepare(struct kimage *image); extern void default_machine_crash_shutdown(struct pt_regs *regs); +typedef void (*crash_shutdown_t)(void); +extern int crash_shutdown_register(crash_shutdown_t handler); +extern int crash_shutdown_unregister(crash_shutdown_t handler); extern void machine_kexec_simple(struct kimage *image); extern void crash_kexec_secondary(struct pt_regs *regs); ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 1/2] Make setjmp/longjmp code generic 2008-01-17 4:45 ` [PATCH 1/2] Make setjmp/longjmp code generic Michael Neuling 2008-01-17 5:38 ` Olof Johansson @ 2008-01-17 6:39 ` Stephen Rothwell 1 sibling, 0 replies; 27+ messages in thread From: Stephen Rothwell @ 2008-01-17 6:39 UTC (permalink / raw) To: Michael Neuling; +Cc: linuxppc-dev, RAISCH, Paul Mackerras, THEMANN [-- Attachment #1: Type: text/plain, Size: 527 bytes --] On Thu, 17 Jan 2008 15:45:42 +1100 Michael Neuling <mikey@neuling.org> wrote: > > +++ linux-2.6-ozlabs/arch/powerpc/kernel/misc.S > @@ -8,6 +8,8 @@ > * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) > * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com) > * > + * setjmp/longjmp and xmon_save_regs code by Paul Mackerras. ^^^^^^^^^^^^^^ This doesn't exist here. -- Cheers, Stephen Rothwell sfr@canb.auug.org.au http://www.canb.auug.org.au/~sfr/ [-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 1/2] Make setjmp/longjmp code generic 2007-12-13 3:16 ` [PATCH 0/2] Add crashdump shutdown hooks Michael Neuling 2007-12-13 3:16 ` [PATCH 2/2] kdump shutdown hook support Michael Neuling @ 2007-12-13 3:16 ` Michael Neuling 1 sibling, 0 replies; 27+ messages in thread From: Michael Neuling @ 2007-12-13 3:16 UTC (permalink / raw) To: Paul Mackerras; +Cc: linuxppc-dev, Michael Neuling, RAISCH, THEMANN This makes the setjmp/longjmp code used by xmon, generically available to other code. It also removes the requirement for debugger hooks to be only called on 0x300 (data storage) exception and adds some documentation. Signed-off-by: Michael Neuling <mikey@neuling.org> --- arch/powerpc/kernel/misc.S | 128 ++++++++++++++++++++++++++++++++++++++++ arch/powerpc/mm/fault.c | 6 - arch/powerpc/xmon/Makefile | 2 arch/powerpc/xmon/setjmp.S | 135 ------------------------------------------- arch/powerpc/xmon/xmon.c | 38 ++++-------- include/asm-powerpc/setjmp.h | 19 ++++++ 6 files changed, 164 insertions(+), 164 deletions(-) Index: clone3/arch/powerpc/kernel/misc.S =================================================================== --- clone3.orig/arch/powerpc/kernel/misc.S +++ clone3/arch/powerpc/kernel/misc.S @@ -8,6 +8,8 @@ * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com) * + * setjmp/longjmp and xmon_save_regs code by Paul Mackerras. + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version @@ -15,6 +17,8 @@ */ #include <asm/ppc_asm.h> #include <asm/unistd.h> +#include <asm/asm-compat.h> +#include <asm/asm-offsets.h> .text @@ -51,3 +55,127 @@ _GLOBAL(kernel_execve) bnslr neg r3,r3 blr + +_GLOBAL(setjmp) + mflr r0 + PPC_STL r0,0(r3) + PPC_STL r1,SZL(r3) + PPC_STL r2,2*SZL(r3) + mfcr r0 + PPC_STL r0,3*SZL(r3) + PPC_STL r13,4*SZL(r3) + PPC_STL r14,5*SZL(r3) + PPC_STL r15,6*SZL(r3) + PPC_STL r16,7*SZL(r3) + PPC_STL r17,8*SZL(r3) + PPC_STL r18,9*SZL(r3) + PPC_STL r19,10*SZL(r3) + PPC_STL r20,11*SZL(r3) + PPC_STL r21,12*SZL(r3) + PPC_STL r22,13*SZL(r3) + PPC_STL r23,14*SZL(r3) + PPC_STL r24,15*SZL(r3) + PPC_STL r25,16*SZL(r3) + PPC_STL r26,17*SZL(r3) + PPC_STL r27,18*SZL(r3) + PPC_STL r28,19*SZL(r3) + PPC_STL r29,20*SZL(r3) + PPC_STL r30,21*SZL(r3) + PPC_STL r31,22*SZL(r3) + li r3,0 + blr + +_GLOBAL(longjmp) + PPC_LCMPI r4,0 + bne 1f + li r4,1 +1: PPC_LL r13,4*SZL(r3) + PPC_LL r14,5*SZL(r3) + PPC_LL r15,6*SZL(r3) + PPC_LL r16,7*SZL(r3) + PPC_LL r17,8*SZL(r3) + PPC_LL r18,9*SZL(r3) + PPC_LL r19,10*SZL(r3) + PPC_LL r20,11*SZL(r3) + PPC_LL r21,12*SZL(r3) + PPC_LL r22,13*SZL(r3) + PPC_LL r23,14*SZL(r3) + PPC_LL r24,15*SZL(r3) + PPC_LL r25,16*SZL(r3) + PPC_LL r26,17*SZL(r3) + PPC_LL r27,18*SZL(r3) + PPC_LL r28,19*SZL(r3) + PPC_LL r29,20*SZL(r3) + PPC_LL r30,21*SZL(r3) + PPC_LL r31,22*SZL(r3) + PPC_LL r0,3*SZL(r3) + mtcrf 0x38,r0 + PPC_LL r0,0(r3) + PPC_LL r1,SZL(r3) + PPC_LL r2,2*SZL(r3) + mtlr r0 + mr r3,r4 + blr + +#ifdef CONFIG_XMON +/* + * Grab the register values as they are now. + * This won't do a particularily good job because we really + * want our caller's caller's registers, and our caller has + * already executed its prologue. + * ToDo: We could reach back into the caller's save area to do + * a better job of representing the caller's state (note that + * that will be different for 32-bit and 64-bit, because of the + * different ABIs, though). + */ +_GLOBAL(xmon_save_regs) + PPC_STL r0,0*SZL(r3) + PPC_STL r2,2*SZL(r3) + PPC_STL r3,3*SZL(r3) + PPC_STL r4,4*SZL(r3) + PPC_STL r5,5*SZL(r3) + PPC_STL r6,6*SZL(r3) + PPC_STL r7,7*SZL(r3) + PPC_STL r8,8*SZL(r3) + PPC_STL r9,9*SZL(r3) + PPC_STL r10,10*SZL(r3) + PPC_STL r11,11*SZL(r3) + PPC_STL r12,12*SZL(r3) + PPC_STL r13,13*SZL(r3) + PPC_STL r14,14*SZL(r3) + PPC_STL r15,15*SZL(r3) + PPC_STL r16,16*SZL(r3) + PPC_STL r17,17*SZL(r3) + PPC_STL r18,18*SZL(r3) + PPC_STL r19,19*SZL(r3) + PPC_STL r20,20*SZL(r3) + PPC_STL r21,21*SZL(r3) + PPC_STL r22,22*SZL(r3) + PPC_STL r23,23*SZL(r3) + PPC_STL r24,24*SZL(r3) + PPC_STL r25,25*SZL(r3) + PPC_STL r26,26*SZL(r3) + PPC_STL r27,27*SZL(r3) + PPC_STL r28,28*SZL(r3) + PPC_STL r29,29*SZL(r3) + PPC_STL r30,30*SZL(r3) + PPC_STL r31,31*SZL(r3) + /* go up one stack frame for SP */ + PPC_LL r4,0(r1) + PPC_STL r4,1*SZL(r3) + /* get caller's LR */ + PPC_LL r0,LRSAVE(r4) + PPC_STL r0,_NIP-STACK_FRAME_OVERHEAD(r3) + PPC_STL r0,_LINK-STACK_FRAME_OVERHEAD(r3) + mfmsr r0 + PPC_STL r0,_MSR-STACK_FRAME_OVERHEAD(r3) + mfctr r0 + PPC_STL r0,_CTR-STACK_FRAME_OVERHEAD(r3) + mfxer r0 + PPC_STL r0,_XER-STACK_FRAME_OVERHEAD(r3) + mfcr r0 + PPC_STL r0,_CCR-STACK_FRAME_OVERHEAD(r3) + li r0,0 + PPC_STL r0,_TRAP-STACK_FRAME_OVERHEAD(r3) + blr +#endif Index: clone3/arch/powerpc/mm/fault.c =================================================================== --- clone3.orig/arch/powerpc/mm/fault.c +++ clone3/arch/powerpc/mm/fault.c @@ -167,10 +167,8 @@ int __kprobes do_page_fault(struct pt_re if (notify_page_fault(regs)) return 0; - if (trap == 0x300) { - if (debugger_fault_handler(regs)) - return 0; - } + if (unlikely(debugger_fault_handler(regs))) + return 0; /* On a kernel SLB miss we can only check for a valid exception entry */ if (!user_mode(regs) && (address >= TASK_SIZE)) Index: clone3/arch/powerpc/xmon/Makefile =================================================================== --- clone3.orig/arch/powerpc/xmon/Makefile +++ clone3/arch/powerpc/xmon/Makefile @@ -4,7 +4,7 @@ ifdef CONFIG_PPC64 EXTRA_CFLAGS += -mno-minimal-toc endif -obj-y += xmon.o setjmp.o start.o nonstdio.o +obj-y += xmon.o start.o nonstdio.o ifdef CONFIG_XMON_DISASSEMBLY obj-y += ppc-dis.o ppc-opc.o Index: clone3/arch/powerpc/xmon/setjmp.S =================================================================== --- clone3.orig/arch/powerpc/xmon/setjmp.S +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 1996 Paul Mackerras. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * NOTE: assert(sizeof(buf) > 23 * sizeof(long)) - */ -#include <asm/processor.h> -#include <asm/ppc_asm.h> -#include <asm/asm-offsets.h> - -_GLOBAL(xmon_setjmp) - mflr r0 - PPC_STL r0,0(r3) - PPC_STL r1,SZL(r3) - PPC_STL r2,2*SZL(r3) - mfcr r0 - PPC_STL r0,3*SZL(r3) - PPC_STL r13,4*SZL(r3) - PPC_STL r14,5*SZL(r3) - PPC_STL r15,6*SZL(r3) - PPC_STL r16,7*SZL(r3) - PPC_STL r17,8*SZL(r3) - PPC_STL r18,9*SZL(r3) - PPC_STL r19,10*SZL(r3) - PPC_STL r20,11*SZL(r3) - PPC_STL r21,12*SZL(r3) - PPC_STL r22,13*SZL(r3) - PPC_STL r23,14*SZL(r3) - PPC_STL r24,15*SZL(r3) - PPC_STL r25,16*SZL(r3) - PPC_STL r26,17*SZL(r3) - PPC_STL r27,18*SZL(r3) - PPC_STL r28,19*SZL(r3) - PPC_STL r29,20*SZL(r3) - PPC_STL r30,21*SZL(r3) - PPC_STL r31,22*SZL(r3) - li r3,0 - blr - -_GLOBAL(xmon_longjmp) - PPC_LCMPI r4,0 - bne 1f - li r4,1 -1: PPC_LL r13,4*SZL(r3) - PPC_LL r14,5*SZL(r3) - PPC_LL r15,6*SZL(r3) - PPC_LL r16,7*SZL(r3) - PPC_LL r17,8*SZL(r3) - PPC_LL r18,9*SZL(r3) - PPC_LL r19,10*SZL(r3) - PPC_LL r20,11*SZL(r3) - PPC_LL r21,12*SZL(r3) - PPC_LL r22,13*SZL(r3) - PPC_LL r23,14*SZL(r3) - PPC_LL r24,15*SZL(r3) - PPC_LL r25,16*SZL(r3) - PPC_LL r26,17*SZL(r3) - PPC_LL r27,18*SZL(r3) - PPC_LL r28,19*SZL(r3) - PPC_LL r29,20*SZL(r3) - PPC_LL r30,21*SZL(r3) - PPC_LL r31,22*SZL(r3) - PPC_LL r0,3*SZL(r3) - mtcrf 0x38,r0 - PPC_LL r0,0(r3) - PPC_LL r1,SZL(r3) - PPC_LL r2,2*SZL(r3) - mtlr r0 - mr r3,r4 - blr - -/* - * Grab the register values as they are now. - * This won't do a particularily good job because we really - * want our caller's caller's registers, and our caller has - * already executed its prologue. - * ToDo: We could reach back into the caller's save area to do - * a better job of representing the caller's state (note that - * that will be different for 32-bit and 64-bit, because of the - * different ABIs, though). - */ -_GLOBAL(xmon_save_regs) - PPC_STL r0,0*SZL(r3) - PPC_STL r2,2*SZL(r3) - PPC_STL r3,3*SZL(r3) - PPC_STL r4,4*SZL(r3) - PPC_STL r5,5*SZL(r3) - PPC_STL r6,6*SZL(r3) - PPC_STL r7,7*SZL(r3) - PPC_STL r8,8*SZL(r3) - PPC_STL r9,9*SZL(r3) - PPC_STL r10,10*SZL(r3) - PPC_STL r11,11*SZL(r3) - PPC_STL r12,12*SZL(r3) - PPC_STL r13,13*SZL(r3) - PPC_STL r14,14*SZL(r3) - PPC_STL r15,15*SZL(r3) - PPC_STL r16,16*SZL(r3) - PPC_STL r17,17*SZL(r3) - PPC_STL r18,18*SZL(r3) - PPC_STL r19,19*SZL(r3) - PPC_STL r20,20*SZL(r3) - PPC_STL r21,21*SZL(r3) - PPC_STL r22,22*SZL(r3) - PPC_STL r23,23*SZL(r3) - PPC_STL r24,24*SZL(r3) - PPC_STL r25,25*SZL(r3) - PPC_STL r26,26*SZL(r3) - PPC_STL r27,27*SZL(r3) - PPC_STL r28,28*SZL(r3) - PPC_STL r29,29*SZL(r3) - PPC_STL r30,30*SZL(r3) - PPC_STL r31,31*SZL(r3) - /* go up one stack frame for SP */ - PPC_LL r4,0(r1) - PPC_STL r4,1*SZL(r3) - /* get caller's LR */ - PPC_LL r0,LRSAVE(r4) - PPC_STL r0,_NIP-STACK_FRAME_OVERHEAD(r3) - PPC_STL r0,_LINK-STACK_FRAME_OVERHEAD(r3) - mfmsr r0 - PPC_STL r0,_MSR-STACK_FRAME_OVERHEAD(r3) - mfctr r0 - PPC_STL r0,_CTR-STACK_FRAME_OVERHEAD(r3) - mfxer r0 - PPC_STL r0,_XER-STACK_FRAME_OVERHEAD(r3) - mfcr r0 - PPC_STL r0,_CCR-STACK_FRAME_OVERHEAD(r3) - li r0,0 - PPC_STL r0,_TRAP-STACK_FRAME_OVERHEAD(r3) - blr Index: clone3/arch/powerpc/xmon/xmon.c =================================================================== --- clone3.orig/arch/powerpc/xmon/xmon.c +++ clone3/arch/powerpc/xmon/xmon.c @@ -40,6 +40,7 @@ #include <asm/spu.h> #include <asm/spu_priv1.h> #include <asm/firmware.h> +#include <asm/setjmp.h> #ifdef CONFIG_PPC64 #include <asm/hvcall.h> @@ -71,12 +72,9 @@ static unsigned long ncsum = 4096; static int termch; static char tmpstr[128]; -#define JMP_BUF_LEN 23 -static long bus_error_jmp[JMP_BUF_LEN]; +static long bus_error_jmp[SETJMP_BUF_LEN]; static int catch_memory_errors; static long *xmon_fault_jmp[NR_CPUS]; -#define setjmp xmon_setjmp -#define longjmp xmon_longjmp /* Breakpoint stuff */ struct bpt { @@ -162,8 +160,6 @@ int xmon_no_auto_backtrace; extern void xmon_enter(void); extern void xmon_leave(void); -extern long setjmp(long *); -extern void longjmp(long *, long); extern void xmon_save_regs(struct pt_regs *); #ifdef CONFIG_PPC64 @@ -338,7 +334,7 @@ static int xmon_core(struct pt_regs *reg { int cmd = 0; struct bpt *bp; - long recurse_jmp[JMP_BUF_LEN]; + long recurse_jmp[SETJMP_BUF_LEN]; unsigned long offset; unsigned long flags; #ifdef CONFIG_SMP @@ -1428,7 +1424,7 @@ void prregs(struct pt_regs *fp) sync(); regs = *(struct pt_regs *)base; sync(); - __delay(200); + __delay(SETJMP_MACHINE_CHECK_DELAY); } else { catch_memory_errors = 0; printf("*** Error reading registers from "REG"\n", @@ -1497,8 +1493,7 @@ void cacheflush(void) cinval((void *) adrs); } sync(); - /* wait a little while to see if we get a machine check */ - __delay(200); + __delay(SETJMP_MACHINE_CHECK_DELAY); } catch_memory_errors = 0; } @@ -1533,8 +1528,7 @@ read_spr(int n) ret = code(); sync(); - /* wait a little while to see if we get a machine check */ - __delay(200); + __delay(SETJMP_MACHINE_CHECK_DELAY); n = size; } @@ -1569,8 +1563,7 @@ write_spr(int n, unsigned long val) code(val); sync(); - /* wait a little while to see if we get a machine check */ - __delay(200); + __delay(SETJMP_MACHINE_CHECK_DELAY); n = size; } } @@ -1676,8 +1669,7 @@ mread(unsigned long adrs, void *buf, int } } sync(); - /* wait a little while to see if we get a machine check */ - __delay(200); + __delay(SETJMP_MACHINE_CHECK_DELAY); n = size; } catch_memory_errors = 0; @@ -1713,8 +1705,7 @@ mwrite(unsigned long adrs, void *buf, in } } sync(); - /* wait a little while to see if we get a machine check */ - __delay(200); + __delay(SETJMP_MACHINE_CHECK_DELAY); n = size; } else { printf("*** Error writing address %x\n", adrs + n); @@ -2521,8 +2512,7 @@ static void xmon_print_symbol(unsigned l name = kallsyms_lookup(address, &size, &offset, &modname, tmpstr); sync(); - /* wait a little while to see if we get a machine check */ - __delay(200); + __delay(SETJMP_MACHINE_CHECK_DELAY); } catch_memory_errors = 0; @@ -2777,7 +2767,7 @@ static void stop_spus(void) spu_mfc_sr1_set(spu, tmp); sync(); - __delay(200); + __delay(SETJMP_MACHINE_CHECK_DELAY); spu_info[i].stopped_ok = 1; @@ -2817,7 +2807,7 @@ static void restart_spus(void) spu_info[i].saved_spu_runcntl_RW); sync(); - __delay(200); + __delay(SETJMP_MACHINE_CHECK_DELAY); printf("Restarted spu %.2d\n", i); } else { @@ -2837,7 +2827,7 @@ do { \ printf(" %-*s = "format"\n", DUMP_WIDTH, \ #field, value); \ sync(); \ - __delay(200); \ + __delay(SETJMP_MACHINE_CHECK_DELAY); \ } else { \ catch_memory_errors = 0; \ printf(" %-*s = *** Error reading field.\n", \ @@ -2899,7 +2889,7 @@ static void dump_spu_ls(unsigned long nu sync(); ls_addr = (unsigned long)spu_info[num].spu->local_store; sync(); - __delay(200); + __delay(SETJMP_MACHINE_CHECK_DELAY); } else { catch_memory_errors = 0; printf("*** Error: accessing spu info for spu %d\n", num); Index: clone3/include/asm-powerpc/setjmp.h =================================================================== --- /dev/null +++ clone3/include/asm-powerpc/setjmp.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2007 Michael Neuling + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ +#ifndef _ASM_POWERPC_SETJMP_H +#define _ASM_POWERPC_SETJMP_H + +#define SETJMP_BUF_LEN 23 +#define SETJMP_MACHINE_CHECK_DELAY 200 + +extern long setjmp(long *); +extern void longjmp(long *, long); + +#endif /* _ASM_POWERPC_SETJMP_H */ ^ permalink raw reply [flat|nested] 27+ messages in thread
end of thread, other threads:[~2008-01-18 4:50 UTC | newest] Thread overview: 27+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2007-12-12 5:45 [PATCH 2/2] kdump shutdown hook support Michael Neuling 2007-12-12 7:01 ` Olof Johansson 2007-12-13 0:53 ` Michael Neuling 2007-12-12 23:07 ` Michael Ellerman 2007-12-13 0:04 ` Michael Neuling 2007-12-13 3:16 ` [PATCH 0/2] Add crashdump shutdown hooks Michael Neuling 2007-12-13 3:16 ` [PATCH 2/2] kdump shutdown hook support Michael Neuling 2007-12-13 5:12 ` Olof Johansson 2007-12-13 5:13 ` Olof Johansson 2007-12-13 9:59 ` [PATCH 0/2] Add crashdump shutdown hooks Michael Neuling 2007-12-13 9:59 ` [PATCH 2/2] kdump shutdown hook support Michael Neuling 2007-12-13 9:59 ` [PATCH 1/2] Make setjmp/longjmp code generic Michael Neuling 2008-01-17 4:45 ` [PATCH 0/2] Add crashdump shutdown hooks Michael Neuling 2008-01-17 4:45 ` [PATCH 2/2] kdump shutdown hook support Michael Neuling 2008-01-17 4:45 ` [PATCH 1/2] Make setjmp/longjmp code generic Michael Neuling 2008-01-17 5:38 ` Olof Johansson 2008-01-17 5:36 ` Michael Neuling 2008-01-17 6:36 ` Stephen Rothwell 2008-01-17 12:45 ` Josh Boyer 2008-01-17 21:49 ` Michael Ellerman 2008-01-17 22:16 ` [PATCH] Add crashdump shutdown hooks Michael Neuling 2008-01-17 22:16 ` [PATCH] Make setjmp/longjmp code generic Michael Neuling 2008-01-18 4:50 ` [PATCH 0/2] Add crashdump shutdown hooks Michael Neuling 2008-01-18 4:50 ` [PATCH 1/2] Make setjmp/longjmp code generic Michael Neuling 2008-01-18 4:50 ` [PATCH 2/2] kdump shutdown hook support Michael Neuling 2008-01-17 6:39 ` [PATCH 1/2] Make setjmp/longjmp code generic Stephen Rothwell 2007-12-13 3:16 ` Michael Neuling
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).