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 /arch/mips/math-emu/cp1emu.c | |
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>
Diffstat (limited to 'arch/mips/math-emu/cp1emu.c')
-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) |