mirror of
https://github.com/FEX-Emu/linux.git
synced 2025-01-01 14:52:32 +00:00
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
Pull MIPS fixes from Ralf Baechle: "A set of MIPS fixes for 4.9: - lots of fixes for printk continuations - six fixes for FP related code. - fix max_low_pfn with disabled highmem - fix KASLR handling of NULL FDT and KASLR for generic kernels - fix build of compressed image - provide default mips_cpc_default_phys_base to ignore CPC - fix reboot on Malta" * 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: MIPS: Fix max_low_pfn with disabled highmem MIPS: Correct MIPS I FP sigcontext layout MIPS: Fix ISA I/II FP signal context offsets MIPS: Remove FIR from ISA I FP signal context MIPS: Fix ISA I FP sigcontext access violation handling MIPS: Fix FCSR Cause bit handling for correct SIGFPE issue MIPS: ptrace: Also initialize the FP context on individual FCSR writes MIPS: dump_tlb: Fix printk continuations MIPS: Fix __show_regs() output MIPS: traps: Fix output of show_code MIPS: traps: Fix output of show_stacktrace MIPS: traps: Fix output of show_backtrace MIPS: Fix build of compressed image MIPS: generic: Fix KASLR for generic kernel. MIPS: KASLR: Fix handling of NULL FDT MIPS: Malta: Fixup reboot MIPS: CPC: Provide default mips_cpc_default_phys_base to ignore CPC
This commit is contained in:
commit
34c510b2ee
@ -263,7 +263,7 @@ KBUILD_CPPFLAGS += -DDATAOFFSET=$(if $(dataoffset-y),$(dataoffset-y),0)
|
||||
|
||||
bootvars-y = VMLINUX_LOAD_ADDRESS=$(load-y) \
|
||||
VMLINUX_ENTRY_ADDRESS=$(entry-y) \
|
||||
PLATFORM=$(platform-y)
|
||||
PLATFORM="$(platform-y)"
|
||||
ifdef CONFIG_32BIT
|
||||
bootvars-y += ADDR_BITS=32
|
||||
endif
|
||||
|
@ -84,12 +84,13 @@
|
||||
fpga_regs: system-controller@1f000000 {
|
||||
compatible = "mti,malta-fpga", "syscon", "simple-mfd";
|
||||
reg = <0x1f000000 0x1000>;
|
||||
native-endian;
|
||||
|
||||
reboot {
|
||||
compatible = "syscon-reboot";
|
||||
regmap = <&fpga_regs>;
|
||||
offset = <0x500>;
|
||||
mask = <0x4d>;
|
||||
mask = <0x42>;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -29,10 +29,20 @@ static __initdata const struct mips_machine *mach;
|
||||
static __initdata const void *mach_match_data;
|
||||
|
||||
void __init prom_init(void)
|
||||
{
|
||||
plat_get_fdt();
|
||||
BUG_ON(!fdt);
|
||||
}
|
||||
|
||||
void __init *plat_get_fdt(void)
|
||||
{
|
||||
const struct mips_machine *check_mach;
|
||||
const struct of_device_id *match;
|
||||
|
||||
if (fdt)
|
||||
/* Already set up */
|
||||
return (void *)fdt;
|
||||
|
||||
if ((fw_arg0 == -2) && !fdt_check_header((void *)fw_arg1)) {
|
||||
/*
|
||||
* We booted using the UHI boot protocol, so we have been
|
||||
@ -75,12 +85,6 @@ void __init prom_init(void)
|
||||
/* Retrieve the machine's FDT */
|
||||
fdt = mach->fdt;
|
||||
}
|
||||
|
||||
BUG_ON(!fdt);
|
||||
}
|
||||
|
||||
void __init *plat_get_fdt(void)
|
||||
{
|
||||
return (void *)fdt;
|
||||
}
|
||||
|
||||
|
@ -63,6 +63,8 @@ do { \
|
||||
extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
|
||||
struct mips_fpu_struct *ctx, int has_fpu,
|
||||
void *__user *fault_addr);
|
||||
void force_fcr31_sig(unsigned long fcr31, void __user *fault_addr,
|
||||
struct task_struct *tsk);
|
||||
int process_fpemu_return(int sig, void __user *fault_addr,
|
||||
unsigned long fcr31);
|
||||
int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
|
||||
@ -81,4 +83,15 @@ static inline void fpu_emulator_init_fpu(void)
|
||||
set_fpr64(&t->thread.fpu.fpr[i], 0, SIGNALLING_NAN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mask the FCSR Cause bits according to the Enable bits, observing
|
||||
* that Unimplemented is always enabled.
|
||||
*/
|
||||
static inline unsigned long mask_fcr31_x(unsigned long fcr31)
|
||||
{
|
||||
return fcr31 & (FPU_CSR_UNI_X |
|
||||
((fcr31 & FPU_CSR_ALL_E) <<
|
||||
(ffs(FPU_CSR_ALL_X) - ffs(FPU_CSR_ALL_E))));
|
||||
}
|
||||
|
||||
#endif /* _ASM_FPU_EMULATOR_H */
|
||||
|
@ -75,6 +75,22 @@ do { if (cpu_has_rw_llb) { \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Check FCSR for any unmasked exceptions pending set with `ptrace',
|
||||
* clear them and send a signal.
|
||||
*/
|
||||
#define __sanitize_fcr31(next) \
|
||||
do { \
|
||||
unsigned long fcr31 = mask_fcr31_x(next->thread.fpu.fcr31); \
|
||||
void __user *pc; \
|
||||
\
|
||||
if (unlikely(fcr31)) { \
|
||||
pc = (void __user *)task_pt_regs(next)->cp0_epc; \
|
||||
next->thread.fpu.fcr31 &= ~fcr31; \
|
||||
force_fcr31_sig(fcr31, pc, next); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* For newly created kernel threads switch_to() will return to
|
||||
* ret_from_kernel_thread, newly created user threads to ret_from_fork.
|
||||
@ -85,6 +101,8 @@ do { if (cpu_has_rw_llb) { \
|
||||
do { \
|
||||
__mips_mt_fpaff_switch_to(prev); \
|
||||
lose_fpu_inatomic(1, prev); \
|
||||
if (tsk_used_math(next)) \
|
||||
__sanitize_fcr31(next); \
|
||||
if (cpu_has_dsp) { \
|
||||
__save_dsp(prev); \
|
||||
__restore_dsp(next); \
|
||||
|
@ -21,6 +21,11 @@ static DEFINE_PER_CPU_ALIGNED(spinlock_t, cpc_core_lock);
|
||||
|
||||
static DEFINE_PER_CPU_ALIGNED(unsigned long, cpc_core_lock_flags);
|
||||
|
||||
phys_addr_t __weak mips_cpc_default_phys_base(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mips_cpc_phys_base - retrieve the physical base address of the CPC
|
||||
*
|
||||
@ -43,8 +48,12 @@ static phys_addr_t mips_cpc_phys_base(void)
|
||||
if (cpc_base & CM_GCR_CPC_BASE_CPCEN_MSK)
|
||||
return cpc_base & CM_GCR_CPC_BASE_CPCBASE_MSK;
|
||||
|
||||
/* Otherwise, give it the default address & enable it */
|
||||
/* Otherwise, use the default address */
|
||||
cpc_base = mips_cpc_default_phys_base();
|
||||
if (!cpc_base)
|
||||
return cpc_base;
|
||||
|
||||
/* Enable the CPC, mapped at the default address */
|
||||
write_gcr_cpc_base(cpc_base | CM_GCR_CPC_BASE_CPCEN_MSK);
|
||||
return cpc_base;
|
||||
}
|
||||
|
@ -899,7 +899,7 @@ static inline int mipsr2_find_op_func(struct pt_regs *regs, u32 inst,
|
||||
* mipsr2_decoder: Decode and emulate a MIPS R2 instruction
|
||||
* @regs: Process register set
|
||||
* @inst: Instruction to decode and emulate
|
||||
* @fcr31: Floating Point Control and Status Register returned
|
||||
* @fcr31: Floating Point Control and Status Register Cause bits returned
|
||||
*/
|
||||
int mipsr2_decoder(struct pt_regs *regs, u32 inst, unsigned long *fcr31)
|
||||
{
|
||||
@ -1172,13 +1172,13 @@ fpu_emul:
|
||||
|
||||
err = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 0,
|
||||
&fault_addr);
|
||||
*fcr31 = current->thread.fpu.fcr31;
|
||||
|
||||
/*
|
||||
* We can't allow the emulated instruction to leave any of
|
||||
* the cause bits set in $fcr31.
|
||||
* We can't allow the emulated instruction to leave any
|
||||
* enabled Cause bits set in $fcr31.
|
||||
*/
|
||||
current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
|
||||
*fcr31 = res = mask_fcr31_x(current->thread.fpu.fcr31);
|
||||
current->thread.fpu.fcr31 &= ~res;
|
||||
|
||||
/*
|
||||
* this is a tricky issue - lose_fpu() uses LL/SC atomics
|
||||
|
@ -79,16 +79,15 @@ void ptrace_disable(struct task_struct *child)
|
||||
}
|
||||
|
||||
/*
|
||||
* Poke at FCSR according to its mask. Don't set the cause bits as
|
||||
* this is currently not handled correctly in FP context restoration
|
||||
* and will cause an oops if a corresponding enable bit is set.
|
||||
* Poke at FCSR according to its mask. Set the Cause bits even
|
||||
* if a corresponding Enable bit is set. This will be noticed at
|
||||
* the time the thread is switched to and SIGFPE thrown accordingly.
|
||||
*/
|
||||
static void ptrace_setfcr31(struct task_struct *child, u32 value)
|
||||
{
|
||||
u32 fcr31;
|
||||
u32 mask;
|
||||
|
||||
value &= ~FPU_CSR_ALL_X;
|
||||
fcr31 = child->thread.fpu.fcr31;
|
||||
mask = boot_cpu_data.fpu_msk31;
|
||||
child->thread.fpu.fcr31 = (value & ~mask) | (fcr31 & mask);
|
||||
@ -817,6 +816,7 @@ long arch_ptrace(struct task_struct *child, long request,
|
||||
break;
|
||||
#endif
|
||||
case FPC_CSR:
|
||||
init_fp_ctx(child);
|
||||
ptrace_setfcr31(child, data);
|
||||
break;
|
||||
case DSP_BASE ... DSP_BASE + 5: {
|
||||
|
@ -19,108 +19,86 @@
|
||||
#include <asm/regdef.h>
|
||||
|
||||
#define EX(a,b) \
|
||||
9: a,##b; \
|
||||
.section __ex_table,"a"; \
|
||||
PTR 9b,fault; \
|
||||
.previous
|
||||
|
||||
#define EX2(a,b) \
|
||||
9: a,##b; \
|
||||
.section __ex_table,"a"; \
|
||||
PTR 9b,bad_stack; \
|
||||
PTR 9b+4,bad_stack; \
|
||||
.previous
|
||||
|
||||
.set noreorder
|
||||
.set mips1
|
||||
/* Save floating point context */
|
||||
|
||||
/**
|
||||
* _save_fp_context() - save FP context from the FPU
|
||||
* @a0 - pointer to fpregs field of sigcontext
|
||||
* @a1 - pointer to fpc_csr field of sigcontext
|
||||
*
|
||||
* Save FP context, including the 32 FP data registers and the FP
|
||||
* control & status register, from the FPU to signal context.
|
||||
*/
|
||||
LEAF(_save_fp_context)
|
||||
.set push
|
||||
SET_HARDFLOAT
|
||||
li v0, 0 # assume success
|
||||
cfc1 t1,fcr31
|
||||
EX(swc1 $f0,(SC_FPREGS+0)(a0))
|
||||
EX(swc1 $f1,(SC_FPREGS+8)(a0))
|
||||
EX(swc1 $f2,(SC_FPREGS+16)(a0))
|
||||
EX(swc1 $f3,(SC_FPREGS+24)(a0))
|
||||
EX(swc1 $f4,(SC_FPREGS+32)(a0))
|
||||
EX(swc1 $f5,(SC_FPREGS+40)(a0))
|
||||
EX(swc1 $f6,(SC_FPREGS+48)(a0))
|
||||
EX(swc1 $f7,(SC_FPREGS+56)(a0))
|
||||
EX(swc1 $f8,(SC_FPREGS+64)(a0))
|
||||
EX(swc1 $f9,(SC_FPREGS+72)(a0))
|
||||
EX(swc1 $f10,(SC_FPREGS+80)(a0))
|
||||
EX(swc1 $f11,(SC_FPREGS+88)(a0))
|
||||
EX(swc1 $f12,(SC_FPREGS+96)(a0))
|
||||
EX(swc1 $f13,(SC_FPREGS+104)(a0))
|
||||
EX(swc1 $f14,(SC_FPREGS+112)(a0))
|
||||
EX(swc1 $f15,(SC_FPREGS+120)(a0))
|
||||
EX(swc1 $f16,(SC_FPREGS+128)(a0))
|
||||
EX(swc1 $f17,(SC_FPREGS+136)(a0))
|
||||
EX(swc1 $f18,(SC_FPREGS+144)(a0))
|
||||
EX(swc1 $f19,(SC_FPREGS+152)(a0))
|
||||
EX(swc1 $f20,(SC_FPREGS+160)(a0))
|
||||
EX(swc1 $f21,(SC_FPREGS+168)(a0))
|
||||
EX(swc1 $f22,(SC_FPREGS+176)(a0))
|
||||
EX(swc1 $f23,(SC_FPREGS+184)(a0))
|
||||
EX(swc1 $f24,(SC_FPREGS+192)(a0))
|
||||
EX(swc1 $f25,(SC_FPREGS+200)(a0))
|
||||
EX(swc1 $f26,(SC_FPREGS+208)(a0))
|
||||
EX(swc1 $f27,(SC_FPREGS+216)(a0))
|
||||
EX(swc1 $f28,(SC_FPREGS+224)(a0))
|
||||
EX(swc1 $f29,(SC_FPREGS+232)(a0))
|
||||
EX(swc1 $f30,(SC_FPREGS+240)(a0))
|
||||
EX(swc1 $f31,(SC_FPREGS+248)(a0))
|
||||
EX(sw t1,(SC_FPC_CSR)(a0))
|
||||
cfc1 t0,$0 # implementation/version
|
||||
cfc1 t1, fcr31
|
||||
EX2(s.d $f0, 0(a0))
|
||||
EX2(s.d $f2, 16(a0))
|
||||
EX2(s.d $f4, 32(a0))
|
||||
EX2(s.d $f6, 48(a0))
|
||||
EX2(s.d $f8, 64(a0))
|
||||
EX2(s.d $f10, 80(a0))
|
||||
EX2(s.d $f12, 96(a0))
|
||||
EX2(s.d $f14, 112(a0))
|
||||
EX2(s.d $f16, 128(a0))
|
||||
EX2(s.d $f18, 144(a0))
|
||||
EX2(s.d $f20, 160(a0))
|
||||
EX2(s.d $f22, 176(a0))
|
||||
EX2(s.d $f24, 192(a0))
|
||||
EX2(s.d $f26, 208(a0))
|
||||
EX2(s.d $f28, 224(a0))
|
||||
EX2(s.d $f30, 240(a0))
|
||||
jr ra
|
||||
EX(sw t1, (a1))
|
||||
.set pop
|
||||
.set nomacro
|
||||
EX(sw t0,(SC_FPC_EIR)(a0))
|
||||
.set macro
|
||||
END(_save_fp_context)
|
||||
|
||||
/*
|
||||
* Restore FPU state:
|
||||
* - fp gp registers
|
||||
* - cp1 status/control register
|
||||
/**
|
||||
* _restore_fp_context() - restore FP context to the FPU
|
||||
* @a0 - pointer to fpregs field of sigcontext
|
||||
* @a1 - pointer to fpc_csr field of sigcontext
|
||||
*
|
||||
* We base the decision which registers to restore from the signal stack
|
||||
* frame on the current content of c0_status, not on the content of the
|
||||
* stack frame which might have been changed by the user.
|
||||
* Restore FP context, including the 32 FP data registers and the FP
|
||||
* control & status register, from signal context to the FPU.
|
||||
*/
|
||||
LEAF(_restore_fp_context)
|
||||
.set push
|
||||
SET_HARDFLOAT
|
||||
li v0, 0 # assume success
|
||||
EX(lw t0,(SC_FPC_CSR)(a0))
|
||||
EX(lwc1 $f0,(SC_FPREGS+0)(a0))
|
||||
EX(lwc1 $f1,(SC_FPREGS+8)(a0))
|
||||
EX(lwc1 $f2,(SC_FPREGS+16)(a0))
|
||||
EX(lwc1 $f3,(SC_FPREGS+24)(a0))
|
||||
EX(lwc1 $f4,(SC_FPREGS+32)(a0))
|
||||
EX(lwc1 $f5,(SC_FPREGS+40)(a0))
|
||||
EX(lwc1 $f6,(SC_FPREGS+48)(a0))
|
||||
EX(lwc1 $f7,(SC_FPREGS+56)(a0))
|
||||
EX(lwc1 $f8,(SC_FPREGS+64)(a0))
|
||||
EX(lwc1 $f9,(SC_FPREGS+72)(a0))
|
||||
EX(lwc1 $f10,(SC_FPREGS+80)(a0))
|
||||
EX(lwc1 $f11,(SC_FPREGS+88)(a0))
|
||||
EX(lwc1 $f12,(SC_FPREGS+96)(a0))
|
||||
EX(lwc1 $f13,(SC_FPREGS+104)(a0))
|
||||
EX(lwc1 $f14,(SC_FPREGS+112)(a0))
|
||||
EX(lwc1 $f15,(SC_FPREGS+120)(a0))
|
||||
EX(lwc1 $f16,(SC_FPREGS+128)(a0))
|
||||
EX(lwc1 $f17,(SC_FPREGS+136)(a0))
|
||||
EX(lwc1 $f18,(SC_FPREGS+144)(a0))
|
||||
EX(lwc1 $f19,(SC_FPREGS+152)(a0))
|
||||
EX(lwc1 $f20,(SC_FPREGS+160)(a0))
|
||||
EX(lwc1 $f21,(SC_FPREGS+168)(a0))
|
||||
EX(lwc1 $f22,(SC_FPREGS+176)(a0))
|
||||
EX(lwc1 $f23,(SC_FPREGS+184)(a0))
|
||||
EX(lwc1 $f24,(SC_FPREGS+192)(a0))
|
||||
EX(lwc1 $f25,(SC_FPREGS+200)(a0))
|
||||
EX(lwc1 $f26,(SC_FPREGS+208)(a0))
|
||||
EX(lwc1 $f27,(SC_FPREGS+216)(a0))
|
||||
EX(lwc1 $f28,(SC_FPREGS+224)(a0))
|
||||
EX(lwc1 $f29,(SC_FPREGS+232)(a0))
|
||||
EX(lwc1 $f30,(SC_FPREGS+240)(a0))
|
||||
EX(lwc1 $f31,(SC_FPREGS+248)(a0))
|
||||
EX(lw t0, (a1))
|
||||
EX2(l.d $f0, 0(a0))
|
||||
EX2(l.d $f2, 16(a0))
|
||||
EX2(l.d $f4, 32(a0))
|
||||
EX2(l.d $f6, 48(a0))
|
||||
EX2(l.d $f8, 64(a0))
|
||||
EX2(l.d $f10, 80(a0))
|
||||
EX2(l.d $f12, 96(a0))
|
||||
EX2(l.d $f14, 112(a0))
|
||||
EX2(l.d $f16, 128(a0))
|
||||
EX2(l.d $f18, 144(a0))
|
||||
EX2(l.d $f20, 160(a0))
|
||||
EX2(l.d $f22, 176(a0))
|
||||
EX2(l.d $f24, 192(a0))
|
||||
EX2(l.d $f26, 208(a0))
|
||||
EX2(l.d $f28, 224(a0))
|
||||
EX2(l.d $f30, 240(a0))
|
||||
jr ra
|
||||
ctc1 t0,fcr31
|
||||
ctc1 t0, fcr31
|
||||
.set pop
|
||||
END(_restore_fp_context)
|
||||
.set reorder
|
||||
|
@ -21,7 +21,14 @@
|
||||
.set push
|
||||
SET_HARDFLOAT
|
||||
|
||||
/* Save floating point context */
|
||||
/**
|
||||
* _save_fp_context() - save FP context from the FPU
|
||||
* @a0 - pointer to fpregs field of sigcontext
|
||||
* @a1 - pointer to fpc_csr field of sigcontext
|
||||
*
|
||||
* Save FP context, including the 32 FP data registers and the FP
|
||||
* control & status register, from the FPU to signal context.
|
||||
*/
|
||||
LEAF(_save_fp_context)
|
||||
mfc0 t0,CP0_STATUS
|
||||
sll t0,t0,2
|
||||
@ -30,59 +37,59 @@
|
||||
|
||||
cfc1 t1,fcr31
|
||||
/* Store the 16 double precision registers */
|
||||
sdc1 $f0,(SC_FPREGS+0)(a0)
|
||||
sdc1 $f2,(SC_FPREGS+16)(a0)
|
||||
sdc1 $f4,(SC_FPREGS+32)(a0)
|
||||
sdc1 $f6,(SC_FPREGS+48)(a0)
|
||||
sdc1 $f8,(SC_FPREGS+64)(a0)
|
||||
sdc1 $f10,(SC_FPREGS+80)(a0)
|
||||
sdc1 $f12,(SC_FPREGS+96)(a0)
|
||||
sdc1 $f14,(SC_FPREGS+112)(a0)
|
||||
sdc1 $f16,(SC_FPREGS+128)(a0)
|
||||
sdc1 $f18,(SC_FPREGS+144)(a0)
|
||||
sdc1 $f20,(SC_FPREGS+160)(a0)
|
||||
sdc1 $f22,(SC_FPREGS+176)(a0)
|
||||
sdc1 $f24,(SC_FPREGS+192)(a0)
|
||||
sdc1 $f26,(SC_FPREGS+208)(a0)
|
||||
sdc1 $f28,(SC_FPREGS+224)(a0)
|
||||
sdc1 $f30,(SC_FPREGS+240)(a0)
|
||||
sdc1 $f0,0(a0)
|
||||
sdc1 $f2,16(a0)
|
||||
sdc1 $f4,32(a0)
|
||||
sdc1 $f6,48(a0)
|
||||
sdc1 $f8,64(a0)
|
||||
sdc1 $f10,80(a0)
|
||||
sdc1 $f12,96(a0)
|
||||
sdc1 $f14,112(a0)
|
||||
sdc1 $f16,128(a0)
|
||||
sdc1 $f18,144(a0)
|
||||
sdc1 $f20,160(a0)
|
||||
sdc1 $f22,176(a0)
|
||||
sdc1 $f24,192(a0)
|
||||
sdc1 $f26,208(a0)
|
||||
sdc1 $f28,224(a0)
|
||||
sdc1 $f30,240(a0)
|
||||
jr ra
|
||||
sw t0,SC_FPC_CSR(a0)
|
||||
sw t0,(a1)
|
||||
1: jr ra
|
||||
nop
|
||||
END(_save_fp_context)
|
||||
|
||||
/* Restore FPU state:
|
||||
* - fp gp registers
|
||||
* - cp1 status/control register
|
||||
/**
|
||||
* _restore_fp_context() - restore FP context to the FPU
|
||||
* @a0 - pointer to fpregs field of sigcontext
|
||||
* @a1 - pointer to fpc_csr field of sigcontext
|
||||
*
|
||||
* We base the decision which registers to restore from the signal stack
|
||||
* frame on the current content of c0_status, not on the content of the
|
||||
* stack frame which might have been changed by the user.
|
||||
* Restore FP context, including the 32 FP data registers and the FP
|
||||
* control & status register, from signal context to the FPU.
|
||||
*/
|
||||
LEAF(_restore_fp_context)
|
||||
mfc0 t0,CP0_STATUS
|
||||
sll t0,t0,2
|
||||
|
||||
bgez t0,1f
|
||||
lw t0,SC_FPC_CSR(a0)
|
||||
lw t0,(a1)
|
||||
/* Restore the 16 double precision registers */
|
||||
ldc1 $f0,(SC_FPREGS+0)(a0)
|
||||
ldc1 $f2,(SC_FPREGS+16)(a0)
|
||||
ldc1 $f4,(SC_FPREGS+32)(a0)
|
||||
ldc1 $f6,(SC_FPREGS+48)(a0)
|
||||
ldc1 $f8,(SC_FPREGS+64)(a0)
|
||||
ldc1 $f10,(SC_FPREGS+80)(a0)
|
||||
ldc1 $f12,(SC_FPREGS+96)(a0)
|
||||
ldc1 $f14,(SC_FPREGS+112)(a0)
|
||||
ldc1 $f16,(SC_FPREGS+128)(a0)
|
||||
ldc1 $f18,(SC_FPREGS+144)(a0)
|
||||
ldc1 $f20,(SC_FPREGS+160)(a0)
|
||||
ldc1 $f22,(SC_FPREGS+176)(a0)
|
||||
ldc1 $f24,(SC_FPREGS+192)(a0)
|
||||
ldc1 $f26,(SC_FPREGS+208)(a0)
|
||||
ldc1 $f28,(SC_FPREGS+224)(a0)
|
||||
ldc1 $f30,(SC_FPREGS+240)(a0)
|
||||
ldc1 $f0,0(a0)
|
||||
ldc1 $f2,16(a0)
|
||||
ldc1 $f4,32(a0)
|
||||
ldc1 $f6,48(a0)
|
||||
ldc1 $f8,64(a0)
|
||||
ldc1 $f10,80(a0)
|
||||
ldc1 $f12,96(a0)
|
||||
ldc1 $f14,112(a0)
|
||||
ldc1 $f16,128(a0)
|
||||
ldc1 $f18,144(a0)
|
||||
ldc1 $f20,160(a0)
|
||||
ldc1 $f22,176(a0)
|
||||
ldc1 $f24,192(a0)
|
||||
ldc1 $f26,208(a0)
|
||||
ldc1 $f28,224(a0)
|
||||
ldc1 $f30,240(a0)
|
||||
jr ra
|
||||
ctc1 t0,fcr31
|
||||
1: jr ra
|
||||
|
@ -200,7 +200,7 @@ static inline __init unsigned long get_random_boot(void)
|
||||
|
||||
#if defined(CONFIG_USE_OF)
|
||||
/* Get any additional entropy passed in device tree */
|
||||
{
|
||||
if (initial_boot_params) {
|
||||
int node, len;
|
||||
u64 *prop;
|
||||
|
||||
|
@ -368,6 +368,19 @@ static void __init bootmem_init(void)
|
||||
end = PFN_DOWN(boot_mem_map.map[i].addr
|
||||
+ boot_mem_map.map[i].size);
|
||||
|
||||
#ifndef CONFIG_HIGHMEM
|
||||
/*
|
||||
* Skip highmem here so we get an accurate max_low_pfn if low
|
||||
* memory stops short of high memory.
|
||||
* If the region overlaps HIGHMEM_START, end is clipped so
|
||||
* max_pfn excludes the highmem portion.
|
||||
*/
|
||||
if (start >= PFN_DOWN(HIGHMEM_START))
|
||||
continue;
|
||||
if (end > PFN_DOWN(HIGHMEM_START))
|
||||
end = PFN_DOWN(HIGHMEM_START);
|
||||
#endif
|
||||
|
||||
if (end > max_low_pfn)
|
||||
max_low_pfn = end;
|
||||
if (start < min_low_pfn)
|
||||
|
@ -156,7 +156,7 @@ static void show_backtrace(struct task_struct *task, const struct pt_regs *regs)
|
||||
print_ip_sym(pc);
|
||||
pc = unwind_stack(task, &sp, pc, &ra);
|
||||
} while (pc);
|
||||
printk("\n");
|
||||
pr_cont("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
@ -174,22 +174,24 @@ static void show_stacktrace(struct task_struct *task,
|
||||
printk("Stack :");
|
||||
i = 0;
|
||||
while ((unsigned long) sp & (PAGE_SIZE - 1)) {
|
||||
if (i && ((i % (64 / field)) == 0))
|
||||
printk("\n ");
|
||||
if (i && ((i % (64 / field)) == 0)) {
|
||||
pr_cont("\n");
|
||||
printk(" ");
|
||||
}
|
||||
if (i > 39) {
|
||||
printk(" ...");
|
||||
pr_cont(" ...");
|
||||
break;
|
||||
}
|
||||
|
||||
if (__get_user(stackdata, sp++)) {
|
||||
printk(" (Bad stack address)");
|
||||
pr_cont(" (Bad stack address)");
|
||||
break;
|
||||
}
|
||||
|
||||
printk(" %0*lx", field, stackdata);
|
||||
pr_cont(" %0*lx", field, stackdata);
|
||||
i++;
|
||||
}
|
||||
printk("\n");
|
||||
pr_cont("\n");
|
||||
show_backtrace(task, regs);
|
||||
}
|
||||
|
||||
@ -229,18 +231,19 @@ static void show_code(unsigned int __user *pc)
|
||||
long i;
|
||||
unsigned short __user *pc16 = NULL;
|
||||
|
||||
printk("\nCode:");
|
||||
printk("Code:");
|
||||
|
||||
if ((unsigned long)pc & 1)
|
||||
pc16 = (unsigned short __user *)((unsigned long)pc & ~1);
|
||||
for(i = -3 ; i < 6 ; i++) {
|
||||
unsigned int insn;
|
||||
if (pc16 ? __get_user(insn, pc16 + i) : __get_user(insn, pc + i)) {
|
||||
printk(" (Bad address in epc)\n");
|
||||
pr_cont(" (Bad address in epc)\n");
|
||||
break;
|
||||
}
|
||||
printk("%c%0*x%c", (i?' ':'<'), pc16 ? 4 : 8, insn, (i?' ':'>'));
|
||||
pr_cont("%c%0*x%c", (i?' ':'<'), pc16 ? 4 : 8, insn, (i?' ':'>'));
|
||||
}
|
||||
pr_cont("\n");
|
||||
}
|
||||
|
||||
static void __show_regs(const struct pt_regs *regs)
|
||||
@ -259,15 +262,15 @@ static void __show_regs(const struct pt_regs *regs)
|
||||
if ((i % 4) == 0)
|
||||
printk("$%2d :", i);
|
||||
if (i == 0)
|
||||
printk(" %0*lx", field, 0UL);
|
||||
pr_cont(" %0*lx", field, 0UL);
|
||||
else if (i == 26 || i == 27)
|
||||
printk(" %*s", field, "");
|
||||
pr_cont(" %*s", field, "");
|
||||
else
|
||||
printk(" %0*lx", field, regs->regs[i]);
|
||||
pr_cont(" %0*lx", field, regs->regs[i]);
|
||||
|
||||
i++;
|
||||
if ((i % 4) == 0)
|
||||
printk("\n");
|
||||
pr_cont("\n");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_HAS_SMARTMIPS
|
||||
@ -288,46 +291,46 @@ static void __show_regs(const struct pt_regs *regs)
|
||||
|
||||
if (cpu_has_3kex) {
|
||||
if (regs->cp0_status & ST0_KUO)
|
||||
printk("KUo ");
|
||||
pr_cont("KUo ");
|
||||
if (regs->cp0_status & ST0_IEO)
|
||||
printk("IEo ");
|
||||
pr_cont("IEo ");
|
||||
if (regs->cp0_status & ST0_KUP)
|
||||
printk("KUp ");
|
||||
pr_cont("KUp ");
|
||||
if (regs->cp0_status & ST0_IEP)
|
||||
printk("IEp ");
|
||||
pr_cont("IEp ");
|
||||
if (regs->cp0_status & ST0_KUC)
|
||||
printk("KUc ");
|
||||
pr_cont("KUc ");
|
||||
if (regs->cp0_status & ST0_IEC)
|
||||
printk("IEc ");
|
||||
pr_cont("IEc ");
|
||||
} else if (cpu_has_4kex) {
|
||||
if (regs->cp0_status & ST0_KX)
|
||||
printk("KX ");
|
||||
pr_cont("KX ");
|
||||
if (regs->cp0_status & ST0_SX)
|
||||
printk("SX ");
|
||||
pr_cont("SX ");
|
||||
if (regs->cp0_status & ST0_UX)
|
||||
printk("UX ");
|
||||
pr_cont("UX ");
|
||||
switch (regs->cp0_status & ST0_KSU) {
|
||||
case KSU_USER:
|
||||
printk("USER ");
|
||||
pr_cont("USER ");
|
||||
break;
|
||||
case KSU_SUPERVISOR:
|
||||
printk("SUPERVISOR ");
|
||||
pr_cont("SUPERVISOR ");
|
||||
break;
|
||||
case KSU_KERNEL:
|
||||
printk("KERNEL ");
|
||||
pr_cont("KERNEL ");
|
||||
break;
|
||||
default:
|
||||
printk("BAD_MODE ");
|
||||
pr_cont("BAD_MODE ");
|
||||
break;
|
||||
}
|
||||
if (regs->cp0_status & ST0_ERL)
|
||||
printk("ERL ");
|
||||
pr_cont("ERL ");
|
||||
if (regs->cp0_status & ST0_EXL)
|
||||
printk("EXL ");
|
||||
pr_cont("EXL ");
|
||||
if (regs->cp0_status & ST0_IE)
|
||||
printk("IE ");
|
||||
pr_cont("IE ");
|
||||
}
|
||||
printk("\n");
|
||||
pr_cont("\n");
|
||||
|
||||
exccode = (cause & CAUSEF_EXCCODE) >> CAUSEB_EXCCODE;
|
||||
printk("Cause : %08x (ExcCode %02x)\n", cause, exccode);
|
||||
@ -705,6 +708,32 @@ asmlinkage void do_ov(struct pt_regs *regs)
|
||||
exception_exit(prev_state);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send SIGFPE according to FCSR Cause bits, which must have already
|
||||
* been masked against Enable bits. This is impotant as Inexact can
|
||||
* happen together with Overflow or Underflow, and `ptrace' can set
|
||||
* any bits.
|
||||
*/
|
||||
void force_fcr31_sig(unsigned long fcr31, void __user *fault_addr,
|
||||
struct task_struct *tsk)
|
||||
{
|
||||
struct siginfo si = { .si_addr = fault_addr, .si_signo = SIGFPE };
|
||||
|
||||
if (fcr31 & FPU_CSR_INV_X)
|
||||
si.si_code = FPE_FLTINV;
|
||||
else if (fcr31 & FPU_CSR_DIV_X)
|
||||
si.si_code = FPE_FLTDIV;
|
||||
else if (fcr31 & FPU_CSR_OVF_X)
|
||||
si.si_code = FPE_FLTOVF;
|
||||
else if (fcr31 & FPU_CSR_UDF_X)
|
||||
si.si_code = FPE_FLTUND;
|
||||
else if (fcr31 & FPU_CSR_INE_X)
|
||||
si.si_code = FPE_FLTRES;
|
||||
else
|
||||
si.si_code = __SI_FAULT;
|
||||
force_sig_info(SIGFPE, &si, tsk);
|
||||
}
|
||||
|
||||
int process_fpemu_return(int sig, void __user *fault_addr, unsigned long fcr31)
|
||||
{
|
||||
struct siginfo si = { 0 };
|
||||
@ -715,27 +744,7 @@ int process_fpemu_return(int sig, void __user *fault_addr, unsigned long fcr31)
|
||||
return 0;
|
||||
|
||||
case SIGFPE:
|
||||
si.si_addr = fault_addr;
|
||||
si.si_signo = sig;
|
||||
/*
|
||||
* Inexact can happen together with Overflow or Underflow.
|
||||
* Respect the mask to deliver the correct exception.
|
||||
*/
|
||||
fcr31 &= (fcr31 & FPU_CSR_ALL_E) <<
|
||||
(ffs(FPU_CSR_ALL_X) - ffs(FPU_CSR_ALL_E));
|
||||
if (fcr31 & FPU_CSR_INV_X)
|
||||
si.si_code = FPE_FLTINV;
|
||||
else if (fcr31 & FPU_CSR_DIV_X)
|
||||
si.si_code = FPE_FLTDIV;
|
||||
else if (fcr31 & FPU_CSR_OVF_X)
|
||||
si.si_code = FPE_FLTOVF;
|
||||
else if (fcr31 & FPU_CSR_UDF_X)
|
||||
si.si_code = FPE_FLTUND;
|
||||
else if (fcr31 & FPU_CSR_INE_X)
|
||||
si.si_code = FPE_FLTRES;
|
||||
else
|
||||
si.si_code = __SI_FAULT;
|
||||
force_sig_info(sig, &si, current);
|
||||
force_fcr31_sig(fcr31, fault_addr, current);
|
||||
return 1;
|
||||
|
||||
case SIGBUS:
|
||||
@ -799,13 +808,13 @@ static int simulate_fp(struct pt_regs *regs, unsigned int opcode,
|
||||
/* Run the emulator */
|
||||
sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1,
|
||||
&fault_addr);
|
||||
fcr31 = current->thread.fpu.fcr31;
|
||||
|
||||
/*
|
||||
* We can't allow the emulated instruction to leave any of
|
||||
* the cause bits set in $fcr31.
|
||||
* We can't allow the emulated instruction to leave any
|
||||
* enabled Cause bits set in $fcr31.
|
||||
*/
|
||||
current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
|
||||
fcr31 = mask_fcr31_x(current->thread.fpu.fcr31);
|
||||
current->thread.fpu.fcr31 &= ~fcr31;
|
||||
|
||||
/* Restore the hardware register state */
|
||||
own_fpu(1);
|
||||
@ -831,7 +840,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
|
||||
goto out;
|
||||
|
||||
/* Clear FCSR.Cause before enabling interrupts */
|
||||
write_32bit_cp1_register(CP1_STATUS, fcr31 & ~FPU_CSR_ALL_X);
|
||||
write_32bit_cp1_register(CP1_STATUS, fcr31 & ~mask_fcr31_x(fcr31));
|
||||
local_irq_enable();
|
||||
|
||||
die_if_kernel("FP exception in kernel code", regs);
|
||||
@ -853,13 +862,13 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
|
||||
/* Run the emulator */
|
||||
sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1,
|
||||
&fault_addr);
|
||||
fcr31 = current->thread.fpu.fcr31;
|
||||
|
||||
/*
|
||||
* We can't allow the emulated instruction to leave any of
|
||||
* the cause bits set in $fcr31.
|
||||
* We can't allow the emulated instruction to leave any
|
||||
* enabled Cause bits set in $fcr31.
|
||||
*/
|
||||
current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
|
||||
fcr31 = mask_fcr31_x(current->thread.fpu.fcr31);
|
||||
current->thread.fpu.fcr31 &= ~fcr31;
|
||||
|
||||
/* Restore the hardware register state */
|
||||
own_fpu(1); /* Using the FPU again. */
|
||||
@ -1424,13 +1433,13 @@ asmlinkage void do_cpu(struct pt_regs *regs)
|
||||
|
||||
sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 0,
|
||||
&fault_addr);
|
||||
fcr31 = current->thread.fpu.fcr31;
|
||||
|
||||
/*
|
||||
* We can't allow the emulated instruction to leave
|
||||
* any of the cause bits set in $fcr31.
|
||||
* any enabled Cause bits set in $fcr31.
|
||||
*/
|
||||
current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
|
||||
fcr31 = mask_fcr31_x(current->thread.fpu.fcr31);
|
||||
current->thread.fpu.fcr31 &= ~fcr31;
|
||||
|
||||
/* Send a signal if required. */
|
||||
if (!process_fpemu_return(sig, fault_addr, fcr31) && !err)
|
||||
|
@ -135,42 +135,42 @@ static void dump_tlb(int first, int last)
|
||||
c0 = (entrylo0 & ENTRYLO_C) >> ENTRYLO_C_SHIFT;
|
||||
c1 = (entrylo1 & ENTRYLO_C) >> ENTRYLO_C_SHIFT;
|
||||
|
||||
printk("va=%0*lx asid=%0*lx",
|
||||
vwidth, (entryhi & ~0x1fffUL),
|
||||
asidwidth, entryhi & asidmask);
|
||||
pr_cont("va=%0*lx asid=%0*lx",
|
||||
vwidth, (entryhi & ~0x1fffUL),
|
||||
asidwidth, entryhi & asidmask);
|
||||
if (cpu_has_guestid)
|
||||
printk(" gid=%02lx",
|
||||
(guestctl1 & MIPS_GCTL1_RID)
|
||||
pr_cont(" gid=%02lx",
|
||||
(guestctl1 & MIPS_GCTL1_RID)
|
||||
>> MIPS_GCTL1_RID_SHIFT);
|
||||
/* RI/XI are in awkward places, so mask them off separately */
|
||||
pa = entrylo0 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI);
|
||||
if (xpa)
|
||||
pa |= (unsigned long long)readx_c0_entrylo0() << 30;
|
||||
pa = (pa << 6) & PAGE_MASK;
|
||||
printk("\n\t[");
|
||||
pr_cont("\n\t[");
|
||||
if (cpu_has_rixi)
|
||||
printk("ri=%d xi=%d ",
|
||||
(entrylo0 & MIPS_ENTRYLO_RI) ? 1 : 0,
|
||||
(entrylo0 & MIPS_ENTRYLO_XI) ? 1 : 0);
|
||||
printk("pa=%0*llx c=%d d=%d v=%d g=%d] [",
|
||||
pwidth, pa, c0,
|
||||
(entrylo0 & ENTRYLO_D) ? 1 : 0,
|
||||
(entrylo0 & ENTRYLO_V) ? 1 : 0,
|
||||
(entrylo0 & ENTRYLO_G) ? 1 : 0);
|
||||
pr_cont("ri=%d xi=%d ",
|
||||
(entrylo0 & MIPS_ENTRYLO_RI) ? 1 : 0,
|
||||
(entrylo0 & MIPS_ENTRYLO_XI) ? 1 : 0);
|
||||
pr_cont("pa=%0*llx c=%d d=%d v=%d g=%d] [",
|
||||
pwidth, pa, c0,
|
||||
(entrylo0 & ENTRYLO_D) ? 1 : 0,
|
||||
(entrylo0 & ENTRYLO_V) ? 1 : 0,
|
||||
(entrylo0 & ENTRYLO_G) ? 1 : 0);
|
||||
/* RI/XI are in awkward places, so mask them off separately */
|
||||
pa = entrylo1 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI);
|
||||
if (xpa)
|
||||
pa |= (unsigned long long)readx_c0_entrylo1() << 30;
|
||||
pa = (pa << 6) & PAGE_MASK;
|
||||
if (cpu_has_rixi)
|
||||
printk("ri=%d xi=%d ",
|
||||
(entrylo1 & MIPS_ENTRYLO_RI) ? 1 : 0,
|
||||
(entrylo1 & MIPS_ENTRYLO_XI) ? 1 : 0);
|
||||
printk("pa=%0*llx c=%d d=%d v=%d g=%d]\n",
|
||||
pwidth, pa, c1,
|
||||
(entrylo1 & ENTRYLO_D) ? 1 : 0,
|
||||
(entrylo1 & ENTRYLO_V) ? 1 : 0,
|
||||
(entrylo1 & ENTRYLO_G) ? 1 : 0);
|
||||
pr_cont("ri=%d xi=%d ",
|
||||
(entrylo1 & MIPS_ENTRYLO_RI) ? 1 : 0,
|
||||
(entrylo1 & MIPS_ENTRYLO_XI) ? 1 : 0);
|
||||
pr_cont("pa=%0*llx c=%d d=%d v=%d g=%d]\n",
|
||||
pwidth, pa, c1,
|
||||
(entrylo1 & ENTRYLO_D) ? 1 : 0,
|
||||
(entrylo1 & ENTRYLO_V) ? 1 : 0,
|
||||
(entrylo1 & ENTRYLO_G) ? 1 : 0);
|
||||
}
|
||||
printk("\n");
|
||||
|
||||
|
@ -53,15 +53,15 @@ static void dump_tlb(int first, int last)
|
||||
*/
|
||||
printk("Index: %2d ", i);
|
||||
|
||||
printk("va=%08lx asid=%08lx"
|
||||
" [pa=%06lx n=%d d=%d v=%d g=%d]",
|
||||
entryhi & PAGE_MASK,
|
||||
entryhi & asid_mask,
|
||||
entrylo0 & PAGE_MASK,
|
||||
(entrylo0 & R3K_ENTRYLO_N) ? 1 : 0,
|
||||
(entrylo0 & R3K_ENTRYLO_D) ? 1 : 0,
|
||||
(entrylo0 & R3K_ENTRYLO_V) ? 1 : 0,
|
||||
(entrylo0 & R3K_ENTRYLO_G) ? 1 : 0);
|
||||
pr_cont("va=%08lx asid=%08lx"
|
||||
" [pa=%06lx n=%d d=%d v=%d g=%d]",
|
||||
entryhi & PAGE_MASK,
|
||||
entryhi & asid_mask,
|
||||
entrylo0 & PAGE_MASK,
|
||||
(entrylo0 & R3K_ENTRYLO_N) ? 1 : 0,
|
||||
(entrylo0 & R3K_ENTRYLO_D) ? 1 : 0,
|
||||
(entrylo0 & R3K_ENTRYLO_V) ? 1 : 0,
|
||||
(entrylo0 & R3K_ENTRYLO_G) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
printk("\n");
|
||||
|
Loading…
Reference in New Issue
Block a user