/[gxemul]/trunk/src/cpus/cpu_dyntrans.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/cpus/cpu_dyntrans.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 42 - (show annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 53401 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1613 2007/06/15 20:11:26 debug Exp $
20070501	Continuing a little on m88k disassembly (control registers,
		more instructions).
		Adding a dummy mvme88k machine mode.
20070502	Re-adding MIPS load/store alignment exceptions.
20070503	Implementing more of the M88K disassembly code.
20070504	Adding disassembly of some more M88K load/store instructions.
		Implementing some relatively simple M88K instructions (br.n,
		xor[.u] imm, and[.u] imm).
20070505	Implementing M88K three-register and, or, xor, and jmp[.n],
		bsr[.n] including function call trace stuff.
		Applying a patch from Bruce M. Simpson which implements the
		SYSCON_BOARD_CPU_CLOCK_FREQ_ID object of the syscon call in
		the yamon PROM emulation.
20070506	Implementing M88K bb0[.n] and bb1[.n], and skeletons for
		ldcr and stcr (although no control regs are implemented yet).
20070509	Found and fixed the bug which caused Linux for QEMU_MIPS to
		stop working in 0.4.5.1: It was a faulty change to the MIPS
		'sc' and 'scd' instructions I made while going through gcc -W
		warnings on 20070428.
20070510	Updating the Linux/QEMU_MIPS section in guestoses.html to
		use mips-test-0.2.tar.gz instead of 0.1.
		A big thank you to Miod Vallat for sending me M88K manuals.
		Implementing more M88K instructions (addu, subu, div[u], mulu,
		ext[u], clr, set, cmp).
20070511	Fixing bugs in the M88K "and" and "and.u" instructions (found
		by comparing against the manual).
		Implementing more M88K instructions (mask[.u], mak, bcnd (auto-
		generated)) and some more control register details.
		Cleanup: Removing the experimental AVR emulation mode and
		corresponding devices; AVR emulation wasn't really meaningful.
		Implementing autogeneration of most M88K loads/stores. The
		rectangle drawing demo (with -O0) for M88K runs :-)
		Beginning on M88K exception handling.
		More M88K instructions: tb0, tb1, rte, sub, jsr[.n].
		Adding some skeleton MVME PROM ("BUG") emulation.
20070512	Fixing a bug in the M88K cmp instruction.
		Adding the M88K lda (scaled register) instruction.
		Fixing bugs in 64-bit (32-bit pairs) M88K loads/stores.
		Removing the unused tick_hz stuff from the machine struct.
		Implementing the M88K xmem instruction. OpenBSD/mvme88k gets
		far enough to display the Copyright banner :-)
		Implementing subu.co (guess), addu.co, addu.ci, ff0, and ff1.
		Adding a dev_mvme187, for MVME187-specific devices/registers.
		OpenBSD/mvme88k prints more boot messages. :)
20070515	Continuing on MVME187 emulation (adding more devices, beginning
		on the CMMUs, etc).
		Adding the M88K and.c, xor.c, and or.c instructions, and making
		sure that mul, div, etc cause exceptions if executed when SFD1
		is disabled.
20070517	Continuing on M88K and MVME187 emulation in general; moving
		the CMMU registers to the CPU struct, separating dev_pcc2 from
		dev_mvme187, and beginning on memory_m88k.c (BATC and PATC).
		Fixing a bug in 64-bit (32-bit pairs) M88K fast stores.
		Implementing the clock part of dev_mk48txx.
		Implementing the M88K fstcr and xcr instructions.
		Implementing m88k_cpu_tlbdump().
		Beginning on the implementation of a separate address space
		for M88K .usr loads/stores.
20070520	Removing the non-working (skeleton) Sandpoint, SonyNEWS, SHARK
		Dnard, and Zaurus machine modes.
		Experimenting with dyntrans to_be_translated read-ahead. It
		seems to give a very small performance increase for MIPS
		emulation, but a large performance degradation for SuperH. Hm.
20070522	Disabling correct SuperH ITLB emulation; it does not seem to be
		necessary in order to let SH4 guest OSes run, and it slows down
		userspace code.
		Implementing "samepage" branches for SuperH emulation, and some
		other minor speed hacks.
20070525	Continuing on M88K memory-related stuff: exceptions, memory
		transaction register contents, etc.
		Implementing the M88K subu.ci instruction.
		Removing the non-working (skeleton) Iyonix machine mode.
		OpenBSD/mvme88k reaches userland :-), starts executing
		/sbin/init's instructions, and issues a few syscalls, before
		crashing.
20070526	Fixing bugs in dev_mk48txx, so that OpenBSD/mvme88k detects
		the correct time-of-day.
		Implementing a generic IRQ controller for the test machines
		(dev_irqc), similar to a proposed patch from Petr Stepan.
		Experimenting some more with translation read-ahead.
		Adding an "expect" script for automated OpenBSD/landisk
		install regression/performance tests.
20070527	Adding a dummy mmEye (SH3) machine mode skeleton.
		FINALLY found the strange M88K bug I have been hunting: I had
		not emulated the SNIP value for exceptions occurring in
		branch delay slots correctly.
		Implementing correct exceptions for 64-bit M88K loads/stores.
		Address to symbol lookups are now disabled when M88K is
		running in usermode (because usermode addresses don't have
		anything to do with supervisor addresses).
20070531	Removing the mmEye machine mode skeleton.
20070604	Some minor code cleanup.
20070605	Moving src/useremul.c into a subdir (src/useremul/), and
		cleaning up some more legacy constructs.
		Adding -Wstrict-aliasing and -fstrict-aliasing detection to
		the configure script.
20070606	Adding a check for broken GCC on Solaris to the configure
		script. (GCC 3.4.3 on Solaris cannot handle static variables
		which are initialized to 0 or NULL. :-/)
		Removing the old (non-working) ARC emulation modes: NEC RD94,
		R94, R96, and R98, and the last traces of Olivetti M700 and
		Deskstation Tyne.
		Removing the non-working skeleton WDSC device (dev_wdsc).
20070607	Thinking about how to use the host's cc + ld at runtime to
		generate native code. (See experiments/native_cc_ld_test.i
		for an example.)
20070608	Adding a program counter sampling timer, which could be useful
		for native code generation experiments.
		The KN02_CSR_NRMMOD bit in the DECstation 5000/200 (KN02) CSR
		should always be set, to allow a 5000/200 PROM to boot.
20070609	Moving out breakpoint details from the machine struct into
		a helper struct, and removing the limit on max nr of
		breakpoints.
20070610	Moving out tick functions into a helper struct as well (which
		also gets rid of the max limit).
20070612	FINALLY figured out why Debian/DECstation stopped working when
		translation read-ahead was enabled: in src/memory_rw.c, the
		call to invalidate_code_translation was made also if the
		memory access was an instruction load (if the page was mapped
		as writable); it shouldn't be called in that case.
20070613	Implementing some more MIPS32/64 revision 2 instructions: di,
		ei, ext, dext, dextm, dextu, and ins.
20070614	Implementing an instruction combination for the NetBSD/arm
		idle loop (making the host not use any cpu if NetBSD/arm
		inside the emulator is not using any cpu).
		Increasing the nr of ARM VPH entries from 128 to 384.
20070615	Removing the ENABLE_arch stuff from the configure script, so
		that all included architectures are included in both release
		and development builds.
		Moving memory related helper functions from misc.c to memory.c.
		Adding preliminary instructions for netbooting NetBSD/pmppc to
		guestoses.html; it doesn't work yet, there are weird timeouts.
		Beginning a total rewrite of the userland emulation modes
		(removing all emulation modes, beginning from scratch with
		NetBSD/MIPS and FreeBSD/Alpha only).
20070616	After fixing a bug in the DEC21143 NIC (the TDSTAT_OWN bit was
		only cleared for the last segment when transmitting, not all
		segments), NetBSD/pmppc boots with root-on-nfs without the
		timeouts. Updating guestoses.html.
		Removing the skeleton PSP (Playstation Portable) mode.
		Moving X11-related stuff in the machine struct into a helper
		struct.
		Cleanup of out-of-memory checks, to use a new CHECK_ALLOCATION
		macro (which prints a meaningful error message).
		Adding a COMMENT to each machine and device (for automagic
		.index comment generation).
		Doing regression testing for the next release.

==============  RELEASE 0.4.6  ==============


1 /*
2 * Copyright (C) 2005-2007 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 * $Id: cpu_dyntrans.c,v 1.165 2007/06/15 21:43:53 debug Exp $
29 *
30 * Common dyntrans routines. Included from cpu_*.c.
31 */
32
33
34 #ifndef STATIC_STUFF
35 #define STATIC_STUFF
36 /*
37 * gather_statistics():
38 */
39 static void gather_statistics(struct cpu *cpu)
40 {
41 char ch, buf[60];
42 struct DYNTRANS_IC *ic = cpu->cd.DYNTRANS_ARCH.next_ic;
43 int i = 0;
44 uint64_t a;
45 int low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t)
46 cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC);
47
48 if (cpu->machine->statistics_file == NULL) {
49 fatal("statistics gathering with no filename set is"
50 " meaningless\n");
51 return;
52 }
53
54 /* low_pc must be within the page! */
55 if (low_pc < 0 || low_pc > DYNTRANS_IC_ENTRIES_PER_PAGE)
56 return;
57
58 buf[0] = '\0';
59
60 while ((ch = cpu->machine->statistics_fields[i]) != '\0') {
61 if (i != 0)
62 strlcat(buf, " ", sizeof(buf));
63
64 switch (ch) {
65 case 'i':
66 snprintf(buf + strlen(buf), sizeof(buf),
67 "%p", (void *)ic->f);
68 break;
69 case 'p':
70 /* Physical program counter address: */
71 cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *)
72 cpu->cd.DYNTRANS_ARCH.cur_ic_page;
73 a = cpu->cd.DYNTRANS_ARCH.cur_physpage->physaddr;
74 a &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
75 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
76 a += low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT;
77 if (cpu->is_32bit)
78 snprintf(buf + strlen(buf), sizeof(buf),
79 "0x%08"PRIx32, (uint32_t)a);
80 else
81 snprintf(buf + strlen(buf), sizeof(buf),
82 "0x%016"PRIx64, (uint64_t)a);
83 break;
84 case 'v':
85 /* Virtual program counter address: */
86 a = cpu->pc;
87 a &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
88 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
89 a += low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT;
90 if (cpu->is_32bit)
91 snprintf(buf + strlen(buf), sizeof(buf),
92 "0x%08"PRIx32, (uint32_t)a);
93 else
94 snprintf(buf + strlen(buf), sizeof(buf),
95 "0x%016"PRIx64, (uint64_t)a);
96 break;
97 }
98 i++;
99 }
100
101 fprintf(cpu->machine->statistics_file, "%s\n", buf);
102 }
103
104
105 #define S gather_statistics(cpu)
106
107
108 #if 1
109
110 /* The normal instruction execution core: */
111 #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic);
112
113 #else
114
115 /* For heavy debugging: */
116 #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; \
117 { \
118 int low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - \
119 (size_t)cpu->cd.DYNTRANS_ARCH.cur_ic_page) / \
120 sizeof(struct DYNTRANS_IC); \
121 printf("cur_ic_page=%p ic=%p (low_pc=0x%x)\n", \
122 cpu->cd.DYNTRANS_ARCH.cur_ic_page, \
123 ic, low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT); \
124 } \
125 ic->f(cpu, ic);
126
127 #endif
128
129 /* static long long nr_of_I_calls = 0; */
130
131 /* Temporary hack for finding NULL bugs: */
132 /* #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; \
133 nr_of_I_calls ++; \
134 if (ic->f == NULL) { \
135 int low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - \
136 (size_t)cpu->cd.DYNTRANS_ARCH.cur_ic_page) / \
137 sizeof(struct DYNTRANS_IC); \
138 cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) << \
139 DYNTRANS_INSTR_ALIGNMENT_SHIFT); \
140 cpu->pc += (low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT);\
141 printf("Crash at %016"PRIx64"\n", cpu->pc); \
142 printf("nr of I calls: %lli\n", nr_of_I_calls); \
143 printf("Next ic = %p\n", cpu->cd. \
144 DYNTRANS_ARCH.next_ic); \
145 printf("cur ic page = %p\n", cpu->cd. \
146 DYNTRANS_ARCH.cur_ic_page); \
147 cpu->running = 0; \
148 return 0; \
149 } \
150 ic->f(cpu, ic); */
151
152 /* Temporary hack for MIPS, to hunt for 32-bit/64-bit sign-extension bugs: */
153 /* #define I { int k; for (k=1; k<=31; k++) \
154 cpu->cd.mips.gpr[k] = (int32_t)cpu->cd.mips.gpr[k];\
155 if (cpu->cd.mips.gpr[0] != 0) { \
156 fatal("NOOOOOO\n"); exit(1); \
157 } \
158 ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic); }
159 */
160 #endif /* STATIC STUFF */
161
162
163
164 #ifdef DYNTRANS_RUN_INSTR
165 /*
166 * XXX_run_instr():
167 *
168 * Execute one or more instructions on a specific CPU, using dyntrans.
169 * (For dualmode archs, this function is included twice.)
170 *
171 * Return value is the number of instructions executed during this call,
172 * 0 if no instructions were executed.
173 */
174 int DYNTRANS_RUN_INSTR(struct cpu *cpu)
175 {
176 MODE_uint_t cached_pc;
177 int low_pc, n_instrs;
178
179 /* Ugly... fix this some day. */
180 #ifdef DYNTRANS_DUALMODE_32
181 #ifdef MODE32
182 DYNTRANS_PC_TO_POINTERS32(cpu);
183 #else
184 DYNTRANS_PC_TO_POINTERS(cpu);
185 #endif
186 #else
187 DYNTRANS_PC_TO_POINTERS(cpu);
188 #endif
189
190 /*
191 * Interrupt assertion? (This is _below_ the initial PC to pointer
192 * conversion; if the conversion caused an exception of some kind
193 * then interrupts are probably disabled, and the exception will get
194 * priority over device interrupts.)
195 *
196 * TODO: Turn this into a family-specific function somewhere...
197 */
198 #ifdef DYNTRANS_ARM
199 if (cpu->cd.arm.irq_asserted && !(cpu->cd.arm.cpsr & ARM_FLAG_I))
200 arm_exception(cpu, ARM_EXCEPTION_IRQ);
201 #endif
202 #ifdef DYNTRANS_MIPS
203 {
204 int enabled, mask;
205 int status = cpu->cd.mips.coproc[0]->reg[COP0_STATUS];
206 if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {
207 /* R3000: */
208 enabled = status & MIPS_SR_INT_IE;
209 } else {
210 /* R4000 and others: */
211 enabled = (status & STATUS_IE)
212 && !(status & STATUS_EXL) && !(status & STATUS_ERL);
213 /* Special case for R5900/C790/TX79: */
214 if (cpu->cd.mips.cpu_type.rev == MIPS_R5900 &&
215 !(status & R5900_STATUS_EIE))
216 enabled = 0;
217 }
218 mask = status & cpu->cd.mips.coproc[0]->reg[COP0_CAUSE]
219 & STATUS_IM_MASK;
220
221 if (enabled && mask)
222 mips_cpu_exception(cpu, EXCEPTION_INT, 0, 0, 0, 0, 0,0);
223 }
224 #endif
225 #ifdef DYNTRANS_PPC
226 if (cpu->cd.ppc.dec_intr_pending && cpu->cd.ppc.msr & PPC_MSR_EE) {
227 if (!(cpu->cd.ppc.cpu_type.flags & PPC_NO_DEC))
228 ppc_exception(cpu, PPC_EXCEPTION_DEC);
229 cpu->cd.ppc.dec_intr_pending = 0;
230 }
231 if (cpu->cd.ppc.irq_asserted && cpu->cd.ppc.msr & PPC_MSR_EE)
232 ppc_exception(cpu, PPC_EXCEPTION_EI);
233 #endif
234 #ifdef DYNTRANS_SH
235 if (cpu->cd.sh.int_to_assert > 0 && !(cpu->cd.sh.sr & SH_SR_BL)
236 && ((cpu->cd.sh.sr & SH_SR_IMASK) >> SH_SR_IMASK_SHIFT)
237 < cpu->cd.sh.int_level)
238 sh_exception(cpu, 0, cpu->cd.sh.int_to_assert, 0);
239 #endif
240
241 cached_pc = cpu->pc;
242
243 cpu->n_translated_instrs = 0;
244
245 cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *)
246 cpu->cd.DYNTRANS_ARCH.cur_ic_page;
247
248 if (single_step || cpu->machine->instruction_trace
249 || cpu->machine->register_dump) {
250 /*
251 * Single-step:
252 */
253 struct DYNTRANS_IC *ic = cpu->cd.DYNTRANS_ARCH.next_ic;
254 if (cpu->machine->register_dump) {
255 debug("\n");
256 cpu_register_dump(cpu->machine, cpu, 1, 0x1);
257 }
258 if (cpu->machine->instruction_trace) {
259 /* TODO/Note: This must be large enough to hold
260 any instruction for any ISA: */
261 unsigned char instr[1 <<
262 DYNTRANS_INSTR_ALIGNMENT_SHIFT];
263 if (!cpu->memory_rw(cpu, cpu->mem, cached_pc, &instr[0],
264 sizeof(instr), MEM_READ, CACHE_INSTRUCTION)) {
265 fatal("XXX_run_instr(): could not read "
266 "the instruction\n");
267 } else {
268 #ifdef DYNTRANS_DELAYSLOT
269 int len =
270 #endif
271 cpu_disassemble_instr(
272 cpu->machine, cpu, instr, 1, 0);
273 #ifdef DYNTRANS_DELAYSLOT
274 /* Show the instruction in the delay slot,
275 if any: */
276 if (cpu->instruction_has_delayslot == NULL)
277 fatal("WARNING: ihd func not yet"
278 " implemented?\n");
279 else if (cpu->instruction_has_delayslot(cpu,
280 instr)) {
281 int saved_delayslot = cpu->delay_slot;
282 cpu->memory_rw(cpu, cpu->mem, cached_pc
283 + len, &instr[0],
284 sizeof(instr), MEM_READ,
285 CACHE_INSTRUCTION);
286 cpu->delay_slot = DELAYED;
287 cpu->pc += len;
288 cpu_disassemble_instr(cpu->machine,
289 cpu, instr, 1, 0);
290 cpu->delay_slot = saved_delayslot;
291 cpu->pc -= len;
292 }
293 #endif
294 }
295 }
296
297 if (cpu->machine->statistics_enabled)
298 S;
299
300 /* Execute just one instruction: */
301 I;
302
303 n_instrs = 1;
304 } else if (cpu->machine->statistics_enabled) {
305 /* Gather statistics while executing multiple instructions: */
306 n_instrs = 0;
307 for (;;) {
308 struct DYNTRANS_IC *ic;
309
310 S; I; S; I; S; I; S; I; S; I; S; I;
311 S; I; S; I; S; I; S; I; S; I; S; I;
312 S; I; S; I; S; I; S; I; S; I; S; I;
313 S; I; S; I; S; I; S; I; S; I; S; I;
314
315 n_instrs += 24;
316
317 if (n_instrs + cpu->n_translated_instrs >=
318 N_SAFE_DYNTRANS_LIMIT)
319 break;
320 }
321 } else {
322 /*
323 * Execute multiple instructions:
324 *
325 * (This is the core dyntrans loop.)
326 */
327 n_instrs = 0;
328 cpu->sampling = 1;
329
330 for (;;) {
331 struct DYNTRANS_IC *ic;
332
333 I; I; I; I; I; I; I; I; I; I;
334 I; I; I; I; I; I; I; I; I; I;
335 I; I; I; I; I; I; I; I; I; I;
336 I; I; I; I; I; I; I; I; I; I;
337 I; I; I; I; I; I; I; I; I; I;
338
339 I; I; I; I; I; I; I; I; I; I;
340
341 I; I; I; I; I; I; I; I; I; I;
342 I; I; I; I; I; I; I; I; I; I;
343 I; I; I; I; I; I; I; I; I; I;
344 I; I; I; I; I; I; I; I; I; I;
345 I; I; I; I; I; I; I; I; I; I;
346
347 I; I; I; I; I; I; I; I; I; I;
348
349 cpu->n_translated_instrs += 120;
350 if (cpu->n_translated_instrs >= N_SAFE_DYNTRANS_LIMIT)
351 break;
352 }
353
354 cpu->sampling = 0;
355 }
356
357 n_instrs += cpu->n_translated_instrs;
358
359 /* Synchronize the program counter: */
360 low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t)
361 cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC);
362 if (low_pc >= 0 && low_pc < DYNTRANS_IC_ENTRIES_PER_PAGE) {
363 cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
364 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
365 cpu->pc += (low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT);
366 } else if (low_pc == DYNTRANS_IC_ENTRIES_PER_PAGE) {
367 /* Switch to next page: */
368 cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
369 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
370 cpu->pc += (DYNTRANS_IC_ENTRIES_PER_PAGE <<
371 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
372 } else if (low_pc == DYNTRANS_IC_ENTRIES_PER_PAGE + 1) {
373 /* Switch to next page and skip an instruction which was
374 already executed (in a delay slot): */
375 cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
376 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
377 cpu->pc += ((DYNTRANS_IC_ENTRIES_PER_PAGE + 1) <<
378 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
379 }
380
381 #ifdef DYNTRANS_MIPS
382 /* Update the count register (on everything except EXC3K): */
383 if (cpu->cd.mips.cpu_type.exc_model != EXC3K) {
384 uint32_t old = cpu->cd.mips.coproc[0]->reg[COP0_COUNT];
385 int32_t diff1 = cpu->cd.mips.coproc[0]->reg[COP0_COMPARE] - old;
386 int32_t diff2;
387 cpu->cd.mips.coproc[0]->reg[COP0_COUNT] =
388 (int32_t) (old + n_instrs);
389 diff2 = cpu->cd.mips.coproc[0]->reg[COP0_COMPARE] -
390 cpu->cd.mips.coproc[0]->reg[COP0_COUNT];
391
392 if (cpu->cd.mips.compare_register_set) {
393 #if 1
394 /* Not yet. TODO */
395 if (cpu->machine->emulated_hz > 0) {
396 if (cpu->cd.mips.compare_interrupts_pending > 0)
397 INTERRUPT_ASSERT(
398 cpu->cd.mips.irq_compare);
399 } else
400 #endif
401 {
402 if (diff1 > 0 && diff2 <= 0)
403 INTERRUPT_ASSERT(
404 cpu->cd.mips.irq_compare);
405 }
406 }
407 }
408 #endif
409 #ifdef DYNTRANS_PPC
410 /* Update the Decrementer and Time base registers: */
411 {
412 uint32_t old = cpu->cd.ppc.spr[SPR_DEC];
413 cpu->cd.ppc.spr[SPR_DEC] = (uint32_t) (old - n_instrs);
414 if ((old >> 31) == 0 && (cpu->cd.ppc.spr[SPR_DEC] >> 31) == 1
415 && !(cpu->cd.ppc.cpu_type.flags & PPC_NO_DEC))
416 cpu->cd.ppc.dec_intr_pending = 1;
417 old = cpu->cd.ppc.spr[SPR_TBL];
418 cpu->cd.ppc.spr[SPR_TBL] += n_instrs;
419 if ((old >> 31) == 1 && (cpu->cd.ppc.spr[SPR_TBL] >> 31) == 0)
420 cpu->cd.ppc.spr[SPR_TBU] ++;
421 }
422 #endif
423
424 cpu->ninstrs += n_instrs;
425
426 /*
427 * Check if there are enough samples to decide whether or not to
428 * perform native code generation:
429 */
430 if (cpu->sampling_curindex == N_PADDR_SAMPLES) {
431 /* TODO: Check against known blocks, etc. */
432
433 cpu->sampling_curindex = 0;
434 }
435
436 /* Return the nr of instructions executed: */
437 return n_instrs;
438 }
439 #endif /* DYNTRANS_RUN_INSTR */
440
441
442
443 #ifdef DYNTRANS_FUNCTION_TRACE
444 /*
445 * XXX_cpu_functioncall_trace():
446 *
447 * Without this function, the main trace tree function prints something
448 * like <f()> or <0x1234()> on a function call. It is up to this
449 * function to print the arguments passed.
450 */
451 void DYNTRANS_FUNCTION_TRACE(struct cpu *cpu, uint64_t f, int n_args)
452 {
453 int show_symbolic_function_name = 1;
454 char strbuf[50];
455 char *symbol;
456 uint64_t ot;
457 int x, print_dots = 1, n_args_to_print =
458 #if defined(DYNTRANS_ALPHA) || defined(DYNTRANS_SPARC)
459 6
460 #else
461 #if defined(DYNTRANS_SH) || defined(DYNTRANS_M88K)
462 8 /* Both for 32-bit and 64-bit SuperH, and M88K */
463 #else
464 4 /* Default value for most archs */
465 #endif
466 #endif
467 ;
468
469 if (n_args >= 0 && n_args <= n_args_to_print) {
470 print_dots = 0;
471 n_args_to_print = n_args;
472 }
473
474 #ifdef DYNTRANS_M88K
475 /* Special hack for M88K userspace: */
476 if (!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE))
477 show_symbolic_function_name = 0;
478 #endif
479
480 /*
481 * TODO: The type of each argument should be taken from the symbol
482 * table, in some way.
483 *
484 * The code here does a kind of "heuristic guess" regarding what the
485 * argument values might mean. Sometimes the output looks weird, but
486 * usually it looks good enough.
487 *
488 * Print ".." afterwards to show that there might be more arguments
489 * than were passed in register.
490 */
491 for (x=0; x<n_args_to_print; x++) {
492 int64_t d = cpu->cd.DYNTRANS_ARCH.
493 #ifdef DYNTRANS_ALPHA
494 r[ALPHA_A0
495 #endif
496 #ifdef DYNTRANS_ARM
497 r[0
498 #endif
499 #ifdef DYNTRANS_AVR
500 /* TODO: 24,25 = first register, but then
501 they go downwards, ie. 22,23 and so on */
502 r[24
503 #endif
504 #ifdef DYNTRANS_MIPS
505 gpr[MIPS_GPR_A0
506 #endif
507 #ifdef DYNTRANS_M88K
508 r[2 /* r2..r9 */
509 #endif
510 #ifdef DYNTRANS_PPC
511 gpr[3
512 #endif
513 #ifdef DYNTRANS_SH
514 r[4 /* NetBSD seems to use 4? But 2 seems
515 to be used by other code? TODO */
516 #endif
517 #ifdef DYNTRANS_SPARC
518 r[8 /* o0..o5 */
519 #endif
520 + x];
521
522 symbol = get_symbol_name(&cpu->machine->symbol_context, d, &ot);
523
524 if (d > -256 && d < 256)
525 fatal("%i", (int)d);
526 else if (memory_points_to_string(cpu, cpu->mem, d, 1))
527 fatal("\"%s\"", memory_conv_to_string(cpu,
528 cpu->mem, d, strbuf, sizeof(strbuf)));
529 else if (symbol != NULL && ot == 0 &&
530 show_symbolic_function_name)
531 fatal("&%s", symbol);
532 else {
533 if (cpu->is_32bit)
534 fatal("0x%"PRIx32, (uint32_t)d);
535 else
536 fatal("0x%"PRIx64, (uint64_t)d);
537 }
538
539 if (x < n_args_to_print - 1)
540 fatal(",");
541 }
542
543 if (print_dots)
544 fatal(",..");
545 }
546 #endif
547
548
549
550 #ifdef DYNTRANS_TIMER_SAMPLE_TICK
551 /*
552 * XXX_timer_sample_tick():
553 *
554 * Gathers statistics about which translation blocks are being executed.
555 * This can then be used to calculate if it is worth the effort to perform
556 * native code generation (which is assumed to have a large overhead, but
557 * will result in faster code).
558 */
559 void DYNTRANS_TIMER_SAMPLE_TICK(struct timer *timer, void *extra)
560 {
561 struct cpu *cpu = extra;
562 struct DYNTRANS_IC *next_ic;
563 size_t low_pc;
564 uint64_t paddr;
565
566 /*
567 * Don't sample if:
568 *
569 * 1) Sampling is not enabled. It should only be enabled during
570 * the core dyntrans loop.
571 * 2) Enough samples have already been gathered.
572 */
573
574 if (!cpu->sampling || cpu->sampling_curindex == N_PADDR_SAMPLES)
575 return;
576
577 /* Get the physical address of the program counter: */
578
579 next_ic = cpu->cd.DYNTRANS_ARCH.next_ic;
580 low_pc = ((size_t)next_ic - (size_t)cpu->cd.DYNTRANS_ARCH.cur_ic_page)
581 / sizeof(struct DYNTRANS_IC);
582
583 /* Not possible to represent as a physical address? Then abort. */
584 if (low_pc > DYNTRANS_IC_ENTRIES_PER_PAGE)
585 return;
586
587 cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *)
588 cpu->cd.DYNTRANS_ARCH.cur_ic_page;
589 paddr = cpu->cd.DYNTRANS_ARCH.cur_physpage->physaddr;
590 paddr &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
591 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
592 paddr += low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT;
593
594 /* ... and finally add the sample to the sampling array: */
595 cpu->sampling_paddr[cpu->sampling_curindex ++] = paddr;
596 }
597 #endif /* DYNTRANS_TIMER_SAMPLE_TICK */
598
599
600
601 #ifdef DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE
602 /*
603 * XXX_tc_allocate_default_page():
604 *
605 * Create a default page (with just pointers to instr(to_be_translated)
606 * at cpu->translation_cache_cur_ofs.
607 */
608 static void DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE(struct cpu *cpu,
609 uint64_t physaddr)
610 {
611 struct DYNTRANS_TC_PHYSPAGE *ppp;
612
613 ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
614 + cpu->translation_cache_cur_ofs);
615
616 /* Copy the entire template page first: */
617 memcpy(ppp, cpu->cd.DYNTRANS_ARCH.physpage_template, sizeof(
618 struct DYNTRANS_TC_PHYSPAGE));
619
620 ppp->physaddr = physaddr & ~(DYNTRANS_PAGESIZE - 1);
621
622 cpu->translation_cache_cur_ofs += sizeof(struct DYNTRANS_TC_PHYSPAGE);
623
624 cpu->translation_cache_cur_ofs --;
625 cpu->translation_cache_cur_ofs |= 127;
626 cpu->translation_cache_cur_ofs ++;
627 }
628 #endif /* DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE */
629
630
631
632 #ifdef DYNTRANS_PC_TO_POINTERS_FUNC
633 /*
634 * XXX_pc_to_pointers_generic():
635 *
636 * Generic case. See DYNTRANS_PC_TO_POINTERS_FUNC below.
637 */
638 void DYNTRANS_PC_TO_POINTERS_GENERIC(struct cpu *cpu)
639 {
640 #ifdef MODE32
641 uint32_t
642 #else
643 uint64_t
644 #endif
645 cached_pc = cpu->pc, physaddr = 0;
646 uint32_t physpage_ofs;
647 int ok, pagenr, table_index;
648 uint32_t *physpage_entryp;
649 struct DYNTRANS_TC_PHYSPAGE *ppp;
650
651 #ifdef MODE32
652 int index = DYNTRANS_ADDR_TO_PAGENR(cached_pc);
653 #else
654 const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1;
655 const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1;
656 const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1;
657 uint32_t x1, x2, x3;
658 struct DYNTRANS_L2_64_TABLE *l2;
659 struct DYNTRANS_L3_64_TABLE *l3;
660
661 x1 = (cached_pc >> (64-DYNTRANS_L1N)) & mask1;
662 x2 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2;
663 x3 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N)) & mask3;
664 /* fatal("X3: cached_pc=%016"PRIx64" x1=%x x2=%x x3=%x\n",
665 (uint64_t)cached_pc, (int)x1, (int)x2, (int)x3); */
666 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
667 /* fatal(" l2 = %p\n", l2); */
668 l3 = l2->l3[x2];
669 /* fatal(" l3 = %p\n", l3); */
670 #endif
671
672 /* Virtual to physical address translation: */
673 ok = 0;
674 #ifdef MODE32
675 if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL) {
676 physaddr = cpu->cd.DYNTRANS_ARCH.phys_addr[index];
677 ok = 1;
678 }
679 #else
680 if (l3->host_load[x3] != NULL) {
681 physaddr = l3->phys_addr[x3];
682 ok = 1;
683 }
684 #endif
685
686 if (!ok) {
687 uint64_t paddr;
688 if (cpu->translate_v2p != NULL) {
689 uint64_t vaddr =
690 #if defined(MODE32) && defined(DYNTRANS_MIPS)
691 /* 32-bit MIPS is _sign_ extend, not zero. */
692 (int32_t)
693 #endif
694 cached_pc;
695 ok = cpu->translate_v2p(
696 cpu, vaddr, &paddr, FLAG_INSTR);
697 } else {
698 paddr = cached_pc;
699 ok = 1;
700 }
701 if (!ok) {
702 /*
703 * The PC is now set to the exception handler.
704 * Try to find the paddr in the translation arrays,
705 * or if that fails, call translate_v2p for the
706 * exception handler.
707 */
708 /* fatal("TODO: instruction vaddr=>paddr translation "
709 "failed. vaddr=0x%"PRIx64"\n", (uint64_t)cached_pc);
710 fatal("!! cpu->pc=0x%"PRIx64"\n", (uint64_t)cpu->pc); */
711
712 /* If there was an exception, the PC has changed.
713 Update cached_pc: */
714 cached_pc = cpu->pc;
715
716 #ifdef MODE32
717 index = DYNTRANS_ADDR_TO_PAGENR(cached_pc);
718 if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL) {
719 paddr = cpu->cd.DYNTRANS_ARCH.phys_addr[index];
720 ok = 1;
721 }
722 #else
723 x1 = (cached_pc >> (64-DYNTRANS_L1N)) & mask1;
724 x2 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N))
725 & mask2;
726 x3 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N
727 - DYNTRANS_L3N)) & mask3;
728 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
729 l3 = l2->l3[x2];
730 if (l3->host_load[x3] != NULL) {
731 paddr = l3->phys_addr[x3];
732 ok = 1;
733 }
734 #endif
735
736 if (!ok) {
737 ok = cpu->translate_v2p(cpu, cpu->pc, &paddr,
738 FLAG_INSTR);
739 }
740
741 /* printf("EXCEPTION HANDLER: vaddr = 0x%x ==> "
742 "paddr = 0x%x\n", (int)cpu->pc, (int)paddr);
743 fatal("!? cpu->pc=0x%"PRIx64"\n", (uint64_t)cpu->pc); */
744
745 if (!ok) {
746 fatal("FATAL: could not find physical"
747 " address of the exception handler?");
748 exit(1);
749 }
750 }
751
752 physaddr = paddr;
753 }
754
755 physaddr &= ~(DYNTRANS_PAGESIZE - 1);
756
757 #ifdef MODE32
758 if (cpu->cd.DYNTRANS_ARCH.host_load[index] == NULL) {
759 #else
760 if (l3->host_load[x3] == NULL) {
761 #endif
762 int q = DYNTRANS_PAGESIZE - 1;
763 unsigned char *host_page = memory_paddr_to_hostaddr(cpu->mem,
764 physaddr, MEM_READ);
765 if (host_page != NULL) {
766 cpu->update_translation_table(cpu, cached_pc & ~q,
767 host_page, 0, physaddr);
768 }
769 }
770
771 if (cpu->translation_cache_cur_ofs >= dyntrans_cache_size) {
772 #ifdef UNSTABLE_DEVEL
773 fatal("[ dyntrans: resetting the translation cache ]\n");
774 #endif
775 cpu_create_or_reset_tc(cpu);
776 }
777
778 pagenr = DYNTRANS_ADDR_TO_PAGENR(physaddr);
779 table_index = PAGENR_TO_TABLE_INDEX(pagenr);
780
781 physpage_entryp = &(((uint32_t *)cpu->translation_cache)[table_index]);
782 physpage_ofs = *physpage_entryp;
783 ppp = NULL;
784
785 /* Traverse the physical page chain: */
786 while (physpage_ofs != 0) {
787 ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
788 + physpage_ofs);
789
790 /* If we found the page in the cache, then we're done: */
791 if (ppp->physaddr == physaddr)
792 break;
793
794 /* Try the next page in the chain: */
795 physpage_ofs = ppp->next_ofs;
796 }
797
798 /*
799 * If the offset is 0, then no translation exists yet for this
800 * physical address. Let's create a new page, and add it first in
801 * the chain.
802 */
803 if (physpage_ofs == 0) {
804 uint32_t previous_first_page_in_chain;
805
806 /* fatal("CREATING page %lli (physaddr 0x%"PRIx64"), table "
807 "index %i\n", (long long)pagenr, (uint64_t)physaddr,
808 (int)table_index); */
809
810 previous_first_page_in_chain = *physpage_entryp;
811
812 /* Insert the new page first in the chain: */
813 *physpage_entryp = physpage_ofs =
814 cpu->translation_cache_cur_ofs;
815
816 /* Allocate a default page, with to_be_translated entries: */
817 DYNTRANS_TC_ALLOCATE(cpu, physaddr);
818
819 ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
820 + physpage_ofs);
821
822 /* Point to the other pages in the same chain: */
823 ppp->next_ofs = previous_first_page_in_chain;
824 }
825
826 /* Here, ppp points to a valid physical page struct. */
827
828 #ifdef MODE32
829 if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL)
830 cpu->cd.DYNTRANS_ARCH.phys_page[index] = ppp;
831 #else
832 if (l3->host_load[x3] != NULL)
833 l3->phys_page[x3] = ppp;
834 #endif
835
836 /*
837 * If there are no translations yet on this page, then mark it
838 * as non-writable. If there are already translations, then it
839 * should already have been marked as non-writable.
840 */
841 if (ppp->translations == 0) {
842 cpu->invalidate_translation_caches(cpu, physaddr,
843 JUST_MARK_AS_NON_WRITABLE | INVALIDATE_PADDR);
844 }
845
846 cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0];
847
848 cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page +
849 DYNTRANS_PC_TO_IC_ENTRY(cached_pc);
850
851 /* printf("cached_pc=0x%016"PRIx64" pagenr=%lli table_index=%lli, "
852 "physpage_ofs=0x%016"PRIx64"\n", (uint64_t)cached_pc, (long long)
853 pagenr, (long long)table_index, (uint64_t)physpage_ofs); */
854 }
855
856
857 /*
858 * XXX_pc_to_pointers():
859 *
860 * This function uses the current program counter (a virtual address) to
861 * find out which physical translation page to use, and then sets the current
862 * translation page pointers to that page.
863 *
864 * If there was no translation page for that physical page, then an empty
865 * one is created.
866 *
867 * NOTE: This is the quick lookup version. See
868 * DYNTRANS_PC_TO_POINTERS_GENERIC above for the generic case.
869 */
870 void DYNTRANS_PC_TO_POINTERS_FUNC(struct cpu *cpu)
871 {
872 #ifdef MODE32
873 uint32_t
874 #else
875 uint64_t
876 #endif
877 cached_pc = cpu->pc;
878 struct DYNTRANS_TC_PHYSPAGE *ppp;
879
880 #ifdef MODE32
881 int index;
882 index = DYNTRANS_ADDR_TO_PAGENR(cached_pc);
883 ppp = cpu->cd.DYNTRANS_ARCH.phys_page[index];
884 if (ppp != NULL)
885 goto have_it;
886 #else
887 const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1;
888 const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1;
889 const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1;
890 uint32_t x1, x2, x3;
891 struct DYNTRANS_L2_64_TABLE *l2;
892 struct DYNTRANS_L3_64_TABLE *l3;
893
894 x1 = (cached_pc >> (64-DYNTRANS_L1N)) & mask1;
895 x2 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2;
896 x3 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N)) & mask3;
897 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
898 l3 = l2->l3[x2];
899 ppp = l3->phys_page[x3];
900 if (ppp != NULL)
901 goto have_it;
902 #endif
903
904 DYNTRANS_PC_TO_POINTERS_GENERIC(cpu);
905 return;
906
907 /* Quick return path: */
908 have_it:
909 cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0];
910 cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page +
911 DYNTRANS_PC_TO_IC_ENTRY(cached_pc);
912
913 /* printf("cached_pc=0x%016"PRIx64" pagenr=%lli table_index=%lli, "
914 "physpage_ofs=0x%016"PRIx64"\n", (uint64_t)cached_pc, (long long)
915 pagenr, (long long)table_index, (uint64_t)physpage_ofs); */
916 }
917 #endif /* DYNTRANS_PC_TO_POINTERS_FUNC */
918
919
920
921 #ifdef DYNTRANS_INIT_TABLES
922
923 /* forward declaration of to_be_translated and end_of_page: */
924 static void instr(to_be_translated)(struct cpu *, struct DYNTRANS_IC *);
925 static void instr(end_of_page)(struct cpu *,struct DYNTRANS_IC *);
926 #ifdef DYNTRANS_DUALMODE_32
927 static void instr32(to_be_translated)(struct cpu *, struct DYNTRANS_IC *);
928 static void instr32(end_of_page)(struct cpu *,struct DYNTRANS_IC *);
929 #endif
930
931 #ifdef DYNTRANS_DELAYSLOT
932 static void instr(end_of_page2)(struct cpu *,struct DYNTRANS_IC *);
933 #ifdef DYNTRANS_DUALMODE_32
934 static void instr32(end_of_page2)(struct cpu *,struct DYNTRANS_IC *);
935 #endif
936 #endif
937
938 /*
939 * XXX_init_tables():
940 *
941 * Initializes the default translation page (for newly allocated pages), and
942 * for 64-bit emulation it also initializes 64-bit dummy tables and pointers.
943 */
944 void DYNTRANS_INIT_TABLES(struct cpu *cpu)
945 {
946 #ifndef MODE32
947 struct DYNTRANS_L2_64_TABLE *dummy_l2;
948 struct DYNTRANS_L3_64_TABLE *dummy_l3;
949 int x1, x2;
950 #endif
951 int i;
952 struct DYNTRANS_TC_PHYSPAGE *ppp;
953
954 CHECK_ALLOCATION(ppp = malloc(sizeof(struct DYNTRANS_TC_PHYSPAGE)));
955
956 ppp->next_ofs = 0;
957 ppp->translations = 0;
958 /* ppp->physaddr is filled in by the page allocator */
959
960 for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++) {
961 ppp->ics[i].f =
962 #ifdef DYNTRANS_DUALMODE_32
963 cpu->is_32bit? instr32(to_be_translated) :
964 #endif
965 instr(to_be_translated);
966 }
967
968 /* End-of-page: */
969 ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 0].f =
970 #ifdef DYNTRANS_DUALMODE_32
971 cpu->is_32bit? instr32(end_of_page) :
972 #endif
973 instr(end_of_page);
974
975 /* End-of-page-2, for delay-slot architectures: */
976 #ifdef DYNTRANS_DELAYSLOT
977 ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 1].f =
978 #ifdef DYNTRANS_DUALMODE_32
979 cpu->is_32bit? instr32(end_of_page2) :
980 #endif
981 instr(end_of_page2);
982 #endif
983
984 cpu->cd.DYNTRANS_ARCH.physpage_template = ppp;
985
986
987 /* Prepare 64-bit virtual address translation tables: */
988 #ifndef MODE32
989 if (cpu->is_32bit)
990 return;
991
992 dummy_l2 = zeroed_alloc(sizeof(struct DYNTRANS_L2_64_TABLE));
993 dummy_l3 = zeroed_alloc(sizeof(struct DYNTRANS_L3_64_TABLE));
994
995 cpu->cd.DYNTRANS_ARCH.l2_64_dummy = dummy_l2;
996 cpu->cd.DYNTRANS_ARCH.l3_64_dummy = dummy_l3;
997
998 for (x1 = 0; x1 < (1 << DYNTRANS_L1N); x1 ++)
999 cpu->cd.DYNTRANS_ARCH.l1_64[x1] = dummy_l2;
1000
1001 for (x2 = 0; x2 < (1 << DYNTRANS_L2N); x2 ++)
1002 dummy_l2->l3[x2] = dummy_l3;
1003 #endif
1004 }
1005 #endif /* DYNTRANS_INIT_TABLES */
1006
1007
1008
1009 #ifdef DYNTRANS_INVAL_ENTRY
1010 /*
1011 * XXX_invalidate_tlb_entry():
1012 *
1013 * Invalidate one translation entry (based on virtual address).
1014 *
1015 * If the JUST_MARK_AS_NON_WRITABLE flag is set, then the translation entry
1016 * is just downgraded to non-writable (ie the host store page is set to
1017 * NULL). Otherwise, the entire translation is removed.
1018 */
1019 static void DYNTRANS_INVALIDATE_TLB_ENTRY(struct cpu *cpu,
1020 #ifdef MODE32
1021 uint32_t
1022 #else
1023 uint64_t
1024 #endif
1025 vaddr_page, int flags)
1026 {
1027 #ifdef MODE32
1028 uint32_t index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1029
1030 #ifdef DYNTRANS_ARM
1031 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5] &= ~(1 << (index & 31));
1032 #endif
1033
1034 if (flags & JUST_MARK_AS_NON_WRITABLE) {
1035 /* printf("JUST MARKING NON-W: vaddr 0x%08x\n",
1036 (int)vaddr_page); */
1037 cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
1038 } else {
1039 int tlbi = cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index];
1040 cpu->cd.DYNTRANS_ARCH.host_load[index] = NULL;
1041 cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
1042 cpu->cd.DYNTRANS_ARCH.phys_addr[index] = 0;
1043 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1044 if (tlbi > 0)
1045 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[tlbi-1].valid = 0;
1046 cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index] = 0;
1047 }
1048 #else
1049 const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1;
1050 const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1;
1051 const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1;
1052 uint32_t x1, x2, x3;
1053 struct DYNTRANS_L2_64_TABLE *l2;
1054 struct DYNTRANS_L3_64_TABLE *l3;
1055
1056 x1 = (vaddr_page >> (64-DYNTRANS_L1N)) & mask1;
1057 x2 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2;
1058 x3 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N))& mask3;
1059
1060 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
1061 if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy)
1062 return;
1063
1064 l3 = l2->l3[x2];
1065 if (l3 == cpu->cd.DYNTRANS_ARCH.l3_64_dummy)
1066 return;
1067
1068 if (flags & JUST_MARK_AS_NON_WRITABLE) {
1069 l3->host_store[x3] = NULL;
1070 return;
1071 }
1072
1073 #ifdef BUGHUNT
1074
1075 {
1076 /* Consistency check, for debugging: */
1077 int x1, x1b; // x2, x3;
1078 struct DYNTRANS_L2_64_TABLE *l2;
1079 //struct DYNTRANS_L3_64_TABLE *l3;
1080
1081 for (x1 = 0; x1 <= mask1; x1 ++) {
1082 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
1083 if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy)
1084 continue;
1085 /* Make sure that this l2 isn't used more than 1 time! */
1086 for (x1b = 0; x1b <= mask1; x1b ++)
1087 if (x1 != x1b &&
1088 l2 == cpu->cd.DYNTRANS_ARCH.l1_64[x1b]) {
1089 fatal("L2 reuse: %p\n", l2);
1090 exit(1);
1091 }
1092 }
1093 }
1094
1095 /* Count how many pages are actually in use: */
1096 {
1097 int n=0, i;
1098 for (i=0; i<=mask3; i++)
1099 if (l3->vaddr_to_tlbindex[i])
1100 n++;
1101 if (n != l3->refcount) {
1102 printf("Z: %i in use, but refcount = %i!\n", n, l3->refcount);
1103 exit(1);
1104 }
1105
1106 n = 0;
1107 for (i=0; i<=mask3; i++)
1108 if (l3->host_load[i] != NULL)
1109 n++;
1110 if (n != l3->refcount) {
1111 printf("ZHL: %i in use, but refcount = %i!\n", n, l3->refcount);
1112 exit(1);
1113 }
1114 }
1115 #endif
1116
1117 l3->host_load[x3] = NULL;
1118 l3->host_store[x3] = NULL;
1119 l3->phys_addr[x3] = 0;
1120 l3->phys_page[x3] = NULL;
1121 if (l3->vaddr_to_tlbindex[x3] != 0) {
1122 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[
1123 l3->vaddr_to_tlbindex[x3] - 1].valid = 0;
1124 l3->refcount --;
1125 }
1126 l3->vaddr_to_tlbindex[x3] = 0;
1127
1128 if (l3->refcount < 0) {
1129 fatal("xxx_invalidate_tlb_entry(): huh? Refcount bug.\n");
1130 exit(1);
1131 }
1132
1133 if (l3->refcount == 0) {
1134 l3->next = cpu->cd.DYNTRANS_ARCH.next_free_l3;
1135 cpu->cd.DYNTRANS_ARCH.next_free_l3 = l3;
1136 l2->l3[x2] = cpu->cd.DYNTRANS_ARCH.l3_64_dummy;
1137
1138 #ifdef BUGHUNT
1139 /* Make sure that we're placing a CLEAN page on the
1140 freelist: */
1141 {
1142 int i;
1143 for (i=0; i<=mask3; i++)
1144 if (l3->host_load[i] != NULL) {
1145 fatal("TRYING TO RETURN A NON-CLEAN L3 PAGE!\n");
1146 exit(1);
1147 }
1148 }
1149 #endif
1150 l2->refcount --;
1151 if (l2->refcount < 0) {
1152 fatal("xxx_invalidate_tlb_entry(): Refcount bug L2.\n");
1153 exit(1);
1154 }
1155 if (l2->refcount == 0) {
1156 l2->next = cpu->cd.DYNTRANS_ARCH.next_free_l2;
1157 cpu->cd.DYNTRANS_ARCH.next_free_l2 = l2;
1158 cpu->cd.DYNTRANS_ARCH.l1_64[x1] =
1159 cpu->cd.DYNTRANS_ARCH.l2_64_dummy;
1160 }
1161 }
1162 #endif
1163 }
1164 #endif
1165
1166
1167 #ifdef DYNTRANS_INVALIDATE_TC
1168 /*
1169 * XXX_invalidate_translation_caches():
1170 *
1171 * Invalidate all entries matching a specific physical address, a specific
1172 * virtual address, or ALL entries.
1173 *
1174 * flags should be one of
1175 * INVALIDATE_PADDR INVALIDATE_VADDR or INVALIDATE_ALL
1176 *
1177 * In addition, for INVALIDATE_ALL, INVALIDATE_VADDR_UPPER4 may be set and
1178 * bit 31..28 of addr are used to select the virtual addresses to invalidate.
1179 * (This is useful for PowerPC emulation, when segment registers are updated.)
1180 *
1181 * In the case when all translations are invalidated, paddr doesn't need
1182 * to be supplied.
1183 *
1184 * NOTE/TODO: When invalidating a virtual address, it is only cleared from
1185 * the quick translation array, not from the linear
1186 * vph_tlb_entry[] array. Hopefully this is enough anyway.
1187 */
1188 void DYNTRANS_INVALIDATE_TC(struct cpu *cpu, uint64_t addr, int flags)
1189 {
1190 int r;
1191 #ifdef MODE32
1192 uint32_t
1193 #else
1194 uint64_t
1195 #endif
1196 addr_page = addr & ~(DYNTRANS_PAGESIZE - 1);
1197
1198 /* fatal("invalidate(): "); */
1199
1200 /* Quick case for _one_ virtual addresses: see note above. */
1201 if (flags & INVALIDATE_VADDR) {
1202 /* fatal("vaddr 0x%08x\n", (int)addr_page); */
1203 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, addr_page, flags);
1204 return;
1205 }
1206
1207 /* Invalidate everything: */
1208 #ifdef DYNTRANS_PPC
1209 if (flags & INVALIDATE_ALL && flags & INVALIDATE_VADDR_UPPER4) {
1210 /* fatal("all, upper4 (PowerPC segment)\n"); */
1211 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
1212 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid &&
1213 (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page
1214 & 0xf0000000) == addr_page) {
1215 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, cpu->cd.
1216 DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
1217 0);
1218 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid=0;
1219 }
1220 }
1221 return;
1222 }
1223 #endif
1224 if (flags & INVALIDATE_ALL) {
1225 /* fatal("all\n"); */
1226 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
1227 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
1228 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, cpu->cd.
1229 DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
1230 0);
1231 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid=0;
1232 }
1233 }
1234 return;
1235 }
1236
1237 /* Invalidate a physical page: */
1238
1239 if (!(flags & INVALIDATE_PADDR))
1240 fatal("HUH? Invalidate: Not vaddr, all, or paddr?\n");
1241
1242 /* fatal("addr 0x%08x\n", (int)addr_page); */
1243
1244 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
1245 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid && addr_page
1246 == cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page) {
1247 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu,
1248 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
1249 flags);
1250 if (flags & JUST_MARK_AS_NON_WRITABLE)
1251 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
1252 .writeflag = 0;
1253 else
1254 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
1255 .valid = 0;
1256 }
1257 }
1258 }
1259 #endif /* DYNTRANS_INVALIDATE_TC */
1260
1261
1262
1263 #ifdef DYNTRANS_INVALIDATE_TC_CODE
1264 /*
1265 * XXX_invalidate_code_translation():
1266 *
1267 * Invalidate code translations for a specific physical address, a specific
1268 * virtual address, or for all entries in the cache.
1269 */
1270 void DYNTRANS_INVALIDATE_TC_CODE(struct cpu *cpu, uint64_t addr, int flags)
1271 {
1272 int r;
1273 #ifdef MODE32
1274 uint32_t
1275 #else
1276 uint64_t
1277 #endif
1278 vaddr_page, paddr_page;
1279
1280 addr &= ~(DYNTRANS_PAGESIZE-1);
1281
1282 /* printf("DYNTRANS_INVALIDATE_TC_CODE addr=0x%08x flags=%i\n",
1283 (int)addr, flags); */
1284
1285 if (flags & INVALIDATE_PADDR) {
1286 int pagenr, table_index;
1287 uint32_t physpage_ofs, *physpage_entryp;
1288 struct DYNTRANS_TC_PHYSPAGE *ppp, *prev_ppp;
1289
1290 pagenr = DYNTRANS_ADDR_TO_PAGENR(addr);
1291 table_index = PAGENR_TO_TABLE_INDEX(pagenr);
1292
1293 physpage_entryp = &(((uint32_t *)cpu->
1294 translation_cache)[table_index]);
1295 physpage_ofs = *physpage_entryp;
1296
1297 /* Return immediately if there is no code translation
1298 for this page. */
1299 if (physpage_ofs == 0)
1300 return;
1301
1302 prev_ppp = ppp = NULL;
1303
1304 /* Traverse the physical page chain: */
1305 while (physpage_ofs != 0) {
1306 prev_ppp = ppp;
1307 ppp = (struct DYNTRANS_TC_PHYSPAGE *)
1308 (cpu->translation_cache + physpage_ofs);
1309
1310 /* If we found the page in the cache,
1311 then we're done: */
1312 if (ppp->physaddr == addr)
1313 break;
1314
1315 /* Try the next page in the chain: */
1316 physpage_ofs = ppp->next_ofs;
1317 }
1318
1319 /* If there is no translation, there is no need to go
1320 on and try to remove it from the vph_tlb_entry array: */
1321 if (physpage_ofs == 0)
1322 return;
1323
1324 #if 0
1325 /*
1326 * "Bypass" the page, removing it from the code cache.
1327 *
1328 * NOTE/TODO: This gives _TERRIBLE_ performance with self-
1329 * modifying code, or when a single page is used for both
1330 * code and (writable) data.
1331 */
1332 if (ppp != NULL) {
1333 if (prev_ppp != NULL)
1334 prev_ppp->next_ofs = ppp->next_ofs;
1335 else
1336 *physpage_entryp = ppp->next_ofs;
1337 }
1338 #else
1339 /*
1340 * Instead of removing the page from the code cache, each
1341 * entry can be set to "to_be_translated". This is slow in
1342 * the general case, but in the case of self-modifying code,
1343 * it might be faster since we don't risk wasting cache
1344 * memory as quickly (which would force unnecessary Restarts).
1345 */
1346 if (ppp != NULL && ppp->translations != 0) {
1347 uint32_t x = ppp->translations; /* TODO:
1348 urk Should be same type as ppp->translations */
1349 int i, j, n, m;
1350 n = 8 * sizeof(x);
1351 m = DYNTRANS_IC_ENTRIES_PER_PAGE / n;
1352
1353 for (i=0; i<n; i++) {
1354 if (x & 1) {
1355 for (j=0; j<m; j++)
1356 ppp->ics[i*m + j].f =
1357 #ifdef DYNTRANS_DUALMODE_32
1358 cpu->is_32bit?
1359 instr32(to_be_translated) :
1360 #endif
1361 instr(to_be_translated);
1362 }
1363
1364 x >>= 1;
1365 }
1366
1367 ppp->translations = 0;
1368 }
1369 #endif
1370 }
1371
1372 /* Invalidate entries in the VPH table: */
1373 for (r = 0; r < DYNTRANS_MAX_VPH_TLB_ENTRIES; r ++) {
1374 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
1375 vaddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
1376 .vaddr_page & ~(DYNTRANS_PAGESIZE-1);
1377 paddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
1378 .paddr_page & ~(DYNTRANS_PAGESIZE-1);
1379
1380 if (flags & INVALIDATE_ALL ||
1381 (flags & INVALIDATE_PADDR && paddr_page == addr) ||
1382 (flags & INVALIDATE_VADDR && vaddr_page == addr)) {
1383 #ifdef MODE32
1384 uint32_t index =
1385 DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1386 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1387 #else
1388 const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1;
1389 const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1;
1390 const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1;
1391 uint32_t x1, x2, x3;
1392 struct DYNTRANS_L2_64_TABLE *l2;
1393 struct DYNTRANS_L3_64_TABLE *l3;
1394
1395 x1 = (vaddr_page >> (64-DYNTRANS_L1N)) & mask1;
1396 x2 = (vaddr_page >> (64-DYNTRANS_L1N -
1397 DYNTRANS_L2N)) & mask2;
1398 x3 = (vaddr_page >> (64-DYNTRANS_L1N -
1399 DYNTRANS_L2N - DYNTRANS_L3N)) & mask3;
1400 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
1401 l3 = l2->l3[x2];
1402 l3->phys_page[x3] = NULL;
1403 #endif
1404 }
1405 }
1406 }
1407 }
1408 #endif /* DYNTRANS_INVALIDATE_TC_CODE */
1409
1410
1411
1412 #ifdef DYNTRANS_UPDATE_TRANSLATION_TABLE
1413 /*
1414 * XXX_update_translation_table():
1415 *
1416 * Update the virtual memory translation tables.
1417 */
1418 void DYNTRANS_UPDATE_TRANSLATION_TABLE(struct cpu *cpu, uint64_t vaddr_page,
1419 unsigned char *host_page, int writeflag, uint64_t paddr_page)
1420 {
1421 int found, r, useraccess = 0;
1422
1423 #ifdef MODE32
1424 uint32_t index;
1425 vaddr_page &= 0xffffffffULL;
1426
1427 if (paddr_page > 0xffffffffULL) {
1428 fatal("update_translation_table(): v=0x%016"PRIx64", h=%p w=%i"
1429 " p=0x%016"PRIx64"\n", vaddr_page, host_page, writeflag,
1430 paddr_page);
1431 exit(1);
1432 }
1433
1434 /* fatal("update_translation_table(): v=0x%x, h=%p w=%i"
1435 " p=0x%x\n", (int)vaddr_page, host_page, writeflag,
1436 (int)paddr_page); */
1437 #else /* !MODE32 */
1438 const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1;
1439 const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1;
1440 const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1;
1441 uint32_t x1, x2, x3;
1442 struct DYNTRANS_L2_64_TABLE *l2;
1443 struct DYNTRANS_L3_64_TABLE *l3;
1444
1445 /* fatal("update_translation_table(): v=0x%016"PRIx64", h=%p w=%i"
1446 " p=0x%016"PRIx64"\n", (uint64_t)vaddr_page, host_page, writeflag,
1447 (uint64_t)paddr_page); */
1448 #endif
1449
1450 assert((vaddr_page & (DYNTRANS_PAGESIZE-1)) == 0);
1451 assert((paddr_page & (DYNTRANS_PAGESIZE-1)) == 0);
1452
1453 if (writeflag & MEMORY_USER_ACCESS) {
1454 writeflag &= ~MEMORY_USER_ACCESS;
1455 useraccess = 1;
1456 }
1457
1458 #ifdef DYNTRANS_M88K
1459 /* TODO */
1460 if (useraccess)
1461 return;
1462 #endif
1463
1464 /* Scan the current TLB entries: */
1465
1466 #ifdef MODE32
1467 /*
1468 * NOTE 1: vaddr_to_tlbindex is one more than the index, so that
1469 * 0 becomes -1, which means a miss.
1470 *
1471 * NOTE 2: When a miss occurs, instead of scanning the entire tlb
1472 * for the entry with the lowest time stamp, just choosing
1473 * one at random will work as well.
1474 */
1475 found = (int)cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[
1476 DYNTRANS_ADDR_TO_PAGENR(vaddr_page)] - 1;
1477 #else
1478 x1 = (vaddr_page >> (64-DYNTRANS_L1N)) & mask1;
1479 x2 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2;
1480 x3 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N))
1481 & mask3;
1482
1483 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
1484 if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy)
1485 found = -1;
1486 else {
1487 l3 = l2->l3[x2];
1488 if (l3 == cpu->cd.DYNTRANS_ARCH.l3_64_dummy)
1489 found = -1;
1490 else
1491 found = (int)l3->vaddr_to_tlbindex[x3] - 1;
1492 }
1493 #endif
1494
1495 if (found < 0) {
1496 /* Create the new TLB entry, overwriting a "random" entry: */
1497 static unsigned int x = 0;
1498 r = (x++) % DYNTRANS_MAX_VPH_TLB_ENTRIES;
1499
1500 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
1501 /* This one has to be invalidated first: */
1502 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu,
1503 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
1504 0);
1505 }
1506
1507 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid = 1;
1508 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].host_page = host_page;
1509 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page = paddr_page;
1510 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page = vaddr_page;
1511 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag =
1512 writeflag & MEM_WRITE;
1513
1514 /* Add the new translation to the table: */
1515 #ifdef MODE32
1516 index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1517 cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page;
1518 cpu->cd.DYNTRANS_ARCH.host_store[index] =
1519 writeflag? host_page : NULL;
1520 cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page;
1521 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1522 cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index] = r + 1;
1523 #ifdef DYNTRANS_ARM
1524 if (useraccess)
1525 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5]
1526 |= 1 << (index & 31);
1527 #endif
1528 #else /* !MODE32 */
1529 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
1530 if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy) {
1531 if (cpu->cd.DYNTRANS_ARCH.next_free_l2 != NULL) {
1532 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1] =
1533 cpu->cd.DYNTRANS_ARCH.next_free_l2;
1534 cpu->cd.DYNTRANS_ARCH.next_free_l2 = l2->next;
1535 } else {
1536 int i;
1537 CHECK_ALLOCATION(l2 =
1538 cpu->cd.DYNTRANS_ARCH.l1_64[x1] = malloc(
1539 sizeof(struct DYNTRANS_L2_64_TABLE)));
1540 l2->refcount = 0;
1541 for (i=0; i<(1 << DYNTRANS_L2N); i++)
1542 l2->l3[i] = cpu->cd.DYNTRANS_ARCH.
1543 l3_64_dummy;
1544 }
1545 if (l2->refcount != 0) {
1546 fatal("Huh? l2 Refcount problem.\n");
1547 exit(1);
1548 }
1549 }
1550 if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy) {
1551 fatal("INTERNAL ERROR L2 reuse\n");
1552 exit(1);
1553 }
1554 l3 = l2->l3[x2];
1555 if (l3 == cpu->cd.DYNTRANS_ARCH.l3_64_dummy) {
1556 if (cpu->cd.DYNTRANS_ARCH.next_free_l3 != NULL) {
1557 l3 = l2->l3[x2] =
1558 cpu->cd.DYNTRANS_ARCH.next_free_l3;
1559 cpu->cd.DYNTRANS_ARCH.next_free_l3 = l3->next;
1560 } else {
1561 l3 = l2->l3[x2] = zeroed_alloc(sizeof(
1562 struct DYNTRANS_L3_64_TABLE));
1563 }
1564 if (l3->refcount != 0) {
1565 fatal("Huh? l3 Refcount problem.\n");
1566 exit(1);
1567 }
1568 l2->refcount ++;
1569 }
1570 if (l3 == cpu->cd.DYNTRANS_ARCH.l3_64_dummy) {
1571 fatal("INTERNAL ERROR L3 reuse\n");
1572 exit(1);
1573 }
1574
1575 l3->host_load[x3] = host_page;
1576 l3->host_store[x3] = writeflag? host_page : NULL;
1577 l3->phys_addr[x3] = paddr_page;
1578 l3->phys_page[x3] = NULL;
1579 l3->vaddr_to_tlbindex[x3] = r + 1;
1580 l3->refcount ++;
1581
1582 #ifdef BUGHUNT
1583 /* Count how many pages are actually in use: */
1584 {
1585 int n=0, i;
1586 for (i=0; i<=mask3; i++)
1587 if (l3->vaddr_to_tlbindex[i])
1588 n++;
1589 if (n != l3->refcount) {
1590 printf("X: %i in use, but refcount = %i!\n", n, l3->refcount);
1591 exit(1);
1592 }
1593
1594 n = 0;
1595 for (i=0; i<=mask3; i++)
1596 if (l3->host_load[i] != NULL)
1597 n++;
1598 if (n != l3->refcount) {
1599 printf("XHL: %i in use, but refcount = %i!\n", n, l3->refcount);
1600 exit(1);
1601 }
1602 }
1603 #endif
1604
1605 #endif /* !MODE32 */
1606 } else {
1607 /*
1608 * The translation was already in the TLB.
1609 * Writeflag = 0: Do nothing.
1610 * Writeflag = 1: Make sure the page is writable.
1611 * Writeflag = MEM_DOWNGRADE: Downgrade to readonly.
1612 */
1613 r = found;
1614 if (writeflag & MEM_WRITE)
1615 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 1;
1616 if (writeflag & MEM_DOWNGRADE)
1617 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 0;
1618 #ifdef MODE32
1619 index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1620 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1621 #ifdef DYNTRANS_ARM
1622 cpu->cd.DYNTRANS_ARCH.is_userpage[index>>5] &= ~(1<<(index&31));
1623 if (useraccess)
1624 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5]
1625 |= 1 << (index & 31);
1626 #endif
1627 if (cpu->cd.DYNTRANS_ARCH.phys_addr[index] == paddr_page) {
1628 if (writeflag & MEM_WRITE)
1629 cpu->cd.DYNTRANS_ARCH.host_store[index] =
1630 host_page;
1631 if (writeflag & MEM_DOWNGRADE)
1632 cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
1633 } else {
1634 /* Change the entire physical/host mapping: */
1635 cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page;
1636 cpu->cd.DYNTRANS_ARCH.host_store[index] =
1637 writeflag? host_page : NULL;
1638 cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page;
1639 }
1640 #else /* !MODE32 */
1641 x1 = (vaddr_page >> (64-DYNTRANS_L1N)) & mask1;
1642 x2 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2;
1643 x3 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N))
1644 & mask3;
1645 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
1646 l3 = l2->l3[x2];
1647 if (l3->phys_addr[x3] == paddr_page) {
1648 if (writeflag & MEM_WRITE)
1649 l3->host_store[x3] = host_page;
1650 if (writeflag & MEM_DOWNGRADE)
1651 l3->host_store[x3] = NULL;
1652 } else {
1653 /* Change the entire physical/host mapping: */
1654 printf("HOST LOAD 2 set to %p\n", host_page);
1655 l3->host_load[x3] = host_page;
1656 l3->host_store[x3] = writeflag? host_page : NULL;
1657 l3->phys_addr[x3] = paddr_page;
1658 }
1659
1660 #ifdef BUGHUNT
1661 /* Count how many pages are actually in use: */
1662 {
1663 int n=0, i;
1664 for (i=0; i<=mask3; i++)
1665 if (l3->vaddr_to_tlbindex[i])
1666 n++;
1667 if (n != l3->refcount) {
1668 printf("Y: %i in use, but refcount = %i!\n", n, l3->refcount);
1669 exit(1);
1670 }
1671
1672 n = 0;
1673 for (i=0; i<=mask3; i++)
1674 if (l3->host_load[i] != NULL)
1675 n++;
1676 if (n != l3->refcount) {
1677 printf("YHL: %i in use, but refcount = %i!\n", n, l3->refcount);
1678 printf("Entry r = %i\n", r);
1679 printf("Valid = %i\n",
1680 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid);
1681 exit(1);
1682 }
1683 }
1684 #endif
1685
1686 #endif /* !MODE32 */
1687 }
1688 }
1689 #endif /* DYNTRANS_UPDATE_TRANSLATION_TABLE */
1690
1691
1692 /*****************************************************************************/
1693
1694
1695 #ifdef DYNTRANS_TO_BE_TRANSLATED_HEAD
1696 /*
1697 * Check for breakpoints.
1698 */
1699 if (!single_step_breakpoint && !cpu->translation_readahead) {
1700 MODE_uint_t curpc = cpu->pc;
1701 int i;
1702 for (i=0; i<cpu->machine->breakpoints.n; i++)
1703 if (curpc == (MODE_uint_t)
1704 cpu->machine->breakpoints.addr[i]) {
1705 if (!cpu->machine->instruction_trace) {
1706 int old_quiet_mode = quiet_mode;
1707 quiet_mode = 0;
1708 DISASSEMBLE(cpu, ib, 1, 0);
1709 quiet_mode = old_quiet_mode;
1710 }
1711 #ifdef MODE32
1712 fatal("BREAKPOINT: pc = 0x%"PRIx32"\n(The "
1713 "instruction has not yet executed.)\n",
1714 (uint32_t)cpu->pc);
1715 #else
1716 fatal("BREAKPOINT: pc = 0x%"PRIx64"\n(The "
1717 "instruction has not yet executed.)\n",
1718 (uint64_t)cpu->pc);
1719 #endif
1720 #ifdef DYNTRANS_DELAYSLOT
1721 if (cpu->delay_slot != NOT_DELAYED)
1722 fatal("ERROR! Breakpoint in a delay"
1723 " slot! Not yet supported.\n");
1724 #endif
1725 single_step_breakpoint = 1;
1726 single_step = ENTER_SINGLE_STEPPING;
1727 goto stop_running_translated;
1728 }
1729 }
1730 #endif /* DYNTRANS_TO_BE_TRANSLATED_HEAD */
1731
1732
1733 /*****************************************************************************/
1734
1735
1736 #ifdef DYNTRANS_TO_BE_TRANSLATED_TAIL
1737 /*
1738 * If we end up here, then an instruction was translated. Let's mark
1739 * the page as containing a translation at this part of the page.
1740 */
1741
1742 /* Make sure cur_physpage is in synch: */
1743 cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *)
1744 cpu->cd.DYNTRANS_ARCH.cur_ic_page;
1745
1746 {
1747 int x = addr & (DYNTRANS_PAGESIZE - 1);
1748 int addr_per_translation_range = DYNTRANS_PAGESIZE / (8 *
1749 sizeof(cpu->cd.DYNTRANS_ARCH.cur_physpage->translations));
1750 x /= addr_per_translation_range;
1751
1752 cpu->cd.DYNTRANS_ARCH.cur_physpage->translations |= (1 << x);
1753 }
1754
1755 /*
1756 * Now it is time to check for combinations of instructions that can
1757 * be converted into a single function call.
1758 *
1759 * Note: Single-stepping or instruction tracing doesn't work with
1760 * instruction combinations. For architectures with delay slots,
1761 * we also ignore combinations if the delay slot is across a page
1762 * boundary.
1763 */
1764 if (!single_step && !cpu->machine->instruction_trace
1765 #ifdef DYNTRANS_DELAYSLOT
1766 && !in_crosspage_delayslot
1767 #endif
1768 && cpu->cd.DYNTRANS_ARCH.combination_check != NULL
1769 && cpu->machine->allow_instruction_combinations) {
1770 cpu->cd.DYNTRANS_ARCH.combination_check(cpu, ic,
1771 addr & (DYNTRANS_PAGESIZE - 1));
1772 }
1773
1774 cpu->cd.DYNTRANS_ARCH.combination_check = NULL;
1775
1776 /* An additional check, to catch some bugs: */
1777 if (ic->f == (
1778 #ifdef DYNTRANS_DUALMODE_32
1779 cpu->is_32bit? instr32(to_be_translated) :
1780 #endif
1781 instr(to_be_translated))) {
1782 fatal("INTERNAL ERROR: ic->f not set!\n");
1783 goto bad;
1784 }
1785 if (ic->f == NULL) {
1786 fatal("INTERNAL ERROR: ic->f == NULL!\n");
1787 goto bad;
1788 }
1789
1790 /* ... and finally execute the translated instruction: */
1791
1792 /* (Except when doing read-ahead!) */
1793 if (cpu->translation_readahead)
1794 return;
1795
1796 /*
1797 * Special case when single-stepping: Execute the translated
1798 * instruction, but then replace it with a "to be translated"
1799 * directly afterwards.
1800 */
1801 if ((single_step_breakpoint && cpu->delay_slot == NOT_DELAYED)
1802 #ifdef DYNTRANS_DELAYSLOT
1803 || in_crosspage_delayslot
1804 #endif
1805 ) {
1806 single_step_breakpoint = 0;
1807 ic->f(cpu, ic);
1808 ic->f =
1809 #ifdef DYNTRANS_DUALMODE_32
1810 cpu->is_32bit? instr32(to_be_translated) :
1811 #endif
1812 instr(to_be_translated);
1813
1814 return;
1815 }
1816
1817 /* Translation read-ahead: */
1818 if (!single_step && !cpu->machine->instruction_trace) {
1819 /* Do readahead: */
1820 int i = 1;
1821 uint64_t pagenr = DYNTRANS_ADDR_TO_PAGENR(cpu->pc);
1822 uint64_t baseaddr = cpu->pc;
1823
1824 cpu->translation_readahead = MAX_DYNTRANS_READAHEAD;
1825
1826 while (DYNTRANS_ADDR_TO_PAGENR(baseaddr +
1827 (i << DYNTRANS_INSTR_ALIGNMENT_SHIFT)) == pagenr &&
1828 cpu->translation_readahead > 0) {
1829 void (*old_f)(struct cpu *,
1830 struct DYNTRANS_IC *) = ic[i].f;
1831
1832 /* Already translated? Then abort: */
1833 if (old_f != (
1834 #ifdef DYNTRANS_DUALMODE_32
1835 cpu->is_32bit? instr32(to_be_translated) :
1836 #endif
1837 instr(to_be_translated)))
1838 break;
1839
1840 /* Translate the instruction: */
1841 ic[i].f(cpu, ic+i);
1842
1843 /* Translation failed? Then abort. */
1844 if (ic[i].f == old_f)
1845 break;
1846
1847 cpu->translation_readahead --;
1848 ++i;
1849 }
1850
1851 cpu->translation_readahead = 0;
1852 }
1853
1854
1855 /*
1856 * Finally finally :-), execute the instruction.
1857 *
1858 * Note: The instruction might have changed during read-ahead, if
1859 * instruction combinations are used.
1860 */
1861
1862 ic->f(cpu, ic);
1863
1864 return;
1865
1866
1867 bad: /*
1868 * Nothing was translated. (Unimplemented or illegal instruction.)
1869 */
1870
1871 /* Clear the translation, in case it was "half-way" done: */
1872 ic->f =
1873 #ifdef DYNTRANS_DUALMODE_32
1874 cpu->is_32bit? instr32(to_be_translated) :
1875 #endif
1876 instr(to_be_translated);
1877
1878 if (cpu->translation_readahead)
1879 return;
1880
1881 quiet_mode = 0;
1882 fatal("to_be_translated(): TODO: unimplemented instruction");
1883
1884 if (cpu->machine->instruction_trace)
1885 #ifdef MODE32
1886 fatal(" at 0x%"PRIx32"\n", (uint32_t)cpu->pc);
1887 #else
1888 fatal(" at 0x%"PRIx64"\n", (uint64_t)cpu->pc);
1889 #endif
1890 else {
1891 fatal(":\n");
1892 DISASSEMBLE(cpu, ib, 1, 0);
1893 }
1894
1895 cpu->running = 0;
1896
1897 /* Note: Single-stepping can jump here. */
1898 stop_running_translated:
1899
1900 debugger_n_steps_left_before_interaction = 0;
1901
1902 ic = cpu->cd.DYNTRANS_ARCH.next_ic = &nothing_call;
1903 cpu->cd.DYNTRANS_ARCH.next_ic ++;
1904
1905 #ifdef DYNTRANS_DELAYSLOT
1906 /* Special hack: If the bad instruction was in a delay slot,
1907 make sure that execution does not continue anyway: */
1908 if (cpu->delay_slot)
1909 cpu->delay_slot |= EXCEPTION_IN_DELAY_SLOT;
1910 #endif
1911
1912 /* Execute the "nothing" instruction: */
1913 ic->f(cpu, ic);
1914
1915 #endif /* DYNTRANS_TO_BE_TRANSLATED_TAIL */
1916

  ViewVC Help
Powered by ViewVC 1.1.26