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:
David Daney 2009-11-02 11:33:46 -08:00 committed by Ralf Baechle
parent 156171c71a
commit da0bac3341

View file

@ -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)