|
1 /* |
|
2 * PowerPC emulation special registers manipulation helpers for qemu. |
|
3 * |
|
4 * Copyright (c) 2003-2007 Jocelyn Mayer |
|
5 * |
|
6 * This library is free software; you can redistribute it and/or |
|
7 * modify it under the terms of the GNU Lesser General Public |
|
8 * License as published by the Free Software Foundation; either |
|
9 * version 2 of the License, or (at your option) any later version. |
|
10 * |
|
11 * This library is distributed in the hope that it will be useful, |
|
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
14 * Lesser General Public License for more details. |
|
15 * |
|
16 * You should have received a copy of the GNU Lesser General Public |
|
17 * License along with this library; if not, write to the Free Software |
|
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
19 */ |
|
20 |
|
21 #if !defined(__HELPER_REGS_H__) |
|
22 #define __HELPER_REGS_H__ |
|
23 |
|
24 /* Swap temporary saved registers with GPRs */ |
|
25 static always_inline void hreg_swap_gpr_tgpr (CPUPPCState *env) |
|
26 { |
|
27 target_ulong tmp; |
|
28 |
|
29 tmp = env->gpr[0]; |
|
30 env->gpr[0] = env->tgpr[0]; |
|
31 env->tgpr[0] = tmp; |
|
32 tmp = env->gpr[1]; |
|
33 env->gpr[1] = env->tgpr[1]; |
|
34 env->tgpr[1] = tmp; |
|
35 tmp = env->gpr[2]; |
|
36 env->gpr[2] = env->tgpr[2]; |
|
37 env->tgpr[2] = tmp; |
|
38 tmp = env->gpr[3]; |
|
39 env->gpr[3] = env->tgpr[3]; |
|
40 env->tgpr[3] = tmp; |
|
41 } |
|
42 |
|
43 static always_inline void hreg_compute_mem_idx (CPUPPCState *env) |
|
44 { |
|
45 /* Precompute MMU index */ |
|
46 if (msr_pr == 0 && msr_hv != 0) { |
|
47 env->mmu_idx = 2; |
|
48 } else { |
|
49 env->mmu_idx = 1 - msr_pr; |
|
50 } |
|
51 } |
|
52 |
|
53 static always_inline void hreg_compute_hflags (CPUPPCState *env) |
|
54 { |
|
55 target_ulong hflags_mask; |
|
56 |
|
57 /* We 'forget' FE0 & FE1: we'll never generate imprecise exceptions */ |
|
58 hflags_mask = (1 << MSR_VR) | (1 << MSR_AP) | (1 << MSR_SA) | |
|
59 (1 << MSR_PR) | (1 << MSR_FP) | (1 << MSR_SE) | (1 << MSR_BE) | |
|
60 (1 << MSR_LE); |
|
61 hflags_mask |= (1ULL << MSR_CM) | (1ULL << MSR_SF) | MSR_HVB; |
|
62 hreg_compute_mem_idx(env); |
|
63 env->hflags = env->msr & hflags_mask; |
|
64 /* Merge with hflags coming from other registers */ |
|
65 env->hflags |= env->hflags_nmsr; |
|
66 } |
|
67 |
|
68 static always_inline int hreg_store_msr (CPUPPCState *env, target_ulong value, |
|
69 int alter_hv) |
|
70 { |
|
71 int excp; |
|
72 |
|
73 excp = 0; |
|
74 value &= env->msr_mask; |
|
75 #if !defined (CONFIG_USER_ONLY) |
|
76 if (!alter_hv) { |
|
77 /* mtmsr cannot alter the hypervisor state */ |
|
78 value &= ~MSR_HVB; |
|
79 value |= env->msr & MSR_HVB; |
|
80 } |
|
81 if (((value >> MSR_IR) & 1) != msr_ir || |
|
82 ((value >> MSR_DR) & 1) != msr_dr) { |
|
83 /* Flush all tlb when changing translation mode */ |
|
84 tlb_flush(env, 1); |
|
85 excp = POWERPC_EXCP_NONE; |
|
86 env->interrupt_request |= CPU_INTERRUPT_EXITTB; |
|
87 } |
|
88 if (unlikely((env->flags & POWERPC_FLAG_TGPR) && |
|
89 ((value ^ env->msr) & (1 << MSR_TGPR)))) { |
|
90 /* Swap temporary saved registers with GPRs */ |
|
91 hreg_swap_gpr_tgpr(env); |
|
92 } |
|
93 if (unlikely((value >> MSR_EP) & 1) != msr_ep) { |
|
94 /* Change the exception prefix on PowerPC 601 */ |
|
95 env->excp_prefix = ((value >> MSR_EP) & 1) * 0xFFF00000; |
|
96 } |
|
97 #endif |
|
98 env->msr = value; |
|
99 hreg_compute_hflags(env); |
|
100 #if !defined (CONFIG_USER_ONLY) |
|
101 if (unlikely(msr_pow == 1)) { |
|
102 if ((*env->check_pow)(env)) { |
|
103 env->halted = 1; |
|
104 excp = EXCP_HALTED; |
|
105 } |
|
106 } |
|
107 #endif |
|
108 |
|
109 return excp; |
|
110 } |
|
111 |
|
112 #endif /* !defined(__HELPER_REGS_H__) */ |