memory_m88k.cc Source File

Back to the index.

memory_m88k.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007-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  * Virtual to physical memory translation for M88K emulation.
29  *
30  * (This is where the actual work of the M8820x chips is emulated.)
31  *
32  *
33  * TODO:
34  * M88204 stuff, where it differs from the M88200.
35  */
36 
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 
41 #include "cpu.h"
42 #include "machine.h"
43 #include "memory.h"
44 #include "misc.h"
45 
46 #include "thirdparty/m8820x.h"
47 #include "thirdparty/m8820x_pte.h"
48 
49 
50 /* #define M8820X_TABLE_SEARCH_DEBUG */
51 
52 
53 /*
54  * m8820x_mark_page_as_modified():
55  *
56  * Helper function which traverses the page table structure in emulated
57  * memory, and marks a page as Modified and Used.
58  */
60  struct m8820x_cmmu *cmmu, uint32_t apr, uint32_t vaddr)
61 {
62  int seg_nr = vaddr >> 22, page_nr = (vaddr >> 12) & 0x3ff;
63  uint32_t *seg_base, *page_base;
64  sdt_entry_t seg_descriptor;
65  pt_entry_t page_descriptor;
66 
67  /* Read the segment descriptor from memory: */
68  seg_base = (uint32_t *) memory_paddr_to_hostaddr(
69  cpu->mem, apr & 0xfffff000, 1);
70  seg_descriptor = seg_base[seg_nr];
72  seg_descriptor = LE32_TO_HOST(seg_descriptor);
73  else
74  seg_descriptor = BE32_TO_HOST(seg_descriptor);
75 
76  /* ... and the page descriptor: */
77  page_base = (uint32_t *) memory_paddr_to_hostaddr(
78  cpu->mem, seg_descriptor & 0xfffff000, 1);
79  page_descriptor = page_base[page_nr];
81  page_descriptor = LE32_TO_HOST(page_descriptor);
82  else
83  page_descriptor = BE32_TO_HOST(page_descriptor);
84 
85  /* ... set the Modified and Used bits: */
86  page_descriptor |= PG_M | PG_U;
87 
88  /* ... and write it back: */
90  page_descriptor = LE32_TO_HOST(page_descriptor);
91  else
92  page_descriptor = BE32_TO_HOST(page_descriptor);
93  page_base[page_nr] = page_descriptor;
94 }
95 
96 
97 /*
98  * m88k_translate_v2p():
99  *
100  * Returns 0 for translation failure (access denied), 1 for read access
101  * (success), or 2 for read/write access (success).
102  */
103 int m88k_translate_v2p(struct cpu *cpu, uint64_t vaddr64,
104  uint64_t *return_paddr, int flags)
105 {
106  int instr = flags & FLAG_INSTR;
107  int writeflag = (flags & FLAG_WRITEFLAG)? 1 : 0;
108  int no_exceptions = flags & FLAG_NOEXCEPTIONS;
109  int exception_type = instr? M88K_EXCEPTION_INSTRUCTION_ACCESS
111  int supervisor = cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE;
112  struct m8820x_cmmu *cmmu = cpu->cd.m88k.cmmu[instr? 0 : 1];
113  uint32_t vaddr = vaddr64;
114  uint32_t apr;
115  uint32_t *seg_base, *page_base;
116  sdt_entry_t seg_descriptor;
117  pt_entry_t page_descriptor;
118  int pfsr_status = CMMU_PFSR_SUCCESS;
119  uint32_t pfar = 0;
120  int accumulated_flags;
121  int i, seg_nr = vaddr >> 22, page_nr = (vaddr >> 12) & 0x3ff;
122 
123  if (flags & MEMORY_USER_ACCESS)
124  supervisor = 0;
125 
126 
127  /*
128  * Is the CMMU not yet initialized? Then return physical = virtual.
129  */
130  *return_paddr = vaddr;
131  if (cmmu == NULL)
132  return 2;
133 
134  if (supervisor)
135  apr = cmmu->reg[CMMU_SAPR];
136  else
137  apr = cmmu->reg[CMMU_UAPR];
138 
139 
140  /*
141  * Address translation not enabled? Then return physical = virtual.
142  */
143  if (!(apr & APR_V))
144  return 2;
145 
146  /*
147  * BATC lookup:
148  *
149  * The BATC is a 10-entry array of virtual to physical mappings,
150  * where the top 13 bits of the virtual address must match.
151  */
152  for (i=0; i<N_M88200_BATC_REGS; i++) {
153  uint32_t batc = cmmu->batc[i];
154 
155  /* The batc entry must be valid: */
156  if (!(batc & BATC_V))
157  continue;
158 
159  /* ... and have a matching supervisor/user bit: */
160  if ((supervisor && !(batc & BATC_SO)) ||
161  (!supervisor && (batc & BATC_SO)))
162  continue;
163 
164  /* ... and matching virtual address: */
165  if ((vaddr & 0xfff80000) != (batc & 0xfff80000))
166  continue;
167 
168  /* A matching BATC entry was found! */
169 
170  /* Is it write protected? */
171  if ((batc & BATC_PROT) && writeflag) {
172  pfsr_status = CMMU_PFSR_WRITE;
173  goto exception;
174  }
175 
176  *return_paddr = ((batc & 0x0007ffc0) << 13)
177  | (vaddr & 0x0007ffff);
178 
179  return batc & BATC_PROT? 1 : 2;
180  }
181 
182  /*
183  * PATC lookup:
184  *
185  * The PATC is a 56-entry array of virtual to physical mappings for
186  * 4 KB pages. If writeflag is set, and a PATC entry is found without
187  * the Modified bit set, a page table search must be performed to
188  * set the Modified bit in emulated memory.
189  */
190  for (i=0; i<N_M88200_PATC_ENTRIES; i++) {
191  uint32_t vaddr_and_control = cmmu->patc_v_and_control[i];
192  uint32_t paddr_and_sbit = cmmu->patc_p_and_supervisorbit[i];
193 
194  /* Skip this entry if the valid bit isn't set: */
195  if (!(vaddr_and_control & PG_V))
196  continue;
197 
198  /* ... or the virtual addresses don't match: */
199  if ((vaddr & 0xfffff000) != (vaddr_and_control & 0xfffff000))
200  continue;
201 
202  /* ... or if the supervisor bit doesn't match: */
203  if (((paddr_and_sbit & M8820X_PATC_SUPERVISOR_BIT)
204  && !supervisor) || (supervisor &&
205  !(paddr_and_sbit & M8820X_PATC_SUPERVISOR_BIT)))
206  continue;
207 
208  /* A matching PATC entry was found! */
209 
210  /* Is it write protected? */
211  if ((vaddr_and_control & PG_PROT) && writeflag) {
212  pfsr_status = CMMU_PFSR_WRITE;
213  goto exception;
214  }
215 
216  /* On writes: Is the page not yet marked as modified? */
217  if (!(vaddr_and_control & PG_M) && writeflag &&
218  !no_exceptions) {
219  /* Then perform a page table search and mark
220  it as Modified (and used): */
221  m8820x_mark_page_as_modified(cpu, cmmu, apr, vaddr);
222 
223  /* ... and mark the PATC entry too: */
224  cmmu->patc_v_and_control[i] |= PG_M;
225  }
226 
227  /* Set the Used bit of the PATC entry: */
228  if (!no_exceptions)
229  cmmu->patc_v_and_control[i] |= PG_U;
230 
231  /* ... and finally return the physical address: */
232  *return_paddr = (paddr_and_sbit & 0xfffff000) | (vaddr & 0xfff);
233  return vaddr_and_control & PG_PROT? 1 : 2;
234  }
235 
236  /*
237  * The address was neither found in the BATC, nor the PATC.
238  */
239 
240  /*
241  * Attempt a search through page tables, to refill the PATC:
242  */
243  seg_base = (uint32_t *) memory_paddr_to_hostaddr(
244  cpu->mem, apr & 0xfffff000, 1);
245 
246  seg_descriptor = seg_base[seg_nr];
248  seg_descriptor = LE32_TO_HOST(seg_descriptor);
249  else
250  seg_descriptor = BE32_TO_HOST(seg_descriptor);
251 
252 #ifdef M8820X_TABLE_SEARCH_DEBUG
253  printf("+--- M8820x page table search debug:\n");
254  printf("| vaddr 0x%08"PRIx32"\n", vaddr);
255  printf("| apr 0x%08"PRIx32"\n", apr);
256  printf("| seg_base %p (on the host)\n", seg_base);
257  printf("| seg_nr 0x%03x\n", seg_nr);
258  printf("| page_nr 0x%03x\n", page_nr);
259  printf("| sd 0x%08"PRIx32"\n", seg_descriptor);
260 #endif
261 
262  /* Segment descriptor invalid? Then cause a segfault exception. */
263  if (!(seg_descriptor & SG_V)) {
264  /* PFAR = physical address of faulting segment descriptor: */
265  pfar = (apr & 0xfffff000) + seg_nr * sizeof(uint32_t);
266  pfsr_status = CMMU_PFSR_SFAULT;
267  goto exception;
268  }
269 
270  /* Usermode attempted to access a supervisor segment? */
271  if ((seg_descriptor & SG_SO) && !supervisor) {
272  /* PFAR = physical address of faulting segment descriptor: */
273  pfar = (apr & 0xfffff000) + seg_nr * sizeof(uint32_t);
274  pfsr_status = CMMU_PFSR_SUPER;
275  goto exception;
276  }
277 
278  accumulated_flags = seg_descriptor & SG_RO;
279 
280  page_base = (uint32_t *) memory_paddr_to_hostaddr(
281  cpu->mem, seg_descriptor & 0xfffff000, 1);
282 
283  page_descriptor = page_base[page_nr];
285  page_descriptor = LE32_TO_HOST(page_descriptor);
286  else
287  page_descriptor = BE32_TO_HOST(page_descriptor);
288 
289 #ifdef M8820X_TABLE_SEARCH_DEBUG
290  printf("| page_base %p (on the host)\n", page_base);
291  printf("| pd 0x%08"PRIx32"\n", page_descriptor);
292 #endif
293 
294  /* Page descriptor invalid? Then cause a page fault exception. */
295  if (!(page_descriptor & PG_V)) {
296  /* PFAR = physical address of faulting page descriptor: */
297  pfar = (seg_descriptor & 0xfffff000)
298  + page_nr * sizeof(uint32_t);
299  pfsr_status = CMMU_PFSR_PFAULT;
300  goto exception;
301  }
302 
303  /* Usermode attempted to access a supervisor page? */
304  if ((page_descriptor & PG_SO) && !supervisor) {
305  /* PFAR = physical address of faulting page descriptor: */
306  pfar = (seg_descriptor & 0xfffff000)
307  + page_nr * sizeof(uint32_t);
308  pfsr_status = CMMU_PFSR_SUPER;
309  goto exception;
310  }
311 
312  accumulated_flags |= (page_descriptor & PG_RO);
313 
314 
315  /*
316  * Overwrite the next entry in the PATC with a new entry:
317  */
318 
319  if (!no_exceptions) {
320  i = cmmu->patc_update_index;
321 
322  /* Invalidate the current entry, if it is valid: */
323  if (cmmu->patc_v_and_control[i] & PG_V)
325  cmmu->patc_v_and_control[i] & 0xfffff000,
327 
328  /* ... and write the new one: */
329  cmmu->patc_update_index ++;
331  cmmu->patc_v_and_control[i] =
332  (vaddr & 0xfffff000) | accumulated_flags | PG_V;
333  cmmu->patc_p_and_supervisorbit[i] =
334  (page_descriptor & 0xfffff000) |
335  (supervisor? M8820X_PATC_SUPERVISOR_BIT : 0);
336  }
337 
338  /* Check for writes to read-only pages: */
339  if (writeflag && (accumulated_flags & PG_RO)) {
340  pfsr_status = CMMU_PFSR_WRITE;
341  goto exception;
342  }
343 
344  if (!no_exceptions) {
345  uint32_t tmp;
346 
347  /* We now know that the page is in use. */
348  cmmu->patc_v_and_control[i] |= PG_U;
349  if (writeflag)
350  cmmu->patc_v_and_control[i] |= PG_M;
351 
352  /*
353  * Write back the U bit (and possibly the M bit) to the page
354  * descriptor in emulated memory:
355  */
356  tmp = page_descriptor | PG_U;
357  if (writeflag)
358  tmp |= PG_M;
359 
361  tmp = LE32_TO_HOST(tmp);
362  else
363  tmp = BE32_TO_HOST(tmp);
364 
365  page_base[page_nr] = tmp;
366  }
367 
368  /* Now finally return with the translated page address: */
369  *return_paddr = (page_descriptor & 0xfffff000) | (vaddr & 0xfff);
370  return (accumulated_flags & PG_RO)? 1 : 2;
371 
372 
373 exception:
374  if (no_exceptions)
375  return 0;
376 
377  /*
378  * Update the Page Fault Status Register of the CMMU which this fault
379  * was associated with, but also clear the PFSR of the _other_ CMMU:
380  */
381 
382  cmmu->reg[CMMU_PFSR] = pfsr_status << 16;
383  cpu->cd.m88k.cmmu[instr? 1 : 0]->reg[CMMU_PFSR] =
384  CMMU_PFSR_SUCCESS << 16;
385 
386  /* ... and (if necessary) update the Page Fault Address Register: */
387 
388  switch (pfsr_status) {
389 
390  case CMMU_PFSR_SUCCESS:
391  fatal("HUH? CMMU_PFSR_SUCCESS:, but exception? TODO\n");
392  exit(1);
393  break;
394 
395  case CMMU_PFSR_WRITE:
396  /* Note: The PFAR is "destroyed"/undefined on write faults. */
397  cmmu->reg[CMMU_PFAR] = 0;
398  break;
399 
400  case CMMU_PFSR_SUPER:
401  case CMMU_PFSR_SFAULT:
402  case CMMU_PFSR_PFAULT:
403  cmmu->reg[CMMU_PFAR] = pfar;
404  break;
405 
406  default:
407  fatal("Internal error in memory_m88k? pfsr_status = %i\n",
408  pfsr_status);
409  exit(1);
410  }
411 
412  /* ... and finally cause the exception: */
413  m88k_exception(cpu, exception_type, 0);
414 
415  return 0;
416 }
417 
M8820X_PATC_SUPERVISOR_BIT
#define M8820X_PATC_SUPERVISOR_BIT
Definition: M88K_CPUComponent.h:321
m88k_cpu::cmmu
struct m8820x_cmmu * cmmu[MAX_M8820X_CMMUS]
Definition: cpu_m88k.h:250
instr
#define instr(n)
Definition: tmp_alpha_head.cc:43
pt_entry_t
u_int32_t pt_entry_t
Definition: m8820x_pte.h:122
PG_M
#define PG_M
Definition: m8820x_pte.h:128
M88K_EXCEPTION_INSTRUCTION_ACCESS
#define M88K_EXCEPTION_INSTRUCTION_ACCESS
Definition: M88K_CPUComponent.h:285
N_M88200_BATC_REGS
#define N_M88200_BATC_REGS
Definition: M88K_CPUComponent.h:319
N_M88200_PATC_ENTRIES
#define N_M88200_PATC_ENTRIES
Definition: M88K_CPUComponent.h:320
M88K_EXCEPTION_DATA_ACCESS
#define M88K_EXCEPTION_DATA_ACCESS
Definition: M88K_CPUComponent.h:286
APR_V
#define APR_V
Definition: m8820x_pte.h:81
CMMU_PFSR_SFAULT
#define CMMU_PFSR_SFAULT
Definition: m8820x.h:126
cpu::byte_order
uint8_t byte_order
Definition: cpu.h:347
LE32_TO_HOST
#define LE32_TO_HOST(x)
Definition: misc.h:180
m8820x.h
BE32_TO_HOST
#define BE32_TO_HOST(x)
Definition: misc.h:181
cpu::m88k
struct m88k_cpu m88k
Definition: cpu.h:445
m8820x_cmmu::patc_p_and_supervisorbit
uint32_t patc_p_and_supervisorbit[N_M88200_PATC_ENTRIES]
Definition: M88K_CPUComponent.h:327
CMMU_PFSR_SUPER
#define CMMU_PFSR_SUPER
Definition: m8820x.h:128
INVALIDATE_VADDR
#define INVALIDATE_VADDR
Definition: cpu.h:483
m8820x_cmmu::reg
uint32_t reg[M8820X_LENGTH/sizeof(uint32_t)]
Definition: M88K_CPUComponent.h:324
fatal
void fatal(const char *fmt,...)
Definition: main.cc:152
misc.h
MEMORY_USER_ACCESS
#define MEMORY_USER_ACCESS
Definition: memory.h:127
cpu::cd
union cpu::@1 cd
machine.h
m8820x_cmmu::patc_update_index
int patc_update_index
Definition: M88K_CPUComponent.h:328
m88k_translate_v2p
int m88k_translate_v2p(struct cpu *cpu, uint64_t vaddr64, uint64_t *return_paddr, int flags)
Definition: memory_m88k.cc:103
m8820x_cmmu::patc_v_and_control
uint32_t patc_v_and_control[N_M88200_PATC_ENTRIES]
Definition: M88K_CPUComponent.h:326
m88k_exception
void m88k_exception(struct cpu *cpu, int vector, int is_trap)
Definition: cpu_m88k.cc:648
BATC_V
#define BATC_V
Definition: m8820x_pte.h:93
cpu::invalidate_translation_caches
void(* invalidate_translation_caches)(struct cpu *, uint64_t paddr, int flags)
Definition: cpu.h:377
M88K_PSR_MODE
#define M88K_PSR_MODE
Definition: m88k_psl.h:70
CMMU_PFSR_SUCCESS
#define CMMU_PFSR_SUCCESS
Definition: m8820x.h:124
cpu.h
m88k_cpu::cr
uint32_t cr[N_M88K_CONTROL_REGS]
Definition: cpu_m88k.h:241
CMMU_PFAR
#define CMMU_PFAR
Definition: m8820x.h:66
cpu::mem
struct memory * mem
Definition: cpu.h:362
EMUL_LITTLE_ENDIAN
#define EMUL_LITTLE_ENDIAN
Definition: misc.h:164
CMMU_PFSR_WRITE
#define CMMU_PFSR_WRITE
Definition: m8820x.h:129
PG_SO
#define PG_SO
Definition: m8820x_pte.h:132
SG_V
#define SG_V
Definition: m8820x_pte.h:107
m8820x_mark_page_as_modified
void m8820x_mark_page_as_modified(struct cpu *cpu, struct m8820x_cmmu *cmmu, uint32_t apr, uint32_t vaddr)
Definition: memory_m88k.cc:59
CMMU_PFSR_PFAULT
#define CMMU_PFSR_PFAULT
Definition: m8820x.h:127
m8820x_cmmu
Definition: M88K_CPUComponent.h:323
BATC_PROT
#define BATC_PROT
Definition: m8820x_pte.h:94
BATC_SO
#define BATC_SO
Definition: m8820x_pte.h:98
M88K_CR_PSR
#define M88K_CR_PSR
Definition: M88K_CPUComponent.h:183
PG_V
#define PG_V
Definition: m8820x_pte.h:124
m8820x_cmmu::batc
uint32_t batc[N_M88200_BATC_REGS]
Definition: M88K_CPUComponent.h:325
sdt_entry_t
u_int32_t sdt_entry_t
Definition: m8820x_pte.h:105
cpu
Definition: cpu.h:326
SG_SO
#define SG_SO
Definition: m8820x_pte.h:112
CMMU_SAPR
#define CMMU_SAPR
Definition: m8820x.h:67
FLAG_NOEXCEPTIONS
#define FLAG_NOEXCEPTIONS
Definition: memory.h:137
CMMU_UAPR
#define CMMU_UAPR
Definition: m8820x.h:68
FLAG_WRITEFLAG
#define FLAG_WRITEFLAG
Definition: memory.h:136
m8820x_pte.h
CMMU_PFSR
#define CMMU_PFSR
Definition: m8820x.h:65
memory.h
PG_U
#define PG_U
Definition: m8820x_pte.h:127
PG_PROT
#define PG_PROT
Definition: m8820x_pte.h:126
PG_RO
#define PG_RO
Definition: m8820x_pte.h:130
FLAG_INSTR
#define FLAG_INSTR
Definition: memory.h:138
memory_paddr_to_hostaddr
unsigned char * memory_paddr_to_hostaddr(struct memory *mem, uint64_t paddr, int writeflag)
Definition: memory.cc:495
SG_RO
#define SG_RO
Definition: m8820x_pte.h:110

Generated on Tue Aug 25 2020 19:25:06 for GXemul by doxygen 1.8.18