memory_ppc.cc Source File

Back to the index.

memory_ppc.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-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  * Included from cpu_ppc.c.
29  */
30 
31 
32 /*
33  * ppc_bat():
34  *
35  * BAT translation. Returns -1 if there was no BAT hit, >= 0 for a hit.
36  * (0 for access denied, 1 for read-only, and 2 for read-write access allowed.)
37  */
38 int ppc_bat(struct cpu *cpu, uint64_t vaddr, uint64_t *return_paddr, int flags,
39  int user)
40 {
41  int i, istart = 0, iend = 8, pp;
42 
43  if (flags & FLAG_INSTR)
44  iend = 4;
45  else
46  istart = 4;
47 
48  if (cpu->cd.ppc.bits != 32) {
49  fatal("TODO: ppc_bat() for non-32-bit\n");
50  exit(1);
51  }
52  if (cpu->cd.ppc.cpu_type.flags & PPC_601) {
53  fatal("TODO: ppc_bat() for PPC 601\n");
54  exit(1);
55  }
56 
57  /* Scan either the 4 instruction BATs or the 4 data BATs: */
58  for (i=istart; i<iend; i++) {
59  int regnr = SPR_IBAT0U + i * 2;
60  uint32_t upper = cpu->cd.ppc.spr[regnr];
61  uint32_t lower = cpu->cd.ppc.spr[regnr + 1];
62  uint32_t phys = lower & BAT_RPN, ebs = upper & BAT_EPI;
63  uint32_t mask = ((upper & BAT_BL) << 15) | 0x1ffff;
64 
65  /* Not valid in either supervisor or user mode? */
66  if (user && !(upper & BAT_Vu))
67  continue;
68  if (!user && !(upper & BAT_Vs))
69  continue;
70 
71  /* Virtual address mismatch? Then skip. */
72  if ((vaddr & ~mask) != (ebs & ~mask))
73  continue;
74 
75  *return_paddr = (vaddr & mask) | (phys & ~mask);
76 
77  pp = lower & BAT_PP;
78  switch (pp) {
79  case BAT_PP_NONE:
80  return 0;
81  case BAT_PP_RO_S:
82  case BAT_PP_RO:
83  return (flags & FLAG_WRITEFLAG)? 0 : 1;
84  default:/* BAT_PP_RW: */
85  return 2;
86  }
87  }
88 
89  return -1;
90 }
91 
92 
93 /*
94  * get_pte_low():
95  *
96  * Scan a PTE group for a cmp (compare) value.
97  *
98  * Returns 1 if the value was found, and *lowp is set to the low PTE word.
99  * Returns 0 if no match was found.
100  */
101 static int get_pte_low(struct cpu *cpu, uint64_t pteg_select,
102  uint32_t *lowp, uint32_t cmp)
103 {
104  unsigned char *d = memory_paddr_to_hostaddr(cpu->mem, pteg_select, 1);
105  int i;
106 
107  for (i=0; i<8; i++) {
108  uint32_t *ep = (uint32_t *) (d + (i << 3)), upper;
109  upper = *ep;
110  upper = BE32_TO_HOST(upper);
111 
112  /* Valid PTE, and correct api and vsid? */
113  if (upper == cmp) {
114  uint32_t lo = ep[1];
115  lo = BE32_TO_HOST(lo);
116  *lowp = lo;
117  return 1;
118  }
119  }
120 
121  return 0;
122 }
123 
124 
125 /*
126  * ppc_vtp32():
127  *
128  * Virtual to physical address translation (32-bit mode).
129  *
130  * Returns 1 if a translation was found, 0 if none was found. However, finding
131  * a translation does not mean that it should be returned; there can be
132  * a permission violation. *resp is set to 0 for no access, 1 for read-only
133  * access, or 2 for read/write access.
134  */
135 static int ppc_vtp32(struct cpu *cpu, uint32_t vaddr, uint64_t *return_paddr,
136  int *resp, uint64_t msr, int writeflag, int instr)
137 {
138  int srn = (vaddr >> 28) & 15, api = (vaddr >> 22) & PTE_API;
139  int access, key, match;
140  uint32_t vsid = cpu->cd.ppc.sr[srn] & 0x00ffffff;
141  uint64_t sdr1 = cpu->cd.ppc.spr[SPR_SDR1], htaborg;
142  uint32_t hash1, hash2, pteg_select, tmp;
143  uint32_t lower_pte = 0, cmp;
144 
145  htaborg = sdr1 & 0xffff0000UL;
146 
147  /* Primary hash: */
148  hash1 = (vsid & 0x7ffff) ^ ((vaddr >> 12) & 0xffff);
149  tmp = (hash1 >> 10) & (sdr1 & 0x1ff);
150  pteg_select = htaborg & 0xfe000000;
151  pteg_select |= ((hash1 & 0x3ff) << 6);
152  pteg_select |= (htaborg & 0x01ff0000) | (tmp << 16);
153  cpu->cd.ppc.spr[SPR_HASH1] = pteg_select;
154  cmp = cpu->cd.ppc.spr[instr? SPR_ICMP : SPR_DCMP] =
155  PTE_VALID | api | (vsid << PTE_VSID_SHFT);
156  match = get_pte_low(cpu, pteg_select, &lower_pte, cmp);
157 
158  /* Secondary hash: */
159  hash2 = hash1 ^ 0x7ffff;
160  tmp = (hash2 >> 10) & (sdr1 & 0x1ff);
161  pteg_select = htaborg & 0xfe000000;
162  pteg_select |= ((hash2 & 0x3ff) << 6);
163  pteg_select |= (htaborg & 0x01ff0000) | (tmp << 16);
164  cpu->cd.ppc.spr[SPR_HASH2] = pteg_select;
165  if (!match) {
166  cmp |= PTE_HID;
167  match = get_pte_low(cpu, pteg_select, &lower_pte, cmp);
168  }
169 
170  *resp = 0;
171 
172  if (!match)
173  return 0;
174 
175  /* Non-executable, or Guarded page? */
176  if (instr && cpu->cd.ppc.sr[srn] & SR_NOEXEC)
177  return 1;
178  if (instr && lower_pte & PTE_G)
179  return 1;
180 
181  access = lower_pte & PTE_PP;
182  *return_paddr = (lower_pte & PTE_RPGN) | (vaddr & ~PTE_RPGN);
183 
184  key = (cpu->cd.ppc.sr[srn] & SR_PRKEY && msr & PPC_MSR_PR) ||
185  (cpu->cd.ppc.sr[srn] & SR_SUKEY && !(msr & PPC_MSR_PR));
186 
187  if (key) {
188  switch (access) {
189  case 1:
190  case 3: *resp = writeflag? 0 : 1;
191  break;
192  case 2: *resp = 2;
193  break;
194  }
195  } else {
196  switch (access) {
197  case 3: *resp = writeflag? 0 : 1;
198  break;
199  default:*resp = 2;
200  }
201  }
202 
203  return 1;
204 }
205 
206 
207 /*
208  * ppc_translate_v2p():
209  *
210  * Return values:
211  * 0 Failure
212  * 1 Success, the page is readable only
213  * 2 Success, the page is read/write
214  */
215 int ppc_translate_v2p(struct cpu *cpu, uint64_t vaddr,
216  uint64_t *return_paddr, int flags)
217 {
218  int instr = flags & FLAG_INSTR, res = 0, match, user;
219  int writeflag = flags & FLAG_WRITEFLAG? 1 : 0;
220  uint64_t msr;
221 
222  reg_access_msr(cpu, &msr, 0, 0);
223  user = msr & PPC_MSR_PR? 1 : 0;
224 
225  if (cpu->cd.ppc.bits == 32)
226  vaddr &= 0xffffffff;
227 
228  if ((instr && !(msr & PPC_MSR_IR)) || (!instr && !(msr & PPC_MSR_DR))) {
229  *return_paddr = vaddr;
230  return 2;
231  }
232 
233  if (cpu->cd.ppc.cpu_type.flags & PPC_601) {
234  fatal("ppc_translate_v2p(): TODO: 601\n");
235  exit(1);
236  }
237 
238  /* Try the BATs first: */
239  if (cpu->cd.ppc.bits == 32) {
240  res = ppc_bat(cpu, vaddr, return_paddr, flags, user);
241  if (res > 0)
242  return res;
243  if (res == 0) {
244  fatal("[ TODO: BAT exception ]\n");
245  exit(1);
246  }
247  }
248 
249  /* Virtual to physical translation: */
250  if (cpu->cd.ppc.bits == 32) {
251  match = ppc_vtp32(cpu, vaddr, return_paddr, &res, msr,
252  writeflag, instr);
253  if (match && res > 0)
254  return res;
255  } else {
256  /* htaborg = sdr1 & 0xfffffffffffc0000ULL; */
257  fatal("TODO: ppc 64-bit translation\n");
258  exit(1);
259  }
260 
261 
262  /*
263  * No match? Then cause an exception.
264  *
265  * PPC603: cause a software TLB reload exception.
266  * All others: cause a DSI or ISI.
267  */
268 
269  if (flags & FLAG_NOEXCEPTIONS)
270  return 0;
271 
272  if (!quiet_mode)
273  fatal("[ memory_ppc: exception! vaddr=0x%" PRIx64" pc=0x%" PRIx64
274  " instr=%i user=%i wf=%i ]\n", (uint64_t) vaddr,
275  (uint64_t) cpu->pc, instr, user, writeflag);
276 
277  if (cpu->cd.ppc.cpu_type.flags & PPC_603) {
278  cpu->cd.ppc.spr[instr? SPR_IMISS : SPR_DMISS] = vaddr;
279 
280  msr |= PPC_MSR_TGPR;
281  reg_access_msr(cpu, &msr, 1, 0);
282 
283  ppc_exception(cpu, instr? 0x10 : (writeflag? 0x12 : 0x11));
284  } else {
285  if (!instr) {
286  cpu->cd.ppc.spr[SPR_DAR] = vaddr;
287  cpu->cd.ppc.spr[SPR_DSISR] = match?
289  if (writeflag)
290  cpu->cd.ppc.spr[SPR_DSISR] |= DSISR_STORE;
291  }
292  ppc_exception(cpu, instr?
294  }
295 
296  return 0;
297 }
298 
#define SPR_DCMP
Definition: ppc_spr.h:286
void fatal(const char *fmt,...)
Definition: main.cc:152
#define BAT_EPI
Definition: ppc_bat.h:104
#define BAT_RPN
Definition: ppc_bat.h:84
#define PTE_VSID_SHFT
Definition: ppc_pte.h:68
uint64_t spr[1024]
Definition: cpu_ppc.h:134
int ppc_translate_v2p(struct cpu *cpu, uint64_t vaddr, uint64_t *return_paddr, int flags)
Definition: memory_ppc.cc:215
#define SR_NOEXEC
Definition: ppc_pte.h:156
#define FLAG_NOEXCEPTIONS
Definition: memory.h:137
#define BAT_Vu
Definition: ppc_bat.h:107
#define PTE_API
Definition: ppc_pte.h:71
#define SPR_HASH2
Definition: ppc_spr.h:289
#define PTE_RPGN
Definition: ppc_pte.h:77
#define SPR_DSISR
Definition: ppc_spr.h:42
#define SR_PRKEY
Definition: ppc_pte.h:155
struct ppc_cpu ppc
Definition: cpu.h:444
union cpu::@1 cd
#define BE32_TO_HOST(x)
Definition: misc.h:181
struct memory * mem
Definition: cpu.h:362
#define SPR_SDR1
Definition: ppc_spr.h:55
#define instr(n)
#define PPC_EXCEPTION_ISI
Definition: cpu_ppc.h:190
#define DSISR_NOTFOUND
Definition: ppc_spr.h:44
#define PTE_PP
Definition: ppc_pte.h:87
#define SPR_HASH1
Definition: ppc_spr.h:287
#define DSISR_STORE
Definition: ppc_spr.h:47
#define PPC_603
Definition: cpu_ppc.h:65
#define PTE_HID
Definition: ppc_pte.h:70
#define BAT_PP_RO
Definition: ppc_bat.h:101
#define SPR_DAR
Definition: ppc_spr.h:51
#define PPC_MSR_PR
Definition: cpu_ppc.h:160
void reg_access_msr(struct cpu *cpu, uint64_t *valuep, int writeflag, int check_for_interrupts)
Definition: cpu_ppc.cc:299
uint64_t pc
Definition: cpu.h:383
#define BAT_PP_RO_S
Definition: ppc_bat.h:99
#define FLAG_INSTR
Definition: memory.h:138
#define PPC_MSR_TGPR
Definition: cpu_ppc.h:157
#define SPR_IBAT0U
Definition: ppc_spr.h:119
int bits
Definition: cpu_ppc.h:116
#define SR_SUKEY
Definition: ppc_pte.h:154
#define BAT_PP_NONE
Definition: ppc_bat.h:98
#define SPR_IMISS
Definition: ppc_spr.h:298
uint32_t sr[16]
Definition: cpu_ppc.h:133
#define PPC_MSR_IR
Definition: cpu_ppc.h:168
int ppc_bat(struct cpu *cpu, uint64_t vaddr, uint64_t *return_paddr, int flags, int user)
Definition: memory_ppc.cc:38
#define PPC_EXCEPTION_DSI
Definition: cpu_ppc.h:189
void ppc_exception(struct cpu *cpu, int exception_nr)
Definition: cpu_ppc.cc:352
int quiet_mode
Definition: emul.cc:68
#define PPC_MSR_DR
Definition: cpu_ppc.h:169
Definition: cpu.h:326
#define PPC_601
Definition: cpu_ppc.h:64
#define BAT_BL
Definition: ppc_bat.h:105
#define SPR_ICMP
Definition: ppc_spr.h:301
#define FLAG_WRITEFLAG
Definition: memory.h:136
#define DSISR_PROTECT
Definition: ppc_spr.h:45
#define SPR_DMISS
Definition: ppc_spr.h:285
#define BAT_Vs
Definition: ppc_bat.h:106
#define PTE_VALID
Definition: ppc_pte.h:66
#define BAT_PP
Definition: ppc_bat.h:97
struct ppc_cpu_type_def cpu_type
Definition: cpu_ppc.h:111
#define PTE_G
Definition: ppc_pte.h:84
unsigned char * memory_paddr_to_hostaddr(struct memory *mem, uint64_t paddr, int writeflag)
Definition: memory.cc:495

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