Commit 59010373 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus' of https://github.com/openrisc/linux

Pull OpenRISC updates from Stafford Horne:
 "A few cleanups and fixups from me:

   - Add a few missing relocations to fix module loading

   - Cleanup FPU state save and restore to be more efficient

   - Cleanups to traps handling and logging

   - Fix issue with poweroff being broken after recent power driver
     refactorings"

* tag 'for-linus' of https://github.com/openrisc/linux:
  openrisc: Move FPU state out of pt_regs
  openrisc: Add FPU config
  openrisc: traps: Don't send signals to kernel mode threads
  openrisc: traps: Remove calls to show_registers before die
  openrisc: traps: Convert printks to pr_<level> macros
  openrisc: Add support for more module relocations
  openrisc: Define openrisc relocation types
  openrisc: Use do_kernel_power_off()
parents c59cebe8 4dc70e1a
...@@ -188,6 +188,15 @@ config SMP ...@@ -188,6 +188,15 @@ config SMP
If you don't know what to do here, say N. If you don't know what to do here, say N.
config FPU
bool "FPU support"
default y
help
Say N here if you want to disable all floating-point related procedures
in the kernel and reduce binary size.
If you don't know what to do here, say Y.
source "kernel/Kconfig.hz" source "kernel/Kconfig.hz"
config OPENRISC_NO_SPR_SR_DSX config OPENRISC_NO_SPR_SR_DSX
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_OPENRISC_FPU_H
#define __ASM_OPENRISC_FPU_H
struct task_struct;
#ifdef CONFIG_FPU
static inline void save_fpu(struct task_struct *task)
{
task->thread.fpcsr = mfspr(SPR_FPCSR);
}
static inline void restore_fpu(struct task_struct *task)
{
mtspr(SPR_FPCSR, task->thread.fpcsr);
}
#else
#define save_fpu(tsk) do { } while (0)
#define restore_fpu(tsk) do { } while (0)
#endif
#endif /* __ASM_OPENRISC_FPU_H */
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
struct task_struct; struct task_struct;
struct thread_struct { struct thread_struct {
long fpcsr; /* Floating point control status register. */
}; };
/* /*
......
...@@ -59,7 +59,7 @@ struct pt_regs { ...@@ -59,7 +59,7 @@ struct pt_regs {
* -1 for all other exceptions. * -1 for all other exceptions.
*/ */
long orig_gpr11; /* For restarting system calls */ long orig_gpr11; /* For restarting system calls */
long fpcsr; /* Floating point control status register. */ long dummy; /* Cheap alignment fix */
long dummy2; /* Cheap alignment fix */ long dummy2; /* Cheap alignment fix */
}; };
...@@ -115,6 +115,5 @@ static inline long regs_return_value(struct pt_regs *regs) ...@@ -115,6 +115,5 @@ static inline long regs_return_value(struct pt_regs *regs)
#define PT_GPR31 124 #define PT_GPR31 124
#define PT_PC 128 #define PT_PC 128
#define PT_ORIG_GPR11 132 #define PT_ORIG_GPR11 132
#define PT_FPCSR 136
#endif /* __ASM_OPENRISC_PTRACE_H */ #endif /* __ASM_OPENRISC_PTRACE_H */
...@@ -34,15 +34,72 @@ ...@@ -34,15 +34,72 @@
#include <asm/ptrace.h> #include <asm/ptrace.h>
/* The OR1K relocation types... not all relevant for module loader */ /* The OR1K relocation types... not all relevant for module loader */
#define R_OR32_NONE 0 #define R_OR1K_NONE 0
#define R_OR32_32 1 #define R_OR1K_32 1
#define R_OR32_16 2 #define R_OR1K_16 2
#define R_OR32_8 3 #define R_OR1K_8 3
#define R_OR32_CONST 4 #define R_OR1K_LO_16_IN_INSN 4
#define R_OR32_CONSTH 5 #define R_OR1K_HI_16_IN_INSN 5
#define R_OR32_JUMPTARG 6 #define R_OR1K_INSN_REL_26 6
#define R_OR32_VTINHERIT 7 #define R_OR1K_GNU_VTENTRY 7
#define R_OR32_VTENTRY 8 #define R_OR1K_GNU_VTINHERIT 8
#define R_OR1K_32_PCREL 9
#define R_OR1K_16_PCREL 10
#define R_OR1K_8_PCREL 11
#define R_OR1K_GOTPC_HI16 12
#define R_OR1K_GOTPC_LO16 13
#define R_OR1K_GOT16 14
#define R_OR1K_PLT26 15
#define R_OR1K_GOTOFF_HI16 16
#define R_OR1K_GOTOFF_LO16 17
#define R_OR1K_COPY 18
#define R_OR1K_GLOB_DAT 19
#define R_OR1K_JMP_SLOT 20
#define R_OR1K_RELATIVE 21
#define R_OR1K_TLS_GD_HI16 22
#define R_OR1K_TLS_GD_LO16 23
#define R_OR1K_TLS_LDM_HI16 24
#define R_OR1K_TLS_LDM_LO16 25
#define R_OR1K_TLS_LDO_HI16 26
#define R_OR1K_TLS_LDO_LO16 27
#define R_OR1K_TLS_IE_HI16 28
#define R_OR1K_TLS_IE_LO16 29
#define R_OR1K_TLS_LE_HI16 30
#define R_OR1K_TLS_LE_LO16 31
#define R_OR1K_TLS_TPOFF 32
#define R_OR1K_TLS_DTPOFF 33
#define R_OR1K_TLS_DTPMOD 34
#define R_OR1K_AHI16 35
#define R_OR1K_GOTOFF_AHI16 36
#define R_OR1K_TLS_IE_AHI16 37
#define R_OR1K_TLS_LE_AHI16 38
#define R_OR1K_SLO16 39
#define R_OR1K_GOTOFF_SLO16 40
#define R_OR1K_TLS_LE_SLO16 41
#define R_OR1K_PCREL_PG21 42
#define R_OR1K_GOT_PG21 43
#define R_OR1K_TLS_GD_PG21 44
#define R_OR1K_TLS_LDM_PG21 45
#define R_OR1K_TLS_IE_PG21 46
#define R_OR1K_LO13 47
#define R_OR1K_GOT_LO13 48
#define R_OR1K_TLS_GD_LO13 49
#define R_OR1K_TLS_LDM_LO13 50
#define R_OR1K_TLS_IE_LO13 51
#define R_OR1K_SLO13 52
#define R_OR1K_PLTA26 53
#define R_OR1K_GOT_AHI16 54
/* Old relocation names */
#define R_OR32_NONE R_OR1K_NONE
#define R_OR32_32 R_OR1K_32
#define R_OR32_16 R_OR1K_16
#define R_OR32_8 R_OR1K_8
#define R_OR32_CONST R_OR1K_LO_16_IN_INSN
#define R_OR32_CONSTH R_OR1K_HI_16_IN_INSN
#define R_OR32_JUMPTARG R_OR1K_INSN_REL_26
#define R_OR32_VTENTRY R_OR1K_GNU_VTENTRY
#define R_OR32_VTINHERIT R_OR1K_GNU_VTINHERIT
typedef unsigned long elf_greg_t; typedef unsigned long elf_greg_t;
......
...@@ -106,8 +106,6 @@ ...@@ -106,8 +106,6 @@
l.mtspr r0,r3,SPR_EPCR_BASE ;\ l.mtspr r0,r3,SPR_EPCR_BASE ;\
l.lwz r3,PT_SR(r1) ;\ l.lwz r3,PT_SR(r1) ;\
l.mtspr r0,r3,SPR_ESR_BASE ;\ l.mtspr r0,r3,SPR_ESR_BASE ;\
l.lwz r3,PT_FPCSR(r1) ;\
l.mtspr r0,r3,SPR_FPCSR ;\
l.lwz r2,PT_GPR2(r1) ;\ l.lwz r2,PT_GPR2(r1) ;\
l.lwz r3,PT_GPR3(r1) ;\ l.lwz r3,PT_GPR3(r1) ;\
l.lwz r4,PT_GPR4(r1) ;\ l.lwz r4,PT_GPR4(r1) ;\
...@@ -177,8 +175,6 @@ handler: ;\ ...@@ -177,8 +175,6 @@ handler: ;\
/* r30 already save */ ;\ /* r30 already save */ ;\
l.sw PT_GPR31(r1),r31 ;\ l.sw PT_GPR31(r1),r31 ;\
TRACE_IRQS_OFF_ENTRY ;\ TRACE_IRQS_OFF_ENTRY ;\
l.mfspr r30,r0,SPR_FPCSR ;\
l.sw PT_FPCSR(r1),r30 ;\
/* Store -1 in orig_gpr11 for non-syscall exceptions */ ;\ /* Store -1 in orig_gpr11 for non-syscall exceptions */ ;\
l.addi r30,r0,-1 ;\ l.addi r30,r0,-1 ;\
l.sw PT_ORIG_GPR11(r1),r30 l.sw PT_ORIG_GPR11(r1),r30
...@@ -219,8 +215,6 @@ handler: ;\ ...@@ -219,8 +215,6 @@ handler: ;\
/* Store -1 in orig_gpr11 for non-syscall exceptions */ ;\ /* Store -1 in orig_gpr11 for non-syscall exceptions */ ;\
l.addi r30,r0,-1 ;\ l.addi r30,r0,-1 ;\
l.sw PT_ORIG_GPR11(r1),r30 ;\ l.sw PT_ORIG_GPR11(r1),r30 ;\
l.mfspr r30,r0,SPR_FPCSR ;\
l.sw PT_FPCSR(r1),r30 ;\
l.addi r3,r1,0 ;\ l.addi r3,r1,0 ;\
/* r4 is exception EA */ ;\ /* r4 is exception EA */ ;\
l.addi r5,r0,vector ;\ l.addi r5,r0,vector ;\
...@@ -852,6 +846,7 @@ _syscall_badsys: ...@@ -852,6 +846,7 @@ _syscall_badsys:
EXCEPTION_ENTRY(_fpe_trap_handler) EXCEPTION_ENTRY(_fpe_trap_handler)
CLEAR_LWA_FLAG(r3) CLEAR_LWA_FLAG(r3)
/* r4: EA of fault (set by EXCEPTION_HANDLE) */ /* r4: EA of fault (set by EXCEPTION_HANDLE) */
l.jal do_fpe_trap l.jal do_fpe_trap
l.addi r3,r1,0 /* pt_regs */ l.addi r3,r1,0 /* pt_regs */
...@@ -1100,10 +1095,6 @@ ENTRY(_switch) ...@@ -1100,10 +1095,6 @@ ENTRY(_switch)
l.sw PT_GPR28(r1),r28 l.sw PT_GPR28(r1),r28
l.sw PT_GPR30(r1),r30 l.sw PT_GPR30(r1),r30
/* Store the old FPU state to new pt_regs */
l.mfspr r29,r0,SPR_FPCSR
l.sw PT_FPCSR(r1),r29
l.addi r11,r10,0 /* Save old 'current' to 'last' return value*/ l.addi r11,r10,0 /* Save old 'current' to 'last' return value*/
/* We use thread_info->ksp for storing the address of the above /* We use thread_info->ksp for storing the address of the above
...@@ -1126,10 +1117,6 @@ ENTRY(_switch) ...@@ -1126,10 +1117,6 @@ ENTRY(_switch)
l.lwz r29,PT_SP(r1) l.lwz r29,PT_SP(r1)
l.sw TI_KSP(r10),r29 l.sw TI_KSP(r10),r29
/* Restore the old value of FPCSR */
l.lwz r29,PT_FPCSR(r1)
l.mtspr r0,r29,SPR_FPCSR
/* ...and restore the registers, except r11 because the return value /* ...and restore the registers, except r11 because the return value
* has already been set above. * has already been set above.
*/ */
......
...@@ -39,22 +39,32 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, ...@@ -39,22 +39,32 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
value = sym->st_value + rel[i].r_addend; value = sym->st_value + rel[i].r_addend;
switch (ELF32_R_TYPE(rel[i].r_info)) { switch (ELF32_R_TYPE(rel[i].r_info)) {
case R_OR32_32: case R_OR1K_32:
*location = value; *location = value;
break; break;
case R_OR32_CONST: case R_OR1K_LO_16_IN_INSN:
*((uint16_t *)location + 1) = value; *((uint16_t *)location + 1) = value;
break; break;
case R_OR32_CONSTH: case R_OR1K_HI_16_IN_INSN:
*((uint16_t *)location + 1) = value >> 16; *((uint16_t *)location + 1) = value >> 16;
break; break;
case R_OR32_JUMPTARG: case R_OR1K_INSN_REL_26:
value -= (uint32_t)location; value -= (uint32_t)location;
value >>= 2; value >>= 2;
value &= 0x03ffffff; value &= 0x03ffffff;
value |= *location & 0xfc000000; value |= *location & 0xfc000000;
*location = value; *location = value;
break; break;
case R_OR1K_AHI16:
/* Adjust the operand to match with a signed LO16. */
value += 0x8000;
*((uint16_t *)location + 1) = value >> 16;
break;
case R_OR1K_SLO16:
/* Split value lower 16-bits. */
value = ((value & 0xf800) << 10) | (value & 0x7ff);
*location = (*location & ~0x3e007ff) | value;
break;
default: default:
pr_err("module %s: Unknown relocation: %u\n", pr_err("module %s: Unknown relocation: %u\n",
me->name, ELF32_R_TYPE(rel[i].r_info)); me->name, ELF32_R_TYPE(rel[i].r_info));
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <asm/fpu.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/spr_defs.h> #include <asm/spr_defs.h>
...@@ -65,7 +66,7 @@ void machine_restart(char *cmd) ...@@ -65,7 +66,7 @@ void machine_restart(char *cmd)
} }
/* /*
* This is used if pm_power_off has not been set by a power management * This is used if a sys-off handler was not set by a power management
* driver, in this case we can assume we are on a simulator. On * driver, in this case we can assume we are on a simulator. On
* OpenRISC simulators l.nop 1 will trigger the simulator exit. * OpenRISC simulators l.nop 1 will trigger the simulator exit.
*/ */
...@@ -89,10 +90,8 @@ void machine_halt(void) ...@@ -89,10 +90,8 @@ void machine_halt(void)
void machine_power_off(void) void machine_power_off(void)
{ {
printk(KERN_INFO "*** MACHINE POWER OFF ***\n"); printk(KERN_INFO "*** MACHINE POWER OFF ***\n");
if (pm_power_off != NULL) do_kernel_power_off();
pm_power_off(); default_power_off();
else
default_power_off();
} }
/* /*
...@@ -246,6 +245,8 @@ struct task_struct *__switch_to(struct task_struct *old, ...@@ -246,6 +245,8 @@ struct task_struct *__switch_to(struct task_struct *old,
local_irq_save(flags); local_irq_save(flags);
save_fpu(current);
/* current_set is an array of saved current pointers /* current_set is an array of saved current pointers
* (one for each cpu). we need them at user->kernel transition, * (one for each cpu). we need them at user->kernel transition,
* while we save them at kernel->user transition * while we save them at kernel->user transition
...@@ -258,6 +259,8 @@ struct task_struct *__switch_to(struct task_struct *old, ...@@ -258,6 +259,8 @@ struct task_struct *__switch_to(struct task_struct *old,
current_thread_info_set[smp_processor_id()] = new_ti; current_thread_info_set[smp_processor_id()] = new_ti;
last = (_switch(old_ti, new_ti))->task; last = (_switch(old_ti, new_ti))->task;
restore_fpu(current);
local_irq_restore(flags); local_irq_restore(flags);
return last; return last;
......
...@@ -88,6 +88,7 @@ static int genregs_set(struct task_struct *target, ...@@ -88,6 +88,7 @@ static int genregs_set(struct task_struct *target,
return ret; return ret;
} }
#ifdef CONFIG_FPU
/* /*
* As OpenRISC shares GPRs and floating point registers we don't need to export * As OpenRISC shares GPRs and floating point registers we don't need to export
* the floating point registers again. So here we only export the fpcsr special * the floating point registers again. So here we only export the fpcsr special
...@@ -97,9 +98,7 @@ static int fpregs_get(struct task_struct *target, ...@@ -97,9 +98,7 @@ static int fpregs_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
struct membuf to) struct membuf to)
{ {
const struct pt_regs *regs = task_pt_regs(target); return membuf_store(&to, target->thread.fpcsr);
return membuf_store(&to, regs->fpcsr);
} }
static int fpregs_set(struct task_struct *target, static int fpregs_set(struct task_struct *target,
...@@ -107,21 +106,20 @@ static int fpregs_set(struct task_struct *target, ...@@ -107,21 +106,20 @@ static int fpregs_set(struct task_struct *target,
unsigned int pos, unsigned int count, unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf) const void *kbuf, const void __user *ubuf)
{ {
struct pt_regs *regs = task_pt_regs(target);
int ret;
/* FPCSR */ /* FPCSR */
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&regs->fpcsr, 0, 4); &target->thread.fpcsr, 0, 4);
return ret;
} }
#endif
/* /*
* Define the register sets available on OpenRISC under Linux * Define the register sets available on OpenRISC under Linux
*/ */
enum or1k_regset { enum or1k_regset {
REGSET_GENERAL, REGSET_GENERAL,
#ifdef CONFIG_FPU
REGSET_FPU, REGSET_FPU,
#endif
}; };
static const struct user_regset or1k_regsets[] = { static const struct user_regset or1k_regsets[] = {
...@@ -133,6 +131,7 @@ static const struct user_regset or1k_regsets[] = { ...@@ -133,6 +131,7 @@ static const struct user_regset or1k_regsets[] = {
.regset_get = genregs_get, .regset_get = genregs_get,
.set = genregs_set, .set = genregs_set,
}, },
#ifdef CONFIG_FPU
[REGSET_FPU] = { [REGSET_FPU] = {
.core_note_type = NT_PRFPREG, .core_note_type = NT_PRFPREG,
.n = sizeof(struct __or1k_fpu_state) / sizeof(long), .n = sizeof(struct __or1k_fpu_state) / sizeof(long),
...@@ -141,6 +140,7 @@ static const struct user_regset or1k_regsets[] = { ...@@ -141,6 +140,7 @@ static const struct user_regset or1k_regsets[] = {
.regset_get = fpregs_get, .regset_get = fpregs_get,
.set = fpregs_set, .set = fpregs_set,
}, },
#endif
}; };
static const struct user_regset_view user_or1k_native_view = { static const struct user_regset_view user_or1k_native_view = {
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/resume_user_mode.h> #include <linux/resume_user_mode.h>
#include <asm/fpu.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/syscall.h> #include <asm/syscall.h>
#include <asm/ucontext.h> #include <asm/ucontext.h>
...@@ -39,6 +40,37 @@ asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs); ...@@ -39,6 +40,37 @@ asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs);
asmlinkage int do_work_pending(struct pt_regs *regs, unsigned int thread_flags, asmlinkage int do_work_pending(struct pt_regs *regs, unsigned int thread_flags,
int syscall); int syscall);
#ifdef CONFIG_FPU
static long restore_fp_state(struct sigcontext __user *sc)
{
long err;
err = __copy_from_user(&current->thread.fpcsr, &sc->fpcsr, sizeof(unsigned long));
if (unlikely(err))
return err;
/* Restore the FPU state */
restore_fpu(current);
return 0;
}
static long save_fp_state(struct sigcontext __user *sc)
{
long err;
/* Sync the user FPU state so we can copy to sigcontext */
save_fpu(current);
err = __copy_to_user(&sc->fpcsr, &current->thread.fpcsr, sizeof(unsigned long));
return err;
}
#else
#define save_fp_state(sc) (0)
#define restore_fp_state(sc) (0)
#endif
static int restore_sigcontext(struct pt_regs *regs, static int restore_sigcontext(struct pt_regs *regs,
struct sigcontext __user *sc) struct sigcontext __user *sc)
{ {
...@@ -55,7 +87,7 @@ static int restore_sigcontext(struct pt_regs *regs, ...@@ -55,7 +87,7 @@ static int restore_sigcontext(struct pt_regs *regs,
err |= __copy_from_user(regs, sc->regs.gpr, 32 * sizeof(unsigned long)); err |= __copy_from_user(regs, sc->regs.gpr, 32 * sizeof(unsigned long));
err |= __copy_from_user(&regs->pc, &sc->regs.pc, sizeof(unsigned long)); err |= __copy_from_user(&regs->pc, &sc->regs.pc, sizeof(unsigned long));
err |= __copy_from_user(&regs->sr, &sc->regs.sr, sizeof(unsigned long)); err |= __copy_from_user(&regs->sr, &sc->regs.sr, sizeof(unsigned long));
err |= __copy_from_user(&regs->fpcsr, &sc->fpcsr, sizeof(unsigned long)); err |= restore_fp_state(sc);
/* make sure the SM-bit is cleared so user-mode cannot fool us */ /* make sure the SM-bit is cleared so user-mode cannot fool us */
regs->sr &= ~SPR_SR_SM; regs->sr &= ~SPR_SR_SM;
...@@ -118,7 +150,7 @@ static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) ...@@ -118,7 +150,7 @@ static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
err |= __copy_to_user(sc->regs.gpr, regs, 32 * sizeof(unsigned long)); err |= __copy_to_user(sc->regs.gpr, regs, 32 * sizeof(unsigned long));
err |= __copy_to_user(&sc->regs.pc, &regs->pc, sizeof(unsigned long)); err |= __copy_to_user(&sc->regs.pc, &regs->pc, sizeof(unsigned long));
err |= __copy_to_user(&sc->regs.sr, &regs->sr, sizeof(unsigned long)); err |= __copy_to_user(&sc->regs.sr, &regs->sr, sizeof(unsigned long));
err |= __copy_to_user(&sc->fpcsr, &regs->fpcsr, sizeof(unsigned long)); err |= save_fp_state(sc);
return err; return err;
} }
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <asm/bug.h> #include <asm/bug.h>
#include <asm/fpu.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/unwinder.h> #include <asm/unwinder.h>
...@@ -51,16 +52,16 @@ static void print_trace(void *data, unsigned long addr, int reliable) ...@@ -51,16 +52,16 @@ static void print_trace(void *data, unsigned long addr, int reliable)
{ {
const char *loglvl = data; const char *loglvl = data;
printk("%s[<%p>] %s%pS\n", loglvl, (void *) addr, reliable ? "" : "? ", pr_info("%s[<%p>] %s%pS\n", loglvl, (void *) addr, reliable ? "" : "? ",
(void *) addr); (void *) addr);
} }
static void print_data(unsigned long base_addr, unsigned long word, int i) static void print_data(unsigned long base_addr, unsigned long word, int i)
{ {
if (i == 0) if (i == 0)
printk("(%08lx:)\t%08lx", base_addr + (i * 4), word); pr_info("(%08lx:)\t%08lx", base_addr + (i * 4), word);
else else
printk(" %08lx:\t%08lx", base_addr + (i * 4), word); pr_info(" %08lx:\t%08lx", base_addr + (i * 4), word);
} }
/* displays a short stack trace */ /* displays a short stack trace */
...@@ -69,7 +70,7 @@ void show_stack(struct task_struct *task, unsigned long *esp, const char *loglvl ...@@ -69,7 +70,7 @@ void show_stack(struct task_struct *task, unsigned long *esp, const char *loglvl
if (esp == NULL) if (esp == NULL)
esp = (unsigned long *)&esp; esp = (unsigned long *)&esp;
printk("%sCall trace:\n", loglvl); pr_info("%sCall trace:\n", loglvl);
unwind_stack((void *)loglvl, esp, print_trace); unwind_stack((void *)loglvl, esp, print_trace);
} }
...@@ -83,57 +84,56 @@ void show_registers(struct pt_regs *regs) ...@@ -83,57 +84,56 @@ void show_registers(struct pt_regs *regs)
if (user_mode(regs)) if (user_mode(regs))
in_kernel = 0; in_kernel = 0;
printk("CPU #: %d\n" pr_info("CPU #: %d\n"
" PC: %08lx SR: %08lx SP: %08lx FPCSR: %08lx\n", " PC: %08lx SR: %08lx SP: %08lx\n",
smp_processor_id(), regs->pc, regs->sr, regs->sp, smp_processor_id(), regs->pc, regs->sr, regs->sp);
regs->fpcsr); pr_info("GPR00: %08lx GPR01: %08lx GPR02: %08lx GPR03: %08lx\n",
printk("GPR00: %08lx GPR01: %08lx GPR02: %08lx GPR03: %08lx\n", 0L, regs->gpr[1], regs->gpr[2], regs->gpr[3]);
0L, regs->gpr[1], regs->gpr[2], regs->gpr[3]); pr_info("GPR04: %08lx GPR05: %08lx GPR06: %08lx GPR07: %08lx\n",
printk("GPR04: %08lx GPR05: %08lx GPR06: %08lx GPR07: %08lx\n", regs->gpr[4], regs->gpr[5], regs->gpr[6], regs->gpr[7]);
regs->gpr[4], regs->gpr[5], regs->gpr[6], regs->gpr[7]); pr_info("GPR08: %08lx GPR09: %08lx GPR10: %08lx GPR11: %08lx\n",
printk("GPR08: %08lx GPR09: %08lx GPR10: %08lx GPR11: %08lx\n", regs->gpr[8], regs->gpr[9], regs->gpr[10], regs->gpr[11]);
regs->gpr[8], regs->gpr[9], regs->gpr[10], regs->gpr[11]); pr_info("GPR12: %08lx GPR13: %08lx GPR14: %08lx GPR15: %08lx\n",
printk("GPR12: %08lx GPR13: %08lx GPR14: %08lx GPR15: %08lx\n", regs->gpr[12], regs->gpr[13], regs->gpr[14], regs->gpr[15]);
regs->gpr[12], regs->gpr[13], regs->gpr[14], regs->gpr[15]); pr_info("GPR16: %08lx GPR17: %08lx GPR18: %08lx GPR19: %08lx\n",
printk("GPR16: %08lx GPR17: %08lx GPR18: %08lx GPR19: %08lx\n", regs->gpr[16], regs->gpr[17], regs->gpr[18], regs->gpr[19]);
regs->gpr[16], regs->gpr[17], regs->gpr[18], regs->gpr[19]); pr_info("GPR20: %08lx GPR21: %08lx GPR22: %08lx GPR23: %08lx\n",
printk("GPR20: %08lx GPR21: %08lx GPR22: %08lx GPR23: %08lx\n", regs->gpr[20], regs->gpr[21], regs->gpr[22], regs->gpr[23]);
regs->gpr[20], regs->gpr[21], regs->gpr[22], regs->gpr[23]); pr_info("GPR24: %08lx GPR25: %08lx GPR26: %08lx GPR27: %08lx\n",
printk("GPR24: %08lx GPR25: %08lx GPR26: %08lx GPR27: %08lx\n", regs->gpr[24], regs->gpr[25], regs->gpr[26], regs->gpr[27]);
regs->gpr[24], regs->gpr[25], regs->gpr[26], regs->gpr[27]); pr_info("GPR28: %08lx GPR29: %08lx GPR30: %08lx GPR31: %08lx\n",
printk("GPR28: %08lx GPR29: %08lx GPR30: %08lx GPR31: %08lx\n", regs->gpr[28], regs->gpr[29], regs->gpr[30], regs->gpr[31]);
regs->gpr[28], regs->gpr[29], regs->gpr[30], regs->gpr[31]); pr_info(" RES: %08lx oGPR11: %08lx\n",
printk(" RES: %08lx oGPR11: %08lx\n", regs->gpr[11], regs->orig_gpr11);
regs->gpr[11], regs->orig_gpr11);
pr_info("Process %s (pid: %d, stackpage=%08lx)\n",
printk("Process %s (pid: %d, stackpage=%08lx)\n", current->comm, current->pid, (unsigned long)current);
current->comm, current->pid, (unsigned long)current);
/* /*
* When in-kernel, we also print out the stack and code at the * When in-kernel, we also print out the stack and code at the
* time of the fault.. * time of the fault..
*/ */
if (in_kernel) { if (in_kernel) {
printk("\nStack: "); pr_info("\nStack: ");
show_stack(NULL, (unsigned long *)esp, KERN_EMERG); show_stack(NULL, (unsigned long *)esp, KERN_EMERG);
if (esp < PAGE_OFFSET) if (esp < PAGE_OFFSET)
goto bad_stack; goto bad_stack;
printk("\n"); pr_info("\n");
for (i = -8; i < 24; i += 1) { for (i = -8; i < 24; i += 1) {
unsigned long word; unsigned long word;
if (__get_user(word, &((unsigned long *)esp)[i])) { if (__get_user(word, &((unsigned long *)esp)[i])) {
bad_stack: bad_stack:
printk(" Bad Stack value."); pr_info(" Bad Stack value.");
break; break;
} }
print_data(esp, word, i); print_data(esp, word, i);
} }
printk("\nCode: "); pr_info("\nCode: ");
if (regs->pc < PAGE_OFFSET) if (regs->pc < PAGE_OFFSET)
goto bad; goto bad;
...@@ -142,14 +142,14 @@ void show_registers(struct pt_regs *regs) ...@@ -142,14 +142,14 @@ void show_registers(struct pt_regs *regs)
if (__get_user(word, &((unsigned long *)regs->pc)[i])) { if (__get_user(word, &((unsigned long *)regs->pc)[i])) {
bad: bad:
printk(" Bad PC value."); pr_info(" Bad PC value.");
break; break;
} }
print_data(regs->pc, word, i); print_data(regs->pc, word, i);
} }
} }
printk("\n"); pr_info("\n");
} }
/* This is normally the 'Oops' routine */ /* This is normally the 'Oops' routine */
...@@ -157,10 +157,10 @@ void __noreturn die(const char *str, struct pt_regs *regs, long err) ...@@ -157,10 +157,10 @@ void __noreturn die(const char *str, struct pt_regs *regs, long err)
{ {
console_verbose(); console_verbose();
printk("\n%s#: %04lx\n", str, err & 0xffff); pr_emerg("\n%s#: %04lx\n", str, err & 0xffff);
show_registers(regs); show_registers(regs);
#ifdef CONFIG_JUMP_UPON_UNHANDLED_EXCEPTION #ifdef CONFIG_JUMP_UPON_UNHANDLED_EXCEPTION
printk("\n\nUNHANDLED_EXCEPTION: entering infinite loop\n"); pr_emerg("\n\nUNHANDLED_EXCEPTION: entering infinite loop\n");
/* shut down interrupts */ /* shut down interrupts */
local_irq_disable(); local_irq_disable();
...@@ -173,36 +173,51 @@ void __noreturn die(const char *str, struct pt_regs *regs, long err) ...@@ -173,36 +173,51 @@ void __noreturn die(const char *str, struct pt_regs *regs, long err)
asmlinkage void unhandled_exception(struct pt_regs *regs, int ea, int vector) asmlinkage void unhandled_exception(struct pt_regs *regs, int ea, int vector)
{ {
printk("Unable to handle exception at EA =0x%x, vector 0x%x", pr_emerg("Unable to handle exception at EA =0x%x, vector 0x%x",
ea, vector); ea, vector);
die("Oops", regs, 9); die("Oops", regs, 9);
} }
asmlinkage void do_fpe_trap(struct pt_regs *regs, unsigned long address) asmlinkage void do_fpe_trap(struct pt_regs *regs, unsigned long address)
{ {
int code = FPE_FLTUNK; if (user_mode(regs)) {
unsigned long fpcsr = regs->fpcsr; int code = FPE_FLTUNK;
#ifdef CONFIG_FPU
if (fpcsr & SPR_FPCSR_IVF) unsigned long fpcsr;
code = FPE_FLTINV;
else if (fpcsr & SPR_FPCSR_OVF) save_fpu(current);
code = FPE_FLTOVF; fpcsr = current->thread.fpcsr;
else if (fpcsr & SPR_FPCSR_UNF)
code = FPE_FLTUND; if (fpcsr & SPR_FPCSR_IVF)
else if (fpcsr & SPR_FPCSR_DZF) code = FPE_FLTINV;
code = FPE_FLTDIV; else if (fpcsr & SPR_FPCSR_OVF)
else if (fpcsr & SPR_FPCSR_IXF) code = FPE_FLTOVF;
code = FPE_FLTRES; else if (fpcsr & SPR_FPCSR_UNF)
code = FPE_FLTUND;
/* Clear all flags */ else if (fpcsr & SPR_FPCSR_DZF)
regs->fpcsr &= ~SPR_FPCSR_ALLF; code = FPE_FLTDIV;
else if (fpcsr & SPR_FPCSR_IXF)
force_sig_fault(SIGFPE, code, (void __user *)regs->pc); code = FPE_FLTRES;
/* Clear all flags */
current->thread.fpcsr &= ~SPR_FPCSR_ALLF;
restore_fpu(current);
#endif
force_sig_fault(SIGFPE, code, (void __user *)regs->pc);
} else {
pr_emerg("KERNEL: Illegal fpe exception 0x%.8lx\n", regs->pc);
die("Die:", regs, SIGFPE);
}
} }
asmlinkage void do_trap(struct pt_regs *regs, unsigned long address) asmlinkage void do_trap(struct pt_regs *regs, unsigned long address)
{ {
force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)regs->pc); if (user_mode(regs)) {
force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)regs->pc);
} else {
pr_emerg("KERNEL: Illegal trap exception 0x%.8lx\n", regs->pc);
die("Die:", regs, SIGILL);
}
} }
asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address) asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address)
...@@ -211,8 +226,7 @@ asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address) ...@@ -211,8 +226,7 @@ asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address)
/* Send a SIGBUS */ /* Send a SIGBUS */
force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)address); force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)address);
} else { } else {
printk("KERNEL: Unaligned Access 0x%.8lx\n", address); pr_emerg("KERNEL: Unaligned Access 0x%.8lx\n", address);
show_registers(regs);
die("Die:", regs, address); die("Die:", regs, address);
} }
...@@ -224,8 +238,7 @@ asmlinkage void do_bus_fault(struct pt_regs *regs, unsigned long address) ...@@ -224,8 +238,7 @@ asmlinkage void do_bus_fault(struct pt_regs *regs, unsigned long address)
/* Send a SIGBUS */ /* Send a SIGBUS */
force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)address); force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)address);
} else { /* Kernel mode */ } else { /* Kernel mode */
printk("KERNEL: Bus error (SIGBUS) 0x%.8lx\n", address); pr_emerg("KERNEL: Bus error (SIGBUS) 0x%.8lx\n", address);
show_registers(regs);
die("Die:", regs, address); die("Die:", regs, address);
} }
} }
...@@ -419,9 +432,8 @@ asmlinkage void do_illegal_instruction(struct pt_regs *regs, ...@@ -419,9 +432,8 @@ asmlinkage void do_illegal_instruction(struct pt_regs *regs,
/* Send a SIGILL */ /* Send a SIGILL */
force_sig_fault(SIGILL, ILL_ILLOPC, (void __user *)address); force_sig_fault(SIGILL, ILL_ILLOPC, (void __user *)address);
} else { /* Kernel mode */ } else { /* Kernel mode */
printk("KERNEL: Illegal instruction (SIGILL) 0x%.8lx\n", pr_emerg("KERNEL: Illegal instruction (SIGILL) 0x%.8lx\n",
address); address);
show_registers(regs);
die("Die:", regs, address); die("Die:", regs, address);
} }
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment