mirror of
https://github.com/torvalds/linux
synced 2024-09-06 18:01:05 +00:00
MIPS: Fix emulation of 64-bit FPU on FPU-less 64-bit CPUs.
Running a 64-bit kernel on a 64-bit CPU without an FPU would cause the emulator to run in 32-bit mode. The c0_Status.FR bit is wired to zero on systems without an FPU, so using that bit to decide how the emulator behaves doesn't allow for proper emulation on 64-bit FPU-less processors. Instead, we need to select the emulator mode based on the user-space ABI. Since the thread flag TIF_32BIT_REGS is used to set c0_Status.FR, we can just use it to decide if the emulator should be in 32-bit or 64-bit mode. Signed-off-by: David Daney <ddaney@caviumnetworks.com> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
parent
156171c71a
commit
da0bac3341
|
@ -163,33 +163,34 @@ static int isBranchInstr(mips_instruction * i)
|
|||
|
||||
/*
|
||||
* In the Linux kernel, we support selection of FPR format on the
|
||||
* basis of the Status.FR bit. This does imply that, if a full 32
|
||||
* FPRs are desired, there needs to be a flip-flop that can be written
|
||||
* to one at that bit position. In any case, O32 MIPS ABI uses
|
||||
* only the even FPRs (Status.FR = 0).
|
||||
* basis of the Status.FR bit. If an FPU is not present, the FR bit
|
||||
* is hardwired to zero, which would imply a 32-bit FPU even for
|
||||
* 64-bit CPUs. For 64-bit kernels with no FPU we use TIF_32BIT_REGS
|
||||
* as a proxy for the FR bit so that a 64-bit FPU is emulated. In any
|
||||
* case, for a 32-bit kernel which uses the O32 MIPS ABI, only the
|
||||
* even FPRs are used (Status.FR = 0).
|
||||
*/
|
||||
|
||||
#define CP0_STATUS_FR_SUPPORT
|
||||
|
||||
#ifdef CP0_STATUS_FR_SUPPORT
|
||||
#define FR_BIT ST0_FR
|
||||
static inline int cop1_64bit(struct pt_regs *xcp)
|
||||
{
|
||||
if (cpu_has_fpu)
|
||||
return xcp->cp0_status & ST0_FR;
|
||||
#ifdef CONFIG_64BIT
|
||||
return !test_thread_flag(TIF_32BIT_REGS);
|
||||
#else
|
||||
#define FR_BIT 0
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define SIFROMREG(si, x) ((si) = \
|
||||
(xcp->cp0_status & FR_BIT) || !(x & 1) ? \
|
||||
(int)ctx->fpr[x] : \
|
||||
(int)(ctx->fpr[x & ~1] >> 32 ))
|
||||
#define SITOREG(si, x) (ctx->fpr[x & ~((xcp->cp0_status & FR_BIT) == 0)] = \
|
||||
(xcp->cp0_status & FR_BIT) || !(x & 1) ? \
|
||||
#define SIFROMREG(si, x) ((si) = cop1_64bit(xcp) || !(x & 1) ? \
|
||||
(int)ctx->fpr[x] : (int)(ctx->fpr[x & ~1] >> 32))
|
||||
|
||||
#define SITOREG(si, x) (ctx->fpr[x & ~(cop1_64bit(xcp) == 0)] = \
|
||||
cop1_64bit(xcp) || !(x & 1) ? \
|
||||
ctx->fpr[x & ~1] >> 32 << 32 | (u32)(si) : \
|
||||
ctx->fpr[x & ~1] << 32 >> 32 | (u64)(si) << 32)
|
||||
|
||||
#define DIFROMREG(di, x) ((di) = \
|
||||
ctx->fpr[x & ~((xcp->cp0_status & FR_BIT) == 0)])
|
||||
#define DITOREG(di, x) (ctx->fpr[x & ~((xcp->cp0_status & FR_BIT) == 0)] \
|
||||
= (di))
|
||||
#define DIFROMREG(di, x) ((di) = ctx->fpr[x & ~(cop1_64bit(xcp) == 0)])
|
||||
#define DITOREG(di, x) (ctx->fpr[x & ~(cop1_64bit(xcp) == 0)] = (di))
|
||||
|
||||
#define SPFROMREG(sp, x) SIFROMREG((sp).bits, x)
|
||||
#define SPTOREG(sp, x) SITOREG((sp).bits, x)
|
||||
|
|
Loading…
Reference in a new issue