Commit 34c510b2 authored by Linus Torvalds's avatar Linus Torvalds

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
parents f7df76e6 16a767ec
...@@ -263,7 +263,7 @@ KBUILD_CPPFLAGS += -DDATAOFFSET=$(if $(dataoffset-y),$(dataoffset-y),0) ...@@ -263,7 +263,7 @@ KBUILD_CPPFLAGS += -DDATAOFFSET=$(if $(dataoffset-y),$(dataoffset-y),0)
bootvars-y = VMLINUX_LOAD_ADDRESS=$(load-y) \ bootvars-y = VMLINUX_LOAD_ADDRESS=$(load-y) \
VMLINUX_ENTRY_ADDRESS=$(entry-y) \ VMLINUX_ENTRY_ADDRESS=$(entry-y) \
PLATFORM=$(platform-y) PLATFORM="$(platform-y)"
ifdef CONFIG_32BIT ifdef CONFIG_32BIT
bootvars-y += ADDR_BITS=32 bootvars-y += ADDR_BITS=32
endif endif
......
...@@ -84,12 +84,13 @@ board-config@3e0000 { ...@@ -84,12 +84,13 @@ board-config@3e0000 {
fpga_regs: system-controller@1f000000 { fpga_regs: system-controller@1f000000 {
compatible = "mti,malta-fpga", "syscon", "simple-mfd"; compatible = "mti,malta-fpga", "syscon", "simple-mfd";
reg = <0x1f000000 0x1000>; reg = <0x1f000000 0x1000>;
native-endian;
reboot { reboot {
compatible = "syscon-reboot"; compatible = "syscon-reboot";
regmap = <&fpga_regs>; regmap = <&fpga_regs>;
offset = <0x500>; offset = <0x500>;
mask = <0x4d>; mask = <0x42>;
}; };
}; };
......
...@@ -29,10 +29,20 @@ static __initdata const struct mips_machine *mach; ...@@ -29,10 +29,20 @@ static __initdata const struct mips_machine *mach;
static __initdata const void *mach_match_data; static __initdata const void *mach_match_data;
void __init prom_init(void) 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 mips_machine *check_mach;
const struct of_device_id *match; const struct of_device_id *match;
if (fdt)
/* Already set up */
return (void *)fdt;
if ((fw_arg0 == -2) && !fdt_check_header((void *)fw_arg1)) { if ((fw_arg0 == -2) && !fdt_check_header((void *)fw_arg1)) {
/* /*
* We booted using the UHI boot protocol, so we have been * We booted using the UHI boot protocol, so we have been
...@@ -75,12 +85,6 @@ void __init prom_init(void) ...@@ -75,12 +85,6 @@ void __init prom_init(void)
/* Retrieve the machine's FDT */ /* Retrieve the machine's FDT */
fdt = mach->fdt; fdt = mach->fdt;
} }
BUG_ON(!fdt);
}
void __init *plat_get_fdt(void)
{
return (void *)fdt; return (void *)fdt;
} }
......
...@@ -63,6 +63,8 @@ do { \ ...@@ -63,6 +63,8 @@ do { \
extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
struct mips_fpu_struct *ctx, int has_fpu, struct mips_fpu_struct *ctx, int has_fpu,
void *__user *fault_addr); 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, int process_fpemu_return(int sig, void __user *fault_addr,
unsigned long fcr31); unsigned long fcr31);
int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
...@@ -81,4 +83,15 @@ static inline void fpu_emulator_init_fpu(void) ...@@ -81,4 +83,15 @@ static inline void fpu_emulator_init_fpu(void)
set_fpr64(&t->thread.fpu.fpr[i], 0, SIGNALLING_NAN); 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 */ #endif /* _ASM_FPU_EMULATOR_H */
...@@ -75,6 +75,22 @@ do { if (cpu_has_rw_llb) { \ ...@@ -75,6 +75,22 @@ do { if (cpu_has_rw_llb) { \
} \ } \
} while (0) } 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 * For newly created kernel threads switch_to() will return to
* ret_from_kernel_thread, newly created user threads to ret_from_fork. * ret_from_kernel_thread, newly created user threads to ret_from_fork.
...@@ -85,6 +101,8 @@ do { if (cpu_has_rw_llb) { \ ...@@ -85,6 +101,8 @@ do { if (cpu_has_rw_llb) { \
do { \ do { \
__mips_mt_fpaff_switch_to(prev); \ __mips_mt_fpaff_switch_to(prev); \
lose_fpu_inatomic(1, prev); \ lose_fpu_inatomic(1, prev); \
if (tsk_used_math(next)) \
__sanitize_fcr31(next); \
if (cpu_has_dsp) { \ if (cpu_has_dsp) { \
__save_dsp(prev); \ __save_dsp(prev); \
__restore_dsp(next); \ __restore_dsp(next); \
......
...@@ -21,6 +21,11 @@ static DEFINE_PER_CPU_ALIGNED(spinlock_t, cpc_core_lock); ...@@ -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); 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 * 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) ...@@ -43,8 +48,12 @@ static phys_addr_t mips_cpc_phys_base(void)
if (cpc_base & CM_GCR_CPC_BASE_CPCEN_MSK) if (cpc_base & CM_GCR_CPC_BASE_CPCEN_MSK)
return cpc_base & CM_GCR_CPC_BASE_CPCBASE_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(); 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); write_gcr_cpc_base(cpc_base | CM_GCR_CPC_BASE_CPCEN_MSK);
return cpc_base; return cpc_base;
} }
......
...@@ -899,7 +899,7 @@ static inline int mipsr2_find_op_func(struct pt_regs *regs, u32 inst, ...@@ -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 * mipsr2_decoder: Decode and emulate a MIPS R2 instruction
* @regs: Process register set * @regs: Process register set
* @inst: Instruction to decode and emulate * @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) int mipsr2_decoder(struct pt_regs *regs, u32 inst, unsigned long *fcr31)
{ {
...@@ -1172,13 +1172,13 @@ int mipsr2_decoder(struct pt_regs *regs, u32 inst, unsigned long *fcr31) ...@@ -1172,13 +1172,13 @@ int mipsr2_decoder(struct pt_regs *regs, u32 inst, unsigned long *fcr31)
err = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 0, err = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 0,
&fault_addr); &fault_addr);
*fcr31 = current->thread.fpu.fcr31;
/* /*
* We can't allow the emulated instruction to leave any of * We can't allow the emulated instruction to leave any
* the cause bits set in $fcr31. * 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 * this is a tricky issue - lose_fpu() uses LL/SC atomics
......
...@@ -79,16 +79,15 @@ void ptrace_disable(struct task_struct *child) ...@@ -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 * Poke at FCSR according to its mask. Set the Cause bits even
* this is currently not handled correctly in FP context restoration * if a corresponding Enable bit is set. This will be noticed at
* and will cause an oops if a corresponding enable bit is set. * the time the thread is switched to and SIGFPE thrown accordingly.
*/ */
static void ptrace_setfcr31(struct task_struct *child, u32 value) static void ptrace_setfcr31(struct task_struct *child, u32 value)
{ {
u32 fcr31; u32 fcr31;
u32 mask; u32 mask;
value &= ~FPU_CSR_ALL_X;
fcr31 = child->thread.fpu.fcr31; fcr31 = child->thread.fpu.fcr31;
mask = boot_cpu_data.fpu_msk31; mask = boot_cpu_data.fpu_msk31;
child->thread.fpu.fcr31 = (value & ~mask) | (fcr31 & mask); child->thread.fpu.fcr31 = (value & ~mask) | (fcr31 & mask);
...@@ -817,6 +816,7 @@ long arch_ptrace(struct task_struct *child, long request, ...@@ -817,6 +816,7 @@ long arch_ptrace(struct task_struct *child, long request,
break; break;
#endif #endif
case FPC_CSR: case FPC_CSR:
init_fp_ctx(child);
ptrace_setfcr31(child, data); ptrace_setfcr31(child, data);
break; break;
case DSP_BASE ... DSP_BASE + 5: { case DSP_BASE ... DSP_BASE + 5: {
......
...@@ -19,108 +19,86 @@ ...@@ -19,108 +19,86 @@
#include <asm/regdef.h> #include <asm/regdef.h>
#define EX(a,b) \ #define EX(a,b) \
9: a,##b; \
.section __ex_table,"a"; \
PTR 9b,fault; \
.previous
#define EX2(a,b) \
9: a,##b; \ 9: a,##b; \
.section __ex_table,"a"; \ .section __ex_table,"a"; \
PTR 9b,bad_stack; \ PTR 9b,bad_stack; \
PTR 9b+4,bad_stack; \
.previous .previous
.set noreorder .set noreorder
.set mips1 .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) LEAF(_save_fp_context)
.set push .set push
SET_HARDFLOAT SET_HARDFLOAT
li v0, 0 # assume success li v0, 0 # assume success
cfc1 t1,fcr31 cfc1 t1, fcr31
EX(swc1 $f0,(SC_FPREGS+0)(a0)) EX2(s.d $f0, 0(a0))
EX(swc1 $f1,(SC_FPREGS+8)(a0)) EX2(s.d $f2, 16(a0))
EX(swc1 $f2,(SC_FPREGS+16)(a0)) EX2(s.d $f4, 32(a0))
EX(swc1 $f3,(SC_FPREGS+24)(a0)) EX2(s.d $f6, 48(a0))
EX(swc1 $f4,(SC_FPREGS+32)(a0)) EX2(s.d $f8, 64(a0))
EX(swc1 $f5,(SC_FPREGS+40)(a0)) EX2(s.d $f10, 80(a0))
EX(swc1 $f6,(SC_FPREGS+48)(a0)) EX2(s.d $f12, 96(a0))
EX(swc1 $f7,(SC_FPREGS+56)(a0)) EX2(s.d $f14, 112(a0))
EX(swc1 $f8,(SC_FPREGS+64)(a0)) EX2(s.d $f16, 128(a0))
EX(swc1 $f9,(SC_FPREGS+72)(a0)) EX2(s.d $f18, 144(a0))
EX(swc1 $f10,(SC_FPREGS+80)(a0)) EX2(s.d $f20, 160(a0))
EX(swc1 $f11,(SC_FPREGS+88)(a0)) EX2(s.d $f22, 176(a0))
EX(swc1 $f12,(SC_FPREGS+96)(a0)) EX2(s.d $f24, 192(a0))
EX(swc1 $f13,(SC_FPREGS+104)(a0)) EX2(s.d $f26, 208(a0))
EX(swc1 $f14,(SC_FPREGS+112)(a0)) EX2(s.d $f28, 224(a0))
EX(swc1 $f15,(SC_FPREGS+120)(a0)) EX2(s.d $f30, 240(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
jr ra jr ra
EX(sw t1, (a1))
.set pop .set pop
.set nomacro
EX(sw t0,(SC_FPC_EIR)(a0))
.set macro
END(_save_fp_context) END(_save_fp_context)
/* /**
* Restore FPU state: * _restore_fp_context() - restore FP context to the FPU
* - fp gp registers * @a0 - pointer to fpregs field of sigcontext
* - cp1 status/control register * @a1 - pointer to fpc_csr field of sigcontext
* *
* We base the decision which registers to restore from the signal stack * Restore FP context, including the 32 FP data registers and the FP
* frame on the current content of c0_status, not on the content of the * control & status register, from signal context to the FPU.
* stack frame which might have been changed by the user.
*/ */
LEAF(_restore_fp_context) LEAF(_restore_fp_context)
.set push .set push
SET_HARDFLOAT SET_HARDFLOAT
li v0, 0 # assume success li v0, 0 # assume success
EX(lw t0,(SC_FPC_CSR)(a0)) EX(lw t0, (a1))
EX(lwc1 $f0,(SC_FPREGS+0)(a0)) EX2(l.d $f0, 0(a0))
EX(lwc1 $f1,(SC_FPREGS+8)(a0)) EX2(l.d $f2, 16(a0))
EX(lwc1 $f2,(SC_FPREGS+16)(a0)) EX2(l.d $f4, 32(a0))
EX(lwc1 $f3,(SC_FPREGS+24)(a0)) EX2(l.d $f6, 48(a0))
EX(lwc1 $f4,(SC_FPREGS+32)(a0)) EX2(l.d $f8, 64(a0))
EX(lwc1 $f5,(SC_FPREGS+40)(a0)) EX2(l.d $f10, 80(a0))
EX(lwc1 $f6,(SC_FPREGS+48)(a0)) EX2(l.d $f12, 96(a0))
EX(lwc1 $f7,(SC_FPREGS+56)(a0)) EX2(l.d $f14, 112(a0))
EX(lwc1 $f8,(SC_FPREGS+64)(a0)) EX2(l.d $f16, 128(a0))
EX(lwc1 $f9,(SC_FPREGS+72)(a0)) EX2(l.d $f18, 144(a0))
EX(lwc1 $f10,(SC_FPREGS+80)(a0)) EX2(l.d $f20, 160(a0))
EX(lwc1 $f11,(SC_FPREGS+88)(a0)) EX2(l.d $f22, 176(a0))
EX(lwc1 $f12,(SC_FPREGS+96)(a0)) EX2(l.d $f24, 192(a0))
EX(lwc1 $f13,(SC_FPREGS+104)(a0)) EX2(l.d $f26, 208(a0))
EX(lwc1 $f14,(SC_FPREGS+112)(a0)) EX2(l.d $f28, 224(a0))
EX(lwc1 $f15,(SC_FPREGS+120)(a0)) EX2(l.d $f30, 240(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))
jr ra jr ra
ctc1 t0,fcr31 ctc1 t0, fcr31
.set pop .set pop
END(_restore_fp_context) END(_restore_fp_context)
.set reorder .set reorder
......
...@@ -21,7 +21,14 @@ ...@@ -21,7 +21,14 @@
.set push .set push
SET_HARDFLOAT 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) LEAF(_save_fp_context)
mfc0 t0,CP0_STATUS mfc0 t0,CP0_STATUS
sll t0,t0,2 sll t0,t0,2
...@@ -30,59 +37,59 @@ ...@@ -30,59 +37,59 @@
cfc1 t1,fcr31 cfc1 t1,fcr31
/* Store the 16 double precision registers */ /* Store the 16 double precision registers */
sdc1 $f0,(SC_FPREGS+0)(a0) sdc1 $f0,0(a0)
sdc1 $f2,(SC_FPREGS+16)(a0) sdc1 $f2,16(a0)
sdc1 $f4,(SC_FPREGS+32)(a0) sdc1 $f4,32(a0)
sdc1 $f6,(SC_FPREGS+48)(a0) sdc1 $f6,48(a0)
sdc1 $f8,(SC_FPREGS+64)(a0) sdc1 $f8,64(a0)
sdc1 $f10,(SC_FPREGS+80)(a0) sdc1 $f10,80(a0)
sdc1 $f12,(SC_FPREGS+96)(a0) sdc1 $f12,96(a0)
sdc1 $f14,(SC_FPREGS+112)(a0) sdc1 $f14,112(a0)
sdc1 $f16,(SC_FPREGS+128)(a0) sdc1 $f16,128(a0)
sdc1 $f18,(SC_FPREGS+144)(a0) sdc1 $f18,144(a0)
sdc1 $f20,(SC_FPREGS+160)(a0) sdc1 $f20,160(a0)
sdc1 $f22,(SC_FPREGS+176)(a0) sdc1 $f22,176(a0)
sdc1 $f24,(SC_FPREGS+192)(a0) sdc1 $f24,192(a0)
sdc1 $f26,(SC_FPREGS+208)(a0) sdc1 $f26,208(a0)
sdc1 $f28,(SC_FPREGS+224)(a0) sdc1 $f28,224(a0)
sdc1 $f30,(SC_FPREGS+240)(a0) sdc1 $f30,240(a0)
jr ra jr ra
sw t0,SC_FPC_CSR(a0) sw t0,(a1)
1: jr ra 1: jr ra
nop nop
END(_save_fp_context) END(_save_fp_context)
/* Restore FPU state: /**
* - fp gp registers * _restore_fp_context() - restore FP context to the FPU
* - cp1 status/control register * @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 * Restore FP context, including the 32 FP data registers and the FP
* frame on the current content of c0_status, not on the content of the * control & status register, from signal context to the FPU.
* stack frame which might have been changed by the user.
*/ */
LEAF(_restore_fp_context) LEAF(_restore_fp_context)
mfc0 t0,CP0_STATUS mfc0 t0,CP0_STATUS
sll t0,t0,2 sll t0,t0,2
bgez t0,1f bgez t0,1f
lw t0,SC_FPC_CSR(a0) lw t0,(a1)
/* Restore the 16 double precision registers */ /* Restore the 16 double precision registers */
ldc1 $f0,(SC_FPREGS+0)(a0) ldc1 $f0,0(a0)
ldc1 $f2,(SC_FPREGS+16)(a0) ldc1 $f2,16(a0)
ldc1 $f4,(SC_FPREGS+32)(a0) ldc1 $f4,32(a0)
ldc1 $f6,(SC_FPREGS+48)(a0) ldc1 $f6,48(a0)
ldc1 $f8,(SC_FPREGS+64)(a0) ldc1 $f8,64(a0)
ldc1 $f10,(SC_FPREGS+80)(a0) ldc1 $f10,80(a0)
ldc1 $f12,(SC_FPREGS+96)(a0) ldc1 $f12,96(a0)
ldc1 $f14,(SC_FPREGS+112)(a0) ldc1 $f14,112(a0)
ldc1 $f16,(SC_FPREGS+128)(a0) ldc1 $f16,128(a0)
ldc1 $f18,(SC_FPREGS+144)(a0) ldc1 $f18,144(a0)
ldc1 $f20,(SC_FPREGS+160)(a0) ldc1 $f20,160(a0)
ldc1 $f22,(SC_FPREGS+176)(a0) ldc1 $f22,176(a0)
ldc1 $f24,(SC_FPREGS+192)(a0) ldc1 $f24,192(a0)
ldc1 $f26,(SC_FPREGS+208)(a0) ldc1 $f26,208(a0)
ldc1 $f28,(SC_FPREGS+224)(a0) ldc1 $f28,224(a0)
ldc1 $f30,(SC_FPREGS+240)(a0) ldc1 $f30,240(a0)
jr ra jr ra
ctc1 t0,fcr31 ctc1 t0,fcr31
1: jr ra 1: jr ra
......
...@@ -200,7 +200,7 @@ static inline __init unsigned long get_random_boot(void) ...@@ -200,7 +200,7 @@ static inline __init unsigned long get_random_boot(void)
#if defined(CONFIG_USE_OF) #if defined(CONFIG_USE_OF)
/* Get any additional entropy passed in device tree */ /* Get any additional entropy passed in device tree */
{ if (initial_boot_params) {
int node, len; int node, len;
u64 *prop; u64 *prop;
......
...@@ -368,6 +368,19 @@ static void __init bootmem_init(void) ...@@ -368,6 +368,19 @@ static void __init bootmem_init(void)
end = PFN_DOWN(boot_mem_map.map[i].addr end = PFN_DOWN(boot_mem_map.map[i].addr
+ boot_mem_map.map[i].size); + 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) if (end > max_low_pfn)
max_low_pfn = end; max_low_pfn = end;
if (start < min_low_pfn) if (start < min_low_pfn)
......
...@@ -156,7 +156,7 @@ static void show_backtrace(struct task_struct *task, const struct pt_regs *regs) ...@@ -156,7 +156,7 @@ static void show_backtrace(struct task_struct *task, const struct pt_regs *regs)
print_ip_sym(pc); print_ip_sym(pc);
pc = unwind_stack(task, &sp, pc, &ra); pc = unwind_stack(task, &sp, pc, &ra);
} while (pc); } while (pc);
printk("\n"); pr_cont("\n");
} }
/* /*
...@@ -174,22 +174,24 @@ static void show_stacktrace(struct task_struct *task, ...@@ -174,22 +174,24 @@ static void show_stacktrace(struct task_struct *task,
printk("Stack :"); printk("Stack :");
i = 0; i = 0;
while ((unsigned long) sp & (PAGE_SIZE - 1)) { while ((unsigned long) sp & (PAGE_SIZE - 1)) {
if (i && ((i % (64 / field)) == 0)) if (i && ((i % (64 / field)) == 0)) {
printk("\n "); pr_cont("\n");
printk(" ");
}
if (i > 39) { if (i > 39) {
printk(" ..."); pr_cont(" ...");
break; break;
} }
if (__get_user(stackdata, sp++)) { if (__get_user(stackdata, sp++)) {
printk(" (Bad stack address)"); pr_cont(" (Bad stack address)");
break; break;
} }
printk(" %0*lx", field, stackdata); pr_cont(" %0*lx", field, stackdata);
i++; i++;
} }
printk("\n"); pr_cont("\n");
show_backtrace(task, regs); show_backtrace(task, regs);
} }
...@@ -229,18 +231,19 @@ static void show_code(unsigned int __user *pc) ...@@ -229,18 +231,19 @@ static void show_code(unsigned int __user *pc)
long i; long i;
unsigned short __user *pc16 = NULL; unsigned short __user *pc16 = NULL;
printk("\nCode:"); printk("Code:");
if ((unsigned long)pc & 1) if ((unsigned long)pc & 1)
pc16 = (unsigned short __user *)((unsigned long)pc & ~1); pc16 = (unsigned short __user *)((unsigned long)pc & ~1);
for(i = -3 ; i < 6 ; i++) { for(i = -3 ; i < 6 ; i++) {
unsigned int insn; unsigned int insn;
if (pc16 ? __get_user(insn, pc16 + i) : __get_user(insn, pc + i)) { 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; 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) static void __show_regs(const struct pt_regs *regs)
...@@ -259,15 +262,15 @@ 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) if ((i % 4) == 0)
printk("$%2d :", i); printk("$%2d :", i);
if (i == 0) if (i == 0)
printk(" %0*lx", field, 0UL); pr_cont(" %0*lx", field, 0UL);
else if (i == 26 || i == 27) else if (i == 26 || i == 27)
printk(" %*s", field, ""); pr_cont(" %*s", field, "");
else else
printk(" %0*lx", field, regs->regs[i]); pr_cont(" %0*lx", field, regs->regs[i]);
i++; i++;
if ((i % 4) == 0) if ((i % 4) == 0)
printk("\n"); pr_cont("\n");
} }
#ifdef CONFIG_CPU_HAS_SMARTMIPS #ifdef CONFIG_CPU_HAS_SMARTMIPS
...@@ -288,46 +291,46 @@ static void __show_regs(const struct pt_regs *regs) ...@@ -288,46 +291,46 @@ static void __show_regs(const struct pt_regs *regs)
if (cpu_has_3kex) { if (cpu_has_3kex) {
if (regs->cp0_status & ST0_KUO) if (regs->cp0_status & ST0_KUO)
printk("KUo "); pr_cont("KUo ");
if (regs->cp0_status & ST0_IEO) if (regs->cp0_status & ST0_IEO)
printk("IEo "); pr_cont("IEo ");
if (regs->cp0_status & ST0_KUP) if (regs->cp0_status & ST0_KUP)
printk("KUp "); pr_cont("KUp ");
if (regs->cp0_status & ST0_IEP) if (regs->cp0_status & ST0_IEP)
printk("IEp "); pr_cont("IEp ");
if (regs->cp0_status & ST0_KUC) if (regs->cp0_status & ST0_KUC)
printk("KUc "); pr_cont("KUc ");
if (regs->cp0_status & ST0_IEC) if (regs->cp0_status & ST0_IEC)
printk("IEc "); pr_cont("IEc ");
} else if (cpu_has_4kex) { } else if (cpu_has_4kex) {
if (regs->cp0_status & ST0_KX) if (regs->cp0_status & ST0_KX)
printk("KX "); pr_cont("KX ");
if (regs->cp0_status & ST0_SX) if (regs->cp0_status & ST0_SX)
printk("SX "); pr_cont("SX ");
if (regs->cp0_status & ST0_UX) if (regs->cp0_status & ST0_UX)
printk("UX "); pr_cont("UX ");
switch (regs->cp0_status & ST0_KSU) { switch (regs->cp0_status & ST0_KSU) {
case KSU_USER: case KSU_USER:
printk("USER "); pr_cont("USER ");
break; break;
case KSU_SUPERVISOR: case KSU_SUPERVISOR:
printk("SUPERVISOR "); pr_cont("SUPERVISOR ");
break; break;
case KSU_KERNEL: case KSU_KERNEL:
printk("KERNEL "); pr_cont("KERNEL ");
break; break;
default: default:
printk("BAD_MODE "); pr_cont("BAD_MODE ");
break; break;
} }
if (regs->cp0_status & ST0_ERL) if (regs->cp0_status & ST0_ERL)
printk("ERL "); pr_cont("ERL ");
if (regs->cp0_status & ST0_EXL) if (regs->cp0_status & ST0_EXL)
printk("EXL "); pr_cont("EXL ");
if (regs->cp0_status & ST0_IE) if (regs->cp0_status & ST0_IE)
printk("IE "); pr_cont("IE ");
} }
printk("\n"); pr_cont("\n");
exccode = (cause & CAUSEF_EXCCODE) >> CAUSEB_EXCCODE; exccode = (cause & CAUSEF_EXCCODE) >> CAUSEB_EXCCODE;
printk("Cause : %08x (ExcCode %02x)\n", cause, exccode); printk("Cause : %08x (ExcCode %02x)\n", cause, exccode);
...@@ -705,6 +708,32 @@ asmlinkage void do_ov(struct pt_regs *regs) ...@@ -705,6 +708,32 @@ asmlinkage void do_ov(struct pt_regs *regs)
exception_exit(prev_state); 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) int process_fpemu_return(int sig, void __user *fault_addr, unsigned long fcr31)
{ {
struct siginfo si = { 0 }; struct siginfo si = { 0 };
...@@ -715,27 +744,7 @@ int process_fpemu_return(int sig, void __user *fault_addr, unsigned long fcr31) ...@@ -715,27 +744,7 @@ int process_fpemu_return(int sig, void __user *fault_addr, unsigned long fcr31)
return 0; return 0;
case SIGFPE: case SIGFPE:
si.si_addr = fault_addr; force_fcr31_sig(fcr31, fault_addr, current);
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);
return 1; return 1;
case SIGBUS: case SIGBUS:
...@@ -799,13 +808,13 @@ static int simulate_fp(struct pt_regs *regs, unsigned int opcode, ...@@ -799,13 +808,13 @@ static int simulate_fp(struct pt_regs *regs, unsigned int opcode,
/* Run the emulator */ /* Run the emulator */
sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1, sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
&fault_addr); &fault_addr);
fcr31 = current->thread.fpu.fcr31;
/* /*
* We can't allow the emulated instruction to leave any of * We can't allow the emulated instruction to leave any
* the cause bits set in $fcr31. * 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 */ /* Restore the hardware register state */
own_fpu(1); own_fpu(1);
...@@ -831,7 +840,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) ...@@ -831,7 +840,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
goto out; goto out;
/* Clear FCSR.Cause before enabling interrupts */ /* 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(); local_irq_enable();
die_if_kernel("FP exception in kernel code", regs); die_if_kernel("FP exception in kernel code", regs);
...@@ -853,13 +862,13 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) ...@@ -853,13 +862,13 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
/* Run the emulator */ /* Run the emulator */
sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1, sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
&fault_addr); &fault_addr);
fcr31 = current->thread.fpu.fcr31;
/* /*
* We can't allow the emulated instruction to leave any of * We can't allow the emulated instruction to leave any
* the cause bits set in $fcr31. * 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 */ /* Restore the hardware register state */
own_fpu(1); /* Using the FPU again. */ own_fpu(1); /* Using the FPU again. */
...@@ -1424,13 +1433,13 @@ asmlinkage void do_cpu(struct pt_regs *regs) ...@@ -1424,13 +1433,13 @@ asmlinkage void do_cpu(struct pt_regs *regs)
sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 0, sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 0,
&fault_addr); &fault_addr);
fcr31 = current->thread.fpu.fcr31;
/* /*
* We can't allow the emulated instruction to leave * 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. */ /* Send a signal if required. */
if (!process_fpemu_return(sig, fault_addr, fcr31) && !err) if (!process_fpemu_return(sig, fault_addr, fcr31) && !err)
......
...@@ -135,42 +135,42 @@ static void dump_tlb(int first, int last) ...@@ -135,42 +135,42 @@ static void dump_tlb(int first, int last)
c0 = (entrylo0 & ENTRYLO_C) >> ENTRYLO_C_SHIFT; c0 = (entrylo0 & ENTRYLO_C) >> ENTRYLO_C_SHIFT;
c1 = (entrylo1 & ENTRYLO_C) >> ENTRYLO_C_SHIFT; c1 = (entrylo1 & ENTRYLO_C) >> ENTRYLO_C_SHIFT;
printk("va=%0*lx asid=%0*lx", pr_cont("va=%0*lx asid=%0*lx",
vwidth, (entryhi & ~0x1fffUL), vwidth, (entryhi & ~0x1fffUL),
asidwidth, entryhi & asidmask); asidwidth, entryhi & asidmask);
if (cpu_has_guestid) if (cpu_has_guestid)
printk(" gid=%02lx", pr_cont(" gid=%02lx",
(guestctl1 & MIPS_GCTL1_RID) (guestctl1 & MIPS_GCTL1_RID)
>> MIPS_GCTL1_RID_SHIFT); >> MIPS_GCTL1_RID_SHIFT);
/* RI/XI are in awkward places, so mask them off separately */ /* RI/XI are in awkward places, so mask them off separately */
pa = entrylo0 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI); pa = entrylo0 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI);
if (xpa) if (xpa)
pa |= (unsigned long long)readx_c0_entrylo0() << 30; pa |= (unsigned long long)readx_c0_entrylo0() << 30;
pa = (pa << 6) & PAGE_MASK; pa = (pa << 6) & PAGE_MASK;
printk("\n\t["); pr_cont("\n\t[");
if (cpu_has_rixi) if (cpu_has_rixi)
printk("ri=%d xi=%d ", pr_cont("ri=%d xi=%d ",
(entrylo0 & MIPS_ENTRYLO_RI) ? 1 : 0, (entrylo0 & MIPS_ENTRYLO_RI) ? 1 : 0,
(entrylo0 & MIPS_ENTRYLO_XI) ? 1 : 0); (entrylo0 & MIPS_ENTRYLO_XI) ? 1 : 0);
printk("pa=%0*llx c=%d d=%d v=%d g=%d] [", pr_cont("pa=%0*llx c=%d d=%d v=%d g=%d] [",
pwidth, pa, c0, pwidth, pa, c0,
(entrylo0 & ENTRYLO_D) ? 1 : 0, (entrylo0 & ENTRYLO_D) ? 1 : 0,
(entrylo0 & ENTRYLO_V) ? 1 : 0, (entrylo0 & ENTRYLO_V) ? 1 : 0,
(entrylo0 & ENTRYLO_G) ? 1 : 0); (entrylo0 & ENTRYLO_G) ? 1 : 0);
/* RI/XI are in awkward places, so mask them off separately */ /* RI/XI are in awkward places, so mask them off separately */
pa = entrylo1 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI); pa = entrylo1 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI);
if (xpa) if (xpa)
pa |= (unsigned long long)readx_c0_entrylo1() << 30; pa |= (unsigned long long)readx_c0_entrylo1() << 30;
pa = (pa << 6) & PAGE_MASK; pa = (pa << 6) & PAGE_MASK;
if (cpu_has_rixi) if (cpu_has_rixi)
printk("ri=%d xi=%d ", pr_cont("ri=%d xi=%d ",
(entrylo1 & MIPS_ENTRYLO_RI) ? 1 : 0, (entrylo1 & MIPS_ENTRYLO_RI) ? 1 : 0,
(entrylo1 & MIPS_ENTRYLO_XI) ? 1 : 0); (entrylo1 & MIPS_ENTRYLO_XI) ? 1 : 0);
printk("pa=%0*llx c=%d d=%d v=%d g=%d]\n", pr_cont("pa=%0*llx c=%d d=%d v=%d g=%d]\n",
pwidth, pa, c1, pwidth, pa, c1,
(entrylo1 & ENTRYLO_D) ? 1 : 0, (entrylo1 & ENTRYLO_D) ? 1 : 0,
(entrylo1 & ENTRYLO_V) ? 1 : 0, (entrylo1 & ENTRYLO_V) ? 1 : 0,
(entrylo1 & ENTRYLO_G) ? 1 : 0); (entrylo1 & ENTRYLO_G) ? 1 : 0);
} }
printk("\n"); printk("\n");
......
...@@ -53,15 +53,15 @@ static void dump_tlb(int first, int last) ...@@ -53,15 +53,15 @@ static void dump_tlb(int first, int last)
*/ */
printk("Index: %2d ", i); printk("Index: %2d ", i);
printk("va=%08lx asid=%08lx" pr_cont("va=%08lx asid=%08lx"
" [pa=%06lx n=%d d=%d v=%d g=%d]", " [pa=%06lx n=%d d=%d v=%d g=%d]",
entryhi & PAGE_MASK, entryhi & PAGE_MASK,
entryhi & asid_mask, entryhi & asid_mask,
entrylo0 & PAGE_MASK, entrylo0 & PAGE_MASK,
(entrylo0 & R3K_ENTRYLO_N) ? 1 : 0, (entrylo0 & R3K_ENTRYLO_N) ? 1 : 0,
(entrylo0 & R3K_ENTRYLO_D) ? 1 : 0, (entrylo0 & R3K_ENTRYLO_D) ? 1 : 0,
(entrylo0 & R3K_ENTRYLO_V) ? 1 : 0, (entrylo0 & R3K_ENTRYLO_V) ? 1 : 0,
(entrylo0 & R3K_ENTRYLO_G) ? 1 : 0); (entrylo0 & R3K_ENTRYLO_G) ? 1 : 0);
} }
} }
printk("\n"); printk("\n");
......
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