/[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 20 - (show annotations)
Mon Oct 8 16:19:23 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 86242 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1055 2005/11/25 22:48:36 debug Exp $
20051031	Adding disassembly support for more ARM instructions (clz,
		smul* etc), and adding a hack to support "new tiny" pages
		for StrongARM.
20051101	Minor documentation updates (NetBSD 2.0.2 -> 2.1, and OpenBSD
		3.7 -> 3.8, and lots of testing).
		Changing from 1-sector PIO mode 0 transfers to 128-sector PIO
		mode 3 (in dev_wdc).
		Various minor ARM dyntrans updates (pc-relative loads from
		within the same page as the instruction are now treated as
		constant "mov").
20051102	Re-enabling instruction combinations (they were accidentally
		disabled).
		Dyntrans TLB entries are now overwritten using a round-robin
		scheme instead of randomly. This increases performance.
		Fixing a typo in file.c (thanks to Chuan-Hua Chang for
		noticing it).
		Experimenting with adding ATAPI support to dev_wdc (to make
		emulated *BSD detect cdroms as cdroms, not harddisks).
20051104	Various minor updates.
20051105	Continuing on the ATAPI emulation. Seems to work well enough
		for a NetBSD/cats installation, but not OpenBSD/cats.
		Various other updates.
20051106	Modifying the -Y command line option to allow scaleup with
		certain graphic controllers (only dev_vga so far), not just
		scaledown.
		Some minor dyntrans cleanups.
20051107	Beginning a cleanup up the PCI subsystem (removing the
		read_register hack, etc).
20051108	Continuing the cleanup; splitting up some pci devices into a
		normal autodev device and some separate pci glue code.
20051109	Continuing on the PCI bus stuff; all old pci_*.c have been
		incorporated into normal devices and/or rewritten as glue code
		only, adding a dummy Intel 82371AB PIIX4 for Malta (not really
		tested yet).
		Minor pckbc fix so that Linux doesn't complain.
		Working on the DEC 21143 NIC (ethernet mac rom stuff mostly).
		Various other minor fixes.
20051110	Some more ARM dyntrans fine-tuning (e.g. some instruction
		combinations (cmps followed by conditional branch within the
		same page) and special cases for DPIs with regform when the
		shifter isn't used).
20051111	ARM dyntrans updates: O(n)->O(1) for just-mark-as-non-
		writable in the generic pc_to_pointers function, and some other
		minor hacks.
		Merging Cobalt and evbmips (Malta) ISA interrupt handling,
		and some minor fixes to allow Linux to accept harddisk irqs.
20051112	Minor device updates (pckbc, dec21143, lpt, ...), most
		importantly fixing the ALI M1543/M5229 so that harddisk irqs
		work with Linux/CATS.
20051113	Some more generalizations of the PCI subsystem.
		Finally took the time to add a hack for SCSI CDROM TOCs; this
		enables OpenBSD to use partition 'a' (as needed by the OpenBSD
		installer), and Windows NT's installer to get a bit further.
		Also fixing dev_wdc to allow Linux to detect ATAPI CDROMs.
		Continuing on the DEC 21143.
20051114	Minor ARM dyntrans tweaks; ARM cmps+branch optimization when
		comparing with 0, and generalizing the xchg instr. comb.
		Adding disassembly of ARM mrrc/mcrr and q{,d}{add,sub}.
20051115	Continuing on various PPC things (BATs, other address trans-
		lation things, various loads/stores, BeBox emulation, etc.).
		Beginning to work on PPC interrupt/exception support.
20051116	Factoring out some code which initializes legacy ISA devices
		from those machines that use them (bus_isa).
		Continuing on PPC interrupt/exception support.
20051117	Minor Malta fixes: RTC year offset = 80, disabling a speed hack
		which caused NetBSD to detect a too fast cpu, and adding a new
		hack to make Linux detect a faster cpu.
		Continuing on the Artesyn PM/PPC emulation mode.
		Adding an Algor emulation skeleton (P4032 and P5064);
		implementing some of the basics.
		Continuing on PPC emulation in general; usage of unimplemented
		SPRs is now easier to track, continuing on memory/exception
		related issues, etc.
20051118	More work on PPC emulation (tgpr0..3, exception handling,
		memory stuff, syscalls, etc.).
20051119	Changing the ARM dyntrans code to mostly use cpu->pc, and not
		necessarily use arm reg 15. Seems to work.
		Various PPC updates; continuing on the PReP emulation mode.
20051120	Adding a workaround/hack to dev_mc146818 to allow NetBSD/prep
		to detect the clock.
20051121	More cleanup of the PCI bus (memory and I/O bases, etc).
		Continuing on various PPC things (decrementer and timebase,
		WDCs on obio (on PReP) use irq 13, not 14/15).
20051122	Continuing on the CPC700 controller (interrupts etc) for PMPPC,
		and on PPC stuff in general.
		Finally! After some bug fixes to the virtual to physical addr
		translation, NetBSD/{prep,pmppc} 2.1 reach userland and are
		stable enough to be interacted with.
		More PCI updates; reverse-endian device access for PowerPC etc.
20051123	Generalizing the IEEE floating point subsystem (moving it out
		from src/cpus/cpu_mips_coproc.c into a new src/float_emul.c).
		Input via slave xterms was sometimes not really working; fixing
		this for ns16550, and a warning message is now displayed if
		multiple non-xterm consoles are active.
		Adding some PPC floating point support, etc.
		Various interrupt related updates (dev_wdc, _ns16550, _8259,
		and the isa32 common code in machine.c).
		NetBSD/prep can now be installed! :-) (Well, with some manual
		commands necessary before running sysinst.) Updating the
		documentation and various other things to reflect this.
20051124	Various minor documentation updates.
		Continuing the work on the DEC 21143 NIC.
20051125	LOTS of work on the 21143. Both OpenBSD and NetBSD work fine
		with it now, except that OpenBSD sometimes gives a time-out
		warning.
		Minor documentation updates.

==============  RELEASE 0.3.7  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26