diff options
Diffstat (limited to 'arch/loongarch/kernel/unaligned.c')
| -rw-r--r-- | arch/loongarch/kernel/unaligned.c | 30 |
1 files changed, 24 insertions, 6 deletions
diff --git a/arch/loongarch/kernel/unaligned.c b/arch/loongarch/kernel/unaligned.c index 487be604b96a..cc929c9fe7e9 100644 --- a/arch/loongarch/kernel/unaligned.c +++ b/arch/loongarch/kernel/unaligned.c @@ -27,12 +27,21 @@ static u32 unaligned_instructions_user; static u32 unaligned_instructions_kernel; #endif -static inline unsigned long read_fpr(unsigned int idx) +static inline u64 read_fpr(unsigned int idx) { +#ifdef CONFIG_64BIT #define READ_FPR(idx, __value) \ __asm__ __volatile__("movfr2gr.d %0, $f"#idx"\n\t" : "=r"(__value)); - - unsigned long __value; +#else +#define READ_FPR(idx, __value) \ +{ \ + u32 __value_lo, __value_hi; \ + __asm__ __volatile__("movfr2gr.s %0, $f"#idx"\n\t" : "=r"(__value_lo)); \ + __asm__ __volatile__("movfrh2gr.s %0, $f"#idx"\n\t" : "=r"(__value_hi)); \ + __value = (__value_lo | ((u64)__value_hi << 32)); \ +} +#endif + u64 __value; switch (idx) { case 0: @@ -138,11 +147,20 @@ static inline unsigned long read_fpr(unsigned int idx) return __value; } -static inline void write_fpr(unsigned int idx, unsigned long value) +static inline void write_fpr(unsigned int idx, u64 value) { +#ifdef CONFIG_64BIT #define WRITE_FPR(idx, value) \ __asm__ __volatile__("movgr2fr.d $f"#idx", %0\n\t" :: "r"(value)); - +#else +#define WRITE_FPR(idx, value) \ +{ \ + u32 value_lo = value; \ + u32 value_hi = value >> 32; \ + __asm__ __volatile__("movgr2fr.w $f"#idx", %0\n\t" :: "r"(value_lo)); \ + __asm__ __volatile__("movgr2frh.w $f"#idx", %0\n\t" :: "r"(value_hi)); \ +} +#endif switch (idx) { case 0: WRITE_FPR(0, value); @@ -252,7 +270,7 @@ void emulate_load_store_insn(struct pt_regs *regs, void __user *addr, unsigned i bool sign, write; bool user = user_mode(regs); unsigned int res, size = 0; - unsigned long value = 0; + u64 value = 0; union loongarch_instruction insn; perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0); |
