memory_mips_v2p.cc Source File

Back to the index.

memory_mips_v2p.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2003-2009 Anders Gavare. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * 3. The name of the author may not be used to endorse or promote products
13  * derived from this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 
29 /*
30  * translate_v2p():
31  *
32  * Translate a virtual MIPS address to a physical address, by looking up the
33  * address in the TLB. On failure, an exception is generated (except for the
34  * case when FLAG_NOEXCEPTIONS is used).
35  *
36  * Note: This function is long and hairy, it is included several times with
37  * various defines set, to produce more or less optimized versions of
38  * the function for different emulated CPU types.
39  *
40  * V2P_MMU3K Defined for R2000/R3000 emulation. If it is not defined,
41  * R4000+/MIPS32/MIPS64 is presumed.
42  * V2P_MMU10K This enables the use of 44 userspace bits, instead of 40.
43  * V2P_MMU4100 VR41xx processors support 1 KB pages, so their page mask
44  * is slightly different. (The emulator only supports 4 KB
45  * pages, though.)
46  * V2P_MMU8K Not yet. (TODO.)
47  *
48  *
49  * Note: Unfortunately, the variable name vpn2 is poorly choosen for R2K/R3K,
50  * since it actual contains the vpn.
51  *
52  * Return values:
53  * 0 Failure
54  * 1 Success, the page is readable only
55  * 2 Success, the page is read/write
56  */
57 int TRANSLATE_ADDRESS(struct cpu *cpu, uint64_t vaddr,
58  uint64_t *return_paddr, int flags)
59 {
60  int writeflag = flags & FLAG_WRITEFLAG? MEM_WRITE : MEM_READ;
61  int no_exceptions = flags & FLAG_NOEXCEPTIONS;
62  int ksu, use_tlb, status, i;
63  uint64_t vaddr_vpn2=0, vaddr_asid=0;
64  int exccode, tlb_refill;
65  struct mips_coproc *cp0;
66 
67 #ifdef V2P_MMU3K
68  const int x_64 = 0;
69  const int n_tlbs = 64;
70  const uint32_t pmask = 0xfff;
71  uint64_t xuseg_top; /* Well, useg actually. */
72 #else
73 #ifdef V2P_MMU10K
74  const uint64_t vpn2_mask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K;
75  uint64_t xuseg_top = ENTRYHI_VPN2_MASK_R10K | 0x1fffULL;
76 #else
77 #ifdef V2P_MMU4100
78  const uint64_t vpn2_mask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK | 0x1800;
79 #else
80  const uint64_t vpn2_mask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK;
81 #endif
82  uint64_t xuseg_top = ENTRYHI_VPN2_MASK | 0x1fffULL;
83 #endif
84  int x_64; /* non-zero for 64-bit address space accesses */
85  int pageshift, n_tlbs;
86  uint32_t pmask;
87 #ifdef V2P_MMU4100
88  const int pagemask_mask = PAGEMASK_MASK_R4100;
89  const int pagemask_shift = PAGEMASK_SHIFT_R4100;
90  const int pfn_shift = 10;
91 #else
92  const int pagemask_mask = PAGEMASK_MASK;
93  const int pagemask_shift = PAGEMASK_SHIFT;
94  const int pfn_shift = 12;
95 #endif
96 #endif /* !V2P_MMU3K */
97 
98 
99  exccode = -1;
100  tlb_refill = 1;
101 
102  /* Cached values: */
103  cp0 = cpu->cd.mips.coproc[0];
104  status = cp0->reg[COP0_STATUS];
105 
106  /*
107  * MIPS R4000+ and MIPS64 Address Translation:
108  *
109  * An address may be in one of the kernel segments, that are directly
110  * mapped to physical addresses, or the address needs to be looked up
111  * in the TLB entries.
112  *
113  * KSU: EXL: ERL: X: Name: Range:
114  * ---- ---- ---- -- ----- ------
115  *
116  * 10 0 0 0 useg 0 - 0x7fffffff (2GB) (via TLB)
117  * 10 0 0 1 xuseg 0 - 0xffffffffff (1TB) (via TLB)
118  *
119  * 01 0 0 0 suseg 0 - 0x7fffffff (2GB via TLB)
120  * 01 0 0 0 ssseg 0xc0000000 - 0xdfffffff (0.5 GB via TLB)
121  * 01 0 0 1 xsuseg 0 - 0xffffffffff (1TB) (via TLB)
122  * 01 0 0 1 xsseg 0x4000000000000000 - 0x400000ffffffffff
123  * (1TB) (via TLB)
124  * 01 0 0 1 csseg 0xffffffffc0000000 - 0xffffffffdfffffff
125  * (0.5TB) (via TLB)
126  *
127  * 00 x x 0 kuseg 0 - 0x7fffffff (2GB) (via TLB) (*)
128  * 00 x x 0 kseg0 0x80000000 - 0x9fffffff (0.5GB)
129  * unmapped, cached
130  * 00 x x 0 kseg1 0xa0000000 - 0xbfffffff (0.5GB)
131  * unmapped, uncached
132  * 00 x x 0 ksseg 0xc0000000 - 0xdfffffff (0.5GB) (via TLB)
133  * 00 x x 0 kseg3 0xe0000000 - 0xffffffff (0.5GB) (via TLB)
134  * 00 x x 1 xksuseg 0 - 0xffffffffff (1TB) (via TLB) (*)
135  * 00 x x 1 xksseg 0x4000000000000000 - 0x400000ffffffffff
136  * (1TB) (via TLB)
137  * 00 x x 1 xkphys 0x8000000000000000 - 0xbfffffffffffffff
138  * 00 x x 1 xkseg 0xc000000000000000 - 0xc00000ff7fffffff
139  * 00 x x 1 ckseg0 0xffffffff80000000 - 0xffffffff9fffffff
140  * 00 x x 1 ckseg1 0xffffffffa0000000 - 0xffffffffbfffffff
141  * 00 x x 1 cksseg 0xffffffffc0000000 - 0xffffffffdfffffff
142  * 00 x x 1 ckseg3 0xffffffffe0000000 - 0xffffffffffffffff
143  * like 0x80000000 - 0xffffffff
144  *
145  * (*) = if ERL=1 then kuseg is not via TLB, but unmapped,
146  * uncached physical memory.
147  *
148  * (KSU==0 or EXL=1 or ERL=1 is enough to use k*seg*.)
149  *
150  * An invalid address causes an Address Error.
151  *
152  * See chapter 4, page 96, in the R4000 manual for more info!
153  */
154 
155 #ifdef V2P_MMU3K
156  if (status & MIPS1_SR_KU_CUR)
157  ksu = KSU_USER;
158  else
159  ksu = KSU_KERNEL;
160 
161  /* These are needed later: */
162  vaddr_asid = cp0->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK;
163  vaddr_vpn2 = vaddr & R2K3K_ENTRYHI_VPN_MASK;
164 #else
165  /* kx,sx,ux = 0 for 32-bit addressing, 1 for 64-bit addressing. */
166  ksu = (status & STATUS_KSU_MASK) >> STATUS_KSU_SHIFT;
167  if (status & (STATUS_EXL | STATUS_ERL))
168  ksu = KSU_KERNEL;
169 
170  switch (ksu) {
171  case KSU_USER:
172  x_64 = status & STATUS_UX;
173  break;
174  case KSU_KERNEL:
175  x_64 = status & STATUS_KX;
176  break;
177  case KSU_SUPERVISOR:
178  x_64 = status & STATUS_SX;
179  /* FALLTHROUGH, since supervisor address spaces are not
180  really implemented yet. */
181  default:fatal("memory_mips_v2p.c: ksu=%i not yet implemented yet\n",
182  ksu);
183  exit(1);
184  }
185 
186  n_tlbs = cpu->cd.mips.cpu_type.nr_of_tlb_entries;
187 
188  /* Having this here suppresses a compiler warning: */
189  pageshift = 12;
190 
191  /* KUSEG: 0x00000000 - 0x7fffffff if ERL = 1 and KSU = kernel: */
192  if (ksu == KSU_KERNEL && (status & STATUS_ERL) &&
193  vaddr <= 0x7fffffff) {
194  *return_paddr = vaddr & 0x7fffffff;
195  return 2;
196  }
197 
198  /*
199  * XKPHYS: 0x8000000000000000 - 0xbfffffffffffffff
200  *
201  * TODO: Is the correct error generated if accessing XKPHYS from
202  * usermode?
203  *
204  * TODO: Magic on SGI machines... Cache control, NUMA, etc.:
205  * 0x9000000080000000 = disable L2 cache (?)
206  * 0x90000000a0000000 = something on IP30?
207  * 0x92.... and 0x96... = NUMA on IP27
208  */
209  if (ksu == KSU_KERNEL && (vaddr & ENTRYHI_R_MASK) == ENTRYHI_R_XKPHYS) {
210  *return_paddr = vaddr & (((uint64_t)1 << 44) - 1);
211  return 2;
212  }
213 
214  /* This is needed later: */
215  vaddr_asid = cp0->reg[COP0_ENTRYHI] & ENTRYHI_ASID;
216  /* vpn2 depends on pagemask, which is not fixed on R4000 */
217 #endif
218 
219  /* If 32-bit, truncate address and sign extend: */
220  if (x_64 == 0) {
221  vaddr = (int32_t) vaddr;
222  xuseg_top = 0x7fffffff;
223  /* (Actually useg for R2000/R3000) */
224  }
225 
226  if (vaddr <= xuseg_top) {
227  use_tlb = 1;
228  } else {
229  if (ksu == KSU_KERNEL) {
230  /* kseg0, kseg1: */
231  if (vaddr >= (uint64_t)0xffffffff80000000ULL &&
232  vaddr <= (uint64_t)0xffffffffbfffffffULL) {
233  *return_paddr = vaddr & 0x1fffffff;
234  return 2;
235  }
236 
237  /* other segments: */
238  use_tlb = 1;
239  } else {
240  use_tlb = 0;
241  }
242  }
243 
244  if (use_tlb) {
245 #ifndef V2P_MMU3K
246  int odd = 0;
247  uint64_t cached_lo1 = 0;
248 #endif
249  int g_bit, v_bit, d_bit;
250  uint64_t cached_hi, cached_lo0;
251  uint64_t entry_vpn2 = 0, entry_asid, pfn;
252  int i_end;
253 
254  i = cpu->cd.mips.last_written_tlb_index;
255  i_end = i == 0? n_tlbs-1 : i - 1;
256 
257  /* Scan all TLB entries: */
258  for (;;) {
259 #ifdef V2P_MMU3K
260  /* R3000 or similar: */
261  cached_hi = cp0->tlbs[i].hi;
262  cached_lo0 = cp0->tlbs[i].lo0;
263 
264  entry_vpn2 = cached_hi & R2K3K_ENTRYHI_VPN_MASK;
265  entry_asid = cached_hi & R2K3K_ENTRYHI_ASID_MASK;
266  g_bit = cached_lo0 & R2K3K_ENTRYLO_G;
267  v_bit = cached_lo0 & R2K3K_ENTRYLO_V;
268  d_bit = cached_lo0 & R2K3K_ENTRYLO_D;
269 #else
270  /* R4000 or similar: */
271  pmask = cp0->tlbs[i].mask & pagemask_mask;
272  cached_hi = cp0->tlbs[i].hi;
273  cached_lo0 = cp0->tlbs[i].lo0;
274  cached_lo1 = cp0->tlbs[i].lo1;
275 
276  /* Optimized for minimum page size: */
277  if (pmask == 0) {
278  pageshift = pagemask_shift - 1;
279  entry_vpn2 = (cached_hi & vpn2_mask)
280  >> pagemask_shift;
281  vaddr_vpn2 = (vaddr & vpn2_mask)
282  >> pagemask_shift;
283  pmask = (1 << (pagemask_shift-1)) - 1;
284  odd = (vaddr >> (pagemask_shift-1)) & 1;
285  } else {
286  /* Non-standard page mask: */
287  switch (pmask | ((1 << pagemask_shift) - 1)) {
288  case 0x00007ff: pageshift = 10; break;
289  case 0x0001fff: pageshift = 12; break;
290  case 0x0007fff: pageshift = 14; break;
291  case 0x001ffff: pageshift = 16; break;
292  case 0x007ffff: pageshift = 18; break;
293  case 0x01fffff: pageshift = 20; break;
294  case 0x07fffff: pageshift = 22; break;
295  case 0x1ffffff: pageshift = 24; break;
296  case 0x7ffffff: pageshift = 26; break;
297  default:fatal("pmask=%08" PRIx32"\n", pmask);
298  exit(1);
299  }
300 
301  entry_vpn2 = (cached_hi &
302  vpn2_mask) >> (pageshift + 1);
303  vaddr_vpn2 = (vaddr & vpn2_mask) >>
304  (pageshift + 1);
305  pmask = (1 << pageshift) - 1;
306  odd = (vaddr >> pageshift) & 1;
307  }
308 
309  /* Assume even virtual page... */
310  v_bit = cached_lo0 & ENTRYLO_V;
311  d_bit = cached_lo0 & ENTRYLO_D;
312 
313 #ifdef V2P_MMU8K
314  /*
315  * TODO: I don't really know anything about the R8000.
316  * http://futuretech.mirror.vuurwerk.net/i2sec7.html
317  * says that it has a three-way associative TLB with
318  * 384 entries, 16KB page size, and some other things.
319  *
320  * It feels like things like the valid bit (ala R4000)
321  * and dirty bit are not implemented the same on R8000.
322  *
323  * http://sgistuff.tastensuppe.de/documents/
324  * R8000_chipset.html
325  * also has some info, but no details.
326  */
327  v_bit = 1; /* Big TODO */
328  d_bit = 1;
329 #endif
330 
331  entry_asid = cached_hi & ENTRYHI_ASID;
332 
333  /* ... reload pfn, v_bit, d_bit if
334  it was the odd virtual page: */
335  if (odd) {
336  v_bit = cached_lo1 & ENTRYLO_V;
337  d_bit = cached_lo1 & ENTRYLO_D;
338  }
339 #ifdef V2P_MMU4100
340  g_bit = cached_lo1 & cached_lo0 & ENTRYLO_G;
341 #else
342  g_bit = cached_hi & TLB_G;
343 #endif
344 
345 #endif
346 
347  /* Is there a VPN and ASID match? */
348  if (entry_vpn2 == vaddr_vpn2 &&
349  (entry_asid == vaddr_asid || g_bit)) {
350  /* debug("OK MAP 1, i=%i { vaddr=%016" PRIx64" "
351  "==> paddr %016" PRIx64" v=%i d=%i "
352  "asid=0x%02x }\n", i, (uint64_t) vaddr,
353  (uint64_t) *return_paddr, v_bit?1:0,
354  d_bit?1:0, vaddr_asid); */
355  if (v_bit) {
356  if (d_bit || (!d_bit &&
357  writeflag == MEM_READ)) {
358  uint64_t paddr;
359  /* debug("OK MAP 2!!! { w=%i "
360  "vaddr=%016" PRIx64" ==> "
361  "d=%i v=%i paddr %016"
362  PRIx64" ",
363  writeflag, (uint64_t)vaddr,
364  d_bit?1:0, v_bit?1:0,
365  (uint64_t) *return_paddr);
366  debug(", tlb entry %2i: ma"
367  "sk=%016" PRIx64" hi=%016"
368  PRIx64" lo0=%016" PRIx64
369  " lo1=%016" PRIx64"\n",
370  i, cp0->tlbs[i].mask, cp0->
371  tlbs[i].hi, cp0->tlbs[i].
372  lo0, cp0->tlbs[i].lo1);
373  */
374 #ifdef V2P_MMU3K
375  pfn = cached_lo0 &
377  paddr = pfn | (vaddr & pmask);
378 #else
379  pfn = ((odd? cached_lo1 :
380  cached_lo0)
383  paddr = ((pfn << pfn_shift) &
384  ~pmask) | (vaddr & pmask);
385 #endif
386 
387  *return_paddr = paddr;
388  return d_bit? 2 : 1;
389  } else {
390  /* TLB modif. exception */
391  tlb_refill = 0;
392  exccode = EXCEPTION_MOD;
393  goto exception;
394  }
395  } else {
396  /* TLB invalid exception */
397  tlb_refill = 0;
398  goto exception;
399  }
400  }
401 
402  if (i == i_end)
403  break;
404 
405  /* Go to the next TLB entry: */
406  i ++;
407  if (i == n_tlbs)
408  i = 0;
409  }
410  }
411 
412  /*
413  * We are here if for example userland code tried to access
414  * kernel memory, OR if there was a TLB refill.
415  */
416 
417  if (!use_tlb) {
418  tlb_refill = 0;
419  if (writeflag == MEM_WRITE)
420  exccode = EXCEPTION_ADES;
421  else
422  exccode = EXCEPTION_ADEL;
423  }
424 
425 exception:
426  if (no_exceptions)
427  return 0;
428 
429  /* TLB Load or Store exception: */
430  if (exccode == -1) {
431  if (writeflag == MEM_WRITE)
432  exccode = EXCEPTION_TLBS;
433  else
434  exccode = EXCEPTION_TLBL;
435  }
436 
437 #ifdef V2P_MMU3K
438  vaddr_asid >>= R2K3K_ENTRYHI_ASID_SHIFT;
439  vaddr_vpn2 >>= 12;
440 #endif
441 
442  mips_cpu_exception(cpu, exccode, tlb_refill, vaddr,
443  0, vaddr_vpn2, vaddr_asid, x_64);
444 
445  /* Return failure: */
446  return 0;
447 }
448 
#define EXCEPTION_ADEL
Definition: cop0.h:187
void fatal(const char *fmt,...)
Definition: main.cc:152
#define ENTRYHI_VPN2_MASK_R10K
Definition: cop0.h:98
#define R2K3K_ENTRYLO_D
Definition: cop0.h:74
#define FLAG_NOEXCEPTIONS
Definition: memory.h:137
#define EXCEPTION_ADES
Definition: cop0.h:188
#define R2K3K_ENTRYHI_ASID_MASK
Definition: cop0.h:106
#define PAGEMASK_SHIFT_R4100
Definition: cop0.h:88
#define KSU_USER
Definition: cop0.h:174
#define PAGEMASK_MASK
Definition: cop0.h:84
#define ENTRYHI_R_XKPHYS
Definition: cop0.h:96
#define STATUS_ERL
Definition: cop0.h:124
#define R2K3K_ENTRYLO_PFN_MASK
Definition: cop0.h:71
#define R2K3K_ENTRYLO_G
Definition: cop0.h:76
union cpu::@1 cd
int TRANSLATE_ADDRESS(struct cpu *cpu, uint64_t vaddr, uint64_t *return_paddr, int flags)
#define COP0_STATUS
Definition: cop0.h:109
#define R2K3K_ENTRYLO_V
Definition: cop0.h:75
#define MEM_READ
Definition: memory.h:116
#define R2K3K_ENTRYHI_ASID_SHIFT
Definition: cop0.h:107
#define ENTRYLO_G
Definition: cop0.h:69
#define ENTRYHI_VPN2_MASK
Definition: cop0.h:99
#define ENTRYHI_ASID
Definition: cop0.h:101
#define KSU_KERNEL
Definition: cop0.h:172
#define STATUS_UX
Definition: cop0.h:121
#define KSU_SUPERVISOR
Definition: cop0.h:173
#define STATUS_SX
Definition: cop0.h:120
#define ENTRYHI_R_MASK
Definition: cop0.h:95
uint64_t mask
Definition: cpu_mips.h:83
uint64_t hi
Definition: cpu_mips.h:80
#define EXCEPTION_TLBL
Definition: cop0.h:185
struct mips_tlb * tlbs
Definition: cpu_mips.h:105
uint64_t reg[N_MIPS_COPROC_REGS]
Definition: cpu_mips.h:102
#define R2K3K_ENTRYHI_VPN_MASK
Definition: cop0.h:104
#define ENTRYLO_PFN_SHIFT
Definition: cop0.h:64
void mips_cpu_exception(struct cpu *cpu, int exccode, int tlb, uint64_t vaddr, int coproc_nr, uint64_t vaddr_vpn2, int vaddr_asid, int x_64)
Definition: cpu_mips.cc:1714
#define MEM_WRITE
Definition: memory.h:117
#define PAGEMASK_MASK_R4100
Definition: cop0.h:86
struct mips_coproc * coproc[N_MIPS_COPROCS]
Definition: cpu_mips.h:219
#define EXCEPTION_MOD
Definition: cop0.h:184
#define ENTRYLO_D
Definition: cop0.h:67
#define ENTRYLO_PFN_MASK
Definition: cop0.h:63
Definition: cpu.h:326
uint64_t lo1
Definition: cpu_mips.h:82
#define PAGEMASK_SHIFT
Definition: cop0.h:85
#define STATUS_KSU_MASK
Definition: cop0.h:122
#define FLAG_WRITEFLAG
Definition: memory.h:136
#define STATUS_EXL
Definition: cop0.h:125
#define MIPS1_SR_KU_CUR
Definition: mips_cpuregs.h:186
#define COP0_ENTRYHI
Definition: cop0.h:93
#define STATUS_KSU_SHIFT
Definition: cop0.h:123
struct mips_cpu mips
Definition: cpu.h:443
uint64_t lo0
Definition: cpu_mips.h:81
#define TLB_G
Definition: cop0.h:102
struct mips_cpu_type_def cpu_type
Definition: cpu_mips.h:206
#define STATUS_KX
Definition: cop0.h:119
#define EXCEPTION_TLBS
Definition: cop0.h:186
#define ENTRYLO_V
Definition: cop0.h:68
int last_written_tlb_index
Definition: cpu_mips.h:222

Generated on Sun Sep 30 2018 16:05:18 for GXemul by doxygen 1.8.13