/[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 14 - (show annotations)
Mon Oct 8 16:18:51 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 86207 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.982 2005/10/07 22:45:32 debug Exp $
20050816	Some success in decoding the way the SGI O2 PROM draws graphics
		during bootup; lines/rectangles and bitmaps work, enough to
		show the bootlogo etc. :-)
		Adding more PPC instructions, and (dummy) BAT registers.
20050817	Updating the pckbc to support scancode type 3 keyboards
		(required in order to interact with the SGI O2 PROM).
		Adding more PPC instructions.
20050818	Adding more ARM instructions; general register forms.
		Importing armreg.h from NetBSD (ARM cpu ids). Adding a (dummy)
		CATS machine mode (using SA110 as the default CPU).
		Continuing on general dyntrans related stuff.
20050819	Register forms for ARM load/stores. Gaah! The Compaq C Compiler
		bug is triggered for ARM loads as well, not just PPC :-(
		Adding full support for ARM PC-relative load/stores, and load/
		stores where the PC register is the destination register.
		Adding support for ARM a.out binaries.
20050820	Continuing to add more ARM instructions, and correcting some
		bugs. Continuing on CATS emulation.
		More work on the PPC stuff.
20050821	Minor PPC and ARM updates. Adding more machine types.
20050822	All ARM "data processing instructions" are now generated
		automatically.
20050824	Beginning the work on the ARM system control coprocessor.
		Adding support for ARM halfword load/stores, and signed loads.
20050825	Fixing an important bug related to the ARM condition codes.
		OpenBSD/zaurus and NetBSD/netwinder now print some boot
		messages. :)
		Adding a dummy SH (Hitachi SuperH) cpu family.
		Beginning to add some ARM virtual address translation.
		MIPS bugfixes: unaligned PC now cause an ADEL exception (at
		least for non-bintrans execution), and ADEL/ADES (not
		TLBL/TLBS) are used if userland tries to access kernel space.
		(Thanks to Joshua Wise for making me aware of these bugs.)
20050827	More work on the ARM emulation, and various other updates.
20050828	More ARM updates.
		Finally taking the time to work on translation invalidation
		(i.e. invalidating translated code mappings when memory is
		written to). Hopefully this doesn't break anything.
20050829	Moving CPU related files from src/ to a new subdir, src/cpus/.
		Moving PROM emulation stuff from src/ to src/promemul/.
		Better debug instruction trace for ARM loads and stores.
20050830	Various ARM updates (correcting CMP flag calculation, etc).
20050831	PPC instruction updates. (Flag fixes, etc.)
20050901	Various minor PPC and ARM instruction emulation updates.
		Minor OpenFirmware emulation updates.
20050903	Adding support for adding arbitrary ARM coprocessors (with
		the i80321 I/O coprocessor as a first test).
		Various other ARM and PPC updates.
20050904	Adding some SHcompact disassembly routines.
20050907	(Re)adding a dummy HPPA CPU module, and a dummy i960 module.
20050908	Began hacking on some Apple Partition Table support.
20050909	Adding support for loading Mach-O (Darwin PPC) binaries.
20050910	Fixing an ARM bug (Carry flag was incorrectly updated for some
		data processing instructions); OpenBSD/cats and NetBSD/
		netwinder get quite a bit further now.
		Applying a patch to dev_wdc, and a one-liner to dev_pcic, to
		make them work better when emulating new versions of OpenBSD.
		(Thanks to Alexander Yurchenko for the patches.)
		Also doing some other minor updates to dev_wdc. (Some cleanup,
		and finally converting to devinit, etc.)
20050912	IRIX doesn't have u_int64_t by default (noticed by Andreas
		<avr@gnulinux.nl>); configure updated to reflect this.
		Working on ARM register bank switching, CPSR vs SPSR issues,
		and beginning the work on interrupt/exception support.
20050913	Various minor ARM updates (speeding up load/store multiple,
		and fixing a ROR bug in R(); NetBSD/cats now boots as far as
		OpenBSD/cats).
20050917	Adding a dummy Atmel AVR (8-bit) cpu family skeleton.
20050918	Various minor updates.
20050919	Symbols are now loaded from Mach-O executables.
		Continuing the work on adding ARM exception support.
20050920	More work on ARM stuff: OpenBSD/cats and NetBSD/cats reach
		userland! :-)
20050921	Some more progress on ARM interrupt specifics.
20050923	Fixing linesize for VR4121 (patch by Yurchenko). Also fixing
		linesizes/cachesizes for some other VR4xxx.
		Adding a dummy Acer Labs M1543 PCI-ISA bridge (for CATS) and a
		dummy Symphony Labs 83C553 bridge (for Netwinder), usable by 
		dev_footbridge.
20050924	Some PPC progress.
20050925	More PPC progress.
20050926	PPC progress (fixing some bugs etc); Darwin's kernel gets
		slightly further than before.
20050928	Various updates: footbridge/ISA/pciide stuff, and finally
		fixing the VGA text scroll-by-changing-the-base-offset bug.
20050930	Adding a dummy S3 ViRGE pci card for CATS emulation, which
		both NetBSD and OpenBSD detects as VGA.
		Continuing on Footbridge (timers, ISA interrupt stuff).
20051001	Continuing... there are still bugs, probably interrupt-
		related.
20051002	More work on the Footbridge (interrupt stuff).
20051003	Various minor updates. (Trying to find the bug(s).)
20051004	Continuing on the ARM stuff.
20051005	More ARM-related fixes.
20051007	FINALLY! Found and fixed 2 ARM bugs: 1 memory related, and the
		other was because of an error in the ARM manual (load multiple
		with the S-bit set should _NOT_ load usermode registers, as the
		manual says, but it should load saved registers, which may or
		may not happen to be usermode registers).
		NetBSD/cats and OpenBSD/cats seem to install fine now :-)
		except for a minor bug at the end of the OpenBSD/cats install.
		Updating the documentation, preparing for the next release.
20051008	Continuing with release testing and cleanup.

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

  ViewVC Help
Powered by ViewVC 1.1.26