1 |
/* |
/* |
2 |
* Copyright (C) 2003-2006 Anders Gavare. All rights reserved. |
* Copyright (C) 2003-2007 Anders Gavare. All rights reserved. |
3 |
* |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
* modification, are permitted provided that the following conditions are met: |
25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: memory_mips_v2p.c,v 1.7 2006/07/16 13:32:26 debug Exp $ |
* $Id: memory_mips_v2p.c,v 1.16 2007/04/28 01:46:07 debug Exp $ |
29 |
*/ |
*/ |
30 |
|
|
31 |
|
|
32 |
/* |
/* |
33 |
* translate_v2p(): |
* translate_v2p(): |
34 |
* |
* |
35 |
* Don't call this function is userland_emul is non-NULL, or cpu is NULL. |
* Translate a virtual MIPS address to a physical address, by looking up the |
36 |
|
* address in the TLB. On failure, an exception is generated (except for the |
37 |
|
* case when FLAG_NOEXCEPTIONS is used). |
38 |
* |
* |
39 |
* TODO: vpn2 is a bad name for R2K/R3K, as it is the actual framenumber. |
* Note: This function is long and hairy, it is included several times with |
40 |
|
* various defines set, to produce more or less optimized versions of |
41 |
|
* the function for different emulated CPU types. |
42 |
|
* |
43 |
|
* V2P_MMU3K Defined for R2000/R3000 emulation. If it is not defined, |
44 |
|
* R4000+/MIPS32/MIPS64 is presumed. |
45 |
|
* V2P_MMU10K This enables the use of 44 userspace bits, instead of 40. |
46 |
|
* V2P_MMU4100 VR41xx processors support 1 KB pages, so their page mask |
47 |
|
* is slightly different. (The emulator only supports 4 KB |
48 |
|
* pages, though.) |
49 |
|
* V2P_MMU8K Not yet. (TODO.) |
50 |
|
* |
51 |
|
* |
52 |
|
* Note: Unfortunately, the variable name vpn2 is poorly choosen for R2K/R3K, |
53 |
|
* since it actual contains the vpn. |
54 |
* |
* |
55 |
* Return values: |
* Return values: |
56 |
* 0 Failure |
* 0 Failure |
71 |
const int x_64 = 0; |
const int x_64 = 0; |
72 |
const int n_tlbs = 64; |
const int n_tlbs = 64; |
73 |
const int pmask = 0xfff; |
const int pmask = 0xfff; |
74 |
|
uint64_t xuseg_top; /* Well, useg actually. */ |
75 |
#else |
#else |
76 |
#ifdef V2P_MMU10K |
#ifdef V2P_MMU10K |
77 |
const uint64_t vpn2_mask = ENTRYHI_VPN2_MASK_R10K; |
const uint64_t vpn2_mask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K; |
78 |
|
uint64_t xuseg_top = ENTRYHI_VPN2_MASK_R10K | 0x1fffULL; |
79 |
#else |
#else |
80 |
#ifdef V2P_MMU4100 |
#ifdef V2P_MMU4100 |
81 |
/* This is ugly */ |
const uint64_t vpn2_mask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK | 0x1800; |
|
const uint64_t vpn2_mask = ENTRYHI_VPN2_MASK | 0x1800; |
|
82 |
#else |
#else |
83 |
const uint64_t vpn2_mask = ENTRYHI_VPN2_MASK; |
const uint64_t vpn2_mask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK; |
84 |
#endif |
#endif |
85 |
|
uint64_t xuseg_top = ENTRYHI_VPN2_MASK | 0x1fffULL; |
86 |
#endif |
#endif |
87 |
int x_64; /* non-zero for 64-bit address space accesses */ |
int x_64; /* non-zero for 64-bit address space accesses */ |
88 |
int pageshift, n_tlbs; |
int pageshift, n_tlbs; |
107 |
status = cp0->reg[COP0_STATUS]; |
status = cp0->reg[COP0_STATUS]; |
108 |
|
|
109 |
/* |
/* |
110 |
* R4000 Address Translation: |
* MIPS R4000+ and MIPS64 Address Translation: |
111 |
* |
* |
112 |
* An address may be in one of the kernel segments, that |
* An address may be in one of the kernel segments, that are directly |
113 |
* are directly mapped, or the address can go through the |
* mapped to physical addresses, or the address needs to be looked up |
114 |
* TLBs to be turned into a physical address. |
* in the TLB entries. |
115 |
* |
* |
116 |
* KSU: EXL: ERL: X: Name: Range: |
* KSU: EXL: ERL: X: Name: Range: |
117 |
* ---- ---- ---- -- ----- ------ |
* ---- ---- ---- -- ----- ------ |
132 |
* unmapped, cached |
* unmapped, cached |
133 |
* 00 x x 0 kseg1 0xa0000000 - 0xbfffffff (0.5GB) |
* 00 x x 0 kseg1 0xa0000000 - 0xbfffffff (0.5GB) |
134 |
* unmapped, uncached |
* unmapped, uncached |
135 |
* 00 x x 0 ksseg 0xc0000000 - 0xdfffffff (0.5GB) |
* 00 x x 0 ksseg 0xc0000000 - 0xdfffffff (0.5GB) (via TLB) |
136 |
* (via TLB) |
* 00 x x 0 kseg3 0xe0000000 - 0xffffffff (0.5GB) (via TLB) |
|
* 00 x x 0 kseg3 0xe0000000 - 0xffffffff (0.5GB) |
|
|
* (via TLB) |
|
137 |
* 00 x x 1 xksuseg 0 - 0xffffffffff (1TB) (via TLB) (*) |
* 00 x x 1 xksuseg 0 - 0xffffffffff (1TB) (via TLB) (*) |
138 |
* 00 x x 1 xksseg 0x4000000000000000 - 0x400000ffffffffff |
* 00 x x 1 xksseg 0x4000000000000000 - 0x400000ffffffffff |
139 |
* (1TB) (via TLB) |
* (1TB) (via TLB) |
140 |
* 00 x x 1 xkphys 0x8000000000000000 - 0xbfffffffffffffff |
* 00 x x 1 xkphys 0x8000000000000000 - 0xbfffffffffffffff |
|
* todo |
|
141 |
* 00 x x 1 xkseg 0xc000000000000000 - 0xc00000ff7fffffff |
* 00 x x 1 xkseg 0xc000000000000000 - 0xc00000ff7fffffff |
|
* todo |
|
142 |
* 00 x x 1 ckseg0 0xffffffff80000000 - 0xffffffff9fffffff |
* 00 x x 1 ckseg0 0xffffffff80000000 - 0xffffffff9fffffff |
|
* like kseg0 |
|
143 |
* 00 x x 1 ckseg1 0xffffffffa0000000 - 0xffffffffbfffffff |
* 00 x x 1 ckseg1 0xffffffffa0000000 - 0xffffffffbfffffff |
|
* like kseg1 |
|
144 |
* 00 x x 1 cksseg 0xffffffffc0000000 - 0xffffffffdfffffff |
* 00 x x 1 cksseg 0xffffffffc0000000 - 0xffffffffdfffffff |
|
* like ksseg |
|
145 |
* 00 x x 1 ckseg3 0xffffffffe0000000 - 0xffffffffffffffff |
* 00 x x 1 ckseg3 0xffffffffe0000000 - 0xffffffffffffffff |
146 |
* like kseg2 |
* like 0x80000000 - 0xffffffff |
147 |
* |
* |
148 |
* (*) = if ERL=1 then kuseg is not via TLB, but unmapped, |
* (*) = if ERL=1 then kuseg is not via TLB, but unmapped, |
149 |
* uncached physical memory. |
* uncached physical memory. |
165 |
vaddr_asid = cp0->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK; |
vaddr_asid = cp0->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK; |
166 |
vaddr_vpn2 = vaddr & R2K3K_ENTRYHI_VPN_MASK; |
vaddr_vpn2 = vaddr & R2K3K_ENTRYHI_VPN_MASK; |
167 |
#else |
#else |
168 |
/* |
/* kx,sx,ux = 0 for 32-bit addressing, 1 for 64-bit addressing. */ |
|
* R4000 and others: |
|
|
* |
|
|
* kx,sx,ux = 0 for 32-bit addressing, |
|
|
* 1 for 64-bit addressing. |
|
|
*/ |
|
|
n_tlbs = cpu->cd.mips.cpu_type.nr_of_tlb_entries; |
|
|
|
|
169 |
ksu = (status & STATUS_KSU_MASK) >> STATUS_KSU_SHIFT; |
ksu = (status & STATUS_KSU_MASK) >> STATUS_KSU_SHIFT; |
170 |
if (status & (STATUS_EXL | STATUS_ERL)) |
if (status & (STATUS_EXL | STATUS_ERL)) |
171 |
ksu = KSU_KERNEL; |
ksu = KSU_KERNEL; |
172 |
|
|
173 |
/* Assume KSU_USER. */ |
switch (ksu) { |
174 |
x_64 = status & STATUS_UX; |
case KSU_USER: |
175 |
|
x_64 = status & STATUS_UX; |
176 |
if (ksu == KSU_KERNEL) |
break; |
177 |
|
case KSU_KERNEL: |
178 |
x_64 = status & STATUS_KX; |
x_64 = status & STATUS_KX; |
179 |
else if (ksu == KSU_SUPERVISOR) |
break; |
180 |
|
case KSU_SUPERVISOR: |
181 |
x_64 = status & STATUS_SX; |
x_64 = status & STATUS_SX; |
182 |
|
/* FALLTHROUGH, since supervisor address spaces are not |
183 |
|
really implemented yet. */ |
184 |
|
default:fatal("memory_mips_v2p.c: ksu=%i not yet implemented yet\n", |
185 |
|
ksu); |
186 |
|
exit(1); |
187 |
|
} |
188 |
|
|
189 |
|
n_tlbs = cpu->cd.mips.cpu_type.nr_of_tlb_entries; |
190 |
|
|
191 |
/* This suppresses a compiler warning: */ |
/* Having this here suppresses a compiler warning: */ |
192 |
pageshift = 12; |
pageshift = 12; |
193 |
|
|
194 |
|
/* KUSEG: 0x00000000 - 0x7fffffff if ERL = 1 and KSU = kernel: */ |
195 |
|
if (ksu == KSU_KERNEL && (status & STATUS_ERL) && |
196 |
|
vaddr <= 0x7fffffff) { |
197 |
|
*return_paddr = vaddr & 0x7fffffff; |
198 |
|
return 2; |
199 |
|
} |
200 |
|
|
201 |
/* |
/* |
202 |
* Physical addressing on R10000 etc: |
* XKPHYS: 0x8000000000000000 - 0xbfffffffffffffff |
203 |
* |
* |
204 |
* TODO: Probably only accessible in kernel mode. |
* TODO: Is the correct error generated if accessing XKPHYS from |
205 |
|
* usermode? |
206 |
* |
* |
207 |
* 0x9000000080000000 = disable L2 cache (?) |
* TODO: Magic on SGI machines... Cache control, NUMA, etc.: |
208 |
* TODO: Make this correct. |
* 0x9000000080000000 = disable L2 cache (?) |
209 |
|
* 0x90000000a0000000 = something on IP30? |
210 |
|
* 0x92.... and 0x96... = NUMA on IP27 |
211 |
*/ |
*/ |
212 |
if ((vaddr >> 62) == 0x2) { |
if (ksu == KSU_KERNEL && (vaddr & ENTRYHI_R_MASK) == ENTRYHI_R_XKPHYS) { |
|
/* |
|
|
* On IP30, addresses such as 0x900000001f600050 are used, |
|
|
* but also things like 0x90000000a0000000. (TODO) |
|
|
* |
|
|
* On IP27 (and probably others), addresses such as |
|
|
* 0x92... and 0x96... have to do with NUMA stuff. |
|
|
*/ |
|
213 |
*return_paddr = vaddr & (((uint64_t)1 << 44) - 1); |
*return_paddr = vaddr & (((uint64_t)1 << 44) - 1); |
214 |
return 2; |
return 2; |
215 |
} |
} |
219 |
/* vpn2 depends on pagemask, which is not fixed on R4000 */ |
/* vpn2 depends on pagemask, which is not fixed on R4000 */ |
220 |
#endif |
#endif |
221 |
|
|
222 |
|
/* If 32-bit, truncate address and sign extend: */ |
223 |
|
if (x_64 == 0) { |
224 |
|
vaddr = (int32_t) vaddr; |
225 |
|
xuseg_top = 0x7fffffff; |
226 |
|
/* (Actually useg for R2000/R3000) */ |
227 |
|
} |
228 |
|
|
229 |
if (vaddr <= 0x7fffffff) |
if (vaddr <= xuseg_top) { |
230 |
use_tlb = 1; |
use_tlb = 1; |
231 |
else { |
} else { |
|
#if 1 |
|
|
/* TODO: This should be removed, but it seems that other |
|
|
bugs are triggered. */ |
|
|
/* Sign-extend vaddr, if necessary: */ |
|
|
if ((vaddr >> 32) == 0 && vaddr & (uint32_t)0x80000000ULL) |
|
|
vaddr |= 0xffffffff00000000ULL; |
|
|
#endif |
|
232 |
if (ksu == KSU_KERNEL) { |
if (ksu == KSU_KERNEL) { |
233 |
/* kseg0, kseg1: */ |
/* kseg0, kseg1: */ |
234 |
if (vaddr >= (uint64_t)0xffffffff80000000ULL && |
if (vaddr >= (uint64_t)0xffffffff80000000ULL && |
237 |
return 2; |
return 2; |
238 |
} |
} |
239 |
|
|
|
/* TODO: supervisor stuff */ |
|
|
|
|
240 |
/* other segments: */ |
/* other segments: */ |
241 |
use_tlb = 1; |
use_tlb = 1; |
242 |
} else |
} else { |
243 |
use_tlb = 0; |
use_tlb = 0; |
244 |
|
} |
245 |
} |
} |
246 |
|
|
247 |
if (use_tlb) { |
if (use_tlb) { |
252 |
int g_bit, v_bit, d_bit; |
int g_bit, v_bit, d_bit; |
253 |
uint64_t cached_hi, cached_lo0; |
uint64_t cached_hi, cached_lo0; |
254 |
uint64_t entry_vpn2 = 0, entry_asid, pfn; |
uint64_t entry_vpn2 = 0, entry_asid, pfn; |
255 |
|
int i_end; |
256 |
|
|
257 |
|
i = cpu->cd.mips.last_written_tlb_index; |
258 |
|
i_end = i == 0? n_tlbs-1 : i - 1; |
259 |
|
|
260 |
for (i=0; i<n_tlbs; i++) { |
/* Scan all TLB entries: */ |
261 |
|
for (;;) { |
262 |
#ifdef V2P_MMU3K |
#ifdef V2P_MMU3K |
263 |
/* R3000 or similar: */ |
/* R3000 or similar: */ |
264 |
cached_hi = cp0->tlbs[i].hi; |
cached_hi = cp0->tlbs[i].hi; |
383 |
cached_lo0) |
cached_lo0) |
384 |
& ENTRYLO_PFN_MASK) |
& ENTRYLO_PFN_MASK) |
385 |
>> ENTRYLO_PFN_SHIFT; |
>> ENTRYLO_PFN_SHIFT; |
386 |
paddr = (pfn << pfn_shift) | |
paddr = ((pfn << pfn_shift) & |
387 |
(vaddr & pmask); |
~pmask) | (vaddr & pmask); |
388 |
#endif |
#endif |
389 |
|
|
390 |
*return_paddr = paddr; |
*return_paddr = paddr; |
401 |
goto exception; |
goto exception; |
402 |
} |
} |
403 |
} |
} |
404 |
|
|
405 |
|
if (i == i_end) |
406 |
|
break; |
407 |
|
|
408 |
|
/* Go to the next TLB entry: */ |
409 |
|
i ++; |
410 |
|
if (i == n_tlbs) |
411 |
|
i = 0; |
412 |
} |
} |
413 |
} |
} |
414 |
|
|