25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: memory_ppc.c,v 1.20 2005/11/22 21:56:18 debug Exp $ |
* $Id: memory_ppc.c,v 1.24 2006/06/24 21:47:23 debug Exp $ |
29 |
* |
* |
30 |
* Included from cpu_ppc.c. |
* Included from cpu_ppc.c. |
31 |
*/ |
*/ |
41 |
* BAT translation. Returns -1 if there was no BAT hit, >= 0 for a hit. |
* BAT translation. Returns -1 if there was no BAT hit, >= 0 for a hit. |
42 |
* (0 for access denied, 1 for read-only, and 2 for read-write access allowed.) |
* (0 for access denied, 1 for read-only, and 2 for read-write access allowed.) |
43 |
*/ |
*/ |
44 |
int ppc_bat(struct cpu *cpu, uint64_t vaddr, uint64_t *return_addr, int flags, |
int ppc_bat(struct cpu *cpu, uint64_t vaddr, uint64_t *return_paddr, int flags, |
45 |
int user) |
int user) |
46 |
{ |
{ |
47 |
int i, pp, regnr; |
int i, istart = 0, iend = 8, pp; |
48 |
|
|
49 |
|
if (flags & FLAG_INSTR) |
50 |
|
iend = 4; |
51 |
|
else |
52 |
|
istart = 4; |
53 |
|
|
54 |
if (cpu->cd.ppc.bits != 32) { |
if (cpu->cd.ppc.bits != 32) { |
55 |
fatal("TODO: ppc_bat() for non-32-bit\n"); |
fatal("TODO: ppc_bat() for non-32-bit\n"); |
60 |
exit(1); |
exit(1); |
61 |
} |
} |
62 |
|
|
63 |
/* 4 instruction BATs, 4 data BATs... */ |
/* Scan either the 4 instruction BATs or the 4 data BATs: */ |
64 |
for (i=0; i<8; i++) { |
for (i=istart; i<iend; i++) { |
65 |
regnr = SPR_IBAT0U + i * 2; |
int regnr = SPR_IBAT0U + i * 2; |
66 |
uint32_t upper = cpu->cd.ppc.spr[regnr]; |
uint32_t upper = cpu->cd.ppc.spr[regnr]; |
67 |
uint32_t lower = cpu->cd.ppc.spr[regnr + 1]; |
uint32_t lower = cpu->cd.ppc.spr[regnr + 1]; |
68 |
uint32_t phys = lower & BAT_RPN, ebs = upper & BAT_EPI; |
uint32_t phys = lower & BAT_RPN, ebs = upper & BAT_EPI; |
69 |
uint32_t mask = ((upper & BAT_BL) << 15) | 0x1ffff; |
uint32_t mask = ((upper & BAT_BL) << 15) | 0x1ffff; |
70 |
|
|
|
/* Instruction BAT, but not instruction lookup? Then skip. */ |
|
|
if (i < 4 && !(flags & FLAG_INSTR)) |
|
|
continue; |
|
|
if (i >= 4 && (flags & FLAG_INSTR)) |
|
|
continue; |
|
|
|
|
71 |
/* Not valid in either supervisor or user mode? */ |
/* Not valid in either supervisor or user mode? */ |
72 |
if (user && !(upper & BAT_Vu)) |
if (user && !(upper & BAT_Vu)) |
73 |
continue; |
continue; |
78 |
if ((vaddr & ~mask) != (ebs & ~mask)) |
if ((vaddr & ~mask) != (ebs & ~mask)) |
79 |
continue; |
continue; |
80 |
|
|
81 |
*return_addr = (vaddr & mask) | (phys & ~mask); |
*return_paddr = (vaddr & mask) | (phys & ~mask); |
82 |
|
|
83 |
pp = lower & BAT_PP; |
pp = lower & BAT_PP; |
84 |
switch (pp) { |
switch (pp) { |
107 |
static int get_pte_low(struct cpu *cpu, uint64_t pteg_select, |
static int get_pte_low(struct cpu *cpu, uint64_t pteg_select, |
108 |
uint32_t *lowp, uint32_t cmp) |
uint32_t *lowp, uint32_t cmp) |
109 |
{ |
{ |
110 |
|
unsigned char *d = memory_paddr_to_hostaddr(cpu->mem, pteg_select, 1) |
111 |
|
+ (pteg_select & ((1 << BITS_PER_MEMBLOCK) - 1)); |
112 |
int i; |
int i; |
|
uint32_t upper; |
|
|
unsigned char d[8]; |
|
113 |
|
|
114 |
for (i=0; i<8; i++) { |
for (i=0; i<8; i++) { |
115 |
cpu->memory_rw(cpu, cpu->mem, pteg_select + i*8, |
uint32_t *ep = (uint32_t *) (d + (i << 3)), upper; |
116 |
&d[0], 8, MEM_READ, PHYSICAL | NO_EXCEPTIONS); |
upper = *ep; |
117 |
upper = (d[0]<<24)+(d[1]<<16)+(d[2]<<8)+d[3]; |
upper = BE32_TO_HOST(upper); |
118 |
|
|
119 |
/* Valid PTE, and correct api and vsid? */ |
/* Valid PTE, and correct api and vsid? */ |
120 |
if (upper == cmp) { |
if (upper == cmp) { |
121 |
*lowp = ((d[4]<<24)+(d[5]<<16)+(d[6]<<8)+d[7]); |
uint32_t lo = ep[1]; |
122 |
|
lo = BE32_TO_HOST(lo); |
123 |
|
*lowp = lo; |
124 |
return 1; |
return 1; |
125 |
} |
} |
126 |
} |
} |
139 |
* a permission violation. *resp is set to 0 for no access, 1 for read-only |
* a permission violation. *resp is set to 0 for no access, 1 for read-only |
140 |
* access, or 2 for read/write access. |
* access, or 2 for read/write access. |
141 |
*/ |
*/ |
142 |
static int ppc_vtp32(struct cpu *cpu, uint32_t vaddr, uint64_t *return_addr, |
static int ppc_vtp32(struct cpu *cpu, uint32_t vaddr, uint64_t *return_paddr, |
143 |
int *resp, uint64_t msr, int writeflag, int instr) |
int *resp, uint64_t msr, int writeflag, int instr) |
144 |
{ |
{ |
145 |
int srn = (vaddr >> 28) & 15, api = (vaddr >> 22) & PTE_API; |
int srn = (vaddr >> 28) & 15, api = (vaddr >> 22) & PTE_API; |
186 |
return 1; |
return 1; |
187 |
|
|
188 |
access = lower_pte & PTE_PP; |
access = lower_pte & PTE_PP; |
189 |
*return_addr = (lower_pte & PTE_RPGN) | (vaddr & ~PTE_RPGN); |
*return_paddr = (lower_pte & PTE_RPGN) | (vaddr & ~PTE_RPGN); |
190 |
|
|
191 |
key = (cpu->cd.ppc.sr[srn] & SR_PRKEY && msr & PPC_MSR_PR) || |
key = (cpu->cd.ppc.sr[srn] & SR_PRKEY && msr & PPC_MSR_PR) || |
192 |
(cpu->cd.ppc.sr[srn] & SR_SUKEY && !(msr & PPC_MSR_PR)); |
(cpu->cd.ppc.sr[srn] & SR_SUKEY && !(msr & PPC_MSR_PR)); |
212 |
|
|
213 |
|
|
214 |
/* |
/* |
215 |
* ppc_translate_address(): |
* ppc_translate_v2p(): |
216 |
* |
* |
217 |
* Don't call this function is userland_emul is non-NULL, or cpu is NULL. |
* Don't call this function is userland_emul is non-NULL, or cpu is NULL. |
218 |
* |
* |
221 |
* 1 Success, the page is readable only |
* 1 Success, the page is readable only |
222 |
* 2 Success, the page is read/write |
* 2 Success, the page is read/write |
223 |
*/ |
*/ |
224 |
int ppc_translate_address(struct cpu *cpu, uint64_t vaddr, |
int ppc_translate_v2p(struct cpu *cpu, uint64_t vaddr, |
225 |
uint64_t *return_addr, int flags) |
uint64_t *return_paddr, int flags) |
226 |
{ |
{ |
227 |
int instr = flags & FLAG_INSTR, res = 0, match, user; |
int instr = flags & FLAG_INSTR, res = 0, match, user; |
228 |
int writeflag = flags & FLAG_WRITEFLAG? 1 : 0; |
int writeflag = flags & FLAG_WRITEFLAG? 1 : 0; |
235 |
vaddr &= 0xffffffff; |
vaddr &= 0xffffffff; |
236 |
|
|
237 |
if ((instr && !(msr & PPC_MSR_IR)) || (!instr && !(msr & PPC_MSR_DR))) { |
if ((instr && !(msr & PPC_MSR_IR)) || (!instr && !(msr & PPC_MSR_DR))) { |
238 |
*return_addr = vaddr; |
*return_paddr = vaddr; |
239 |
return 2; |
return 2; |
240 |
} |
} |
241 |
|
|
242 |
if (cpu->cd.ppc.cpu_type.flags & PPC_601) { |
if (cpu->cd.ppc.cpu_type.flags & PPC_601) { |
243 |
fatal("ppc_translate_address(): TODO: 601\n"); |
fatal("ppc_translate_v2p(): TODO: 601\n"); |
244 |
exit(1); |
exit(1); |
245 |
} |
} |
246 |
|
|
247 |
/* Try the BATs first: */ |
/* Try the BATs first: */ |
248 |
if (cpu->cd.ppc.bits == 32) { |
if (cpu->cd.ppc.bits == 32) { |
249 |
res = ppc_bat(cpu, vaddr, return_addr, flags, user); |
res = ppc_bat(cpu, vaddr, return_paddr, flags, user); |
250 |
if (res > 0) |
if (res > 0) |
251 |
return res; |
return res; |
252 |
if (res == 0) { |
if (res == 0) { |
257 |
|
|
258 |
/* Virtual to physical translation: */ |
/* Virtual to physical translation: */ |
259 |
if (cpu->cd.ppc.bits == 32) { |
if (cpu->cd.ppc.bits == 32) { |
260 |
match = ppc_vtp32(cpu, vaddr, return_addr, &res, msr, |
match = ppc_vtp32(cpu, vaddr, return_paddr, &res, msr, |
261 |
writeflag, instr); |
writeflag, instr); |
262 |
if (match && res > 0) |
if (match && res > 0) |
263 |
return res; |
return res; |
279 |
return 0; |
return 0; |
280 |
|
|
281 |
if (!quiet_mode) |
if (!quiet_mode) |
282 |
fatal("[ memory_ppc: exception! vaddr=0x%llx pc=0x%llx " |
fatal("[ memory_ppc: exception! vaddr=0x%"PRIx64" pc=0x%"PRIx64 |
283 |
"instr=%i user=%i wf=%i ]\n", (long long)vaddr, |
" instr=%i user=%i wf=%i ]\n", (uint64_t) vaddr, |
284 |
(long long)cpu->pc, instr, user, writeflag); |
(uint64_t) cpu->pc, instr, user, writeflag); |
285 |
|
|
286 |
if (cpu->cd.ppc.cpu_type.flags & PPC_603) { |
if (cpu->cd.ppc.cpu_type.flags & PPC_603) { |
287 |
cpu->cd.ppc.spr[instr? SPR_IMISS : SPR_DMISS] = vaddr; |
cpu->cd.ppc.spr[instr? SPR_IMISS : SPR_DMISS] = vaddr; |