diff options
| author | David Daney <ddaney@caviumnetworks.com> | 2009-11-02 14:33:46 -0500 |
|---|---|---|
| committer | Ralf Baechle <ralf@linux-mips.org> | 2009-11-13 12:10:37 -0500 |
| commit | da0bac33413b2888d3623dad3ad19ce76b688f07 (patch) | |
| tree | 6d95ce81145b0a11868dd38f5571f58d9d8a79e6 | |
| parent | 156171c71a0dc4bce12b4408bb1591f8fe32dc1a (diff) | |
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>
| -rw-r--r-- | arch/mips/math-emu/cp1emu.c | 41 |
1 files changed, 21 insertions, 20 deletions
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 890f77927d62..454b53924490 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c | |||
| @@ -163,33 +163,34 @@ static int isBranchInstr(mips_instruction * i) | |||
| 163 | 163 | ||
| 164 | /* | 164 | /* |
| 165 | * In the Linux kernel, we support selection of FPR format on the | 165 | * In the Linux kernel, we support selection of FPR format on the |
| 166 | * basis of the Status.FR bit. This does imply that, if a full 32 | 166 | * basis of the Status.FR bit. If an FPU is not present, the FR bit |
| 167 | * FPRs are desired, there needs to be a flip-flop that can be written | 167 | * is hardwired to zero, which would imply a 32-bit FPU even for |
| 168 | * to one at that bit position. In any case, O32 MIPS ABI uses | 168 | * 64-bit CPUs. For 64-bit kernels with no FPU we use TIF_32BIT_REGS |
| 169 | * only the even FPRs (Status.FR = 0). | 169 | * as a proxy for the FR bit so that a 64-bit FPU is emulated. In any |
| 170 | * case, for a 32-bit kernel which uses the O32 MIPS ABI, only the | ||
| 171 | * even FPRs are used (Status.FR = 0). | ||
| 170 | */ | 172 | */ |
| 171 | 173 | static inline int cop1_64bit(struct pt_regs *xcp) | |
| 172 | #define CP0_STATUS_FR_SUPPORT | 174 | { |
| 173 | 175 | if (cpu_has_fpu) | |
| 174 | #ifdef CP0_STATUS_FR_SUPPORT | 176 | return xcp->cp0_status & ST0_FR; |
| 175 | #define FR_BIT ST0_FR | 177 | #ifdef CONFIG_64BIT |
| 178 | return !test_thread_flag(TIF_32BIT_REGS); | ||
| 176 | #else | 179 | #else |
| 177 | #define FR_BIT 0 | 180 | return 0; |
| 178 | #endif | 181 | #endif |
| 182 | } | ||
| 183 | |||
| 184 | #define SIFROMREG(si, x) ((si) = cop1_64bit(xcp) || !(x & 1) ? \ | ||
| 185 | (int)ctx->fpr[x] : (int)(ctx->fpr[x & ~1] >> 32)) | ||
| 179 | 186 | ||
| 180 | #define SIFROMREG(si, x) ((si) = \ | 187 | #define SITOREG(si, x) (ctx->fpr[x & ~(cop1_64bit(xcp) == 0)] = \ |
| 181 | (xcp->cp0_status & FR_BIT) || !(x & 1) ? \ | 188 | cop1_64bit(xcp) || !(x & 1) ? \ |
| 182 | (int)ctx->fpr[x] : \ | ||
| 183 | (int)(ctx->fpr[x & ~1] >> 32 )) | ||
| 184 | #define SITOREG(si, x) (ctx->fpr[x & ~((xcp->cp0_status & FR_BIT) == 0)] = \ | ||
| 185 | (xcp->cp0_status & FR_BIT) || !(x & 1) ? \ | ||
| 186 | ctx->fpr[x & ~1] >> 32 << 32 | (u32)(si) : \ | 189 | ctx->fpr[x & ~1] >> 32 << 32 | (u32)(si) : \ |
| 187 | ctx->fpr[x & ~1] << 32 >> 32 | (u64)(si) << 32) | 190 | ctx->fpr[x & ~1] << 32 >> 32 | (u64)(si) << 32) |
| 188 | 191 | ||
| 189 | #define DIFROMREG(di, x) ((di) = \ | 192 | #define DIFROMREG(di, x) ((di) = ctx->fpr[x & ~(cop1_64bit(xcp) == 0)]) |
| 190 | ctx->fpr[x & ~((xcp->cp0_status & FR_BIT) == 0)]) | 193 | #define DITOREG(di, x) (ctx->fpr[x & ~(cop1_64bit(xcp) == 0)] = (di)) |
| 191 | #define DITOREG(di, x) (ctx->fpr[x & ~((xcp->cp0_status & FR_BIT) == 0)] \ | ||
| 192 | = (di)) | ||
| 193 | 194 | ||
| 194 | #define SPFROMREG(sp, x) SIFROMREG((sp).bits, x) | 195 | #define SPFROMREG(sp, x) SIFROMREG((sp).bits, x) |
| 195 | #define SPTOREG(sp, x) SITOREG((sp).bits, x) | 196 | #define SPTOREG(sp, x) SITOREG((sp).bits, x) |
