2 * MIPS TLB (Translation lookaside buffer) helpers.
4 * Copyright (c) 2004-2005 Jocelyn Mayer
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.1 of the License, or (at your option) any later version.
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.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 #include "qemu/osdep.h"
21 #include "exec/exec-all.h"
22 #include "../internal.h"
24 static int is_seg_am_mapped(unsigned int am
, bool eu
, int mmu_idx
)
27 * Interpret access control mode and mmu_idx.
30 * UK 0 0 1 1 0 0 - - 0
31 * MK 1 0 1 1 0 1 - - !eu
32 * MSK 2 0 0 1 0 1 1 - !eu
33 * MUSK 3 0 0 0 0 1 1 1 !eu
34 * MUSUK 4 0 0 0 0 0 1 1 0
35 * USK 5 0 0 1 0 0 0 - 0
37 * UUSK 7 0 0 0 0 0 0 0 0
43 /* If EU is set, always unmapped */
49 /* Never AdE, TLB mapped if AM={1,2,3} */
50 adetlb_mask
= 0x70000000;
54 /* AdE if AM={0,1}, TLB mapped if AM={2,3,4} */
55 adetlb_mask
= 0xc0380000;
59 /* AdE if AM={0,1,2,5}, TLB mapped if AM={3,4} */
60 adetlb_mask
= 0xe4180000;
63 /* does this AM cause AdE in current execution mode */
64 if ((adetlb_mask
<< am
) < 0) {
65 return TLBRET_BADADDR
;
70 /* is this AM mapped in current execution mode */
71 return ((adetlb_mask
<< am
) < 0);
74 return TLBRET_BADADDR
;
78 static int get_seg_physical_address(CPUMIPSState
*env
, hwaddr
*physical
,
79 int *prot
, target_ulong real_address
,
80 MMUAccessType access_type
, int mmu_idx
,
81 unsigned int am
, bool eu
,
85 int mapped
= is_seg_am_mapped(am
, eu
, mmu_idx
);
88 /* is_seg_am_mapped can report TLBRET_BADADDR */
91 /* The segment is TLB mapped */
92 return env
->tlb
->map_address(env
, physical
, prot
, real_address
,
95 /* The segment is unmapped */
96 *physical
= physical_base
| (real_address
& segmask
);
97 *prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
102 static int get_segctl_physical_address(CPUMIPSState
*env
, hwaddr
*physical
,
103 int *prot
, target_ulong real_address
,
104 MMUAccessType access_type
, int mmu_idx
,
105 uint16_t segctl
, target_ulong segmask
)
107 unsigned int am
= (segctl
& CP0SC_AM_MASK
) >> CP0SC_AM
;
108 bool eu
= (segctl
>> CP0SC_EU
) & 1;
109 hwaddr pa
= ((hwaddr
)segctl
& CP0SC_PA_MASK
) << 20;
111 return get_seg_physical_address(env
, physical
, prot
, real_address
,
112 access_type
, mmu_idx
, am
, eu
, segmask
,
113 pa
& ~(hwaddr
)segmask
);
116 int get_physical_address(CPUMIPSState
*env
, hwaddr
*physical
,
117 int *prot
, target_ulong real_address
,
118 MMUAccessType access_type
, int mmu_idx
)
120 /* User mode can only access useg/xuseg */
121 #if defined(TARGET_MIPS64)
122 int user_mode
= mmu_idx
== MIPS_HFLAG_UM
;
123 int supervisor_mode
= mmu_idx
== MIPS_HFLAG_SM
;
124 int kernel_mode
= !user_mode
&& !supervisor_mode
;
125 int UX
= (env
->CP0_Status
& (1 << CP0St_UX
)) != 0;
126 int SX
= (env
->CP0_Status
& (1 << CP0St_SX
)) != 0;
127 int KX
= (env
->CP0_Status
& (1 << CP0St_KX
)) != 0;
129 int ret
= TLBRET_MATCH
;
130 /* effective address (modified for KVM T&E kernel segments) */
131 target_ulong address
= real_address
;
133 if (mips_um_ksegs_enabled()) {
134 /* KVM T&E adds guest kernel segments in useg */
135 if (real_address
>= KVM_KSEG0_BASE
) {
136 if (real_address
< KVM_KSEG2_BASE
) {
138 address
+= KSEG0_BASE
- KVM_KSEG0_BASE
;
139 } else if (real_address
<= USEG_LIMIT
) {
141 address
+= KSEG2_BASE
- KVM_KSEG2_BASE
;
146 if (address
<= USEG_LIMIT
) {
150 if (address
>= 0x40000000UL
) {
151 segctl
= env
->CP0_SegCtl2
;
153 segctl
= env
->CP0_SegCtl2
>> 16;
155 ret
= get_segctl_physical_address(env
, physical
, prot
,
156 real_address
, access_type
,
157 mmu_idx
, segctl
, 0x3FFFFFFF);
158 #if defined(TARGET_MIPS64)
159 } else if (address
< 0x4000000000000000ULL
) {
161 if (UX
&& address
<= (0x3FFFFFFFFFFFFFFFULL
& env
->SEGMask
)) {
162 ret
= env
->tlb
->map_address(env
, physical
, prot
,
163 real_address
, access_type
);
165 ret
= TLBRET_BADADDR
;
167 } else if (address
< 0x8000000000000000ULL
) {
169 if ((supervisor_mode
|| kernel_mode
) &&
170 SX
&& address
<= (0x7FFFFFFFFFFFFFFFULL
& env
->SEGMask
)) {
171 ret
= env
->tlb
->map_address(env
, physical
, prot
,
172 real_address
, access_type
);
174 ret
= TLBRET_BADADDR
;
176 } else if (address
< 0xC000000000000000ULL
) {
178 if ((address
& 0x07FFFFFFFFFFFFFFULL
) <= env
->PAMask
) {
179 /* KX/SX/UX bit to check for each xkphys EVA access mode */
180 static const uint8_t am_ksux
[8] = {
181 [CP0SC_AM_UK
] = (1u << CP0St_KX
),
182 [CP0SC_AM_MK
] = (1u << CP0St_KX
),
183 [CP0SC_AM_MSK
] = (1u << CP0St_SX
),
184 [CP0SC_AM_MUSK
] = (1u << CP0St_UX
),
185 [CP0SC_AM_MUSUK
] = (1u << CP0St_UX
),
186 [CP0SC_AM_USK
] = (1u << CP0St_SX
),
187 [6] = (1u << CP0St_KX
),
188 [CP0SC_AM_UUSK
] = (1u << CP0St_UX
),
190 unsigned int am
= CP0SC_AM_UK
;
191 unsigned int xr
= (env
->CP0_SegCtl2
& CP0SC2_XR_MASK
) >> CP0SC2_XR
;
193 if (xr
& (1 << ((address
>> 59) & 0x7))) {
194 am
= (env
->CP0_SegCtl1
& CP0SC1_XAM_MASK
) >> CP0SC1_XAM
;
196 /* Does CP0_Status.KX/SX/UX permit the access mode (am) */
197 if (env
->CP0_Status
& am_ksux
[am
]) {
198 ret
= get_seg_physical_address(env
, physical
, prot
,
199 real_address
, access_type
,
200 mmu_idx
, am
, false, env
->PAMask
,
203 ret
= TLBRET_BADADDR
;
206 ret
= TLBRET_BADADDR
;
208 } else if (address
< 0xFFFFFFFF80000000ULL
) {
210 if (kernel_mode
&& KX
&&
211 address
<= (0xFFFFFFFF7FFFFFFFULL
& env
->SEGMask
)) {
212 ret
= env
->tlb
->map_address(env
, physical
, prot
,
213 real_address
, access_type
);
215 ret
= TLBRET_BADADDR
;
218 } else if (address
< KSEG1_BASE
) {
220 ret
= get_segctl_physical_address(env
, physical
, prot
, real_address
,
221 access_type
, mmu_idx
,
222 env
->CP0_SegCtl1
>> 16, 0x1FFFFFFF);
223 } else if (address
< KSEG2_BASE
) {
225 ret
= get_segctl_physical_address(env
, physical
, prot
, real_address
,
226 access_type
, mmu_idx
,
227 env
->CP0_SegCtl1
, 0x1FFFFFFF);
228 } else if (address
< KSEG3_BASE
) {
230 ret
= get_segctl_physical_address(env
, physical
, prot
, real_address
,
231 access_type
, mmu_idx
,
232 env
->CP0_SegCtl0
>> 16, 0x1FFFFFFF);
236 * XXX: debug segment is not emulated
238 ret
= get_segctl_physical_address(env
, physical
, prot
, real_address
,
239 access_type
, mmu_idx
,
240 env
->CP0_SegCtl0
, 0x1FFFFFFF);
245 hwaddr
mips_cpu_get_phys_page_debug(CPUState
*cs
, vaddr addr
)
247 MIPSCPU
*cpu
= MIPS_CPU(cs
);
248 CPUMIPSState
*env
= &cpu
->env
;
252 if (get_physical_address(env
, &phys_addr
, &prot
, addr
, MMU_DATA_LOAD
,
253 cpu_mmu_index(env
, false)) != 0) {