/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (show annotations)
Mon Oct 8 16:20:58 2007 UTC (13 years 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 /*
2 * Copyright (C) 2005-2006 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: cpu_x86.c,v 1.18 2006/09/23 03:49:02 debug Exp $
29 *
30 * x86 (and amd64) CPU emulation.
31 *
32 *
33 * 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 *
37 * Right now, it is completely bogus.
38 */
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 #include "settings.h"
51 #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 cpu->translate_v2p = x86_translate_v2p;
94
95 /* 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 cpu->cd.x86.cursegment = X86_S_CS;
110
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 cpu->is_32bit = (cpu->cd.x86.model.model_number < X86_MODEL_AMD64)?
119 1 : 0;
120
121 if (cpu->is_32bit) {
122 cpu->run_instr = x8632_run_instr;
123 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 cpu->run_instr = x86_run_instr;
130 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 /* 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 /*
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 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 for (j=0; j<10-(int)strlen(models[i].name); j++)
205 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 if (LONG_MODE) {
226 /* 64-bit long mode: */
227 symbol = get_symbol_name(&cpu->machine->symbol_context,
228 cpu->pc, &offset);
229
230 debug("cpu%i: rip = 0x%016"PRIx64, x, cpu->pc);
231 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
232
233 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 } else {
265 /* 32-bit protected mode: */
266 symbol = get_symbol_name(&cpu->machine->symbol_context,
267 cpu->pc, &offset);
268
269 debug("cpu%i: eip=0x%08"PRIx32, x, (uint32_t)cpu->pc);
270 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
271
272 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 }
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 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 }
331
332 if (PROTECTED_MODE) {
333 /* Protected mode: */
334 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 }
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 uint32_t read_imm(unsigned char **instrp, uint64_t *newpcp,
393 int mode)
394 {
395 return read_imm_common(instrp, newpcp, mode, 0);
396 }
397
398
399 void print_csip(struct cpu *cpu)
400 {
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 * 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 * 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 fatal("WARNING: tr_limit = 0x%"PRIx16", must be at least "
567 "0x67!\n", (uint16_t)cpu->cd.x86.tr_limit);
568
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 uint64_t base, limit, table_base;
625 int64_t table_limit;
626
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 int running, uint64_t dumpaddr)
1405 {
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 void x86_cpuid(struct cpu *cpu)
2341 {
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 if (nr * 8 > (int)cpu->cd.x86.idtr_limit) {
2509 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 if (nr * 4 > (int)cpu->cd.x86.idtr_limit) {
2651 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 #define TRANSLATE_ADDRESS x86_translate_v2p
3038 #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