root / target-ppc / mmu-hash64.c @ 10b46525
History | View | Annotate | Download (5.6 kB)
1 |
/*
|
---|---|
2 |
* PowerPC MMU, TLB, SLB and BAT emulation helpers for QEMU.
|
3 |
*
|
4 |
* Copyright (c) 2003-2007 Jocelyn Mayer
|
5 |
* Copyright (c) 2013 David Gibson, IBM Corporation
|
6 |
*
|
7 |
* This library is free software; you can redistribute it and/or
|
8 |
* modify it under the terms of the GNU Lesser General Public
|
9 |
* License as published by the Free Software Foundation; either
|
10 |
* version 2 of the License, or (at your option) any later version.
|
11 |
*
|
12 |
* This library is distributed in the hope that it will be useful,
|
13 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
15 |
* Lesser General Public License for more details.
|
16 |
*
|
17 |
* You should have received a copy of the GNU Lesser General Public
|
18 |
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
19 |
*/
|
20 |
#include "cpu.h" |
21 |
#include "helper.h" |
22 |
#include "sysemu/kvm.h" |
23 |
#include "kvm_ppc.h" |
24 |
#include "mmu-hash64.h" |
25 |
|
26 |
//#define DEBUG_SLB
|
27 |
|
28 |
#ifdef DEBUG_SLB
|
29 |
# define LOG_SLB(...) qemu_log(__VA_ARGS__)
|
30 |
#else
|
31 |
# define LOG_SLB(...) do { } while (0) |
32 |
#endif
|
33 |
|
34 |
/*
|
35 |
* SLB handling
|
36 |
*/
|
37 |
|
38 |
ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr) |
39 |
{ |
40 |
uint64_t esid_256M, esid_1T; |
41 |
int n;
|
42 |
|
43 |
LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr); |
44 |
|
45 |
esid_256M = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V; |
46 |
esid_1T = (eaddr & SEGMENT_MASK_1T) | SLB_ESID_V; |
47 |
|
48 |
for (n = 0; n < env->slb_nr; n++) { |
49 |
ppc_slb_t *slb = &env->slb[n]; |
50 |
|
51 |
LOG_SLB("%s: slot %d %016" PRIx64 " %016" |
52 |
PRIx64 "\n", __func__, n, slb->esid, slb->vsid);
|
53 |
/* We check for 1T matches on all MMUs here - if the MMU
|
54 |
* doesn't have 1T segment support, we will have prevented 1T
|
55 |
* entries from being inserted in the slbmte code. */
|
56 |
if (((slb->esid == esid_256M) &&
|
57 |
((slb->vsid & SLB_VSID_B) == SLB_VSID_B_256M)) |
58 |
|| ((slb->esid == esid_1T) && |
59 |
((slb->vsid & SLB_VSID_B) == SLB_VSID_B_1T))) { |
60 |
return slb;
|
61 |
} |
62 |
} |
63 |
|
64 |
return NULL; |
65 |
} |
66 |
|
67 |
void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
|
68 |
{ |
69 |
int i;
|
70 |
uint64_t slbe, slbv; |
71 |
|
72 |
cpu_synchronize_state(env); |
73 |
|
74 |
cpu_fprintf(f, "SLB\tESID\t\t\tVSID\n");
|
75 |
for (i = 0; i < env->slb_nr; i++) { |
76 |
slbe = env->slb[i].esid; |
77 |
slbv = env->slb[i].vsid; |
78 |
if (slbe == 0 && slbv == 0) { |
79 |
continue;
|
80 |
} |
81 |
cpu_fprintf(f, "%d\t0x%016" PRIx64 "\t0x%016" PRIx64 "\n", |
82 |
i, slbe, slbv); |
83 |
} |
84 |
} |
85 |
|
86 |
void helper_slbia(CPUPPCState *env)
|
87 |
{ |
88 |
int n, do_invalidate;
|
89 |
|
90 |
do_invalidate = 0;
|
91 |
/* XXX: Warning: slbia never invalidates the first segment */
|
92 |
for (n = 1; n < env->slb_nr; n++) { |
93 |
ppc_slb_t *slb = &env->slb[n]; |
94 |
|
95 |
if (slb->esid & SLB_ESID_V) {
|
96 |
slb->esid &= ~SLB_ESID_V; |
97 |
/* XXX: given the fact that segment size is 256 MB or 1TB,
|
98 |
* and we still don't have a tlb_flush_mask(env, n, mask)
|
99 |
* in QEMU, we just invalidate all TLBs
|
100 |
*/
|
101 |
do_invalidate = 1;
|
102 |
} |
103 |
} |
104 |
if (do_invalidate) {
|
105 |
tlb_flush(env, 1);
|
106 |
} |
107 |
} |
108 |
|
109 |
void helper_slbie(CPUPPCState *env, target_ulong addr)
|
110 |
{ |
111 |
ppc_slb_t *slb; |
112 |
|
113 |
slb = slb_lookup(env, addr); |
114 |
if (!slb) {
|
115 |
return;
|
116 |
} |
117 |
|
118 |
if (slb->esid & SLB_ESID_V) {
|
119 |
slb->esid &= ~SLB_ESID_V; |
120 |
|
121 |
/* XXX: given the fact that segment size is 256 MB or 1TB,
|
122 |
* and we still don't have a tlb_flush_mask(env, n, mask)
|
123 |
* in QEMU, we just invalidate all TLBs
|
124 |
*/
|
125 |
tlb_flush(env, 1);
|
126 |
} |
127 |
} |
128 |
|
129 |
int ppc_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
|
130 |
{ |
131 |
int slot = rb & 0xfff; |
132 |
ppc_slb_t *slb = &env->slb[slot]; |
133 |
|
134 |
if (rb & (0x1000 - env->slb_nr)) { |
135 |
return -1; /* Reserved bits set or slot too high */ |
136 |
} |
137 |
if (rs & (SLB_VSID_B & ~SLB_VSID_B_1T)) {
|
138 |
return -1; /* Bad segment size */ |
139 |
} |
140 |
if ((rs & SLB_VSID_B) && !(env->mmu_model & POWERPC_MMU_1TSEG)) {
|
141 |
return -1; /* 1T segment on MMU that doesn't support it */ |
142 |
} |
143 |
|
144 |
/* Mask out the slot number as we store the entry */
|
145 |
slb->esid = rb & (SLB_ESID_ESID | SLB_ESID_V); |
146 |
slb->vsid = rs; |
147 |
|
148 |
LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64 |
149 |
" %016" PRIx64 "\n", __func__, slot, rb, rs, |
150 |
slb->esid, slb->vsid); |
151 |
|
152 |
return 0; |
153 |
} |
154 |
|
155 |
static int ppc_load_slb_esid(CPUPPCState *env, target_ulong rb, |
156 |
target_ulong *rt) |
157 |
{ |
158 |
int slot = rb & 0xfff; |
159 |
ppc_slb_t *slb = &env->slb[slot]; |
160 |
|
161 |
if (slot >= env->slb_nr) {
|
162 |
return -1; |
163 |
} |
164 |
|
165 |
*rt = slb->esid; |
166 |
return 0; |
167 |
} |
168 |
|
169 |
static int ppc_load_slb_vsid(CPUPPCState *env, target_ulong rb, |
170 |
target_ulong *rt) |
171 |
{ |
172 |
int slot = rb & 0xfff; |
173 |
ppc_slb_t *slb = &env->slb[slot]; |
174 |
|
175 |
if (slot >= env->slb_nr) {
|
176 |
return -1; |
177 |
} |
178 |
|
179 |
*rt = slb->vsid; |
180 |
return 0; |
181 |
} |
182 |
|
183 |
void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
|
184 |
{ |
185 |
if (ppc_store_slb(env, rb, rs) < 0) { |
186 |
helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, |
187 |
POWERPC_EXCP_INVAL); |
188 |
} |
189 |
} |
190 |
|
191 |
target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb) |
192 |
{ |
193 |
target_ulong rt = 0;
|
194 |
|
195 |
if (ppc_load_slb_esid(env, rb, &rt) < 0) { |
196 |
helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, |
197 |
POWERPC_EXCP_INVAL); |
198 |
} |
199 |
return rt;
|
200 |
} |
201 |
|
202 |
target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb) |
203 |
{ |
204 |
target_ulong rt = 0;
|
205 |
|
206 |
if (ppc_load_slb_vsid(env, rb, &rt) < 0) { |
207 |
helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, |
208 |
POWERPC_EXCP_INVAL); |
209 |
} |
210 |
return rt;
|
211 |
} |