/[gxemul]/trunk/src/cpus/cpu_x86.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

Annotation of /trunk/src/cpus/cpu_x86.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (hide annotations)
Mon Oct 8 16:20:58 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 84586 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1421 2006/11/06 05:32:37 debug Exp $
20060816	Adding a framework for emulated/virtual timers (src/timer.c),
		using only setitimer().
		Rewriting the mc146818 to use the new timer framework.
20060817	Adding a call to gettimeofday() every now and then (once every
		second, at the moment) to resynch the timer if it drifts.
		Beginning to convert the ISA timer interrupt mechanism (8253
		and 8259) to use the new timer framework.
		Removing the -I command line option.
20060819	Adding the -I command line option again, with new semantics.
		Working on Footbridge timer interrupts; NetBSD/NetWinder and
		NetBSD/CATS now run at correct speed, but unfortunately with
		HUGE delays during bootup.
20060821	Some minor m68k updates. Adding the first instruction: nop. :)
		Minor Alpha emulation updates.
20060822	Adding a FreeBSD development specific YAMON environment
		variable ("khz") (as suggested by Bruce M. Simpson).
		Moving YAMON environment variable initialization from
		machine_evbmips.c into promemul/yamon.c, and adding some more
		variables.
		Continuing on the LCA PCI bus controller (for Alpha machines).
20060823	Continuing on the timer stuff: experimenting with MIPS count/
		compare interrupts connected to the timer framework.
20060825	Adding bogus SCSI commands 0x51 (SCSICDROM_READ_DISCINFO) and
		0x52 (SCSICDROM_READ_TRACKINFO) to the SCSI emulation layer,
		to allow NetBSD/pmax 4.0_BETA to be installed from CDROM.
		Minor updates to the LCA PCI controller.
20060827	Implementing a CHIP8 cpu mode, and a corresponding CHIP8
		machine, for fun. Disassembly support for all instructions,
		and most of the common instructions have been implemented: mvi,
		mov_imm, add_imm, jmp, rand, cls, sprite, skeq_imm, jsr,
		skne_imm, bcd, rts, ldr, str, mov, or, and, xor, add, sub,
		font, ssound, sdelay, gdelay, bogus skup/skpr, skeq, skne.
20060828	Beginning to convert the CHIP8 cpu in the CHIP8 machine to a
		(more correct) RCA 180x cpu. (Disassembly for all 1802
		instructions has been implemented, but no execution yet, and
		no 1805 extended instructions.)
20060829	Minor Alpha emulation updates.
20060830	Beginning to experiment a little with PCI IDE for SGI O2.
		Fixing the cursor key mappings for MobilePro 770 emulation.
		Fixing the LK201 warning caused by recent NetBSD/pmax.
		The MIPS R41xx standby, suspend, and hibernate instructions now
		behave like the RM52xx/MIPS32/MIPS64 wait instruction.
		Fixing dev_wdc so it calculates correct (64-bit) offsets before
		giving them to diskimage_access().
20060831	Continuing on Alpha emulation (OSF1 PALcode).
20060901	Minor Alpha updates; beginning on virtual memory pagetables.
		Removed the limit for max nr of devices (in preparation for
		allowing devices' base addresses to be changed during runtime).
		Adding a hack for MIPS [d]mfc0 select 0 (except the count
		register), so that the coproc register is simply copied.
		The MIPS suspend instruction now exits the emulator, instead
		of being treated as a wait instruction (this causes NetBSD/
		hpcmips to get correct 'halt' behavior).
		The VR41xx RTC now returns correct time.
		Connecting the VR41xx timer to the timer framework (fixed at
		128 Hz, for now).
		Continuing on SPARC emulation, adding more instructions:
		restore, ba_xcc, ble. The rectangle drawing demo works :)
		Removing the last traces of the old ENABLE_CACHE_EMULATION
		MIPS stuff (not usable with dyntrans anyway).
20060902	Splitting up src/net.c into several smaller files in its own
		subdirectory (src/net/).
20060903	Cleanup of the files in src/net/, to make them less ugly.
20060904	Continuing on the 'settings' subsystem.
		Minor progress on the SPARC emulation mode.
20060905	Cleanup of various things, and connecting the settings
		infrastructure to various subsystems (emul, machine, cpu, etc).
		Changing the lk201 mouse update routine to not rely on any
		emulated hardware framebuffer cursor coordinates, but instead
		always do (semi-usable) relative movements.
20060906	Continuing on the lk201 mouse stuff. Mouse behaviour with
		multiple framebuffers (which was working in Ultrix) is now
		semi-broken (but it still works, in a way).
		Moving the documentation about networking into its own file
		(networking.html), and refreshing it a bit. Adding an example
		of how to use ethernet frame direct-access (udp_snoop).
20060907	Continuing on the settings infrastructure.
20060908	Minor updates to SH emulation: for 32-bit emulation: delay
		slots and the 'jsr @Rn' instruction. I'm putting 64-bit SH5 on
		ice, for now.
20060909-10	Implementing some more 32-bit SH instructions. Removing the
		64-bit mode completely. Enough has now been implemented to run
		the rectangle drawing demo. :-)
20060912	Adding more SH instructions.
20060916	Continuing on SH emulation (some more instructions: div0u,
		div1, rotcl/rotcr, more mov instructions, dt, braf, sets, sett,
		tst_imm, dmuls.l, subc, ldc_rm_vbr, movt, clrt, clrs, clrmac).
		Continuing on the settings subsystem (beginning on reading/
		writing settings, removing bugs, and connecting more cpus to
		the framework).
20060919	More work on SH emulation; adding an ldc banked instruction,
		and attaching a 640x480 framebuffer to the Dreamcast machine
		mode (NetBSD/dreamcast prints the NetBSD copyright banner :-),
		and then panics).
20060920	Continuing on the settings subsystem.
20060921	Fixing the Footbridge timer stuff so that NetBSD/cats and
		NetBSD/netwinder boot up without the delays.
20060922	Temporarily hardcoding MIPS timer interrupt to 100 Hz. With
		'wait' support disabled, NetBSD/malta and Linux/malta run at
		correct speed.
20060923	Connecting dev_gt to the timer framework, so that NetBSD/cobalt
		runs at correct speed.
		Moving SH4-specific memory mapped registers into its own
		device (dev_sh4.c).
		Running with -N now prints "idling" instead of bogus nr of
		instrs/second (which isn't valid anyway) while idling.
20060924	Algor emulation should now run at correct speed.
		Adding disassembly support for some MIPS64 revision 2
		instructions: ext, dext, dextm, dextu.
20060926	The timer framework now works also when the MIPS wait
		instruction is used.
20060928	Re-implementing checks for coprocessor availability for MIPS
		cop0 instructions. (Thanks to Carl van Schaik for noticing the
		lack of cop0 availability checks.)
20060929	Implementing an instruction combination hack which treats
		NetBSD/pmax' idle loop as a wait-like instruction.
20060930	The ENTRYHI_R_MASK was missing in (at least) memory_mips_v2p.c,
		causing TLB lookups to sometimes succeed when they should have
		failed. (A big thank you to Juli Mallett for noticing the
		problem.)
		Adding disassembly support for more MIPS64 revision 2 opcodes
		(seb, seh, wsbh, jalr.hb, jr.hb, synci, ins, dins, dinsu,
		dinsm, dsbh, dshd, ror, dror, rorv, drorv, dror32). Also
		implementing seb, seh, dsbh, dshd, and wsbh.
		Implementing an instruction combination hack for Linux/pmax'
		idle loop, similar to the NetBSD/pmax case.
20061001	Changing the NetBSD/sgimips install instructions to extract
		files from an iso image, instead of downloading them via ftp.
20061002	More-than-31-bit userland addresses in memory_mips_v2p.c were
		not actually working; applying a fix from Carl van Schaik to
		enable them to work + making some other updates (adding kuseg
		support).
		Fixing hpcmips (vr41xx) timer initialization.
		Experimenting with O(n)->O(1) reduction in the MIPS TLB lookup
		loop. Seems to work both for R3000 and non-R3000.
20061003	Continuing a little on SH emulation (adding more control
		registers; mini-cleanup of memory_sh.c).
20061004	Beginning on a dev_rtc, a clock/timer device for the test
		machines; also adding a demo, and some documentation.
		Fixing a bug in SH "mov.w @(disp,pc),Rn" (the result wasn't
		sign-extended), and adding the addc and ldtlb instructions.
20061005	Contining on SH emulation: virtual to physical address
		translation, and a skeleton exception mechanism.
20061006	Adding more SH instructions (various loads and stores, rte,
		negc, muls.w, various privileged register-move instructions).
20061007	More SH instructions: various move instructions, trapa, div0s,
		float, fdiv, ftrc.
		Continuing on dev_rtc; removing the rtc demo.
20061008	Adding a dummy Dreamcast PROM module. (Homebrew Dreamcast
		programs using KOS libs need this.)
		Adding more SH instructions: "stc vbr,rn", rotl, rotr, fsca,
		fmul, fadd, various floating-point moves, etc. A 256-byte
		demo for Dreamcast runs :-)
20061012	Adding the SH "lds Rm,pr" and bsr instructions.
20061013	More SH instructions: "sts fpscr,rn", tas.b, and some more
		floating point instructions, cmp/str, and more moves.
		Adding a dummy dev_pvr (Dreamcast graphics controller).
20061014	Generalizing the expression evaluator (used in the built-in
		debugger) to support parentheses and +-*/%^&|.
20061015	Removing the experimental tlb index hint code in
		mips_memory_v2p.c, since it didn't really have any effect.
20061017	Minor SH updates; adding the "sts pr,Rn", fcmp/gt, fneg,
		frchg, and some other instructions. Fixing missing sign-
		extension in an 8-bit load instruction.
20061019	Adding a simple dev_dreamcast_rtc.
		Implementing memory-mapped access to the SH ITLB/UTLB arrays.
20061021	Continuing on various SH and Dreamcast things: sh4 timers,
		debug messages for dev_pvr, fixing some virtual address
		translation bugs, adding the bsrf instruction.
		The NetBSD/dreamcast GENERIC_MD kernel now reaches userland :)
		Adding a dummy dev_dreamcast_asic.c (not really useful yet).
		Implementing simple support for Store Queues.
		Beginning on the PVR Tile Accelerator.
20061022	Generalizing the PVR framebuffer to support off-screen drawing,
		multiple bit-depths, etc. (A small speed penalty, but most
		likely worth it.)
		Adding more SH instructions (mulu.w, fcmp/eq, fsub, fmac,
		fschg, and some more); correcting bugs in "fsca" and "float".
20061024	Adding the SH ftrv (matrix * vector) instruction. Marcus
		Comstedt's "tatest" example runs :) (wireframe only).
		Correcting disassembly for SH floating point instructions that
		use the xd* registers.
		Adding the SH fsts instruction.
		In memory_device_dyntrans_access(), only the currently used
		range is now invalidated, and not the entire device range.
20061025	Adding a dummy AVR32 cpu mode skeleton.
20061026	Various Dreamcast updates; beginning on a Maple bus controller.
20061027	Continuing on the Maple bus. A bogus Controller, Keyboard, and
		Mouse can now be detected by NetBSD and KOS homebrew programs.
		Cleaning up the SH4 Timer Management Unit, and beginning on
		SH4 interrupts.
		Implementing the Dreamcast SYSASIC.
20061028	Continuing on the SYSASIC.
		Adding the SH fsqrt instruction.
		memory_sh.c now actually scans the ITLB.
		Fixing a bug in dev_sh4.c, related to associative writes into
		the memory-mapped UTLB array. NetBSD/dreamcast now reaches
		userland stably, and prints the "Terminal type?" message :-]
		Implementing enough of the Dreamcast keyboard to make NetBSD
		accept it for input.
		Enabling SuperH for stable (non-development) builds.
		Adding NetBSD/dreamcast to the documentation, although it
		doesn't support root-on-nfs yet.
20061029	Changing usleep(1) calls in the debugger to to usleep(10000)
		(according to Brian Foley, this makes GXemul run better on
		MacOS X).
		Making the Maple "Controller" do something (enough to barely
		interact with dcircus.elf).
20061030-31	Some progress on the PVR. More test programs start running (but
		with strange output).
		Various other SH4-related updates.
20061102	Various Dreamcast and SH4 updates; more KOS demos run now.
20061104	Adding a skeleton dev_mb8696x.c (the Dreamcast's LAN adapter).
20061105	Continuing on the MB8696x; NetBSD/dreamcast detects it as mbe0.
		Testing for the release.

==============  RELEASE 0.4.3  ==============


1 dpavlin 14 /*
2 dpavlin 24 * Copyright (C) 2005-2006 Anders Gavare. All rights reserved.
3 dpavlin 14 *
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 dpavlin 32 * $Id: cpu_x86.c,v 1.18 2006/09/23 03:49:02 debug Exp $
29 dpavlin 14 *
30     * x86 (and amd64) CPU emulation.
31     *
32     *
33 dpavlin 32 * NOTE: I ripped out pretty much everything that had to do with x86
34     * emulation, when doing the transition to dyntrans. This CPU mode
35     * hasn't been rewritten yet.
36 dpavlin 14 *
37 dpavlin 32 * Right now, it is completely bogus.
38 dpavlin 14 */
39    
40     #include <stdio.h>
41     #include <stdlib.h>
42     #include <string.h>
43     #include <ctype.h>
44    
45     #include "cpu.h"
46     #include "devices.h"
47     #include "machine.h"
48     #include "memory.h"
49     #include "misc.h"
50 dpavlin 32 #include "settings.h"
51 dpavlin 14 #include "symbol.h"
52    
53     #define DYNTRANS_DUALMODE_32
54     #define DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
55     #include "tmp_x86_head.c"
56    
57    
58     static struct x86_model models[] = x86_models;
59     static char *reg_names[N_X86_REGS] = x86_reg_names;
60     static char *reg_names_bytes[8] = x86_reg_names_bytes;
61     static char *seg_names[N_X86_SEGS] = x86_seg_names;
62     static char *cond_names[N_X86_CONDS] = x86_cond_names;
63    
64     #define REP_REP 1
65     #define REP_REPNE 2
66    
67    
68     /*
69     * x86_cpu_new():
70     *
71     * Create a new x86 cpu object.
72     */
73     int x86_cpu_new(struct cpu *cpu, struct memory *mem, struct machine *machine,
74     int cpu_id, char *cpu_type_name)
75     {
76     int i = 0;
77    
78     /* Try to find a match: */
79     while (models[i].model_number != 0) {
80     if (strcasecmp(cpu_type_name, models[i].name) == 0)
81     break;
82     i++;
83     }
84    
85     if (models[i].name == NULL)
86     return 0;
87    
88     cpu->memory_rw = x86_memory_rw;
89     cpu->byte_order = EMUL_LITTLE_ENDIAN;
90    
91     cpu->cd.x86.model = models[i];
92    
93 dpavlin 26 cpu->translate_v2p = x86_translate_v2p;
94 dpavlin 20
95 dpavlin 14 /* Initial startup is in 16-bit real mode: */
96     cpu->pc = 0xfff0;
97    
98     /* Initial segments: */
99     cpu->cd.x86.descr_cache[X86_S_CS].valid = 1;
100     cpu->cd.x86.descr_cache[X86_S_CS].default_op_size = 16;
101     cpu->cd.x86.descr_cache[X86_S_CS].access_rights = 0x93;
102     cpu->cd.x86.descr_cache[X86_S_CS].base = 0xf0000; /* ffff0000 */
103     cpu->cd.x86.descr_cache[X86_S_CS].limit = 0xffff;
104     cpu->cd.x86.descr_cache[X86_S_CS].descr_type = DESCR_TYPE_CODE;
105     cpu->cd.x86.descr_cache[X86_S_CS].readable = 1;
106     cpu->cd.x86.descr_cache[X86_S_CS].writable = 1;
107     cpu->cd.x86.descr_cache[X86_S_CS].granularity = 0;
108     cpu->cd.x86.s[X86_S_CS] = 0xf000;
109 dpavlin 20 cpu->cd.x86.cursegment = X86_S_CS;
110 dpavlin 14
111     cpu->cd.x86.idtr = 0;
112     cpu->cd.x86.idtr_limit = 0x3ff;
113    
114     cpu->cd.x86.rflags = 0x0002;
115     if (cpu->cd.x86.model.model_number == X86_MODEL_8086)
116     cpu->cd.x86.rflags |= 0xf000;
117    
118 dpavlin 20 cpu->is_32bit = (cpu->cd.x86.model.model_number < X86_MODEL_AMD64)?
119     1 : 0;
120    
121     if (cpu->is_32bit) {
122 dpavlin 28 cpu->run_instr = x8632_run_instr;
123 dpavlin 20 cpu->update_translation_table = x8632_update_translation_table;
124     cpu->invalidate_translation_caches =
125     x8632_invalidate_translation_caches;
126     cpu->invalidate_code_translation =
127     x8632_invalidate_code_translation;
128     } else {
129 dpavlin 28 cpu->run_instr = x86_run_instr;
130 dpavlin 20 cpu->update_translation_table = x86_update_translation_table;
131     cpu->invalidate_translation_caches =
132     x86_invalidate_translation_caches;
133     cpu->invalidate_code_translation =
134     x86_invalidate_code_translation;
135     }
136    
137 dpavlin 14 /* Only show name and caches etc for CPU nr 0 (in SMP machines): */
138     if (cpu_id == 0) {
139     debug("%s", cpu->name);
140     }
141    
142 dpavlin 32 /*
143     * Add all register names to the settings:
144     *
145     * Note that the name 'pc' is also added. It equals 64-bit RIP.
146     */
147     CPU_SETTINGS_ADD_REGISTER64("pc", cpu->pc);
148    
149     /* TODO: All of the following: */
150     #if 0
151     if (strcasecmp(name, "pc") == 0 || strcasecmp(name, "rip") == 0) {
152     if (strcasecmp(name, "ip") == 0) {
153     if (strcasecmp(name, "eip") == 0) {
154     if (strcasecmp(name, "rflags") == 0) {
155     if (strcasecmp(name, "eflags") == 0) {
156     if (strcasecmp(name, "flags") == 0) {
157     /* 8-bit low */
158     if (strcasecmp(name, reg_names_bytes[r]) == 0) {
159     /* 8-bit high: */
160     for (r=0; r<4; r++)
161     if (strcasecmp(name, reg_names_bytes[r+4]) == 0) {
162     /* 16-, 32-, 64-bit registers: */
163     for (r=0; r<N_X86_REGS; r++) {
164     if (r<8 && strcasecmp(name, reg_names[r]) == 0) {
165     /* 32-bit: */
166     if (r<8 && (name[0]=='e' || name[0]=='E') &&
167     /* 64-bit: */
168     if ((name[0]=='r' || name[0]=='R') &&
169     strcasecmp(name+1, reg_names[r]) == 0) {
170     /* segment names: */
171     for (r=0; r<N_X86_SEGS; r++) {
172     if (strcasecmp(name, seg_names[r]) == 0) {
173     /* control registers: (TODO: 32- vs 64-bit on AMD64?) */
174     if (strncasecmp(name, "cr", 2) == 0 && atoi(name+2) < N_X86_CREGS ) {
175     #endif
176    
177    
178 dpavlin 14 return 1;
179     }
180    
181    
182     /*
183     * x86_cpu_dumpinfo():
184     */
185     void x86_cpu_dumpinfo(struct cpu *cpu)
186     {
187     debug(", currently in %s mode", PROTECTED_MODE? "protected" : "real");
188     debug("\n");
189     }
190    
191    
192     /*
193     * x86_cpu_list_available_types():
194     *
195     * Print a list of available x86 CPU types.
196     */
197     void x86_cpu_list_available_types(void)
198     {
199     int i = 0, j;
200    
201     while (models[i].model_number != 0) {
202     debug("%s", models[i].name);
203    
204 dpavlin 22 for (j=0; j<10-(int)strlen(models[i].name); j++)
205 dpavlin 14 debug(" ");
206     i++;
207     if ((i % 6) == 0 || models[i].name == NULL)
208     debug("\n");
209     }
210     }
211    
212    
213     /*
214     * x86_cpu_register_dump():
215     *
216     * Dump cpu registers in a relatively readable format.
217     * (gprs and coprocs are mostly useful for the MIPS version of this function.)
218     */
219     void x86_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs)
220     {
221     char *symbol;
222     uint64_t offset;
223     int i, x = cpu->cpu_id;
224    
225 dpavlin 24 if (LONG_MODE) {
226     /* 64-bit long mode: */
227 dpavlin 14 symbol = get_symbol_name(&cpu->machine->symbol_context,
228     cpu->pc, &offset);
229    
230 dpavlin 24 debug("cpu%i: rip = 0x%016"PRIx64, x, cpu->pc);
231 dpavlin 14 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
232    
233 dpavlin 24 for (i=0; i<N_X86_REGS; i++) {
234     if ((i & 1) == 0)
235     debug("cpu%i:", x);
236     debug(" r%s = 0x%016"PRIx64, reg_names[i],
237     (uint64_t)cpu->cd.x86.r[i]);
238     if ((i & 1) == 1)
239     debug("\n");
240     }
241     } else if (REAL_MODE) {
242     /* 16-bit real-mode: */
243     debug("cpu%i: cs:ip = 0x%04"PRIx16":0x%04"PRIx16"\n", x,
244     cpu->cd.x86.s[X86_S_CS], (uint16_t)cpu->pc);
245    
246     debug("cpu%i: ax = 0x%04"PRIx16" bx = 0x%04"PRIx16
247     " cx = 0x%04"PRIx16" dx = 0x%04"PRIx16"\n", x,
248     (uint16_t)cpu->cd.x86.r[X86_R_AX],
249     (uint16_t)cpu->cd.x86.r[X86_R_BX],
250     (uint16_t)cpu->cd.x86.r[X86_R_CX],
251     (uint16_t)cpu->cd.x86.r[X86_R_DX]);
252     debug("cpu%i: si = 0x%04"PRIx16" di = 0x%04"PRIx16
253     " bp = 0x%04"PRIx16" sp = 0x%04"PRIx16"\n", x,
254     (uint16_t)cpu->cd.x86.r[X86_R_SI],
255     (uint16_t)cpu->cd.x86.r[X86_R_DI],
256     (uint16_t)cpu->cd.x86.r[X86_R_BP],
257     (uint16_t)cpu->cd.x86.r[X86_R_SP]);
258     debug("cpu%i: ds = 0x%04"PRIx16" es = 0x%04"PRIx16
259     " ss = 0x%04"PRIx16" flags = 0x%04"PRIx16"\n", x,
260     (uint16_t)cpu->cd.x86.s[X86_S_DS],
261     (uint16_t)cpu->cd.x86.s[X86_S_ES],
262     (uint16_t)cpu->cd.x86.s[X86_S_SS],
263     (uint16_t)cpu->cd.x86.rflags);
264 dpavlin 14 } else {
265 dpavlin 24 /* 32-bit protected mode: */
266 dpavlin 14 symbol = get_symbol_name(&cpu->machine->symbol_context,
267     cpu->pc, &offset);
268    
269 dpavlin 24 debug("cpu%i: eip=0x%08"PRIx32, x, (uint32_t)cpu->pc);
270 dpavlin 14 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
271    
272 dpavlin 24 debug("cpu%i: eax=0x%08"PRIx32" ebx=0x%08"PRIx32
273     " ecx=0x%08"PRIx32" edx=0x%08"PRIx32"\n", x,
274     (uint32_t)cpu->cd.x86.r[X86_R_AX],
275     (uint32_t)cpu->cd.x86.r[X86_R_BX],
276     (uint32_t)cpu->cd.x86.r[X86_R_CX],
277     (uint32_t)cpu->cd.x86.r[X86_R_DX]);
278     debug("cpu%i: esi=0x%08"PRIx32" edi=0x%08"PRIx32
279     " ebp=0x%08"PRIx32" esp=0x%08"PRIx32"\n", x,
280     (uint32_t)cpu->cd.x86.r[X86_R_SI],
281     (uint32_t)cpu->cd.x86.r[X86_R_DI],
282     (uint32_t)cpu->cd.x86.r[X86_R_BP],
283     (uint32_t)cpu->cd.x86.r[X86_R_SP]);
284 dpavlin 14 }
285    
286     if (coprocs != 0) {
287     for (i=0; i<6; i++) {
288     debug("cpu%i: %s=0x%04x (", x, seg_names[i],
289     cpu->cd.x86.s[i]);
290     if (cpu->cd.x86.descr_cache[i].valid) {
291     debug("base=0x%08x, limit=0x%08x, ",
292     (int)cpu->cd.x86.descr_cache[i].base,
293     (int)cpu->cd.x86.descr_cache[i].limit);
294     debug("%s", cpu->cd.x86.descr_cache[i].
295     descr_type==DESCR_TYPE_CODE?"CODE":"DATA");
296     debug(", %i-bit", cpu->cd.x86.descr_cache[i].
297     default_op_size);
298     debug(", %s%s", cpu->cd.x86.descr_cache[i].
299     readable? "R" : "-", cpu->cd.x86.
300     descr_cache[i].writable? "W" : "-");
301     } else
302     debug("invalid");
303     debug(")\n");
304     }
305     debug("cpu%i: gdtr=0x%08llx:0x%04x idtr=0x%08llx:0x%04x "
306     " ldtr=0x%08x:0x%04x\n", x, (long long)cpu->cd.x86.gdtr,
307     (int)cpu->cd.x86.gdtr_limit, (long long)cpu->cd.x86.idtr,
308     (int)cpu->cd.x86.idtr_limit, (long long)cpu->cd.x86.
309     ldtr_base, (int)cpu->cd.x86.ldtr_limit);
310     debug("cpu%i: pic1: irr=0x%02x ier=0x%02x isr=0x%02x "
311     "base=0x%02x\n", x, cpu->machine->isa_pic_data.pic1->irr,
312     cpu->machine->isa_pic_data.pic1->ier,
313     cpu->machine->isa_pic_data.pic1->isr,
314     cpu->machine->isa_pic_data.pic1->irq_base);
315     debug("cpu%i: pic2: irr=0x%02x ier=0x%02x isr=0x%02x "
316     "base=0x%02x\n", x, cpu->machine->isa_pic_data.pic2->irr,
317     cpu->machine->isa_pic_data.pic2->ier,
318     cpu->machine->isa_pic_data.pic2->isr,
319     cpu->machine->isa_pic_data.pic2->irq_base);
320     } else if (PROTECTED_MODE) {
321     /* Protected mode: */
322 dpavlin 24 debug("cpu%i: cs=0x%04"PRIx16" ds=0x%04"PRIx16" es=0x%04"
323     PRIx16" fs=0x%04"PRIx16" gs=0x%04"PRIx16" ss=0x%04"
324     PRIx16"\n", x, (uint16_t)cpu->cd.x86.s[X86_S_CS],
325     (uint16_t)cpu->cd.x86.s[X86_S_DS],
326     (uint16_t)cpu->cd.x86.s[X86_S_ES],
327     (uint16_t)cpu->cd.x86.s[X86_S_FS],
328     (uint16_t)cpu->cd.x86.s[X86_S_GS],
329     (uint16_t)cpu->cd.x86.s[X86_S_SS]);
330 dpavlin 14 }
331    
332     if (PROTECTED_MODE) {
333     /* Protected mode: */
334 dpavlin 24 debug("cpu%i: cr0=0x%08"PRIx32" cr2=0x%08"PRIx32" cr3=0x%08"
335     PRIx32" eflags=0x%08"PRIx32"\n", x,
336     (uint32_t)cpu->cd.x86.cr[0], (uint32_t)cpu->cd.x86.cr[2],
337     (uint32_t)cpu->cd.x86.cr[3], (uint32_t)cpu->cd.x86.rflags);
338     debug("cpu%i: tr = 0x%04"PRIx16" (base=0x%"PRIx64", limit=0x"
339     PRIx32")\n", x, (uint16_t)cpu->cd.x86.tr, (uint64_t)
340     cpu->cd.x86.tr_base, (uint32_t)cpu->cd.x86.tr_limit);
341 dpavlin 14 }
342     }
343    
344    
345     /* Macro which modifies the lower part of a value, or the entire value,
346     depending on 'mode': */
347     #define modify(old,new) ( \
348     mode==16? ( \
349     ((old) & ~0xffff) + ((new) & 0xffff) \
350     ) : ((new) & 0xffffffffULL) )
351    
352     /* "volatile" here, because some versions of gcc with -O3 on i386 are buggy */
353     #define HEXPRINT(x,n) { volatile int j; for (j=0; j<(n); j++) \
354     debug("%02x",(x)[j]); }
355     #define HEXSPACES(i) { int j; j = (i)>10? 10:(i); while (j++<10) debug(" "); \
356     debug(" "); }
357     #define SPACES HEXSPACES(ilen)
358    
359    
360     static uint32_t read_imm_common(unsigned char **instrp, uint64_t *ilenp,
361     int len, int printflag)
362     {
363     uint32_t imm;
364     unsigned char *instr = *instrp;
365    
366     if (len == 8)
367     imm = instr[0];
368     else if (len == 16)
369     imm = instr[0] + (instr[1] << 8);
370     else
371     imm = instr[0] + (instr[1] << 8) +
372     (instr[2] << 16) + (instr[3] << 24);
373    
374     if (printflag)
375     HEXPRINT(instr, len / 8);
376    
377     if (ilenp != NULL)
378     (*ilenp) += len/8;
379    
380     (*instrp) += len/8;
381     return imm;
382     }
383    
384    
385     static uint32_t read_imm_and_print(unsigned char **instrp, uint64_t *ilenp,
386     int mode)
387     {
388     return read_imm_common(instrp, ilenp, mode, 1);
389     }
390    
391    
392 dpavlin 22 uint32_t read_imm(unsigned char **instrp, uint64_t *newpcp,
393 dpavlin 14 int mode)
394     {
395     return read_imm_common(instrp, newpcp, mode, 0);
396     }
397    
398    
399 dpavlin 22 void print_csip(struct cpu *cpu)
400 dpavlin 14 {
401     fatal("0x%04x:", cpu->cd.x86.s[X86_S_CS]);
402     if (PROTECTED_MODE)
403     fatal("0x%llx", (long long)cpu->pc);
404     else
405     fatal("0x%04x", (int)cpu->pc);
406     }
407    
408    
409     /*
410 dpavlin 24 * x86_cpu_tlbdump():
411     *
412     * Called from the debugger to dump the TLB in a readable format.
413     * x is the cpu number to dump, or -1 to dump all CPUs.
414     *
415     * If rawflag is nonzero, then the TLB contents isn't formated nicely,
416     * just dumped.
417     */
418     void x86_cpu_tlbdump(struct machine *m, int x, int rawflag)
419     {
420     }
421    
422    
423     /*
424     * x86_cpu_gdb_stub():
425     *
426     * Execute a "remote GDB" command. Returns a newly allocated response string
427     * on success, NULL on failure.
428     */
429     char *x86_cpu_gdb_stub(struct cpu *cpu, char *cmd)
430     {
431     fatal("x86_cpu_gdb_stub(): TODO\n");
432     return NULL;
433     }
434    
435    
436     /*
437 dpavlin 14 * x86_cpu_interrupt():
438     *
439     * NOTE: Interacting with the 8259 PIC is done in src/machine.c.
440     */
441     int x86_cpu_interrupt(struct cpu *cpu, uint64_t nr)
442     {
443     if (cpu->machine->md_interrupt != NULL)
444     cpu->machine->md_interrupt(cpu->machine, cpu, nr, 1);
445     else {
446     fatal("x86_cpu_interrupt(): no md_interrupt()?\n");
447     return 1;
448     }
449    
450     return 1;
451     }
452    
453    
454     /*
455     * x86_cpu_interrupt_ack():
456     *
457     * NOTE: Interacting with the 8259 PIC is done in src/machine.c.
458     */
459     int x86_cpu_interrupt_ack(struct cpu *cpu, uint64_t nr)
460     {
461     if (cpu->machine->md_interrupt != NULL)
462     cpu->machine->md_interrupt(cpu->machine, cpu, nr, 0);
463     else {
464     fatal("x86_cpu_interrupt(): no md_interrupt()?\n");
465     return 1;
466     }
467    
468     return 1;
469     }
470    
471    
472     /* (NOTE: Don't use the lowest 3 bits in these defines) */
473     #define RELOAD_TR 0x1000
474     #define RELOAD_LDTR 0x1008
475    
476    
477     /*
478     * x86_task_switch():
479     *
480     * Save away current state into the current task state segment, and
481     * load the new state from the new task.
482     *
483     * TODO: 16-bit TSS, etc. And clean up all of this :)
484     *
485     * TODO: Link word. AMD64 stuff. And lots more.
486     */
487     void x86_task_switch(struct cpu *cpu, int new_tr, uint64_t *curpc)
488     {
489     unsigned char old_descr[8];
490     unsigned char new_descr[8];
491     uint32_t value, ofs;
492     int i;
493     unsigned char buf[4];
494    
495     fatal("x86_task_switch():\n");
496     cpu->pc = *curpc;
497    
498     if (!cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.gdtr + cpu->cd.x86.tr,
499     old_descr, sizeof(old_descr), MEM_READ, NO_SEGMENTATION)) {
500     fatal("x86_task_switch(): TODO: 1\n");
501     cpu->running = 0;
502     return;
503     }
504    
505     /* Check the busy bit, and then clear it: */
506     if (!(old_descr[5] & 0x02)) {
507     fatal("x86_task_switch(): TODO: switching FROM a non-BUSY"
508     " TSS descriptor?\n");
509     cpu->running = 0;
510     return;
511     }
512     old_descr[5] &= ~0x02;
513     if (!cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.gdtr + cpu->cd.x86.tr,
514     old_descr, sizeof(old_descr), MEM_WRITE, NO_SEGMENTATION)) {
515     fatal("x86_task_switch(): TODO: could not clear busy bit\n");
516     cpu->running = 0;
517     return;
518     }
519    
520     x86_cpu_register_dump(cpu, 1, 1);
521    
522     /* Set the task-switched bit in CR0: */
523     cpu->cd.x86.cr[0] |= X86_CR0_TS;
524    
525     /* Save away all the old registers: */
526     #define WRITE_VALUE { buf[0]=value; buf[1]=value>>8; buf[2]=value>>16; \
527     buf[3]=value>>24; cpu->memory_rw(cpu, cpu->mem, \
528     cpu->cd.x86.tr_base + ofs, buf, sizeof(buf), MEM_WRITE, \
529     NO_SEGMENTATION); }
530    
531     ofs = 0x1c; value = cpu->cd.x86.cr[3]; WRITE_VALUE;
532     ofs = 0x20; value = cpu->pc; WRITE_VALUE;
533     ofs = 0x24; value = cpu->cd.x86.rflags; WRITE_VALUE;
534     for (i=0; i<N_X86_REGS; i++) {
535     ofs = 0x28+i*4; value = cpu->cd.x86.r[i]; WRITE_VALUE;
536     }
537     for (i=0; i<6; i++) {
538     ofs = 0x48+i*4; value = cpu->cd.x86.s[i]; WRITE_VALUE;
539     }
540    
541     fatal("-------\n");
542    
543     if ((cpu->cd.x86.tr & 0xfffc) == 0) {
544     fatal("TODO: x86_task_switch(): task switch, but old TR"
545     " was 0?\n");
546     cpu->running = 0;
547     return;
548     }
549    
550     if (!cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.gdtr + new_tr,
551     new_descr, sizeof(new_descr), MEM_READ, NO_SEGMENTATION)) {
552     fatal("x86_task_switch(): TODO: 1\n");
553     cpu->running = 0;
554     return;
555     }
556     if (new_descr[5] & 0x02) {
557     fatal("x86_task_switch(): TODO: switching TO an already BUSY"
558     " TSS descriptor?\n");
559     cpu->running = 0;
560     return;
561     }
562    
563     reload_segment_descriptor(cpu, RELOAD_TR, new_tr, NULL);
564    
565     if (cpu->cd.x86.tr_limit < 0x67)
566 dpavlin 24 fatal("WARNING: tr_limit = 0x%"PRIx16", must be at least "
567     "0x67!\n", (uint16_t)cpu->cd.x86.tr_limit);
568 dpavlin 14
569     /* Read new registers: */
570     #define READ_VALUE { cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.tr_base + \
571     ofs, buf, sizeof(buf), MEM_READ, NO_SEGMENTATION); \
572     value = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24); }
573    
574     ofs = 0x1c; READ_VALUE; cpu->cd.x86.cr[3] = value;
575     ofs = 0x20; READ_VALUE; cpu->pc = value;
576     ofs = 0x24; READ_VALUE; cpu->cd.x86.rflags = value;
577     for (i=0; i<N_X86_REGS; i++) {
578     ofs = 0x28+i*4; READ_VALUE; cpu->cd.x86.r[i] = value;
579     }
580     for (i=0; i<6; i++) {
581     ofs = 0x48+i*4; READ_VALUE;
582     reload_segment_descriptor(cpu, i, value, NULL);
583     }
584     ofs = 0x60; READ_VALUE; value &= 0xffff;
585     reload_segment_descriptor(cpu, RELOAD_LDTR, value, NULL);
586    
587     if ((cpu->cd.x86.s[X86_S_CS] & X86_PL_MASK) !=
588     (cpu->cd.x86.s[X86_S_SS] & X86_PL_MASK))
589     fatal("WARNING: rpl in CS and SS differ!\n");
590    
591     if ((cpu->cd.x86.s[X86_S_CS] & X86_PL_MASK) == X86_RING3 &&
592     !(cpu->cd.x86.rflags & X86_FLAGS_IF))
593     fatal("WARNING (?): switching to userland task, but interrupts"
594     " are disabled?\n");
595    
596     x86_cpu_register_dump(cpu, 1, 1);
597     fatal("-------\n");
598    
599     *curpc = cpu->pc;
600    
601     /* cpu->machine->instruction_trace = 1; */
602     /* cpu->running = 0; */
603     }
604    
605    
606     /*
607     * reload_segment_descriptor():
608     *
609     * Loads base, limit and other settings from the Global Descriptor Table into
610     * segment descriptors.
611     *
612     * This function can also be used to reload the TR (task register).
613     *
614     * And also to do a task switch, or jump into a trap handler etc.
615     * (Perhaps this function should be renamed.)
616     */
617     void reload_segment_descriptor(struct cpu *cpu, int segnr, int selector,
618     uint64_t *curpcp)
619     {
620     int res, i, readable, writable, granularity, descr_type;
621     int segment = 1, rpl, orig_selector = selector;
622     unsigned char descr[8];
623     char *table_name = "GDT";
624 dpavlin 22 uint64_t base, limit, table_base;
625     int64_t table_limit;
626 dpavlin 14
627     if (segnr > 0x100) /* arbitrary, larger than N_X86_SEGS */
628     segment = 0;
629    
630     if (segment && (segnr < 0 || segnr >= N_X86_SEGS)) {
631     fatal("reload_segment_descriptor(): segnr = %i\n", segnr);
632     exit(1);
633     }
634    
635     if (segment && REAL_MODE) {
636     /* Real mode: */
637     cpu->cd.x86.descr_cache[segnr].valid = 1;
638     cpu->cd.x86.descr_cache[segnr].default_op_size = 16;
639     cpu->cd.x86.descr_cache[segnr].access_rights = 0x93;
640     cpu->cd.x86.descr_cache[segnr].descr_type =
641     segnr == X86_S_CS? DESCR_TYPE_CODE : DESCR_TYPE_DATA;
642     cpu->cd.x86.descr_cache[segnr].readable = 1;
643     cpu->cd.x86.descr_cache[segnr].writable = 1;
644     cpu->cd.x86.descr_cache[segnr].granularity = 0;
645     cpu->cd.x86.descr_cache[segnr].base = selector << 4;
646     cpu->cd.x86.descr_cache[segnr].limit = 0xffff;
647     cpu->cd.x86.s[segnr] = selector;
648     return;
649     }
650    
651     /*
652     * Protected mode: Load the descriptor cache from the GDT.
653     */
654    
655     table_base = cpu->cd.x86.gdtr;
656     table_limit = cpu->cd.x86.gdtr_limit;
657     if (selector & 4) {
658     table_name = "LDT";
659     /* fatal("TODO: x86 translation via LDT: 0x%04x\n",
660     selector); */
661     table_base = cpu->cd.x86.ldtr_base;
662     table_limit = cpu->cd.x86.ldtr_limit;
663     }
664    
665     /* Special case: Null-descriptor: */
666     if (segment && (selector & ~3) == 0) {
667     cpu->cd.x86.descr_cache[segnr].valid = 0;
668     cpu->cd.x86.s[segnr] = selector;
669     return;
670     }
671    
672     rpl = selector & 3;
673    
674     /* TODO: check rpl */
675    
676     selector &= ~7;
677    
678     if (selector + 7 > table_limit) {
679     fatal("TODO: selector 0x%04x outside %s limit (0x%04x)\n",
680     selector, table_name, (int)table_limit);
681     cpu->running = 0;
682     return;
683     }
684    
685     res = cpu->memory_rw(cpu, cpu->mem, table_base + selector,
686     descr, sizeof(descr), MEM_READ, NO_SEGMENTATION);
687     if (!res) {
688     fatal("reload_segment_descriptor(): TODO: "
689     "could not read the GDT\n");
690     cpu->running = 0;
691     return;
692     }
693    
694     base = descr[2] + (descr[3] << 8) + (descr[4] << 16) +
695     (descr[7] << 24);
696     limit = descr[0] + (descr[1] << 8) + ((descr[6]&15) << 16);
697    
698     descr_type = readable = writable = granularity = 0;
699     granularity = (descr[6] & 0x80)? 1 : 0;
700     if (limit == 0) {
701     fatal("WARNING: descriptor limit = 0\n");
702     limit = 0xfffff;
703     }
704     if (granularity)
705     limit = (limit << 12) | 0xfff;
706    
707     #if 0
708     printf("base = %llx\n",(long long)base);
709     for (i=0; i<8; i++)
710     fatal(" %02x", descr[i]);
711     #endif
712    
713     if (selector != 0x0000 && (descr[5] & 0x80) == 0x00) {
714     fatal("TODO: nonpresent descriptor?\n");
715     goto fail_dump;
716     }
717    
718     if (!segment) {
719     switch (segnr) {
720     case RELOAD_TR:
721     /* Check that this is indeed a TSS descriptor: */
722     if ((descr[5] & 0x15) != 0x01) {
723     fatal("TODO: load TR but entry in table is"
724     " not a TSS descriptor?\n");
725     goto fail_dump;
726     }
727    
728     /* Reload the task register: */
729     cpu->cd.x86.tr = selector;
730     cpu->cd.x86.tr_base = base;
731     cpu->cd.x86.tr_limit = limit;
732    
733     /* Mark the TSS as busy: */
734     descr[5] |= 0x02;
735     res = cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.gdtr +
736     selector, descr, sizeof(descr), MEM_WRITE,
737     NO_SEGMENTATION);
738     break;
739     case RELOAD_LDTR:
740     /* Reload the Local Descriptor Table register: */
741     cpu->cd.x86.ldtr = selector;
742     cpu->cd.x86.ldtr_base = base;
743     cpu->cd.x86.ldtr_limit = limit;
744     break;
745     }
746     return;
747     }
748    
749     if ((descr[5] & 0x18) == 0x18) {
750     descr_type = DESCR_TYPE_CODE;
751     readable = descr[5] & 0x02? 1 : 0;
752     if ((descr[5] & 0x98) != 0x98) {
753     fatal("TODO CODE\n");
754     goto fail_dump;
755     }
756     } else if ((descr[5] & 0x18) == 0x10) {
757     descr_type = DESCR_TYPE_DATA;
758     readable = 1;
759     writable = descr[5] & 0x02? 1 : 0;
760     if ((descr[5] & 0x98) != 0x90) {
761     fatal("TODO DATA\n");
762     goto fail_dump;
763     }
764     } else if (segnr == X86_S_CS && (descr[5] & 0x15) == 0x01
765     && curpcp != NULL) {
766     /* TSS */
767     x86_task_switch(cpu, selector, curpcp);
768     return;
769     } else {
770     fatal("TODO: other\n");
771     goto fail_dump;
772     }
773    
774     cpu->cd.x86.descr_cache[segnr].valid = 1;
775     cpu->cd.x86.descr_cache[segnr].default_op_size =
776     (descr[6] & 0x40)? 32 : 16;
777     cpu->cd.x86.descr_cache[segnr].access_rights = descr[5];
778     cpu->cd.x86.descr_cache[segnr].descr_type = descr_type;
779     cpu->cd.x86.descr_cache[segnr].readable = readable;
780     cpu->cd.x86.descr_cache[segnr].writable = writable;
781     cpu->cd.x86.descr_cache[segnr].granularity = granularity;
782     cpu->cd.x86.descr_cache[segnr].base = base;
783     cpu->cd.x86.descr_cache[segnr].limit = limit;
784     cpu->cd.x86.s[segnr] = orig_selector;
785     return;
786    
787     fail_dump:
788     for (i=0; i<8; i++)
789     fatal(" %02x", descr[i]);
790     cpu->running = 0;
791     }
792    
793    
794     /*
795     * x86_load():
796     *
797     * Returns same error code as memory_rw().
798     */
799     static int x86_load(struct cpu *cpu, uint64_t addr, uint64_t *data, int len)
800     {
801     unsigned char databuf[8];
802     int res;
803     uint64_t d;
804    
805     res = cpu->memory_rw(cpu, cpu->mem, addr, &databuf[0], len,
806     MEM_READ, CACHE_DATA);
807    
808     d = databuf[0];
809     if (len > 1) {
810     d += ((uint64_t)databuf[1] << 8);
811     if (len > 2) {
812     d += ((uint64_t)databuf[2] << 16);
813     d += ((uint64_t)databuf[3] << 24);
814     if (len > 4) {
815     d += ((uint64_t)databuf[4] << 32);
816     d += ((uint64_t)databuf[5] << 40);
817     d += ((uint64_t)databuf[6] << 48);
818     d += ((uint64_t)databuf[7] << 56);
819     }
820     }
821     }
822    
823     *data = d;
824     return res;
825     }
826    
827    
828     /*
829     * x86_store():
830     *
831     * Returns same error code as memory_rw().
832     */
833     static int x86_store(struct cpu *cpu, uint64_t addr, uint64_t data, int len)
834     {
835     unsigned char databuf[8];
836    
837     /* x86 is always little-endian: */
838     databuf[0] = data;
839     if (len > 1) {
840     databuf[1] = data >> 8;
841     if (len > 2) {
842     databuf[2] = data >> 16;
843     databuf[3] = data >> 24;
844     if (len > 4) {
845     databuf[4] = data >> 32;
846     databuf[5] = data >> 40;
847     databuf[6] = data >> 48;
848     databuf[7] = data >> 56;
849     }
850     }
851     }
852    
853     return cpu->memory_rw(cpu, cpu->mem, addr, &databuf[0], len,
854     MEM_WRITE, CACHE_DATA);
855     }
856    
857    
858     /*
859     * x86_write_cr():
860     *
861     * Write to a control register.
862     */
863     static void x86_write_cr(struct cpu *cpu, int r, uint64_t value)
864     {
865     uint64_t new, tmp;
866    
867     switch (r) {
868     case 0: new = cpu->cd.x86.cr[r] = value;
869     /* Warn about unimplemented bits: */
870     tmp = new & ~(X86_CR0_PE | X86_CR0_PG);
871     if (cpu->cd.x86.model.model_number <= X86_MODEL_80386) {
872     if (tmp & X86_CR0_WP)
873     fatal("WARNING: cr0 WP bit set, but this is"
874     " not an 80486 or higher (?)\n");
875     }
876     tmp &= ~X86_CR0_WP;
877     if (tmp != 0)
878     fatal("x86_write_cr(): unimplemented cr0 bits: "
879     "0x%08llx\n", (long long)tmp);
880     break;
881     case 2:
882     case 3: new = cpu->cd.x86.cr[r] = value;
883     break;
884     case 4: new = cpu->cd.x86.cr[r] = value;
885     /* Warn about unimplemented bits: */
886     tmp = new; /* & ~(X86_CR0_PE | X86_CR0_PG); */
887     if (tmp != 0)
888     fatal("x86_write_cr(): unimplemented cr4 bits: "
889     "0x%08llx\n", (long long)tmp);
890     break;
891     default:fatal("x86_write_cr(): write to UNIMPLEMENTED cr%i\n", r);
892     cpu->running = 0;
893     }
894     }
895    
896    
897     static char *ofs_string(int32_t imm)
898     {
899     static char buf[25];
900     buf[0] = buf[sizeof(buf)-1] = '\0';
901    
902     if (imm > 32)
903     sprintf(buf, "+0x%x", imm);
904     else if (imm > 0)
905     sprintf(buf, "+%i", imm);
906     else if (imm < -32)
907     sprintf(buf, "-0x%x", -imm);
908     else if (imm < 0)
909     sprintf(buf, "-%i", -imm);
910    
911     return buf;
912     }
913    
914    
915     static char modrm_r[65];
916     static char modrm_rm[65];
917     #define MODRM_READ 0
918     #define MODRM_WRITE_RM 1
919     #define MODRM_WRITE_R 2
920     /* flags: */
921     #define MODRM_EIGHTBIT 1
922     #define MODRM_SEG 2
923     #define MODRM_JUST_GET_ADDR 4
924     #define MODRM_CR 8
925     #define MODRM_DR 16
926     #define MODRM_R_NONEIGHTBIT 32
927     #define MODRM_RM_16BIT 64
928    
929    
930     /*
931     * modrm():
932     *
933     * Yuck. I have a feeling that this function will become really ugly.
934     */
935     static int modrm(struct cpu *cpu, int writeflag, int mode, int mode67,
936     int flags, unsigned char **instrp, uint64_t *lenp,
937     uint64_t *op1p, uint64_t *op2p)
938     {
939     uint32_t imm, imm2;
940     uint64_t addr = 0;
941     int mod, r, rm, res = 1, z, q = mode/8, sib, s, i, b, immlen;
942     char *e, *f;
943     int disasm = (op1p == NULL);
944    
945     /* e for data, f for addresses */
946     e = f = "";
947    
948     if (disasm) {
949     if (mode == 32)
950     e = "e";
951     if (mode == 64)
952     e = "r";
953     if (mode67 == 32)
954     f = "e";
955     if (mode67 == 64)
956     f = "r";
957     modrm_rm[0] = modrm_rm[sizeof(modrm_rm)-1] = '\0';
958     modrm_r[0] = modrm_r[sizeof(modrm_r)-1] = '\0';
959     }
960    
961     immlen = mode67;
962     if (immlen == 64)
963     immlen = 32;
964    
965     imm = read_imm_common(instrp, lenp, 8, disasm);
966     mod = (imm >> 6) & 3; r = (imm >> 3) & 7; rm = imm & 7;
967    
968     if (flags & MODRM_EIGHTBIT)
969     q = 1;
970    
971     /*
972     * R/M:
973     */
974    
975     switch (mod) {
976     case 0:
977     if (disasm) {
978     if (mode67 >= 32) {
979     if (rm == 5) {
980     imm2 = read_imm_common(instrp, lenp,
981     immlen, disasm);
982     sprintf(modrm_rm, "[0x%x]", imm2);
983     } else if (rm == 4) {
984     char tmp[20];
985     sib = read_imm_common(instrp, lenp,
986     8, disasm);
987     s = 1 << (sib >> 6);
988     i = (sib >> 3) & 7;
989     b = sib & 7;
990     if (b == 5) { /* imm base */
991     imm2 = read_imm_common(instrp,
992     lenp, immlen, disasm);
993     sprintf(tmp, ofs_string(imm2));
994     } else
995     sprintf(tmp, "+%s%s", f,
996     reg_names[b]);
997     if (i == 4)
998     sprintf(modrm_rm, "[%s]", tmp);
999     else if (s == 1)
1000     sprintf(modrm_rm, "[%s%s%s]",
1001     f, reg_names[i], tmp);
1002     else
1003     sprintf(modrm_rm, "[%s%s*%i%s"
1004     "]", f, reg_names[i],
1005     s, tmp);
1006     } else {
1007     sprintf(modrm_rm, "[%s%s]", f,
1008     reg_names[rm]);
1009     }
1010     } else {
1011     switch (rm) {
1012     case 0: sprintf(modrm_rm, "[bx+si]");
1013     break;
1014     case 1: sprintf(modrm_rm, "[bx+di]");
1015     break;
1016     case 2: sprintf(modrm_rm, "[bp+si]");
1017     break;
1018     case 3: sprintf(modrm_rm, "[bp+di]");
1019     break;
1020     case 4: sprintf(modrm_rm, "[si]");
1021     break;
1022     case 5: sprintf(modrm_rm, "[di]");
1023     break;
1024     case 6: imm2 = read_imm_common(instrp, lenp,
1025     immlen, disasm);
1026     sprintf(modrm_rm, "[0x%x]", imm2);
1027     break;
1028     case 7: sprintf(modrm_rm, "[bx]");
1029     break;
1030     }
1031     }
1032     } else {
1033     if (mode67 >= 32) {
1034     if (rm == 5) {
1035     addr = read_imm_common(instrp, lenp,
1036     immlen, disasm);
1037     } else if (rm == 4) {
1038     sib = read_imm_common(instrp, lenp,
1039     8, disasm);
1040     s = 1 << (sib >> 6);
1041     i = (sib >> 3) & 7;
1042     b = sib & 7;
1043     if (b == 4 &&
1044     !cpu->cd.x86.seg_override)
1045     cpu->cd.x86.cursegment=X86_S_SS;
1046     if (b == 5)
1047     addr = read_imm_common(instrp,
1048     lenp, mode67, disasm);
1049     else
1050     addr = cpu->cd.x86.r[b];
1051     if (i != 4)
1052     addr += cpu->cd.x86.r[i] * s;
1053     } else {
1054     addr = cpu->cd.x86.r[rm];
1055     }
1056     } else {
1057     switch (rm) {
1058     case 0: addr = cpu->cd.x86.r[X86_R_BX] +
1059     cpu->cd.x86.r[X86_R_SI]; break;
1060     case 1: addr = cpu->cd.x86.r[X86_R_BX] +
1061     cpu->cd.x86.r[X86_R_DI]; break;
1062     case 2: addr = cpu->cd.x86.r[X86_R_BP] +
1063     cpu->cd.x86.r[X86_R_SI];
1064     if (!cpu->cd.x86.seg_override)
1065     cpu->cd.x86.cursegment=X86_S_SS;
1066     break;
1067     case 3: addr = cpu->cd.x86.r[X86_R_BP] +
1068     cpu->cd.x86.r[X86_R_DI];
1069     if (!cpu->cd.x86.seg_override)
1070     cpu->cd.x86.cursegment=X86_S_SS;
1071     break;
1072     case 4: addr = cpu->cd.x86.r[X86_R_SI]; break;
1073     case 5: addr = cpu->cd.x86.r[X86_R_DI]; break;
1074     case 6: addr = read_imm_common(instrp, lenp,
1075     immlen, disasm); break;
1076     case 7: addr = cpu->cd.x86.r[X86_R_BX]; break;
1077     }
1078     }
1079    
1080     if (mode67 == 16)
1081     addr &= 0xffff;
1082     if (mode67 == 32)
1083     addr &= 0xffffffffULL;
1084    
1085     switch (writeflag) {
1086     case MODRM_WRITE_RM:
1087     res = x86_store(cpu, addr, *op1p, q);
1088     break;
1089     case MODRM_READ: /* read */
1090     if (flags & MODRM_JUST_GET_ADDR)
1091     *op1p = addr;
1092     else
1093     res = x86_load(cpu, addr, op1p, q);
1094     }
1095     }
1096     break;
1097     case 1:
1098     case 2:
1099     z = (mod == 1)? 8 : immlen;
1100     if (disasm) {
1101     if (mode67 >= 32) {
1102     if (rm == 4) {
1103     sib = read_imm_common(instrp, lenp,
1104     8, disasm);
1105     s = 1 << (sib >> 6);
1106     i = (sib >> 3) & 7;
1107     b = sib & 7;
1108     imm2 = read_imm_common(instrp, lenp,
1109     z, disasm);
1110     if (z == 8) imm2 = (signed char)imm2;
1111     if (i == 4)
1112     sprintf(modrm_rm, "[%s%s%s]",
1113     f, reg_names[b],
1114     ofs_string(imm2));
1115     else if (s == 1)
1116     sprintf(modrm_rm, "[%s%s%s"
1117     "%s%s]", f, reg_names[i],
1118     f, reg_names[b],
1119     ofs_string(imm2));
1120     else
1121     sprintf(modrm_rm, "[%s%s*%i+%s"
1122     "%s%s]", f, reg_names[i], s,
1123     f, reg_names[b],
1124     ofs_string(imm2));
1125     } else {
1126     imm2 = read_imm_common(instrp, lenp,
1127     z, disasm);
1128     if (z == 8) imm2 = (signed char)imm2;
1129     sprintf(modrm_rm, "[%s%s%s]", f,
1130     reg_names[rm], ofs_string(imm2));
1131     }
1132     } else
1133     switch (rm) {
1134     case 0: imm2 = read_imm_common(instrp, lenp, z, disasm);
1135     if (z == 8) imm2 = (signed char)imm2;
1136     sprintf(modrm_rm, "[bx+si%s]",ofs_string(imm2));
1137     break;
1138     case 1: imm2 = read_imm_common(instrp, lenp, z, disasm);
1139     if (z == 8) imm2 = (signed char)imm2;
1140     sprintf(modrm_rm, "[bx+di%s]",ofs_string(imm2));
1141     break;
1142     case 2: imm2 = read_imm_common(instrp, lenp, z, disasm);
1143     if (z == 8) imm2 = (signed char)imm2;
1144     sprintf(modrm_rm, "[bp+si%s]",ofs_string(imm2));
1145     break;
1146     case 3: imm2 = read_imm_common(instrp, lenp, z, disasm);
1147     if (z == 8) imm2 = (signed char)imm2;
1148     sprintf(modrm_rm, "[bp+di%s]",ofs_string(imm2));
1149     break;
1150     case 4: imm2 = read_imm_common(instrp, lenp, z, disasm);
1151     if (z == 8) imm2 = (signed char)imm2;
1152     sprintf(modrm_rm, "[si%s]", ofs_string(imm2));
1153     break;
1154     case 5: imm2 = read_imm_common(instrp, lenp, z, disasm);
1155     if (z == 8) imm2 = (signed char)imm2;
1156     sprintf(modrm_rm, "[di%s]", ofs_string(imm2));
1157     break;
1158     case 6: imm2 = read_imm_common(instrp, lenp, z, disasm);
1159     if (z == 8) imm2 = (signed char)imm2;
1160     sprintf(modrm_rm, "[bp%s]", ofs_string(imm2));
1161     break;
1162     case 7: imm2 = read_imm_common(instrp, lenp, z, disasm);
1163     if (z == 8) imm2 = (signed char)imm2;
1164     sprintf(modrm_rm, "[bx%s]", ofs_string(imm2));
1165     break;
1166     }
1167     } else {
1168     if (mode67 >= 32) {
1169     if (rm == 4) {
1170     sib = read_imm_common(instrp, lenp,
1171     8, disasm);
1172     s = 1 << (sib >> 6);
1173     i = (sib >> 3) & 7;
1174     b = sib & 7;
1175     addr = read_imm_common(instrp, lenp,
1176     z, disasm);
1177     if ((b == 4 || b == 5) &&
1178     !cpu->cd.x86.seg_override)
1179     cpu->cd.x86.cursegment=X86_S_SS;
1180     if (z == 8)
1181     addr = (signed char)addr;
1182     if (i == 4)
1183     addr = cpu->cd.x86.r[b] + addr;
1184     else
1185     addr = cpu->cd.x86.r[i] * s +
1186     cpu->cd.x86.r[b] + addr;
1187     } else {
1188     addr = read_imm_common(instrp, lenp,
1189     z, disasm);
1190     if (z == 8)
1191     addr = (signed char)addr;
1192     addr = cpu->cd.x86.r[rm] + addr;
1193     }
1194     } else {
1195     addr = read_imm_common(instrp, lenp, z, disasm);
1196     if (z == 8)
1197     addr = (signed char)addr;
1198     switch (rm) {
1199     case 0: addr += cpu->cd.x86.r[X86_R_BX]
1200     + cpu->cd.x86.r[X86_R_SI];
1201     break;
1202     case 1: addr += cpu->cd.x86.r[X86_R_BX]
1203     + cpu->cd.x86.r[X86_R_DI];
1204     break;
1205     case 2: addr += cpu->cd.x86.r[X86_R_BP]
1206     + cpu->cd.x86.r[X86_R_SI];
1207     if (!cpu->cd.x86.seg_override)
1208     cpu->cd.x86.cursegment=X86_S_SS;
1209     break;
1210     case 3: addr += cpu->cd.x86.r[X86_R_BP]
1211     + cpu->cd.x86.r[X86_R_DI];
1212     if (!cpu->cd.x86.seg_override)
1213     cpu->cd.x86.cursegment=X86_S_SS;
1214     break;
1215     case 4: addr += cpu->cd.x86.r[X86_R_SI];
1216     break;
1217     case 5: addr += cpu->cd.x86.r[X86_R_DI];
1218     break;
1219     case 6: addr += cpu->cd.x86.r[X86_R_BP];
1220     if (!cpu->cd.x86.seg_override)
1221     cpu->cd.x86.cursegment=X86_S_SS;
1222     break;
1223     case 7: addr += cpu->cd.x86.r[X86_R_BX];
1224     break;
1225     }
1226     }
1227    
1228     if (mode67 == 16)
1229     addr &= 0xffff;
1230     if (mode67 == 32)
1231     addr &= 0xffffffffULL;
1232    
1233     switch (writeflag) {
1234     case MODRM_WRITE_RM:
1235     res = x86_store(cpu, addr, *op1p, q);
1236     break;
1237     case MODRM_READ: /* read */
1238     if (flags & MODRM_JUST_GET_ADDR)
1239     *op1p = addr;
1240     else
1241     res = x86_load(cpu, addr, op1p, q);
1242     }
1243     }
1244     break;
1245     case 3:
1246     if (flags & MODRM_EIGHTBIT) {
1247     if (disasm) {
1248     strlcpy(modrm_rm, reg_names_bytes[rm],
1249     sizeof(modrm_rm));
1250     } else {
1251     switch (writeflag) {
1252     case MODRM_WRITE_RM:
1253     if (rm < 4)
1254     cpu->cd.x86.r[rm] =
1255     (cpu->cd.x86.r[rm] &
1256     ~0xff) | (*op1p & 0xff);
1257     else
1258     cpu->cd.x86.r[rm&3] = (cpu->
1259     cd.x86.r[rm&3] & ~0xff00) |
1260     ((*op1p & 0xff) << 8);
1261     break;
1262     case MODRM_READ:
1263     if (rm < 4)
1264     *op1p = cpu->cd.x86.r[rm] &
1265     0xff;
1266     else
1267     *op1p = (cpu->cd.x86.r[rm&3] &
1268     0xff00) >> 8;
1269     }
1270     }
1271     } else {
1272     if (disasm) {
1273     if (mode == 16 || flags & MODRM_RM_16BIT)
1274     strlcpy(modrm_rm, reg_names[rm],
1275     sizeof(modrm_rm));
1276     else
1277     sprintf(modrm_rm, "%s%s", e,
1278     reg_names[rm]);
1279     } else {
1280     switch (writeflag) {
1281     case MODRM_WRITE_RM:
1282     if (mode == 16 ||
1283     flags & MODRM_RM_16BIT)
1284     cpu->cd.x86.r[rm] = (
1285     cpu->cd.x86.r[rm] & ~0xffff)
1286     | (*op1p & 0xffff);
1287     else
1288     cpu->cd.x86.r[rm] =
1289     modify(cpu->cd.x86.r[rm],
1290     *op1p);
1291     break;
1292     case MODRM_READ: /* read */
1293     if (mode == 16 ||
1294     flags & MODRM_RM_16BIT)
1295     *op1p = cpu->cd.x86.r[rm]
1296     & 0xffff;
1297     else
1298     *op1p = cpu->cd.x86.r[rm];
1299     }
1300     }
1301     }
1302     break;
1303     default:
1304     fatal("modrm(): unimplemented mod %i\n", mod);
1305     exit(1);
1306     }
1307    
1308    
1309     /*
1310     * R:
1311     */
1312    
1313     if (flags & MODRM_EIGHTBIT && !(flags & MODRM_R_NONEIGHTBIT)) {
1314     if (disasm) {
1315     strlcpy(modrm_r, reg_names_bytes[r],
1316     sizeof(modrm_r));
1317     } else {
1318     switch (writeflag) {
1319     case MODRM_WRITE_R:
1320     if (r < 4)
1321     cpu->cd.x86.r[r] = (cpu->cd.x86.r[r] &
1322     ~0xff) | (*op2p & 0xff);
1323     else
1324     cpu->cd.x86.r[r&3] = (cpu->cd.x86.r[r&3]
1325     & ~0xff00) | ((*op2p & 0xff) << 8);
1326     break;
1327     case MODRM_READ:
1328     if (r < 4)
1329     *op2p = cpu->cd.x86.r[r] & 0xff;
1330     else
1331     *op2p = (cpu->cd.x86.r[r&3] &
1332     0xff00) >>8;
1333     }
1334     }
1335     } else {
1336     if (disasm) {
1337     if (flags & MODRM_SEG)
1338     strlcpy(modrm_r, seg_names[r],
1339     sizeof(modrm_r));
1340     else if (flags & MODRM_CR)
1341     sprintf(modrm_r, "cr%i", r);
1342     else if (flags & MODRM_DR)
1343     sprintf(modrm_r, "dr%i", r);
1344     else {
1345     if (mode >= 32)
1346     sprintf(modrm_r, "%s%s", e,
1347     reg_names[r]);
1348     else
1349     strlcpy(modrm_r, reg_names[r],
1350     sizeof(modrm_r));
1351     }
1352     } else {
1353     switch (writeflag) {
1354     case MODRM_WRITE_R:
1355     if (flags & MODRM_SEG)
1356     cpu->cd.x86.s[r] = *op2p;
1357     else if (flags & MODRM_CR)
1358     x86_write_cr(cpu, r, *op2p);
1359     else if (flags & MODRM_DR)
1360     cpu->cd.x86.dr[r] = *op2p;
1361     else
1362     cpu->cd.x86.r[r] =
1363     modify(cpu->cd.x86.r[r], *op2p);
1364     break;
1365     case MODRM_READ:
1366     if (flags & MODRM_SEG)
1367     *op2p = cpu->cd.x86.s[r];
1368     else if (flags & MODRM_CR)
1369     *op2p = cpu->cd.x86.cr[r];
1370     else if (flags & MODRM_DR)
1371     *op2p = cpu->cd.x86.dr[r];
1372     else
1373     *op2p = cpu->cd.x86.r[r];
1374     }
1375     }
1376     }
1377    
1378     if (!disasm) {
1379     switch (mode) {
1380     case 16:*op1p &= 0xffff; *op2p &= 0xffff; break;
1381     case 32:*op1p &= 0xffffffffULL; *op2p &= 0xffffffffULL; break;
1382     }
1383     }
1384    
1385     return res;
1386     }
1387    
1388    
1389     /*
1390     * x86_cpu_disassemble_instr():
1391     *
1392     * Convert an instruction word into human readable format, for instruction
1393     * tracing.
1394     *
1395     * If running&1 is 1, cpu->pc should be the address of the instruction.
1396     *
1397     * If running&1 is 0, things that depend on the runtime environment (eg.
1398     * register contents) will not be shown, and addr will be used instead of
1399     * cpu->pc for relative addresses.
1400     *
1401     * The rest of running tells us the default (code) operand size.
1402     */
1403     int x86_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr,
1404 dpavlin 24 int running, uint64_t dumpaddr)
1405 dpavlin 14 {
1406     int op, rep = 0, lock = 0, n_prefix_bytes = 0;
1407     uint64_t ilen = 0, offset;
1408     uint32_t imm=0, imm2;
1409     int mode = running & ~1;
1410     int mode67;
1411     char *symbol, *mnem = "ERROR", *e = "e", *prefix = NULL;
1412    
1413     if (running)
1414     dumpaddr = cpu->pc;
1415    
1416     if (mode == 0) {
1417     mode = cpu->cd.x86.descr_cache[X86_S_CS].default_op_size;
1418     if (mode == 0) {
1419     fatal("x86_cpu_disassemble_instr(): no mode: TODO\n");
1420     return 1;
1421     }
1422     }
1423    
1424     mode67 = mode;
1425    
1426     symbol = get_symbol_name(&cpu->machine->symbol_context,
1427     dumpaddr, &offset);
1428     if (symbol != NULL && offset==0)
1429     debug("<%s>\n", symbol);
1430    
1431     if (cpu->machine->ncpus > 1 && running)
1432     debug("cpu%i: ", cpu->cpu_id);
1433    
1434     if (mode == 32)
1435     debug("%08x: ", (int)dumpaddr);
1436     else if (mode == 64)
1437     debug("%016llx: ", (long long)dumpaddr);
1438     else { /* 16-bit mode */
1439     debug("%04x:%04x ", cpu->cd.x86.s[X86_S_CS],
1440     (int)dumpaddr & 0xffff);
1441     }
1442    
1443     /*
1444     * Decode the instruction:
1445     */
1446    
1447     /* All instructions are at least 1 byte long: */
1448     HEXPRINT(instr,1);
1449     ilen = 1;
1450    
1451     /* Any prefix? */
1452     for (;;) {
1453     if (instr[0] == 0x66) {
1454     if (mode == 16)
1455     mode = 32;
1456     else
1457     mode = 16;
1458     } else if (instr[0] == 0x67) {
1459     if (mode67 == 16)
1460     mode67 = 32;
1461     else
1462     mode67 = 16;
1463     } else if (instr[0] == 0xf2) {
1464     rep = REP_REPNE;
1465     } else if (instr[0] == 0xf3) {
1466     rep = REP_REP;
1467     } else if (instr[0] == 0x26) {
1468     prefix = "es:";
1469     } else if (instr[0] == 0x2e) {
1470     prefix = "cs:";
1471     } else if (instr[0] == 0x36) {
1472     prefix = "ss:";
1473     } else if (instr[0] == 0x3e) {
1474     prefix = "ds:";
1475     } else if (instr[0] == 0x64) {
1476     prefix = "fs:";
1477     } else if (instr[0] == 0x65) {
1478     prefix = "gs:";
1479     } else if (instr[0] == 0xf0) {
1480     lock = 1;
1481     } else
1482     break;
1483    
1484     if (++n_prefix_bytes > 4) {
1485     SPACES; debug("more than 4 prefix bytes?\n");
1486     return 4;
1487     }
1488    
1489     /* TODO: lock, segment overrides etc */
1490     instr ++; ilen ++;
1491     debug("%02x", instr[0]);
1492     }
1493    
1494     if (mode == 16)
1495     e = "";
1496    
1497     op = instr[0];
1498     instr ++;
1499    
1500     if ((op & 0xf0) <= 0x30 && (op & 7) <= 5) {
1501     switch (op & 0x38) {
1502     case 0x00: mnem = "add"; break;
1503     case 0x08: mnem = "or"; break;
1504     case 0x10: mnem = "adc"; break;
1505     case 0x18: mnem = "sbb"; break;
1506     case 0x20: mnem = "and"; break;
1507     case 0x28: mnem = "sub"; break;
1508     case 0x30: mnem = "xor"; break;
1509     case 0x38: mnem = "cmp"; break;
1510     }
1511     switch (op & 7) {
1512     case 4: imm = read_imm_and_print(&instr, &ilen, 8);
1513     SPACES; debug("%s\tal,0x%02x", mnem, imm);
1514     break;
1515     case 5: imm = read_imm_and_print(&instr, &ilen, mode);
1516     SPACES; debug("%s\t%sax,0x%x", mnem, e, imm);
1517     break;
1518     default:modrm(cpu, MODRM_READ, mode, mode67, op&1? 0 :
1519     MODRM_EIGHTBIT, &instr, &ilen, NULL, NULL);
1520     SPACES; debug("%s\t", mnem);
1521     if (op & 2)
1522     debug("%s,%s", modrm_r, modrm_rm);
1523     else
1524     debug("%s,%s", modrm_rm, modrm_r);
1525     }
1526     } else if (op == 0xf) {
1527     /* "pop cs" on 8086 */
1528     if (cpu->cd.x86.model.model_number == X86_MODEL_8086) {
1529     SPACES; debug("pop\tcs");
1530     } else {
1531     imm = read_imm_and_print(&instr, &ilen, 8);
1532     if (imm == 0x00) {
1533     int subop = (*instr >> 3) & 0x7;
1534     switch (subop) {
1535     case 0: modrm(cpu, MODRM_READ, mode, mode67,
1536     0, &instr, &ilen, NULL, NULL);
1537     SPACES; debug("sldt\t%s", modrm_rm);
1538     break;
1539     case 1: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1540     mode67, 0, &instr, &ilen,
1541     NULL, NULL);
1542     SPACES; debug("str\t%s", modrm_rm);
1543     break;
1544     case 2: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1545     mode67, 0, &instr, &ilen,
1546     NULL, NULL);
1547     SPACES; debug("lldt\t%s", modrm_rm);
1548     break;
1549     case 3: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1550     mode67, 0, &instr, &ilen,
1551     NULL, NULL);
1552     SPACES; debug("ltr\t%s", modrm_rm);
1553     break;
1554     case 4: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1555     mode67, 0, &instr, &ilen,
1556     NULL, NULL);
1557     SPACES; debug("verr\t%s", modrm_rm);
1558     break;
1559     case 5: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1560     mode67, 0, &instr, &ilen,
1561     NULL, NULL);
1562     SPACES; debug("verw\t%s", modrm_rm);
1563     break;
1564     default:SPACES; debug("UNIMPLEMENTED 0x%02x,0x"
1565     "%02x,0x%02x", op, imm, *instr);
1566     }
1567     } else if (imm == 0x01) {
1568     int subop = (*instr >> 3) & 0x7;
1569     switch (subop) {
1570     case 0:
1571     case 1:
1572     case 2:
1573     case 3: modrm(cpu, MODRM_READ, mode, mode67,
1574     0, &instr, &ilen, NULL, NULL);
1575     SPACES; debug("%s%s\t%s",
1576     subop < 2? "s" : "l",
1577     subop&1? "idt" : "gdt", modrm_rm);
1578     break;
1579     case 4:
1580     case 6: if (((*instr >> 3) & 0x7) == 4)
1581     mnem = "smsw";
1582     else
1583     mnem = "lmsw";
1584     modrm(cpu, MODRM_READ, 16, mode67,
1585     0, &instr, &ilen, NULL, NULL);
1586     SPACES; debug("%s\t%s", mnem, modrm_rm);
1587     break;
1588     case 7: modrm(cpu, MODRM_READ, mode,
1589     mode67, 0, &instr, &ilen,
1590     NULL, NULL);
1591     SPACES; debug("invlpg\t%s", modrm_rm);
1592     break;
1593     default:SPACES; debug("UNIMPLEMENTED 0x%02x,0x"
1594     "%02x,0x%02x", op, imm, *instr);
1595     }
1596     } else if (imm == 0x02) {
1597     modrm(cpu, MODRM_READ, mode, mode67,
1598     0, &instr, &ilen, NULL, NULL);
1599     SPACES; debug("lar\t%s,%s", modrm_r, modrm_rm);
1600     } else if (imm == 0x03) {
1601     modrm(cpu, MODRM_READ, mode, mode67,
1602     0, &instr, &ilen, NULL, NULL);
1603     SPACES; debug("lsl\t%s,%s", modrm_r, modrm_rm);
1604     } else if (imm == 0x05) {
1605     SPACES; /* TODO: exactly which models?*/
1606     if (cpu->cd.x86.model.model_number >
1607     X86_MODEL_80486)
1608     debug("syscall");
1609     else
1610     debug("loadall286");
1611     } else if (imm == 0x06) {
1612     SPACES; debug("clts");
1613     } else if (imm == 0x07) {
1614     SPACES; /* TODO: exactly which models?*/
1615     if (cpu->cd.x86.model.model_number >
1616     X86_MODEL_80486)
1617     debug("sysret");
1618     else
1619     debug("loadall");
1620     } else if (imm == 0x08) {
1621     SPACES; debug("invd");
1622     } else if (imm == 0x09) {
1623     SPACES; debug("wbinvd");
1624     } else if (imm == 0x0b) {
1625     SPACES; debug("reserved_0b");
1626     } else if (imm == 0x20 || imm == 0x21) {
1627     modrm(cpu, MODRM_READ, 32 /* note: 32 */,
1628     mode67, imm == 0x20? MODRM_CR : MODRM_DR,
1629     &instr, &ilen, NULL, NULL);
1630     SPACES; debug("mov\t%s,%s", modrm_rm, modrm_r);
1631     } else if (imm == 0x22 || imm == 0x23) {
1632     modrm(cpu, MODRM_READ, 32 /* note: 32 */,
1633     mode67, imm == 0x22? MODRM_CR : MODRM_DR,
1634     &instr, &ilen, NULL, NULL);
1635     SPACES; debug("mov\t%s,%s", modrm_r, modrm_rm);
1636     } else if (imm == 0x30) {
1637     SPACES; debug("wrmsr");
1638     } else if (imm == 0x31) {
1639     SPACES; debug("rdtsc");
1640     } else if (imm == 0x32) {
1641     SPACES; debug("rdmsr");
1642     } else if (imm == 0x33) {
1643     SPACES; debug("rdpmc"); /* http://www
1644     .x86.org/secrets/opcodes/rdpmc.htm */
1645     } else if (imm == 0x34) {
1646     SPACES; debug("sysenter");
1647     } else if (imm == 0x36) {
1648     SPACES; debug("sysexit");
1649     } else if (imm >= 0x40 && imm <= 0x4f) {
1650     modrm(cpu, MODRM_READ, mode, mode67, 0,
1651     &instr, &ilen, NULL, NULL);
1652     op = imm & 0xf;
1653     SPACES; debug("cmov%s%s\t%s,%s", op&1? "n"
1654     : "", cond_names[(op/2) & 0x7],
1655     modrm_r, modrm_rm);
1656     } else if (imm >= 0x80 && imm <= 0x8f) {
1657     op = imm & 0xf;
1658     imm = read_imm_and_print(&instr, &ilen, mode);
1659     imm = dumpaddr + 2 + mode/8 + imm;
1660     SPACES; debug("j%s%s\tnear 0x%x", op&1? "n"
1661     : "", cond_names[(op/2) & 0x7], imm);
1662     } else if (imm >= 0x90 && imm <= 0x9f) {
1663     op = imm;
1664     modrm(cpu, MODRM_READ, mode,
1665     mode67, MODRM_EIGHTBIT, &instr, &ilen,
1666     NULL, NULL);
1667     SPACES; debug("set%s%s\t%s", op&1? "n"
1668     : "", cond_names[(op/2) & 0x7], modrm_rm);
1669     } else if (imm == 0xa0) {
1670     SPACES; debug("push\tfs");
1671     } else if (imm == 0xa1) {
1672     SPACES; debug("pop\tfs");
1673     } else if (imm == 0xa2) {
1674     SPACES; debug("cpuid");
1675     } else if (imm == 0xa3 || imm == 0xab
1676     || imm == 0xb3 || imm == 0xbb) {
1677     modrm(cpu, MODRM_READ, mode, mode67,
1678     0, &instr, &ilen, NULL, NULL);
1679     switch (imm) {
1680     case 0xa3: mnem = "bt"; break;
1681     case 0xab: mnem = "bts"; break;
1682     case 0xb3: mnem = "btr"; break;
1683     case 0xbb: mnem = "btc"; break;
1684     }
1685     SPACES; debug("%s\t%s,%s",
1686     mnem, modrm_rm, modrm_r);
1687     } else if (imm == 0xa4 || imm == 0xa5 ||
1688     imm == 0xac || imm == 0xad) {
1689     modrm(cpu, MODRM_READ, mode, mode67,
1690     0, &instr, &ilen, NULL, NULL);
1691     if (!(imm & 1))
1692     imm2 = read_imm_and_print(&instr,
1693     &ilen, 8);
1694     else
1695     imm2 = 0;
1696     SPACES; debug("sh%sd\t%s,%s,",
1697     imm <= 0xa5? "l" : "r",
1698     modrm_rm, modrm_r);
1699     if (imm & 1)
1700     debug("cl");
1701     else
1702     debug("%i", imm2);
1703     } else if (imm == 0xa8) {
1704     SPACES; debug("push\tgs");
1705     } else if (imm == 0xa9) {
1706     SPACES; debug("pop\tgs");
1707     } else if (imm == 0xaa) {
1708     SPACES; debug("rsm");
1709     } else if (imm == 0xaf) {
1710     modrm(cpu, MODRM_READ, mode, mode67,
1711     0, &instr, &ilen, NULL, NULL);
1712     SPACES; debug("imul\t%s,%s", modrm_r, modrm_rm);
1713     } else if (imm == 0xb0 || imm == 0xb1) {
1714     modrm(cpu, MODRM_READ, mode, mode67,
1715     imm == 0xb0? MODRM_EIGHTBIT : 0,
1716     &instr, &ilen, NULL, NULL);
1717     SPACES; debug("cmpxchg\t%s,%s",
1718     modrm_rm, modrm_r);
1719     } else if (imm == 0xb2 || imm == 0xb4 || imm == 0xb5) {
1720     modrm(cpu, MODRM_READ, mode, mode67, 0,
1721     &instr, &ilen, NULL, NULL);
1722     switch (imm) {
1723     case 0xb2: mnem = "lss"; break;
1724     case 0xb4: mnem = "lfs"; break;
1725     case 0xb5: mnem = "lgs"; break;
1726     }
1727     SPACES; debug("%s\t%s,%s", mnem,
1728     modrm_r, modrm_rm);
1729     } else if (imm == 0xb6 || imm == 0xb7 ||
1730     imm == 0xbe || imm == 0xbf) {
1731     modrm(cpu, MODRM_READ, mode, mode67,
1732     (imm&1)==0? (MODRM_EIGHTBIT |
1733     MODRM_R_NONEIGHTBIT) : MODRM_RM_16BIT,
1734     &instr, &ilen, NULL, NULL);
1735     mnem = "movsx";
1736     if (imm <= 0xb7)
1737     mnem = "movzx";
1738     SPACES; debug("%s\t%s,%s", mnem,
1739     modrm_r, modrm_rm);
1740     } else if (imm == 0xba) {
1741     int subop = (*instr >> 3) & 0x7;
1742     switch (subop) {
1743     case 4: modrm(cpu, MODRM_READ, mode, mode67,
1744     0, &instr, &ilen, NULL, NULL);
1745     imm2 = read_imm_and_print(&instr,
1746     &ilen, 8);
1747     SPACES; debug("bt\t%s,%i",
1748     modrm_rm, imm2);
1749     break;
1750     case 5: modrm(cpu, MODRM_READ, mode, mode67,
1751     0, &instr, &ilen, NULL, NULL);
1752     imm2 = read_imm_and_print(&instr,
1753     &ilen, 8);
1754     SPACES; debug("bts\t%s,%i",
1755     modrm_rm, imm2);
1756     break;
1757     case 6: modrm(cpu, MODRM_READ, mode, mode67,
1758     0, &instr, &ilen, NULL, NULL);
1759     imm2 = read_imm_and_print(&instr,
1760     &ilen, 8);
1761     SPACES; debug("btr\t%s,%i",
1762     modrm_rm, imm2);
1763     break;
1764     case 7: modrm(cpu, MODRM_READ, mode, mode67,
1765     0, &instr, &ilen, NULL, NULL);
1766     imm2 = read_imm_and_print(&instr,
1767     &ilen, 8);
1768     SPACES; debug("btc\t%s,%i",
1769     modrm_rm, imm2);
1770     break;
1771     default:SPACES; debug("UNIMPLEMENTED 0x%02x,0x"
1772     "%02x,0x%02x", op, imm, *instr);
1773     }
1774     } else if (imm == 0xbc || imm == 0xbd) {
1775     modrm(cpu, MODRM_READ, mode, mode67,
1776     0, &instr, &ilen, NULL, NULL);
1777     if (imm == 0xbc)
1778     mnem = "bsf";
1779     else
1780     mnem = "bsr";
1781     SPACES; debug("%s\t%s,%s", mnem, modrm_r,
1782     modrm_rm);
1783     } else if (imm == 0xc0 || imm == 0xc1) {
1784     modrm(cpu, MODRM_READ, mode, mode67,
1785     imm&1? 0 : MODRM_EIGHTBIT,
1786     &instr, &ilen, NULL, NULL);
1787     SPACES; debug("xadd\t%s,%s", modrm_rm, modrm_r);
1788     } else if (imm == 0xc7) {
1789     int subop = (*instr >> 3) & 0x7;
1790     switch (subop) {
1791     case 1: modrm(cpu, MODRM_READ, 64, mode67,
1792     0, &instr, &ilen, NULL, NULL);
1793     SPACES; debug("cmpxchg8b\t%s",modrm_rm);
1794     break;
1795     default:SPACES; debug("UNIMPLEMENTED 0x%02x,0x"
1796     "%02x,0x%02x", op, imm, *instr);
1797     }
1798     } else if (imm >= 0xc8 && imm <= 0xcf) {
1799     SPACES; debug("bswap\te%s", reg_names[imm & 7]);
1800     } else {
1801     SPACES; debug("UNIMPLEMENTED 0x0f,0x%02x", imm);
1802     }
1803     }
1804     } else if (op < 0x20 && (op & 7) == 6) {
1805     SPACES; debug("push\t%s", seg_names[op/8]);
1806     } else if (op < 0x20 && (op & 7) == 7) {
1807     SPACES; debug("pop\t%s", seg_names[op/8]);
1808     } else if (op >= 0x20 && op < 0x40 && (op & 7) == 7) {
1809     SPACES; debug("%sa%s", op < 0x30? "d" : "a",
1810     (op & 0xf)==7? "a" : "s");
1811     } else if (op >= 0x40 && op <= 0x5f) {
1812     switch (op & 0x38) {
1813     case 0x00: mnem = "inc"; break;
1814     case 0x08: mnem = "dec"; break;
1815     case 0x10: mnem = "push"; break;
1816     case 0x18: mnem = "pop"; break;
1817     }
1818     SPACES; debug("%s\t%s%s", mnem, e, reg_names[op & 7]);
1819     } else if (op == 0x60) {
1820     SPACES; debug("pusha%s", mode==16? "" : (mode==32? "d" : "q"));
1821     } else if (op == 0x61) {
1822     SPACES; debug("popa%s", mode==16? "" : (mode==32? "d" : "q"));
1823     } else if (op == 0x62) {
1824     modrm(cpu, MODRM_READ, mode, mode67,
1825     0, &instr, &ilen, NULL, NULL);
1826     SPACES; debug("bound\t%s,%s", modrm_r, modrm_rm);
1827     } else if (op == 0x63) {
1828     modrm(cpu, MODRM_READ, 16, mode67,
1829     0, &instr, &ilen, NULL, NULL);
1830     SPACES; debug("arpl\t%s,%s", modrm_rm, modrm_r);
1831     } else if (op == 0x68) {
1832     imm = read_imm_and_print(&instr, &ilen, mode);
1833     SPACES; debug("push\t%sword 0x%x", mode==32?"d":"", imm);
1834     } else if (op == 0x69 || op == 0x6b) {
1835     modrm(cpu, MODRM_READ, mode, mode67,
1836     0, &instr, &ilen, NULL, NULL);
1837     if (op == 0x69)
1838     imm = read_imm_and_print(&instr, &ilen, mode);
1839     else
1840     imm = (signed char)read_imm_and_print(&instr, &ilen, 8);
1841     SPACES; debug("imul\t%s,%s,%i", modrm_r, modrm_rm, imm);
1842     } else if (op == 0x6a) {
1843     imm = (signed char)read_imm_and_print(&instr, &ilen, 8);
1844     SPACES; debug("push\tbyte 0x%x", imm);
1845     } else if (op == 0x6c) {
1846     SPACES; debug("insb");
1847     } else if (op == 0x6d) {
1848     SPACES; debug("ins%s", mode==16? "w" : (mode==32? "d" : "q"));
1849     } else if (op == 0x6e) {
1850     SPACES; debug("outsb");
1851     } else if (op == 0x6f) {
1852     SPACES; debug("outs%s", mode==16? "w" : (mode==32? "d" : "q"));
1853     } else if ((op & 0xf0) == 0x70) {
1854     imm = (signed char)read_imm_and_print(&instr, &ilen, 8);
1855     imm = dumpaddr + 2 + imm;
1856     SPACES; debug("j%s%s\t0x%x", op&1? "n" : "",
1857     cond_names[(op/2) & 0x7], imm);
1858     } else if (op == 0x80 || op == 0x81) {
1859     switch ((*instr >> 3) & 0x7) {
1860     case 0: mnem = "add"; break;
1861     case 1: mnem = "or"; break;
1862     case 2: mnem = "adc"; break;
1863     case 3: mnem = "sbb"; break;
1864     case 4: mnem = "and"; break;
1865     case 5: mnem = "sub"; break;
1866     case 6: mnem = "xor"; break;
1867     case 7: mnem = "cmp"; break;
1868     default:
1869     SPACES; debug("UNIMPLEMENTED 0x%02x", op);
1870     }
1871     modrm(cpu, MODRM_READ, mode, mode67,
1872     op == 0x80? MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
1873     imm = read_imm_and_print(&instr, &ilen, op==0x80? 8 : mode);
1874     SPACES; debug("%s\t%s,0x%x", mnem, modrm_rm, imm);
1875     } else if (op == 0x83) {
1876     switch ((*instr >> 3) & 0x7) {
1877     case 0: mnem = "add"; break;
1878     case 1: mnem = "or"; break;
1879     case 2: mnem = "adc"; break;
1880     case 3: mnem = "sbb"; break;
1881     case 4: mnem = "and"; break;
1882     case 5: mnem = "sub"; break;
1883     case 6: mnem = "xor"; break;
1884     case 7: mnem = "cmp"; break;
1885     default:
1886     SPACES; debug("UNIMPLEMENTED 0x%02x", op);
1887     }
1888     modrm(cpu, MODRM_READ, mode, mode67, 0, &instr, &ilen,
1889     NULL, NULL);
1890     imm = (signed char)read_imm_and_print(&instr, &ilen, 8);
1891     SPACES; debug("%s\t%s,0x%x", mnem, modrm_rm, imm);
1892     } else if (op == 0x84 || op == 0x85) {
1893     modrm(cpu, MODRM_READ, mode, mode67,
1894     op == 0x84? MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
1895     SPACES; debug("test\t%s,%s", modrm_rm, modrm_r);
1896     } else if (op == 0x86 || op == 0x87) {
1897     modrm(cpu, MODRM_READ, mode, mode67, op == 0x86?
1898     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
1899     SPACES; debug("xchg\t%s,%s", modrm_rm, modrm_r);
1900     } else if (op == 0x88 || op == 0x89) {
1901     modrm(cpu, MODRM_READ, mode, mode67, op == 0x88?
1902     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
1903     SPACES; debug("mov\t%s,%s", modrm_rm, modrm_r);
1904     } else if (op == 0x8a || op == 0x8b) {
1905     modrm(cpu, MODRM_READ, mode, mode67, op == 0x8a?
1906     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
1907     SPACES; debug("mov\t%s,%s", modrm_r, modrm_rm);
1908     } else if (op == 0x8c || op == 0x8e) {
1909     modrm(cpu, MODRM_READ, mode, mode67, MODRM_SEG, &instr, &ilen,
1910     NULL, NULL);
1911     SPACES; debug("mov\t");
1912     if (op == 0x8c)
1913     debug("%s,%s", modrm_rm, modrm_r);
1914     else
1915     debug("%s,%s", modrm_r, modrm_rm);
1916     } else if (op == 0x8d) {
1917     modrm(cpu, MODRM_READ, mode, mode67, 0, &instr, &ilen,
1918     NULL, NULL);
1919     SPACES; debug("lea\t%s,%s", modrm_r, modrm_rm);
1920     } else if (op == 0x8f) {
1921     switch ((*instr >> 3) & 0x7) {
1922     case 0: /* POP m16/m32 */
1923     modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
1924     &ilen, NULL, NULL);
1925     SPACES; debug("pop\t%sword %s", mode == 32? "d" : "",
1926     modrm_rm);
1927     break;
1928     default:
1929     SPACES; debug("UNIMPLEMENTED 0x%02x", op);
1930     }
1931     } else if (op == 0x90) {
1932     SPACES; debug("nop");
1933     } else if (op >= 0x91 && op <= 0x97) {
1934     SPACES; debug("xchg\t%sax,%s%s", e, e, reg_names[op & 7]);
1935     } else if (op == 0x98) {
1936     SPACES; debug("cbw");
1937     } else if (op == 0x99) {
1938     SPACES; debug("cwd");
1939     } else if (op == 0x9a) {
1940     imm = read_imm_and_print(&instr, &ilen, mode);
1941     imm2 = read_imm_and_print(&instr, &ilen, 16);
1942     SPACES; debug("call\t0x%04x:", imm2);
1943     if (mode == 16)
1944     debug("0x%04x", imm);
1945     else
1946     debug("0x%08x", imm);
1947     } else if (op == 0x9b) {
1948     SPACES; debug("wait");
1949     } else if (op == 0x9c) {
1950     SPACES; debug("pushf%s", mode==16? "" : (mode==32? "d" : "q"));
1951     } else if (op == 0x9d) {
1952     SPACES; debug("popf%s", mode==16? "" : (mode==32? "d" : "q"));
1953     } else if (op == 0x9e) {
1954     SPACES; debug("sahf");
1955     } else if (op == 0x9f) {
1956     SPACES; debug("lahf");
1957     } else if (op == 0xa0) {
1958     imm = read_imm_and_print(&instr, &ilen, mode67);
1959     SPACES; debug("mov\tal,[0x%x]", imm);
1960     } else if (op == 0xa1) {
1961     imm = read_imm_and_print(&instr, &ilen, mode67);
1962     SPACES; debug("mov\t%sax,[0x%x]", e, imm);
1963     } else if (op == 0xa2) {
1964     imm = read_imm_and_print(&instr, &ilen, mode67);
1965     SPACES; debug("mov\t[0x%x],al", imm);
1966     } else if (op == 0xa3) {
1967     imm = read_imm_and_print(&instr, &ilen, mode67);
1968     SPACES; debug("mov\t[0x%x],%sax", imm, e);
1969     } else if (op == 0xa4) {
1970     SPACES; debug("movsb");
1971     } else if (op == 0xa5) {
1972     SPACES; debug("movs%s", mode==16? "w" : (mode==32? "d" : "q"));
1973     } else if (op == 0xa6) {
1974     SPACES; debug("cmpsb");
1975     } else if (op == 0xa7) {
1976     SPACES; debug("cmps%s", mode==16? "w" : (mode==32? "d" : "q"));
1977     } else if (op == 0xa8 || op == 0xa9) {
1978     imm = read_imm_and_print(&instr, &ilen, op == 0xa8? 8 : mode);
1979     if (op == 0xa8)
1980     mnem = "al";
1981     else if (mode == 16)
1982     mnem = "ax";
1983     else
1984     mnem = "eax";
1985     SPACES; debug("test\t%s,0x%x", mnem, imm);
1986     } else if (op == 0xaa) {
1987     SPACES; debug("stosb");
1988     } else if (op == 0xab) {
1989     SPACES; debug("stos%s", mode==16? "w" : (mode==32? "d" : "q"));
1990     } else if (op == 0xac) {
1991     SPACES; debug("lodsb");
1992     } else if (op == 0xad) {
1993     SPACES; debug("lods%s", mode==16? "w" : (mode==32? "d" : "q"));
1994     } else if (op == 0xae) {
1995     SPACES; debug("scasb");
1996     } else if (op == 0xaf) {
1997     SPACES; debug("scas%s", mode==16? "w" : (mode==32? "d" : "q"));
1998     } else if (op >= 0xb0 && op <= 0xb7) {
1999     imm = read_imm_and_print(&instr, &ilen, 8);
2000     SPACES; debug("mov\t%s,0x%x", reg_names_bytes[op&7], imm);
2001     } else if (op >= 0xb8 && op <= 0xbf) {
2002     imm = read_imm_and_print(&instr, &ilen, mode);
2003     SPACES; debug("mov\t%s%s,0x%x", e, reg_names[op & 7], imm);
2004     } else if (op == 0xc0 || op == 0xc1) {
2005     switch ((*instr >> 3) & 0x7) {
2006     case 0: mnem = "rol"; break;
2007     case 1: mnem = "ror"; break;
2008     case 2: mnem = "rcl"; break;
2009     case 3: mnem = "rcr"; break;
2010     case 4: mnem = "shl"; break;
2011     case 5: mnem = "shr"; break;
2012     case 6: mnem = "sal"; break;
2013     case 7: mnem = "sar"; break;
2014     }
2015     modrm(cpu, MODRM_READ, mode, mode67, op == 0xc0?
2016     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2017     imm = read_imm_and_print(&instr, &ilen, 8);
2018     SPACES; debug("%s\t%s,%i", mnem, modrm_rm, imm);
2019     } else if (op == 0xc2) {
2020     imm = read_imm_and_print(&instr, &ilen, 16);
2021     SPACES; debug("ret\t0x%x", imm);
2022     } else if (op == 0xc3) {
2023     SPACES; debug("ret");
2024     } else if (op == 0xc4 || op == 0xc5) {
2025     modrm(cpu, MODRM_READ, mode, mode67, 0, &instr, &ilen,
2026     NULL, NULL);
2027     switch (op) {
2028     case 0xc4: mnem = "les"; break;
2029     case 0xc5: mnem = "lds"; break;
2030     }
2031     SPACES; debug("%s\t%s,%s", mnem, modrm_r, modrm_rm);
2032     } else if (op == 0xc6 || op == 0xc7) {
2033     switch ((*instr >> 3) & 0x7) {
2034     case 0: modrm(cpu, MODRM_READ, mode, mode67, op == 0xc6?
2035     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2036     imm = read_imm_and_print(&instr, &ilen,
2037     op == 0xc6? 8 : mode);
2038     SPACES; debug("mov\t%s,0x%x", modrm_rm, imm);
2039     break;
2040     default:
2041     SPACES; debug("UNIMPLEMENTED 0x%02x", op);
2042     }
2043     } else if (op == 0xc8) {
2044     imm = read_imm_and_print(&instr, &ilen, 16);
2045     imm2 = read_imm_and_print(&instr, &ilen, 8);
2046     SPACES; debug("enter\t0x%x,%i", imm, imm2);
2047     } else if (op == 0xc9) {
2048     SPACES; debug("leave");
2049     } else if (op == 0xca) {
2050     imm = read_imm_and_print(&instr, &ilen, 16);
2051     SPACES; debug("retf\t0x%x", imm);
2052     } else if (op == 0xcb) {
2053     SPACES; debug("retf");
2054     } else if (op == 0xcc) {
2055     SPACES; debug("int3");
2056     } else if (op == 0xcd) {
2057     imm = read_imm_and_print(&instr, &ilen, 8);
2058     SPACES; debug("int\t0x%x", imm);
2059     } else if (op == 0xce) {
2060     SPACES; debug("into");
2061     } else if (op == 0xcf) {
2062     SPACES; debug("iret");
2063     } else if (op >= 0xd0 && op <= 0xd3) {
2064     int subop = (*instr >> 3) & 0x7;
2065     modrm(cpu, MODRM_READ, mode, mode67, op&1? 0 :
2066     MODRM_EIGHTBIT, &instr, &ilen, NULL, NULL);
2067     switch (subop) {
2068     case 0: mnem = "rol"; break;
2069     case 1: mnem = "ror"; break;
2070     case 2: mnem = "rcl"; break;
2071     case 3: mnem = "rcr"; break;
2072     case 4: mnem = "shl"; break;
2073     case 5: mnem = "shr"; break;
2074     case 6: mnem = "sal"; break;
2075     case 7: mnem = "sar"; break;
2076     }
2077     SPACES; debug("%s\t%s,", mnem, modrm_rm);
2078     if (op <= 0xd1)
2079     debug("1");
2080     else
2081     debug("cl");
2082     } else if (op == 0xd4) {
2083     imm = read_imm_and_print(&instr, &ilen, 8);
2084     SPACES; debug("aam");
2085     if (imm != 10)
2086     debug("\t%i", imm);
2087     } else if (op == 0xd5) {
2088     imm = read_imm_and_print(&instr, &ilen, 8);
2089     SPACES; debug("aad");
2090     if (imm != 10)
2091     debug("\t%i", imm);
2092     } else if (op == 0xd6) {
2093     SPACES; debug("salc"); /* undocumented? */
2094     } else if (op == 0xd7) {
2095     SPACES; debug("xlat");
2096     } else if (op == 0xd9) {
2097     int subop = (*instr >> 3) & 7;
2098     imm = *instr;
2099     if (subop == 5) {
2100     modrm(cpu, MODRM_READ, 16, mode67, 0,
2101     &instr, &ilen, NULL, NULL);
2102     SPACES; debug("fldcw\t%s", modrm_rm);
2103     } else if (subop == 7) {
2104     modrm(cpu, MODRM_READ, 16, mode67, 0,
2105     &instr, &ilen, NULL, NULL);
2106     SPACES; debug("fstcw\t%s", modrm_rm);
2107     } else {
2108     SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op, imm);
2109     }
2110     } else if (op == 0xdb) {
2111     imm = *instr;
2112     if (imm == 0xe2) {
2113     read_imm_and_print(&instr, &ilen, 8);
2114     SPACES; debug("fclex");
2115     } else if (imm == 0xe3) {
2116     read_imm_and_print(&instr, &ilen, 8);
2117     SPACES; debug("finit");
2118     } else if (imm == 0xe4) {
2119     read_imm_and_print(&instr, &ilen, 8);
2120     SPACES; debug("fsetpm");
2121     } else {
2122     SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op, imm);
2123     }
2124     } else if (op == 0xdd) {
2125     int subop = (*instr >> 3) & 7;
2126     imm = *instr;
2127     if (subop == 7) {
2128     modrm(cpu, MODRM_READ, 16, mode67, 0,
2129     &instr, &ilen, NULL, NULL);
2130     SPACES; debug("fstsw\t%s", modrm_rm);
2131     } else {
2132     SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op, imm);
2133     }
2134     } else if (op == 0xdf) {
2135     imm = *instr;
2136     if (imm == 0xe0) {
2137     read_imm_and_print(&instr, &ilen, 8);
2138     SPACES; debug("fstsw\tax");
2139     } else {
2140     SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op, imm);
2141     }
2142     } else if (op == 0xe3) {
2143     imm = read_imm_and_print(&instr, &ilen, 8);
2144     imm = dumpaddr + ilen + (signed char)imm;
2145     if (mode == 16)
2146     mnem = "jcxz";
2147     else
2148     mnem = "jecxz";
2149     SPACES; debug("%s\t0x%x", mnem, imm);
2150     } else if (op == 0xe4) {
2151     imm = read_imm_and_print(&instr, &ilen, 8);
2152     SPACES; debug("in\tal,0x%x", imm);
2153     } else if (op == 0xe5) {
2154     imm = read_imm_and_print(&instr, &ilen, 8);
2155     SPACES; debug("in\t%sax,0x%x", e, imm);
2156     } else if (op == 0xe6) {
2157     imm = read_imm_and_print(&instr, &ilen, 8);
2158     SPACES; debug("out\t0x%x,al", imm);
2159     } else if (op == 0xe7) {
2160     imm = read_imm_and_print(&instr, &ilen, 8);
2161     SPACES; debug("out\t0x%x,%sax", imm, e);
2162     } else if (op == 0xe8 || op == 0xe9) {
2163     imm = read_imm_and_print(&instr, &ilen, mode);
2164     if (mode == 16)
2165     imm = (int16_t)imm;
2166     imm = dumpaddr + ilen + imm;
2167     switch (op) {
2168     case 0xe8: mnem = "call"; break;
2169     case 0xe9: mnem = "jmp"; break;
2170     }
2171     SPACES; debug("%s\t0x%x", mnem, imm);
2172     } else if (op == 0xea) {
2173     imm = read_imm_and_print(&instr, &ilen, mode);
2174     imm2 = read_imm_and_print(&instr, &ilen, 16);
2175     SPACES; debug("jmp\t0x%04x:", imm2);
2176     if (mode == 16)
2177     debug("0x%04x", imm);
2178     else
2179     debug("0x%08x", imm);
2180     } else if ((op >= 0xe0 && op <= 0xe2) || op == 0xeb) {
2181     imm = read_imm_and_print(&instr, &ilen, 8);
2182     imm = dumpaddr + ilen + (signed char)imm;
2183     switch (op) {
2184     case 0xe0: mnem = "loopnz"; break;
2185     case 0xe1: mnem = "loopz"; break;
2186     case 0xe2: mnem = "loop"; break;
2187     case 0xeb: mnem = "jmp"; break;
2188     }
2189     SPACES; debug("%s\t0x%x", mnem, imm);
2190     } else if (op == 0xec) {
2191     SPACES; debug("in\tal,dx");
2192     } else if (op == 0xed) {
2193     SPACES; debug("in\t%sax,dx", e);
2194     } else if (op == 0xee) {
2195     SPACES; debug("out\tdx,al");
2196     } else if (op == 0xef) {
2197     SPACES; debug("out\tdx,%sax", e);
2198     } else if (op == 0xf1) {
2199     SPACES; debug("icebp"); /* undocumented? */
2200     /* http://www.x86.org/secrets/opcodes/icebp.htm */
2201     } else if (op == 0xf4) {
2202     SPACES; debug("hlt");
2203     } else if (op == 0xf5) {
2204     SPACES; debug("cmc");
2205     } else if (op == 0xf8) {
2206     SPACES; debug("clc");
2207     } else if (op == 0xf9) {
2208     SPACES; debug("stc");
2209     } else if (op == 0xfa) {
2210     SPACES; debug("cli");
2211     } else if (op == 0xfb) {
2212     SPACES; debug("sti");
2213     } else if (op == 0xfc) {
2214     SPACES; debug("cld");
2215     } else if (op == 0xfd) {
2216     SPACES; debug("std");
2217     } else if (op == 0xf6 || op == 0xf7) {
2218     switch ((*instr >> 3) & 0x7) {
2219     case 0: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2220     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2221     imm = read_imm_and_print(&instr, &ilen,
2222     op == 0xf6? 8 : mode);
2223     SPACES; debug("test\t%s,0x%x", modrm_rm, imm);
2224     break;
2225     case 2: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2226     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2227     SPACES; debug("not\t%s", modrm_rm);
2228     break;
2229     case 3: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2230     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2231     SPACES; debug("neg\t%s", modrm_rm);
2232     break;
2233     case 4: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2234     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2235     SPACES; debug("mul\t%s", modrm_rm);
2236     break;
2237     case 5: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2238     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2239     SPACES; debug("imul\t%s", modrm_rm);
2240     break;
2241     case 6: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2242     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2243     SPACES; debug("div\t%s", modrm_rm);
2244     break;
2245     case 7: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2246     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2247     SPACES; debug("idiv\t%s", modrm_rm);
2248     break;
2249     default:
2250     SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op,*instr);
2251     }
2252     } else if (op == 0xfe || op == 0xff) {
2253     /* FE /0 = inc r/m8 */
2254     /* FE /1 = dec r/m8 */
2255     /* FF /2 = call near rm16/32 */
2256     /* FF /3 = call far m16:32 */
2257     /* FF /6 = push r/m16/32 */
2258     switch ((*instr >> 3) & 0x7) {
2259     case 0: modrm(cpu, MODRM_READ, mode, mode67, op == 0xfe?
2260     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2261     SPACES; debug("inc\t%s", modrm_rm);
2262     break;
2263     case 1: modrm(cpu, MODRM_READ, mode, mode67, op == 0xfe?
2264     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2265     SPACES; debug("dec\t%s", modrm_rm);
2266     break;
2267     case 2: if (op == 0xfe) {
2268     SPACES; debug("UNIMPLEMENTED "
2269     "0x%02x,0x%02x", op,*instr);
2270     } else {
2271     modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2272     &ilen, NULL, NULL);
2273     SPACES; debug("call\t%s", modrm_rm);
2274     }
2275     break;
2276     case 3: if (op == 0xfe) {
2277     SPACES; debug("UNIMPLEMENTED "
2278     "0x%02x,0x%02x", op,*instr);
2279     } else {
2280     modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2281     &ilen, NULL, NULL);
2282     SPACES; debug("call\tfar %s", modrm_rm);
2283     }
2284     break;
2285     case 4: if (op == 0xfe) {
2286     SPACES; debug("UNIMPLEMENTED "
2287     "0x%02x,0x%02x", op,*instr);
2288     } else {
2289     modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2290     &ilen, NULL, NULL);
2291     SPACES; debug("jmp\t%s", modrm_rm);
2292     }
2293     break;
2294     case 5: if (op == 0xfe) {
2295     SPACES; debug("UNIMPLEMENTED "
2296     "0x%02x,0x%02x", op,*instr);
2297     } else {
2298     modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2299     &ilen, NULL, NULL);
2300     SPACES; debug("jmp\tfar %s", modrm_rm);
2301     }
2302     break;
2303     case 6: if (op == 0xfe) {
2304     SPACES; debug("UNIMPLEMENTED "
2305     "0x%02x,0x%02x", op,*instr);
2306     } else {
2307     modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2308     &ilen, NULL, NULL);
2309     SPACES; debug("push\t%sword %s",
2310     mode == 32? "d" : "", modrm_rm);
2311     }
2312     break;
2313     default:
2314     SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op,*instr);
2315     }
2316     } else {
2317     SPACES; debug("UNIMPLEMENTED 0x%02x", op);
2318     }
2319    
2320     switch (rep) {
2321     case REP_REP: debug(" (rep)"); break;
2322     case REP_REPNE: debug(" (repne)"); break;
2323     }
2324     if (prefix != NULL)
2325     debug(" (%s)", prefix);
2326     if (lock)
2327     debug(" (lock)");
2328    
2329     debug("\n");
2330     return ilen;
2331     }
2332    
2333    
2334    
2335     /*
2336     * x86_cpuid():
2337     *
2338     * TODO: Level 1 and 2 info.
2339     */
2340 dpavlin 22 void x86_cpuid(struct cpu *cpu)
2341 dpavlin 14 {
2342     switch (cpu->cd.x86.r[X86_R_AX]) {
2343     /* Normal CPU id: */
2344     case 0: cpu->cd.x86.r[X86_R_AX] = 2;
2345     /* Intel... */
2346     cpu->cd.x86.r[X86_R_BX] = 0x756e6547; /* "Genu" */
2347     cpu->cd.x86.r[X86_R_DX] = 0x49656e69; /* "ineI" */
2348     cpu->cd.x86.r[X86_R_CX] = 0x6c65746e; /* "ntel" */
2349     /* ... or AMD: */
2350     cpu->cd.x86.r[X86_R_BX] = 0x68747541; /* "Auth" */
2351     cpu->cd.x86.r[X86_R_DX] = 0x69746E65; /* "enti" */
2352     cpu->cd.x86.r[X86_R_CX] = 0x444D4163; /* "cAMD" */
2353     break;
2354     case 1: /* TODO */
2355     cpu->cd.x86.r[X86_R_AX] = 0x0623;
2356     cpu->cd.x86.r[X86_R_BX] = (cpu->cpu_id << 24);
2357     /* TODO: are bits 8..15 the _total_ nr of cpus, or the
2358     cpu id of this one? */
2359     cpu->cd.x86.r[X86_R_CX] = X86_CPUID_ECX_CX16;
2360     cpu->cd.x86.r[X86_R_DX] = X86_CPUID_EDX_CX8 | X86_CPUID_EDX_FPU
2361     | X86_CPUID_EDX_MSR | X86_CPUID_EDX_TSC | X86_CPUID_EDX_MTRR
2362     | X86_CPUID_EDX_CMOV | X86_CPUID_EDX_PSE |
2363     X86_CPUID_EDX_SEP | X86_CPUID_EDX_PGE |
2364     X86_CPUID_EDX_MMX | X86_CPUID_EDX_FXSR;
2365     break;
2366     case 2: /* TODO: actual Cache info */
2367     /* This is just bogus */
2368     cpu->cd.x86.r[X86_R_AX] = 0x03020101;
2369     cpu->cd.x86.r[X86_R_BX] = 0x00000000;
2370     cpu->cd.x86.r[X86_R_CX] = 0x00000000;
2371     cpu->cd.x86.r[X86_R_DX] = 0x06040a42;
2372     break;
2373    
2374     /* Extended CPU id: */
2375     case 0x80000000:
2376     cpu->cd.x86.r[X86_R_AX] = 0x80000008;
2377     /* AMD... */
2378     cpu->cd.x86.r[X86_R_BX] = 0x68747541;
2379     cpu->cd.x86.r[X86_R_DX] = 0x444D4163;
2380     cpu->cd.x86.r[X86_R_CX] = 0x69746E65;
2381     break;
2382     case 0x80000001:
2383     cpu->cd.x86.r[X86_R_AX] = 0;
2384     cpu->cd.x86.r[X86_R_BX] = 0;
2385     cpu->cd.x86.r[X86_R_CX] = 0;
2386     cpu->cd.x86.r[X86_R_DX] = (cpu->cd.x86.model.model_number
2387     >= X86_MODEL_AMD64)? X86_CPUID_EXT_EDX_LM : 0;
2388     break;
2389     case 0x80000002:
2390     case 0x80000003:
2391     case 0x80000004:
2392     case 0x80000005:
2393     case 0x80000006:
2394     case 0x80000007:
2395     fatal("[ CPUID 0x%08x ]\n", (int)cpu->cd.x86.r[X86_R_AX]);
2396     cpu->cd.x86.r[X86_R_AX] = 0;
2397     cpu->cd.x86.r[X86_R_BX] = 0;
2398     cpu->cd.x86.r[X86_R_CX] = 0;
2399     cpu->cd.x86.r[X86_R_DX] = 0;
2400     break;
2401     case 0x80000008:
2402     cpu->cd.x86.r[X86_R_AX] = 0x00003028;
2403     cpu->cd.x86.r[X86_R_BX] = 0;
2404     cpu->cd.x86.r[X86_R_CX] = 0;
2405     cpu->cd.x86.r[X86_R_DX] = 0;
2406     break;
2407     default:fatal("x86_cpuid(): unimplemented eax = 0x%x\n",
2408     (int)cpu->cd.x86.r[X86_R_AX]);
2409     cpu->running = 0;
2410     }
2411     }
2412    
2413    
2414     /*
2415     * x86_push():
2416     */
2417     int x86_push(struct cpu *cpu, uint64_t value, int mode)
2418     {
2419     int res = 1, oldseg;
2420     int ssize = cpu->cd.x86.descr_cache[X86_S_SS].default_op_size;
2421     uint64_t new_esp;
2422     uint64_t old_esp = cpu->cd.x86.r[X86_R_SP];
2423     uint16_t old_ss = cpu->cd.x86.s[X86_S_SS];
2424     uint64_t old_eip = cpu->pc;
2425     uint16_t old_cs = cpu->cd.x86.s[X86_S_CS];
2426    
2427     /* TODO: up/down? */
2428     /* TODO: stacksize? */
2429     ssize = mode;
2430    
2431     oldseg = cpu->cd.x86.cursegment;
2432     cpu->cd.x86.cursegment = X86_S_SS;
2433     if (ssize == 16)
2434     new_esp = (cpu->cd.x86.r[X86_R_SP] & ~0xffff)
2435     | ((cpu->cd.x86.r[X86_R_SP] - (ssize / 8)) & 0xffff);
2436     else
2437     new_esp = (cpu->cd.x86.r[X86_R_SP] -
2438     (ssize / 8)) & 0xffffffff;
2439     res = x86_store(cpu, new_esp, value, ssize / 8);
2440     if (!res) {
2441     fatal("WARNING: x86_push store failed: cs:eip=0x%04x:0x%08x"
2442     " ss:esp=0x%04x:0x%08x\n", (int)old_cs,
2443     (int)old_eip, (int)old_ss, (int)old_esp);
2444     if ((old_cs & X86_PL_MASK) != X86_RING3)
2445     cpu->running = 0;
2446     } else {
2447     cpu->cd.x86.r[X86_R_SP] = new_esp;
2448     }
2449     cpu->cd.x86.cursegment = oldseg;
2450     return res;
2451     }
2452    
2453    
2454     /*
2455     * x86_pop():
2456     */
2457     int x86_pop(struct cpu *cpu, uint64_t *valuep, int mode)
2458     {
2459     int res = 1, oldseg;
2460     int ssize = cpu->cd.x86.descr_cache[X86_S_SS].default_op_size;
2461    
2462     /* TODO: up/down? */
2463     /* TODO: stacksize? */
2464     ssize = mode;
2465    
2466     oldseg = cpu->cd.x86.cursegment;
2467     cpu->cd.x86.cursegment = X86_S_SS;
2468     res = x86_load(cpu, cpu->cd.x86.r[X86_R_SP], valuep, ssize / 8);
2469     if (!res) {
2470     fatal("WARNING: x86_pop load failed\n");
2471     } else {
2472     if (ssize == 16)
2473     cpu->cd.x86.r[X86_R_SP] = (cpu->cd.x86.r[X86_R_SP] &
2474     ~0xffff) | ((cpu->cd.x86.r[X86_R_SP] + (ssize / 8))
2475     & 0xffff);
2476     else
2477     cpu->cd.x86.r[X86_R_SP] = (cpu->cd.x86.r[X86_R_SP] +
2478     (ssize / 8)) & 0xffffffff;
2479     }
2480     cpu->cd.x86.cursegment = oldseg;
2481     return res;
2482     }
2483    
2484    
2485     #define INT_TYPE_CALLGATE 1
2486     #define INT_TYPE_INTGATE 2
2487     #define INT_TYPE_TRAPGATE 3
2488     /*
2489     * x86_interrupt():
2490     *
2491     * Read the interrupt descriptor table (or, in real mode, the interrupt
2492     * vector table), push flags/cs/eip, and jump to the interrupt handler.
2493     */
2494     int x86_interrupt(struct cpu *cpu, int nr, int errcode)
2495     {
2496     uint16_t seg, old_cs;
2497     uint32_t ofs;
2498     int res, mode;
2499     unsigned char buf[8];
2500    
2501     old_cs = cpu->cd.x86.s[X86_S_CS];
2502    
2503     debug("{ x86_interrupt %i }\n", nr);
2504    
2505     if (PROTECTED_MODE) {
2506     int i, int_type = 0;
2507    
2508 dpavlin 22 if (nr * 8 > (int)cpu->cd.x86.idtr_limit) {
2509 dpavlin 14 fatal("TODO: protected mode int 0x%02x outside idtr"
2510     " limit (%i)?\n", nr, (int)cpu->cd.x86.idtr_limit);
2511     cpu->running = 0;
2512     return 0;
2513     }
2514    
2515     /* Read the interrupt descriptor: */
2516     res = cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.idtr + nr*8,
2517     buf, 8, MEM_READ, NO_SEGMENTATION);
2518     if (!res) {
2519     fatal("x86_interrupt(): could not read the"
2520     " interrupt descriptor table (prot. mode)\n");
2521     cpu->running = 0;
2522     return 0;
2523     }
2524    
2525     if ((buf[5] & 0x17) == 0x04)
2526     int_type = INT_TYPE_CALLGATE;
2527     if ((buf[5] & 0x17) == 0x06)
2528     int_type = INT_TYPE_INTGATE;
2529     if ((buf[5] & 0x17) == 0x07)
2530     int_type = INT_TYPE_TRAPGATE;
2531    
2532     if (!int_type) {
2533     fatal("x86_interrupt(): TODO:\n");
2534     for (i=0; i<8; i++)
2535     fatal(" %02x", buf[i]);
2536     fatal("\n");
2537     cpu->running = 0;
2538     return 0;
2539     }
2540    
2541     seg = buf[2] + (buf[3] << 8);
2542     ofs = buf[0] + (buf[1] << 8) + (buf[6] << 16) + (buf[7] << 24);
2543    
2544     switch (int_type) {
2545     case INT_TYPE_INTGATE:
2546     case INT_TYPE_TRAPGATE:
2547     break;
2548     default:
2549     fatal("INT type: %i, cs:eip = 0x%04x:0x%08x\n",
2550     int_type, (int)seg, (int)ofs);
2551     cpu->running = 0;
2552     return 0;
2553     }
2554    
2555     reload_segment_descriptor(cpu, X86_S_CS, seg, &cpu->pc);
2556    
2557     /*
2558     * If we're changing privilege level, the we should change
2559     * stack here, and push the old SS:ESP.
2560     */
2561     if ((seg & X86_PL_MASK) < (old_cs & X86_PL_MASK)) {
2562     unsigned char buf[16];
2563     uint16_t new_ss, old_ss;
2564     uint32_t new_esp, old_esp;
2565     int pl;
2566    
2567     pl = seg & X86_PL_MASK;
2568    
2569     /* Load SSx:ESPx from the Task State Segment: */
2570     if (cpu->cd.x86.tr < 4)
2571     fatal("WARNING: interrupt with stack switch"
2572     ", but task register = 0?\n");
2573    
2574     /* fatal("::: old SS:ESP=0x%04x:0x%08x\n",
2575     (int)cpu->cd.x86.s[X86_S_SS],
2576     (int)cpu->cd.x86.r[X86_R_SP]); */
2577    
2578     if (!cpu->memory_rw(cpu, cpu->mem, 4 + pl*8 +
2579     cpu->cd.x86.tr_base, buf, sizeof(buf), MEM_READ,
2580     NO_SEGMENTATION)) {
2581     fatal("ERROR: couldn't read tss blah blah\n");
2582     cpu->running = 0;
2583     return 0;
2584     }
2585    
2586     new_esp = buf[0] + (buf[1] << 8) +
2587     (buf[2] << 16) + (buf[3] << 24);
2588     new_ss = buf[4] + (buf[5] << 8);
2589    
2590     old_ss = cpu->cd.x86.s[X86_S_SS];
2591     old_esp = cpu->cd.x86.r[X86_R_SP];
2592    
2593     reload_segment_descriptor(cpu, X86_S_SS, new_ss, NULL);
2594     cpu->cd.x86.r[X86_R_SP] = new_esp;
2595    
2596     fatal("::: Switching Stack: new SS:ESP=0x%04x:0x%08x\n",
2597     (int)new_ss, (int)new_esp);
2598    
2599     mode = cpu->cd.x86.descr_cache[X86_S_CS].
2600     default_op_size;
2601    
2602     if (!x86_push(cpu, old_ss, mode)) {
2603     fatal("TODO: problem adgsadg 1\n");
2604     cpu->running = 0;
2605     }
2606     if (!x86_push(cpu, old_esp, mode)) {
2607     fatal("TODO: problem adgsadg 2\n");
2608     cpu->running = 0;
2609     }
2610     }
2611    
2612     /* Push flags, cs, and ip (pc): */
2613     mode = cpu->cd.x86.descr_cache[X86_S_CS].default_op_size;
2614     if (!x86_push(cpu, cpu->cd.x86.rflags, mode)) {
2615     fatal("TODO: how to handle this 1 asdf\n");
2616     cpu->running = 0;
2617     }
2618     if (!x86_push(cpu, old_cs, mode)) {
2619     fatal("TODO: how to handle this 2 sdghser\n");
2620     cpu->running = 0;
2621     }
2622     if (!x86_push(cpu, cpu->pc, mode)) {
2623     fatal("TODO: how to handle this 3 we\n");
2624     cpu->running = 0;
2625     }
2626    
2627     /* Push error code for some exceptions: */
2628     if ((nr >= 8 && nr <=14) || nr == 17) {
2629     if (!x86_push(cpu, errcode, mode)) {
2630     fatal("x86_interrupt(): TODO: asdgblah\n");
2631     cpu->running = 0;
2632     }
2633     }
2634    
2635     /* Only turn off interrupts for Interrupt Gates: */
2636     if (int_type == INT_TYPE_INTGATE)
2637     cpu->cd.x86.rflags &= ~X86_FLAGS_IF;
2638    
2639     /* Turn off TF for Interrupt and Trap Gates: */
2640     if (int_type == INT_TYPE_INTGATE ||
2641     int_type == INT_TYPE_TRAPGATE)
2642     cpu->cd.x86.rflags &= ~X86_FLAGS_TF;
2643    
2644     goto int_jump;
2645     }
2646    
2647     /*
2648     * Real mode:
2649     */
2650 dpavlin 22 if (nr * 4 > (int)cpu->cd.x86.idtr_limit) {
2651 dpavlin 14 fatal("TODO: real mode int 0x%02x outside idtr limit ("
2652     "%i)?\n", nr, (int)cpu->cd.x86.idtr_limit);
2653     cpu->running = 0;
2654     return 0;
2655     }
2656     /* Read the interrupt vector: */
2657     res = cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.idtr + nr*4, buf, 4,
2658     MEM_READ, NO_SEGMENTATION);
2659     if (!res) {
2660     fatal("x86_interrupt(): could not read the"
2661     " interrupt descriptor table\n");
2662     cpu->running = 0;
2663     return 0;
2664     }
2665     ofs = buf[0] + (buf[1] << 8); seg = buf[2] + (buf[3] << 8);
2666    
2667     reload_segment_descriptor(cpu, X86_S_CS, seg, &cpu->pc);
2668    
2669     /* Push old flags, old cs, and old ip (pc): */
2670     mode = cpu->cd.x86.descr_cache[X86_S_CS].default_op_size;
2671    
2672     if (!x86_push(cpu, cpu->cd.x86.rflags, mode)) {
2673     fatal("x86_interrupt(): TODO: how to handle this 4\n");
2674     cpu->running = 0;
2675     }
2676     if (!x86_push(cpu, old_cs, mode)) {
2677     fatal("x86_interrupt(): TODO: how to handle this 5\n");
2678     cpu->running = 0;
2679     }
2680     if (!x86_push(cpu, cpu->pc, mode)) {
2681     fatal("x86_interrupt(): TODO: how to handle this 6\n");
2682     cpu->running = 0;
2683     }
2684    
2685     /* Turn off interrupts and the Trap Flag, and jump to the interrupt
2686     handler: */
2687     cpu->cd.x86.rflags &= ~(X86_FLAGS_IF | X86_FLAGS_TF);
2688    
2689     int_jump:
2690     cpu->pc = ofs;
2691    
2692     return 1;
2693     }
2694    
2695    
2696     #define CALCFLAGS_OP_ADD 1
2697     #define CALCFLAGS_OP_SUB 2
2698     #define CALCFLAGS_OP_XOR 3
2699     /*
2700     * x86_calc_flags():
2701     */
2702     void x86_calc_flags(struct cpu *cpu, uint64_t a, uint64_t b, int mode,
2703     int op)
2704     {
2705     uint64_t c=0, mask;
2706     int i, count;
2707    
2708     if (mode == 8)
2709     mask = 0xff;
2710     else if (mode == 16)
2711     mask = 0xffff;
2712     else if (mode == 32)
2713     mask = 0xffffffffULL;
2714     else if (mode == 64)
2715     mask = 0xffffffffffffffffULL;
2716     else {
2717     fatal("x86_calc_flags(): Bad mode (%i)\n", mode);
2718     return;
2719     }
2720    
2721     a &= mask;
2722     b &= mask;
2723    
2724     /* CF: */
2725     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
2726     switch (op) {
2727     case CALCFLAGS_OP_ADD:
2728     if (((a + b)&mask) < a && ((a + b)&mask) < b)
2729     cpu->cd.x86.rflags |= X86_FLAGS_CF;
2730     break;
2731     case CALCFLAGS_OP_SUB:
2732     if (a < b)
2733     cpu->cd.x86.rflags |= X86_FLAGS_CF;
2734     break;
2735     case CALCFLAGS_OP_XOR:
2736     break;
2737     }
2738    
2739     switch (op) {
2740     case CALCFLAGS_OP_ADD:
2741     c = (a + b) & mask;
2742     break;
2743     case CALCFLAGS_OP_SUB:
2744     c = (a - b) & mask;
2745     break;
2746     case CALCFLAGS_OP_XOR:
2747     c = a;
2748     }
2749    
2750     /* ZF: */
2751     cpu->cd.x86.rflags &= ~X86_FLAGS_ZF;
2752     if (c == 0)
2753     cpu->cd.x86.rflags |= X86_FLAGS_ZF;
2754    
2755     /* SF: */
2756     cpu->cd.x86.rflags &= ~X86_FLAGS_SF;
2757     if ((mode == 8 && (c & 0x80)) ||
2758     (mode == 16 && (c & 0x8000)) ||
2759     (mode == 32 && (c & 0x80000000ULL)) ||
2760     (mode == 64 && (c & 0x8000000000000000ULL))) {
2761     cpu->cd.x86.rflags |= X86_FLAGS_SF;
2762     }
2763    
2764     /* OF: */
2765     cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
2766     switch (op) {
2767     case CALCFLAGS_OP_ADD:
2768     /* TODO */
2769     break;
2770     case CALCFLAGS_OP_SUB:
2771     if (cpu->cd.x86.rflags & X86_FLAGS_SF)
2772     cpu->cd.x86.rflags |= X86_FLAGS_OF;
2773     if (mode == 8 && (int8_t)a < (int8_t)b)
2774     cpu->cd.x86.rflags ^= X86_FLAGS_OF;
2775     if (mode == 16 && (int16_t)a < (int16_t)b)
2776     cpu->cd.x86.rflags ^= X86_FLAGS_OF;
2777     if (mode == 32 && (int32_t)a < (int32_t)b)
2778     cpu->cd.x86.rflags ^= X86_FLAGS_OF;
2779     break;
2780     case CALCFLAGS_OP_XOR:
2781     ;
2782     }
2783    
2784     /* AF: */
2785     switch (op) {
2786     case CALCFLAGS_OP_ADD:
2787     if ((a & 0xf) + (b & 0xf) > 15)
2788     cpu->cd.x86.rflags |= X86_FLAGS_AF;
2789     else
2790     cpu->cd.x86.rflags &= ~X86_FLAGS_AF;
2791     break;
2792     case CALCFLAGS_OP_SUB:
2793     if ((b & 0xf) > (a & 0xf))
2794     cpu->cd.x86.rflags |= X86_FLAGS_AF;
2795     else
2796     cpu->cd.x86.rflags &= ~X86_FLAGS_AF;
2797     break;
2798     case CALCFLAGS_OP_XOR:
2799     ;
2800     }
2801    
2802     /* PF: (NOTE: Only the lowest 8 bits) */
2803     cpu->cd.x86.rflags &= ~X86_FLAGS_PF;
2804     count = 0;
2805     for (i=0; i<8; i++) {
2806     if (c & 1)
2807     count ++;
2808     c >>= 1;
2809     }
2810     if (!(count&1))
2811     cpu->cd.x86.rflags |= X86_FLAGS_PF;
2812     }
2813    
2814    
2815     /*
2816     * x86_condition():
2817     *
2818     * Returns 0 or 1 (false or true) depending on flag bits.
2819     */
2820     int x86_condition(struct cpu *cpu, int op)
2821     {
2822     int success = 0;
2823    
2824     switch (op & 0xe) {
2825     case 0x00: /* o */
2826     success = cpu->cd.x86.rflags & X86_FLAGS_OF;
2827     break;
2828     case 0x02: /* c */
2829     success = cpu->cd.x86.rflags & X86_FLAGS_CF;
2830     break;
2831     case 0x04: /* z */
2832     success = cpu->cd.x86.rflags & X86_FLAGS_ZF;
2833     break;
2834     case 0x06: /* be */
2835     success = (cpu->cd.x86.rflags & X86_FLAGS_ZF) ||
2836     (cpu->cd.x86.rflags & X86_FLAGS_CF);
2837     break;
2838     case 0x08: /* s */
2839     success = cpu->cd.x86.rflags & X86_FLAGS_SF;
2840     break;
2841     case 0x0a: /* p */
2842     success = cpu->cd.x86.rflags & X86_FLAGS_PF;
2843     break;
2844     case 0x0c: /* nge */
2845     success = (cpu->cd.x86.rflags & X86_FLAGS_SF? 1 : 0)
2846     != (cpu->cd.x86.rflags & X86_FLAGS_OF? 1 : 0);
2847     break;
2848     case 0x0e: /* ng */
2849     success = (cpu->cd.x86.rflags & X86_FLAGS_SF? 1 : 0)
2850     != (cpu->cd.x86.rflags & X86_FLAGS_OF? 1 : 0);
2851     success |= (cpu->cd.x86.rflags & X86_FLAGS_ZF ? 1 : 0);
2852     break;
2853     }
2854    
2855     if (op & 1)
2856     success = !success;
2857    
2858     return success? 1 : 0;
2859     }
2860    
2861    
2862     /*
2863     * x86_shiftrotate():
2864     */
2865     void x86_shiftrotate(struct cpu *cpu, uint64_t *op1p, int op,
2866     int n, int mode)
2867     {
2868     uint64_t op1 = *op1p;
2869     int cf = -1, oldcf = 0;
2870    
2871     n &= 31;
2872     if (mode != 64)
2873     op1 &= (((uint64_t)1 << mode) - 1);
2874    
2875     oldcf = cpu->cd.x86.rflags & X86_FLAGS_CF? 1 : 0;
2876    
2877     while (n-- > 0) {
2878     cf = 0;
2879    
2880     if (op & 1) { /* right */
2881     if (op1 & 1)
2882     cf = 1;
2883     } else { /* left */
2884     cf = (op1 & ((uint64_t)1 << (mode-1)))? 1 : 0;
2885     }
2886    
2887     switch (op) {
2888     case 0: /* rol */
2889     op1 = (op1 << 1) | cf;
2890     break;
2891     case 1: /* ror */
2892     op1 >>= 1;
2893     op1 |= ((uint64_t)cf << (mode - 1));
2894     break;
2895     case 2: /* rcl */
2896     op1 = (op1 << 1) | oldcf;
2897     oldcf = cf;
2898     break;
2899     case 3: /* rcr */
2900     op1 >>= 1;
2901     op1 |= ((uint64_t)oldcf << (mode - 1));
2902     oldcf = cf;
2903     break;
2904     case 4: /* shl */
2905     case 6: /* sal */
2906     op1 <<= 1;
2907     break;
2908     case 5: /* shr */
2909     op1 >>= 1;
2910     break;
2911     case 7: /* sar */
2912     op1 >>= 1;
2913     if (mode == 8 && op1 & 0x40)
2914     op1 |= 0x80;
2915     if (mode == 16 && op1 & 0x4000)
2916     op1 |= 0x8000;
2917     if (mode == 32 && op1 & 0x40000000ULL)
2918     op1 |= 0x80000000ULL;
2919     break;
2920     default:
2921     fatal("x86_shiftrotate(): unimplemented op %i\n", op);
2922     cpu->running = 0;
2923     }
2924     if (mode != 64)
2925     op1 &= (((uint64_t)1 << mode) - 1);
2926     x86_calc_flags(cpu, op1, 0, mode, CALCFLAGS_OP_XOR);
2927     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
2928     if (cf)
2929     cpu->cd.x86.rflags |= X86_FLAGS_CF;
2930     }
2931    
2932     /* TODO: OF flag */
2933    
2934     *op1p = op1;
2935     }
2936    
2937    
2938     /*
2939     * x86_msr():
2940     *
2941     * This function reads or writes the MSRs (Model Specific Registers).
2942     */
2943     void x86_msr(struct cpu *cpu, int writeflag)
2944     {
2945     uint32_t regnr = cpu->cd.x86.r[X86_R_CX] & 0xffffffff;
2946     uint64_t odata=0, idata = (cpu->cd.x86.r[X86_R_AX] & 0xffffffff) +
2947     ((cpu->cd.x86.r[X86_R_DX] & 0xffffffff) << 32);
2948    
2949     switch (regnr) {
2950     case 0xc0000080: /* AMD64 EFER */
2951     if (writeflag) {
2952     if (cpu->cd.x86.efer & X86_EFER_LME &&
2953     !(idata & X86_EFER_LME))
2954     debug("[ switching FROM 64-bit mode ]\n");
2955     if (!(cpu->cd.x86.efer & X86_EFER_LME) &&
2956     idata & X86_EFER_LME)
2957     debug("[ switching to 64-bit mode ]\n");
2958     cpu->cd.x86.efer = idata;
2959     } else
2960     odata = cpu->cd.x86.efer;
2961     break;
2962     default:fatal("x86_msr: unimplemented MSR 0x%08x\n", (int)regnr);
2963     cpu->running = 0;
2964     }
2965    
2966     if (!writeflag) {
2967     cpu->cd.x86.r[X86_R_AX] = odata & 0xffffffff;
2968     cpu->cd.x86.r[X86_R_DX] = (odata >> 32) & 0xffffffff;
2969     }
2970     }
2971    
2972    
2973     /*
2974     * cause_interrupt():
2975     *
2976     * Read the registers of PIC1 (and possibly PIC2) to find out which interrupt
2977     * has occured.
2978     *
2979     * Returns 1 if an interrupt happened, 0 otherwise (for example if the
2980     * in-service bit of an interrupt was already set).
2981     */
2982     int cause_interrupt(struct cpu *cpu)
2983     {
2984     int i, irq_nr = -1;
2985    
2986     for (i=0; i<8; i++) {
2987     if (cpu->machine->isa_pic_data.pic1->irr &
2988     (~cpu->machine->isa_pic_data.pic1->ier) & (1 << i))
2989     irq_nr = i;
2990     }
2991    
2992     if (irq_nr == 2) {
2993     for (i=0; i<8; i++) {
2994     if (cpu->machine->isa_pic_data.pic2->irr &
2995     (~cpu->machine->isa_pic_data.pic2->ier) & (1 << i))
2996     irq_nr = 8+i;
2997     }
2998     }
2999    
3000     if (irq_nr == 2) {
3001     fatal("cause_interrupt(): Huh? irq 2 but no secondary irq\n");
3002     cpu->running = 0;
3003     }
3004    
3005     /*
3006     * TODO: How about multiple interrupt levels?
3007     */
3008    
3009     #if 0
3010     printf("cause1: %i (irr1=%02x ier1=%02x, irr2=%02x ier2=%02x\n", irq_nr,
3011     cpu->machine->isa_pic_data.pic1->irr, cpu->machine->isa_pic_data.pic1->ier,
3012     cpu->machine->isa_pic_data.pic2->irr, cpu->machine->isa_pic_data.pic2->ier);
3013     #endif
3014    
3015     /* Set the in-service bit, and calculate actual INT nr: */
3016     if (irq_nr < 8) {
3017     if (cpu->machine->isa_pic_data.pic1->isr & (1 << irq_nr))
3018     return 0;
3019     cpu->machine->isa_pic_data.pic1->isr |= (1 << irq_nr);
3020     irq_nr = cpu->machine->isa_pic_data.pic1->irq_base + irq_nr;
3021     } else {
3022     if (cpu->machine->isa_pic_data.pic2->isr & (1 << (irq_nr & 7)))
3023     return 0;
3024     cpu->machine->isa_pic_data.pic2->isr |= (1 << (irq_nr&7));
3025     irq_nr = cpu->machine->isa_pic_data.pic2->irq_base +
3026     (irq_nr & 7);
3027     }
3028    
3029     /* printf("cause2: %i\n", irq_nr); */
3030    
3031     x86_interrupt(cpu, irq_nr, 0);
3032     cpu->cd.x86.halted = 0;
3033     return 1;
3034     }
3035    
3036    
3037 dpavlin 26 #define TRANSLATE_ADDRESS x86_translate_v2p
3038 dpavlin 14 #include "memory_x86.c"
3039     #undef TRANSLATE_ADDRESS
3040    
3041    
3042     #include "tmp_x86_tail.c"
3043    

  ViewVC Help
Powered by ViewVC 1.1.26