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()
This commit is contained in:
@@ -188,6 +188,15 @@ config SMP
|
||||
|
||||
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"
|
||||
|
||||
config OPENRISC_NO_SPR_SR_DSX
|
||||
|
||||
22
arch/openrisc/include/asm/fpu.h
Normal file
22
arch/openrisc/include/asm/fpu.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/* 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 @@
|
||||
struct task_struct;
|
||||
|
||||
struct thread_struct {
|
||||
long fpcsr; /* Floating point control status register. */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -59,7 +59,7 @@ struct pt_regs {
|
||||
* -1 for all other exceptions.
|
||||
*/
|
||||
long orig_gpr11; /* For restarting system calls */
|
||||
long fpcsr; /* Floating point control status register. */
|
||||
long dummy; /* Cheap alignment fix */
|
||||
long dummy2; /* Cheap alignment fix */
|
||||
};
|
||||
|
||||
@@ -115,6 +115,5 @@ static inline long regs_return_value(struct pt_regs *regs)
|
||||
#define PT_GPR31 124
|
||||
#define PT_PC 128
|
||||
#define PT_ORIG_GPR11 132
|
||||
#define PT_FPCSR 136
|
||||
|
||||
#endif /* __ASM_OPENRISC_PTRACE_H */
|
||||
|
||||
@@ -34,15 +34,72 @@
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
/* The OR1K relocation types... not all relevant for module loader */
|
||||
#define R_OR32_NONE 0
|
||||
#define R_OR32_32 1
|
||||
#define R_OR32_16 2
|
||||
#define R_OR32_8 3
|
||||
#define R_OR32_CONST 4
|
||||
#define R_OR32_CONSTH 5
|
||||
#define R_OR32_JUMPTARG 6
|
||||
#define R_OR32_VTINHERIT 7
|
||||
#define R_OR32_VTENTRY 8
|
||||
#define R_OR1K_NONE 0
|
||||
#define R_OR1K_32 1
|
||||
#define R_OR1K_16 2
|
||||
#define R_OR1K_8 3
|
||||
#define R_OR1K_LO_16_IN_INSN 4
|
||||
#define R_OR1K_HI_16_IN_INSN 5
|
||||
#define R_OR1K_INSN_REL_26 6
|
||||
#define R_OR1K_GNU_VTENTRY 7
|
||||
#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;
|
||||
|
||||
|
||||
@@ -106,8 +106,6 @@
|
||||
l.mtspr r0,r3,SPR_EPCR_BASE ;\
|
||||
l.lwz r3,PT_SR(r1) ;\
|
||||
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 r3,PT_GPR3(r1) ;\
|
||||
l.lwz r4,PT_GPR4(r1) ;\
|
||||
@@ -177,8 +175,6 @@ handler: ;\
|
||||
/* r30 already save */ ;\
|
||||
l.sw PT_GPR31(r1),r31 ;\
|
||||
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 */ ;\
|
||||
l.addi r30,r0,-1 ;\
|
||||
l.sw PT_ORIG_GPR11(r1),r30
|
||||
@@ -219,8 +215,6 @@ handler: ;\
|
||||
/* Store -1 in orig_gpr11 for non-syscall exceptions */ ;\
|
||||
l.addi r30,r0,-1 ;\
|
||||
l.sw PT_ORIG_GPR11(r1),r30 ;\
|
||||
l.mfspr r30,r0,SPR_FPCSR ;\
|
||||
l.sw PT_FPCSR(r1),r30 ;\
|
||||
l.addi r3,r1,0 ;\
|
||||
/* r4 is exception EA */ ;\
|
||||
l.addi r5,r0,vector ;\
|
||||
@@ -852,6 +846,7 @@ _syscall_badsys:
|
||||
|
||||
EXCEPTION_ENTRY(_fpe_trap_handler)
|
||||
CLEAR_LWA_FLAG(r3)
|
||||
|
||||
/* r4: EA of fault (set by EXCEPTION_HANDLE) */
|
||||
l.jal do_fpe_trap
|
||||
l.addi r3,r1,0 /* pt_regs */
|
||||
@@ -1100,10 +1095,6 @@ ENTRY(_switch)
|
||||
l.sw PT_GPR28(r1),r28
|
||||
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*/
|
||||
|
||||
/* We use thread_info->ksp for storing the address of the above
|
||||
@@ -1126,10 +1117,6 @@ ENTRY(_switch)
|
||||
l.lwz r29,PT_SP(r1)
|
||||
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
|
||||
* has already been set above.
|
||||
*/
|
||||
|
||||
@@ -39,22 +39,32 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
|
||||
value = sym->st_value + rel[i].r_addend;
|
||||
|
||||
switch (ELF32_R_TYPE(rel[i].r_info)) {
|
||||
case R_OR32_32:
|
||||
case R_OR1K_32:
|
||||
*location = value;
|
||||
break;
|
||||
case R_OR32_CONST:
|
||||
case R_OR1K_LO_16_IN_INSN:
|
||||
*((uint16_t *)location + 1) = value;
|
||||
break;
|
||||
case R_OR32_CONSTH:
|
||||
case R_OR1K_HI_16_IN_INSN:
|
||||
*((uint16_t *)location + 1) = value >> 16;
|
||||
break;
|
||||
case R_OR32_JUMPTARG:
|
||||
case R_OR1K_INSN_REL_26:
|
||||
value -= (uint32_t)location;
|
||||
value >>= 2;
|
||||
value &= 0x03ffffff;
|
||||
value |= *location & 0xfc000000;
|
||||
*location = value;
|
||||
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:
|
||||
pr_err("module %s: Unknown relocation: %u\n",
|
||||
me->name, ELF32_R_TYPE(rel[i].r_info));
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <linux/reboot.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/fpu.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/spr_defs.h>
|
||||
@@ -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
|
||||
* OpenRISC simulators l.nop 1 will trigger the simulator exit.
|
||||
*/
|
||||
@@ -89,10 +90,8 @@ void machine_halt(void)
|
||||
void machine_power_off(void)
|
||||
{
|
||||
printk(KERN_INFO "*** MACHINE POWER OFF ***\n");
|
||||
if (pm_power_off != NULL)
|
||||
pm_power_off();
|
||||
else
|
||||
default_power_off();
|
||||
do_kernel_power_off();
|
||||
default_power_off();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -246,6 +245,8 @@ struct task_struct *__switch_to(struct task_struct *old,
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
save_fpu(current);
|
||||
|
||||
/* current_set is an array of saved current pointers
|
||||
* (one for each cpu). we need them at user->kernel transition,
|
||||
* while we save them at kernel->user transition
|
||||
@@ -258,6 +259,8 @@ struct task_struct *__switch_to(struct task_struct *old,
|
||||
current_thread_info_set[smp_processor_id()] = new_ti;
|
||||
last = (_switch(old_ti, new_ti))->task;
|
||||
|
||||
restore_fpu(current);
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
return last;
|
||||
|
||||
@@ -88,6 +88,7 @@ static int genregs_set(struct task_struct *target,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FPU
|
||||
/*
|
||||
* 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
|
||||
@@ -97,9 +98,7 @@ static int fpregs_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
struct membuf to)
|
||||
{
|
||||
const struct pt_regs *regs = task_pt_regs(target);
|
||||
|
||||
return membuf_store(&to, regs->fpcsr);
|
||||
return membuf_store(&to, target->thread.fpcsr);
|
||||
}
|
||||
|
||||
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,
|
||||
const void *kbuf, const void __user *ubuf)
|
||||
{
|
||||
struct pt_regs *regs = task_pt_regs(target);
|
||||
int ret;
|
||||
|
||||
/* FPCSR */
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
®s->fpcsr, 0, 4);
|
||||
return ret;
|
||||
return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.fpcsr, 0, 4);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define the register sets available on OpenRISC under Linux
|
||||
*/
|
||||
enum or1k_regset {
|
||||
REGSET_GENERAL,
|
||||
#ifdef CONFIG_FPU
|
||||
REGSET_FPU,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct user_regset or1k_regsets[] = {
|
||||
@@ -133,6 +131,7 @@ static const struct user_regset or1k_regsets[] = {
|
||||
.regset_get = genregs_get,
|
||||
.set = genregs_set,
|
||||
},
|
||||
#ifdef CONFIG_FPU
|
||||
[REGSET_FPU] = {
|
||||
.core_note_type = NT_PRFPREG,
|
||||
.n = sizeof(struct __or1k_fpu_state) / sizeof(long),
|
||||
@@ -141,6 +140,7 @@ static const struct user_regset or1k_regsets[] = {
|
||||
.regset_get = fpregs_get,
|
||||
.set = fpregs_set,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct user_regset_view user_or1k_native_view = {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/resume_user_mode.h>
|
||||
|
||||
#include <asm/fpu.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/syscall.h>
|
||||
#include <asm/ucontext.h>
|
||||
@@ -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,
|
||||
int syscall);
|
||||
|
||||
#ifdef CONFIG_FPU
|
||||
static long restore_fp_state(struct sigcontext __user *sc)
|
||||
{
|
||||
long err;
|
||||
|
||||
err = __copy_from_user(¤t->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, ¤t->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,
|
||||
struct sigcontext __user *sc)
|
||||
{
|
||||
@@ -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(®s->pc, &sc->regs.pc, sizeof(unsigned long));
|
||||
err |= __copy_from_user(®s->sr, &sc->regs.sr, sizeof(unsigned long));
|
||||
err |= __copy_from_user(®s->fpcsr, &sc->fpcsr, sizeof(unsigned long));
|
||||
err |= restore_fp_state(sc);
|
||||
|
||||
/* make sure the SM-bit is cleared so user-mode cannot fool us */
|
||||
regs->sr &= ~SPR_SR_SM;
|
||||
@@ -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.pc, ®s->pc, sizeof(unsigned long));
|
||||
err |= __copy_to_user(&sc->regs.sr, ®s->sr, sizeof(unsigned long));
|
||||
err |= __copy_to_user(&sc->fpcsr, ®s->fpcsr, sizeof(unsigned long));
|
||||
err |= save_fp_state(sc);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/bug.h>
|
||||
#include <asm/fpu.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/unwinder.h>
|
||||
@@ -51,16 +52,16 @@ static void print_trace(void *data, unsigned long addr, int reliable)
|
||||
{
|
||||
const char *loglvl = data;
|
||||
|
||||
printk("%s[<%p>] %s%pS\n", loglvl, (void *) addr, reliable ? "" : "? ",
|
||||
(void *) addr);
|
||||
pr_info("%s[<%p>] %s%pS\n", loglvl, (void *) addr, reliable ? "" : "? ",
|
||||
(void *) addr);
|
||||
}
|
||||
|
||||
static void print_data(unsigned long base_addr, unsigned long word, int i)
|
||||
{
|
||||
if (i == 0)
|
||||
printk("(%08lx:)\t%08lx", base_addr + (i * 4), word);
|
||||
pr_info("(%08lx:)\t%08lx", base_addr + (i * 4), word);
|
||||
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 */
|
||||
@@ -69,7 +70,7 @@ void show_stack(struct task_struct *task, unsigned long *esp, const char *loglvl
|
||||
if (esp == NULL)
|
||||
esp = (unsigned long *)&esp;
|
||||
|
||||
printk("%sCall trace:\n", loglvl);
|
||||
pr_info("%sCall trace:\n", loglvl);
|
||||
unwind_stack((void *)loglvl, esp, print_trace);
|
||||
}
|
||||
|
||||
@@ -83,57 +84,56 @@ void show_registers(struct pt_regs *regs)
|
||||
if (user_mode(regs))
|
||||
in_kernel = 0;
|
||||
|
||||
printk("CPU #: %d\n"
|
||||
" PC: %08lx SR: %08lx SP: %08lx FPCSR: %08lx\n",
|
||||
smp_processor_id(), regs->pc, regs->sr, regs->sp,
|
||||
regs->fpcsr);
|
||||
printk("GPR00: %08lx GPR01: %08lx GPR02: %08lx GPR03: %08lx\n",
|
||||
0L, regs->gpr[1], regs->gpr[2], regs->gpr[3]);
|
||||
printk("GPR04: %08lx GPR05: %08lx GPR06: %08lx GPR07: %08lx\n",
|
||||
regs->gpr[4], regs->gpr[5], regs->gpr[6], regs->gpr[7]);
|
||||
printk("GPR08: %08lx GPR09: %08lx GPR10: %08lx GPR11: %08lx\n",
|
||||
regs->gpr[8], regs->gpr[9], regs->gpr[10], regs->gpr[11]);
|
||||
printk("GPR12: %08lx GPR13: %08lx GPR14: %08lx GPR15: %08lx\n",
|
||||
regs->gpr[12], regs->gpr[13], regs->gpr[14], regs->gpr[15]);
|
||||
printk("GPR16: %08lx GPR17: %08lx GPR18: %08lx GPR19: %08lx\n",
|
||||
regs->gpr[16], regs->gpr[17], regs->gpr[18], regs->gpr[19]);
|
||||
printk("GPR20: %08lx GPR21: %08lx GPR22: %08lx GPR23: %08lx\n",
|
||||
regs->gpr[20], regs->gpr[21], regs->gpr[22], regs->gpr[23]);
|
||||
printk("GPR24: %08lx GPR25: %08lx GPR26: %08lx GPR27: %08lx\n",
|
||||
regs->gpr[24], regs->gpr[25], regs->gpr[26], regs->gpr[27]);
|
||||
printk("GPR28: %08lx GPR29: %08lx GPR30: %08lx GPR31: %08lx\n",
|
||||
regs->gpr[28], regs->gpr[29], regs->gpr[30], regs->gpr[31]);
|
||||
printk(" RES: %08lx oGPR11: %08lx\n",
|
||||
regs->gpr[11], regs->orig_gpr11);
|
||||
pr_info("CPU #: %d\n"
|
||||
" PC: %08lx SR: %08lx SP: %08lx\n",
|
||||
smp_processor_id(), regs->pc, regs->sr, regs->sp);
|
||||
pr_info("GPR00: %08lx GPR01: %08lx GPR02: %08lx GPR03: %08lx\n",
|
||||
0L, regs->gpr[1], regs->gpr[2], regs->gpr[3]);
|
||||
pr_info("GPR04: %08lx GPR05: %08lx GPR06: %08lx GPR07: %08lx\n",
|
||||
regs->gpr[4], regs->gpr[5], regs->gpr[6], regs->gpr[7]);
|
||||
pr_info("GPR08: %08lx GPR09: %08lx GPR10: %08lx GPR11: %08lx\n",
|
||||
regs->gpr[8], regs->gpr[9], regs->gpr[10], regs->gpr[11]);
|
||||
pr_info("GPR12: %08lx GPR13: %08lx GPR14: %08lx GPR15: %08lx\n",
|
||||
regs->gpr[12], regs->gpr[13], regs->gpr[14], regs->gpr[15]);
|
||||
pr_info("GPR16: %08lx GPR17: %08lx GPR18: %08lx GPR19: %08lx\n",
|
||||
regs->gpr[16], regs->gpr[17], regs->gpr[18], regs->gpr[19]);
|
||||
pr_info("GPR20: %08lx GPR21: %08lx GPR22: %08lx GPR23: %08lx\n",
|
||||
regs->gpr[20], regs->gpr[21], regs->gpr[22], regs->gpr[23]);
|
||||
pr_info("GPR24: %08lx GPR25: %08lx GPR26: %08lx GPR27: %08lx\n",
|
||||
regs->gpr[24], regs->gpr[25], regs->gpr[26], regs->gpr[27]);
|
||||
pr_info("GPR28: %08lx GPR29: %08lx GPR30: %08lx GPR31: %08lx\n",
|
||||
regs->gpr[28], regs->gpr[29], regs->gpr[30], regs->gpr[31]);
|
||||
pr_info(" RES: %08lx oGPR11: %08lx\n",
|
||||
regs->gpr[11], regs->orig_gpr11);
|
||||
|
||||
printk("Process %s (pid: %d, stackpage=%08lx)\n",
|
||||
current->comm, current->pid, (unsigned long)current);
|
||||
pr_info("Process %s (pid: %d, stackpage=%08lx)\n",
|
||||
current->comm, current->pid, (unsigned long)current);
|
||||
/*
|
||||
* When in-kernel, we also print out the stack and code at the
|
||||
* time of the fault..
|
||||
*/
|
||||
if (in_kernel) {
|
||||
|
||||
printk("\nStack: ");
|
||||
pr_info("\nStack: ");
|
||||
show_stack(NULL, (unsigned long *)esp, KERN_EMERG);
|
||||
|
||||
if (esp < PAGE_OFFSET)
|
||||
goto bad_stack;
|
||||
|
||||
printk("\n");
|
||||
pr_info("\n");
|
||||
for (i = -8; i < 24; i += 1) {
|
||||
unsigned long word;
|
||||
|
||||
if (__get_user(word, &((unsigned long *)esp)[i])) {
|
||||
bad_stack:
|
||||
printk(" Bad Stack value.");
|
||||
pr_info(" Bad Stack value.");
|
||||
break;
|
||||
}
|
||||
|
||||
print_data(esp, word, i);
|
||||
}
|
||||
|
||||
printk("\nCode: ");
|
||||
pr_info("\nCode: ");
|
||||
if (regs->pc < PAGE_OFFSET)
|
||||
goto bad;
|
||||
|
||||
@@ -142,14 +142,14 @@ bad_stack:
|
||||
|
||||
if (__get_user(word, &((unsigned long *)regs->pc)[i])) {
|
||||
bad:
|
||||
printk(" Bad PC value.");
|
||||
pr_info(" Bad PC value.");
|
||||
break;
|
||||
}
|
||||
|
||||
print_data(regs->pc, word, i);
|
||||
}
|
||||
}
|
||||
printk("\n");
|
||||
pr_info("\n");
|
||||
}
|
||||
|
||||
/* This is normally the 'Oops' routine */
|
||||
@@ -157,10 +157,10 @@ void __noreturn die(const char *str, struct pt_regs *regs, long err)
|
||||
{
|
||||
|
||||
console_verbose();
|
||||
printk("\n%s#: %04lx\n", str, err & 0xffff);
|
||||
pr_emerg("\n%s#: %04lx\n", str, err & 0xffff);
|
||||
show_registers(regs);
|
||||
#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 */
|
||||
local_irq_disable();
|
||||
@@ -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)
|
||||
{
|
||||
printk("Unable to handle exception at EA =0x%x, vector 0x%x",
|
||||
ea, vector);
|
||||
pr_emerg("Unable to handle exception at EA =0x%x, vector 0x%x",
|
||||
ea, vector);
|
||||
die("Oops", regs, 9);
|
||||
}
|
||||
|
||||
asmlinkage void do_fpe_trap(struct pt_regs *regs, unsigned long address)
|
||||
{
|
||||
int code = FPE_FLTUNK;
|
||||
unsigned long fpcsr = regs->fpcsr;
|
||||
if (user_mode(regs)) {
|
||||
int code = FPE_FLTUNK;
|
||||
#ifdef CONFIG_FPU
|
||||
unsigned long fpcsr;
|
||||
|
||||
if (fpcsr & SPR_FPCSR_IVF)
|
||||
code = FPE_FLTINV;
|
||||
else if (fpcsr & SPR_FPCSR_OVF)
|
||||
code = FPE_FLTOVF;
|
||||
else if (fpcsr & SPR_FPCSR_UNF)
|
||||
code = FPE_FLTUND;
|
||||
else if (fpcsr & SPR_FPCSR_DZF)
|
||||
code = FPE_FLTDIV;
|
||||
else if (fpcsr & SPR_FPCSR_IXF)
|
||||
code = FPE_FLTRES;
|
||||
save_fpu(current);
|
||||
fpcsr = current->thread.fpcsr;
|
||||
|
||||
/* Clear all flags */
|
||||
regs->fpcsr &= ~SPR_FPCSR_ALLF;
|
||||
if (fpcsr & SPR_FPCSR_IVF)
|
||||
code = FPE_FLTINV;
|
||||
else if (fpcsr & SPR_FPCSR_OVF)
|
||||
code = FPE_FLTOVF;
|
||||
else if (fpcsr & SPR_FPCSR_UNF)
|
||||
code = FPE_FLTUND;
|
||||
else if (fpcsr & SPR_FPCSR_DZF)
|
||||
code = FPE_FLTDIV;
|
||||
else if (fpcsr & SPR_FPCSR_IXF)
|
||||
code = FPE_FLTRES;
|
||||
|
||||
force_sig_fault(SIGFPE, code, (void __user *)regs->pc);
|
||||
/* 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)
|
||||
{
|
||||
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)
|
||||
@@ -211,8 +226,7 @@ asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address)
|
||||
/* Send a SIGBUS */
|
||||
force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)address);
|
||||
} else {
|
||||
printk("KERNEL: Unaligned Access 0x%.8lx\n", address);
|
||||
show_registers(regs);
|
||||
pr_emerg("KERNEL: Unaligned Access 0x%.8lx\n", address);
|
||||
die("Die:", regs, address);
|
||||
}
|
||||
|
||||
@@ -224,8 +238,7 @@ asmlinkage void do_bus_fault(struct pt_regs *regs, unsigned long address)
|
||||
/* Send a SIGBUS */
|
||||
force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)address);
|
||||
} else { /* Kernel mode */
|
||||
printk("KERNEL: Bus error (SIGBUS) 0x%.8lx\n", address);
|
||||
show_registers(regs);
|
||||
pr_emerg("KERNEL: Bus error (SIGBUS) 0x%.8lx\n", address);
|
||||
die("Die:", regs, address);
|
||||
}
|
||||
}
|
||||
@@ -419,9 +432,8 @@ asmlinkage void do_illegal_instruction(struct pt_regs *regs,
|
||||
/* Send a SIGILL */
|
||||
force_sig_fault(SIGILL, ILL_ILLOPC, (void __user *)address);
|
||||
} else { /* Kernel mode */
|
||||
printk("KERNEL: Illegal instruction (SIGILL) 0x%.8lx\n",
|
||||
address);
|
||||
show_registers(regs);
|
||||
pr_emerg("KERNEL: Illegal instruction (SIGILL) 0x%.8lx\n",
|
||||
address);
|
||||
die("Die:", regs, address);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user