Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /**************************************************************************** |
2 | * | |
3 | * Realmode X86 Emulator Library | |
4 | * | |
5 | * Copyright (C) 1996-1999 SciTech Software, Inc. | |
6 | * Copyright (C) David Mosberger-Tang | |
7 | * Copyright (C) 1999 Egbert Eich | |
8 | * | |
9 | * ======================================================================== | |
10 | * | |
11 | * Permission to use, copy, modify, distribute, and sell this software and | |
12 | * its documentation for any purpose is hereby granted without fee, | |
13 | * provided that the above copyright notice appear in all copies and that | |
14 | * both that copyright notice and this permission notice appear in | |
15 | * supporting documentation, and that the name of the authors not be used | |
16 | * in advertising or publicity pertaining to distribution of the software | |
17 | * without specific, written prior permission. The authors makes no | |
18 | * representations about the suitability of this software for any purpose. | |
19 | * It is provided "as is" without express or implied warranty. | |
20 | * | |
21 | * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | |
22 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | |
23 | * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR | |
24 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF | |
25 | * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR | |
26 | * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | |
27 | * PERFORMANCE OF THIS SOFTWARE. | |
28 | * | |
29 | * ======================================================================== | |
30 | * | |
31 | * Language: ANSI C | |
32 | * Environment: Any | |
33 | * Developer: Kendall Bennett | |
34 | * | |
35 | * Description: This file includes subroutines which are related to | |
36 | * instruction decoding and accessess of immediate data via IP. etc. | |
37 | * | |
38 | ****************************************************************************/ | |
39 | ||
40 | #include <stdlib.h> | |
41 | ||
42 | #if defined(__sun) && defined(CS) /* avoid conflicts with Solaris sys/regset.h */ | |
43 | # undef CS | |
44 | # undef DS | |
45 | # undef SS | |
46 | # undef ES | |
47 | # undef FS | |
48 | # undef GS | |
49 | #endif | |
50 | ||
51 | #include "x86emu/x86emui.h" | |
52 | ||
53 | /*----------------------------- Implementation ----------------------------*/ | |
54 | ||
55 | /**************************************************************************** | |
56 | REMARKS: | |
57 | Handles any pending asychronous interrupts. | |
58 | ****************************************************************************/ | |
59 | static void | |
60 | x86emu_intr_handle(void) | |
61 | { | |
62 | u8 intno; | |
63 | ||
64 | if (M.x86.intr & INTR_SYNCH) { | |
65 | intno = M.x86.intno; | |
66 | if (_X86EMU_intrTab[intno]) { | |
67 | (*_X86EMU_intrTab[intno]) (intno); | |
68 | } | |
69 | else { | |
70 | push_word((u16) M.x86.R_FLG); | |
71 | CLEAR_FLAG(F_IF); | |
72 | CLEAR_FLAG(F_TF); | |
73 | push_word(M.x86.R_CS); | |
74 | M.x86.R_CS = mem_access_word(intno * 4 + 2); | |
75 | push_word(M.x86.R_IP); | |
76 | M.x86.R_IP = mem_access_word(intno * 4); | |
77 | M.x86.intr = 0; | |
78 | } | |
79 | } | |
80 | } | |
81 | ||
82 | /**************************************************************************** | |
83 | PARAMETERS: | |
84 | intrnum - Interrupt number to raise | |
85 | ||
86 | REMARKS: | |
87 | Raise the specified interrupt to be handled before the execution of the | |
88 | next instruction. | |
89 | ****************************************************************************/ | |
90 | void | |
91 | x86emu_intr_raise(u8 intrnum) | |
92 | { | |
93 | M.x86.intno = intrnum; | |
94 | M.x86.intr |= INTR_SYNCH; | |
95 | } | |
96 | ||
97 | /**************************************************************************** | |
98 | REMARKS: | |
99 | Main execution loop for the emulator. We return from here when the system | |
100 | halts, which is normally caused by a stack fault when we return from the | |
101 | original real mode call. | |
102 | ****************************************************************************/ | |
103 | void | |
104 | X86EMU_exec(void) | |
105 | { | |
106 | u8 op1; | |
107 | ||
108 | M.x86.intr = 0; | |
109 | DB(x86emu_end_instr(); | |
110 | ) | |
111 | ||
112 | for (;;) { | |
113 | DB(if (CHECK_IP_FETCH()) | |
114 | x86emu_check_ip_access();) | |
115 | /* If debugging, save the IP and CS values. */ | |
116 | SAVE_IP_CS(M.x86.R_CS, M.x86.R_IP); | |
117 | INC_DECODED_INST_LEN(1); | |
118 | if (M.x86.intr) { | |
119 | if (M.x86.intr & INTR_HALTED) { | |
120 | DB(if (M.x86.R_SP != 0) { | |
121 | printk("halted\n"); X86EMU_trace_regs();} | |
122 | else { | |
123 | if (M.x86.debug) | |
124 | printk("Service completed successfully\n");} | |
125 | ) | |
126 | return; | |
127 | } | |
128 | if (((M.x86.intr & INTR_SYNCH) && | |
129 | (M.x86.intno == 0 || M.x86.intno == 2)) || | |
130 | !ACCESS_FLAG(F_IF)) { | |
131 | x86emu_intr_handle(); | |
132 | } | |
133 | } | |
134 | op1 = (*sys_rdb) (((u32) M.x86.R_CS << 4) + (M.x86.R_IP++)); | |
135 | (*x86emu_optab[op1]) (op1); | |
136 | if (M.x86.debug & DEBUG_EXIT) { | |
137 | M.x86.debug &= ~DEBUG_EXIT; | |
138 | return; | |
139 | } | |
140 | } | |
141 | } | |
142 | ||
143 | /**************************************************************************** | |
144 | REMARKS: | |
145 | Halts the system by setting the halted system flag. | |
146 | ****************************************************************************/ | |
147 | void | |
148 | X86EMU_halt_sys(void) | |
149 | { | |
150 | M.x86.intr |= INTR_HALTED; | |
151 | } | |
152 | ||
153 | /**************************************************************************** | |
154 | PARAMETERS: | |
155 | mod - Mod value from decoded byte | |
156 | regh - Reg h value from decoded byte | |
157 | regl - Reg l value from decoded byte | |
158 | ||
159 | REMARKS: | |
160 | Raise the specified interrupt to be handled before the execution of the | |
161 | next instruction. | |
162 | ||
163 | NOTE: Do not inline this function, as (*sys_rdb) is already inline! | |
164 | ****************************************************************************/ | |
165 | void | |
166 | fetch_decode_modrm(int *mod, int *regh, int *regl) | |
167 | { | |
168 | int fetched; | |
169 | ||
170 | DB(if (CHECK_IP_FETCH()) | |
171 | x86emu_check_ip_access();) | |
172 | fetched = (*sys_rdb) (((u32) M.x86.R_CS << 4) + (M.x86.R_IP++)); | |
173 | INC_DECODED_INST_LEN(1); | |
174 | *mod = (fetched >> 6) & 0x03; | |
175 | *regh = (fetched >> 3) & 0x07; | |
176 | *regl = (fetched >> 0) & 0x07; | |
177 | } | |
178 | ||
179 | /**************************************************************************** | |
180 | RETURNS: | |
181 | Immediate byte value read from instruction queue | |
182 | ||
183 | REMARKS: | |
184 | This function returns the immediate byte from the instruction queue, and | |
185 | moves the instruction pointer to the next value. | |
186 | ||
187 | NOTE: Do not inline this function, as (*sys_rdb) is already inline! | |
188 | ****************************************************************************/ | |
189 | u8 | |
190 | fetch_byte_imm(void) | |
191 | { | |
192 | u8 fetched; | |
193 | ||
194 | DB(if (CHECK_IP_FETCH()) | |
195 | x86emu_check_ip_access();) | |
196 | fetched = (*sys_rdb) (((u32) M.x86.R_CS << 4) + (M.x86.R_IP++)); | |
197 | INC_DECODED_INST_LEN(1); | |
198 | return fetched; | |
199 | } | |
200 | ||
201 | /**************************************************************************** | |
202 | RETURNS: | |
203 | Immediate word value read from instruction queue | |
204 | ||
205 | REMARKS: | |
206 | This function returns the immediate byte from the instruction queue, and | |
207 | moves the instruction pointer to the next value. | |
208 | ||
209 | NOTE: Do not inline this function, as (*sys_rdw) is already inline! | |
210 | ****************************************************************************/ | |
211 | u16 | |
212 | fetch_word_imm(void) | |
213 | { | |
214 | u16 fetched; | |
215 | ||
216 | DB(if (CHECK_IP_FETCH()) | |
217 | x86emu_check_ip_access();) | |
218 | fetched = (*sys_rdw) (((u32) M.x86.R_CS << 4) + (M.x86.R_IP)); | |
219 | M.x86.R_IP += 2; | |
220 | INC_DECODED_INST_LEN(2); | |
221 | return fetched; | |
222 | } | |
223 | ||
224 | /**************************************************************************** | |
225 | RETURNS: | |
226 | Immediate lone value read from instruction queue | |
227 | ||
228 | REMARKS: | |
229 | This function returns the immediate byte from the instruction queue, and | |
230 | moves the instruction pointer to the next value. | |
231 | ||
232 | NOTE: Do not inline this function, as (*sys_rdw) is already inline! | |
233 | ****************************************************************************/ | |
234 | u32 | |
235 | fetch_long_imm(void) | |
236 | { | |
237 | u32 fetched; | |
238 | ||
239 | DB(if (CHECK_IP_FETCH()) | |
240 | x86emu_check_ip_access();) | |
241 | fetched = (*sys_rdl) (((u32) M.x86.R_CS << 4) + (M.x86.R_IP)); | |
242 | M.x86.R_IP += 4; | |
243 | INC_DECODED_INST_LEN(4); | |
244 | return fetched; | |
245 | } | |
246 | ||
247 | /**************************************************************************** | |
248 | RETURNS: | |
249 | Value of the default data segment | |
250 | ||
251 | REMARKS: | |
252 | Inline function that returns the default data segment for the current | |
253 | instruction. | |
254 | ||
255 | On the x86 processor, the default segment is not always DS if there is | |
256 | no segment override. Address modes such as -3[BP] or 10[BP+SI] all refer to | |
257 | addresses relative to SS (ie: on the stack). So, at the minimum, all | |
258 | decodings of addressing modes would have to set/clear a bit describing | |
259 | whether the access is relative to DS or SS. That is the function of the | |
260 | cpu-state-varible M.x86.mode. There are several potential states: | |
261 | ||
262 | repe prefix seen (handled elsewhere) | |
263 | repne prefix seen (ditto) | |
264 | ||
265 | cs segment override | |
266 | ds segment override | |
267 | es segment override | |
268 | fs segment override | |
269 | gs segment override | |
270 | ss segment override | |
271 | ||
272 | ds/ss select (in absense of override) | |
273 | ||
274 | Each of the above 7 items are handled with a bit in the mode field. | |
275 | ****************************************************************************/ | |
276 | _INLINE u32 | |
277 | get_data_segment(void) | |
278 | { | |
279 | #define GET_SEGMENT(segment) | |
280 | switch (M.x86.mode & SYSMODE_SEGMASK) { | |
281 | case 0: /* default case: use ds register */ | |
282 | case SYSMODE_SEGOVR_DS: | |
283 | case SYSMODE_SEGOVR_DS | SYSMODE_SEG_DS_SS: | |
284 | return M.x86.R_DS; | |
285 | case SYSMODE_SEG_DS_SS: /* non-overridden, use ss register */ | |
286 | return M.x86.R_SS; | |
287 | case SYSMODE_SEGOVR_CS: | |
288 | case SYSMODE_SEGOVR_CS | SYSMODE_SEG_DS_SS: | |
289 | return M.x86.R_CS; | |
290 | case SYSMODE_SEGOVR_ES: | |
291 | case SYSMODE_SEGOVR_ES | SYSMODE_SEG_DS_SS: | |
292 | return M.x86.R_ES; | |
293 | case SYSMODE_SEGOVR_FS: | |
294 | case SYSMODE_SEGOVR_FS | SYSMODE_SEG_DS_SS: | |
295 | return M.x86.R_FS; | |
296 | case SYSMODE_SEGOVR_GS: | |
297 | case SYSMODE_SEGOVR_GS | SYSMODE_SEG_DS_SS: | |
298 | return M.x86.R_GS; | |
299 | case SYSMODE_SEGOVR_SS: | |
300 | case SYSMODE_SEGOVR_SS | SYSMODE_SEG_DS_SS: | |
301 | return M.x86.R_SS; | |
302 | default: | |
303 | #ifdef DEBUG | |
304 | printk("error: should not happen: multiple overrides.\n"); | |
305 | #endif | |
306 | HALT_SYS(); | |
307 | return 0; | |
308 | } | |
309 | } | |
310 | ||
311 | /**************************************************************************** | |
312 | PARAMETERS: | |
313 | offset - Offset to load data from | |
314 | ||
315 | RETURNS: | |
316 | Byte value read from the absolute memory location. | |
317 | ||
318 | NOTE: Do not inline this function as (*sys_rdX) is already inline! | |
319 | ****************************************************************************/ | |
320 | u8 | |
321 | fetch_data_byte(uint offset) | |
322 | { | |
323 | #ifdef DEBUG | |
324 | if (CHECK_DATA_ACCESS()) | |
325 | x86emu_check_data_access((u16) get_data_segment(), offset); | |
326 | #endif | |
327 | return (*sys_rdb) ((get_data_segment() << 4) + offset); | |
328 | } | |
329 | ||
330 | /**************************************************************************** | |
331 | PARAMETERS: | |
332 | offset - Offset to load data from | |
333 | ||
334 | RETURNS: | |
335 | Word value read from the absolute memory location. | |
336 | ||
337 | NOTE: Do not inline this function as (*sys_rdX) is already inline! | |
338 | ****************************************************************************/ | |
339 | u16 | |
340 | fetch_data_word(uint offset) | |
341 | { | |
342 | #ifdef DEBUG | |
343 | if (CHECK_DATA_ACCESS()) | |
344 | x86emu_check_data_access((u16) get_data_segment(), offset); | |
345 | #endif | |
346 | return (*sys_rdw) ((get_data_segment() << 4) + offset); | |
347 | } | |
348 | ||
349 | /**************************************************************************** | |
350 | PARAMETERS: | |
351 | offset - Offset to load data from | |
352 | ||
353 | RETURNS: | |
354 | Long value read from the absolute memory location. | |
355 | ||
356 | NOTE: Do not inline this function as (*sys_rdX) is already inline! | |
357 | ****************************************************************************/ | |
358 | u32 | |
359 | fetch_data_long(uint offset) | |
360 | { | |
361 | #ifdef DEBUG | |
362 | if (CHECK_DATA_ACCESS()) | |
363 | x86emu_check_data_access((u16) get_data_segment(), offset); | |
364 | #endif | |
365 | return (*sys_rdl) ((get_data_segment() << 4) + offset); | |
366 | } | |
367 | ||
368 | /**************************************************************************** | |
369 | PARAMETERS: | |
370 | segment - Segment to load data from | |
371 | offset - Offset to load data from | |
372 | ||
373 | RETURNS: | |
374 | Byte value read from the absolute memory location. | |
375 | ||
376 | NOTE: Do not inline this function as (*sys_rdX) is already inline! | |
377 | ****************************************************************************/ | |
378 | u8 | |
379 | fetch_data_byte_abs(uint segment, uint offset) | |
380 | { | |
381 | #ifdef DEBUG | |
382 | if (CHECK_DATA_ACCESS()) | |
383 | x86emu_check_data_access(segment, offset); | |
384 | #endif | |
385 | return (*sys_rdb) (((u32) segment << 4) + offset); | |
386 | } | |
387 | ||
388 | /**************************************************************************** | |
389 | PARAMETERS: | |
390 | segment - Segment to load data from | |
391 | offset - Offset to load data from | |
392 | ||
393 | RETURNS: | |
394 | Word value read from the absolute memory location. | |
395 | ||
396 | NOTE: Do not inline this function as (*sys_rdX) is already inline! | |
397 | ****************************************************************************/ | |
398 | u16 | |
399 | fetch_data_word_abs(uint segment, uint offset) | |
400 | { | |
401 | #ifdef DEBUG | |
402 | if (CHECK_DATA_ACCESS()) | |
403 | x86emu_check_data_access(segment, offset); | |
404 | #endif | |
405 | return (*sys_rdw) (((u32) segment << 4) + offset); | |
406 | } | |
407 | ||
408 | /**************************************************************************** | |
409 | PARAMETERS: | |
410 | segment - Segment to load data from | |
411 | offset - Offset to load data from | |
412 | ||
413 | RETURNS: | |
414 | Long value read from the absolute memory location. | |
415 | ||
416 | NOTE: Do not inline this function as (*sys_rdX) is already inline! | |
417 | ****************************************************************************/ | |
418 | u32 | |
419 | fetch_data_long_abs(uint segment, uint offset) | |
420 | { | |
421 | #ifdef DEBUG | |
422 | if (CHECK_DATA_ACCESS()) | |
423 | x86emu_check_data_access(segment, offset); | |
424 | #endif | |
425 | return (*sys_rdl) (((u32) segment << 4) + offset); | |
426 | } | |
427 | ||
428 | /**************************************************************************** | |
429 | PARAMETERS: | |
430 | offset - Offset to store data at | |
431 | val - Value to store | |
432 | ||
433 | REMARKS: | |
434 | Writes a word value to an segmented memory location. The segment used is | |
435 | the current 'default' segment, which may have been overridden. | |
436 | ||
437 | NOTE: Do not inline this function as (*sys_wrX) is already inline! | |
438 | ****************************************************************************/ | |
439 | void | |
440 | store_data_byte(uint offset, u8 val) | |
441 | { | |
442 | #ifdef DEBUG | |
443 | if (CHECK_DATA_ACCESS()) | |
444 | x86emu_check_data_access((u16) get_data_segment(), offset); | |
445 | #endif | |
446 | (*sys_wrb) ((get_data_segment() << 4) + offset, val); | |
447 | } | |
448 | ||
449 | /**************************************************************************** | |
450 | PARAMETERS: | |
451 | offset - Offset to store data at | |
452 | val - Value to store | |
453 | ||
454 | REMARKS: | |
455 | Writes a word value to an segmented memory location. The segment used is | |
456 | the current 'default' segment, which may have been overridden. | |
457 | ||
458 | NOTE: Do not inline this function as (*sys_wrX) is already inline! | |
459 | ****************************************************************************/ | |
460 | void | |
461 | store_data_word(uint offset, u16 val) | |
462 | { | |
463 | #ifdef DEBUG | |
464 | if (CHECK_DATA_ACCESS()) | |
465 | x86emu_check_data_access((u16) get_data_segment(), offset); | |
466 | #endif | |
467 | (*sys_wrw) ((get_data_segment() << 4) + offset, val); | |
468 | } | |
469 | ||
470 | /**************************************************************************** | |
471 | PARAMETERS: | |
472 | offset - Offset to store data at | |
473 | val - Value to store | |
474 | ||
475 | REMARKS: | |
476 | Writes a long value to an segmented memory location. The segment used is | |
477 | the current 'default' segment, which may have been overridden. | |
478 | ||
479 | NOTE: Do not inline this function as (*sys_wrX) is already inline! | |
480 | ****************************************************************************/ | |
481 | void | |
482 | store_data_long(uint offset, u32 val) | |
483 | { | |
484 | #ifdef DEBUG | |
485 | if (CHECK_DATA_ACCESS()) | |
486 | x86emu_check_data_access((u16) get_data_segment(), offset); | |
487 | #endif | |
488 | (*sys_wrl) ((get_data_segment() << 4) + offset, val); | |
489 | } | |
490 | ||
491 | /**************************************************************************** | |
492 | PARAMETERS: | |
493 | segment - Segment to store data at | |
494 | offset - Offset to store data at | |
495 | val - Value to store | |
496 | ||
497 | REMARKS: | |
498 | Writes a byte value to an absolute memory location. | |
499 | ||
500 | NOTE: Do not inline this function as (*sys_wrX) is already inline! | |
501 | ****************************************************************************/ | |
502 | void | |
503 | store_data_byte_abs(uint segment, uint offset, u8 val) | |
504 | { | |
505 | #ifdef DEBUG | |
506 | if (CHECK_DATA_ACCESS()) | |
507 | x86emu_check_data_access(segment, offset); | |
508 | #endif | |
509 | (*sys_wrb) (((u32) segment << 4) + offset, val); | |
510 | } | |
511 | ||
512 | /**************************************************************************** | |
513 | PARAMETERS: | |
514 | segment - Segment to store data at | |
515 | offset - Offset to store data at | |
516 | val - Value to store | |
517 | ||
518 | REMARKS: | |
519 | Writes a word value to an absolute memory location. | |
520 | ||
521 | NOTE: Do not inline this function as (*sys_wrX) is already inline! | |
522 | ****************************************************************************/ | |
523 | void | |
524 | store_data_word_abs(uint segment, uint offset, u16 val) | |
525 | { | |
526 | #ifdef DEBUG | |
527 | if (CHECK_DATA_ACCESS()) | |
528 | x86emu_check_data_access(segment, offset); | |
529 | #endif | |
530 | (*sys_wrw) (((u32) segment << 4) + offset, val); | |
531 | } | |
532 | ||
533 | /**************************************************************************** | |
534 | PARAMETERS: | |
535 | segment - Segment to store data at | |
536 | offset - Offset to store data at | |
537 | val - Value to store | |
538 | ||
539 | REMARKS: | |
540 | Writes a long value to an absolute memory location. | |
541 | ||
542 | NOTE: Do not inline this function as (*sys_wrX) is already inline! | |
543 | ****************************************************************************/ | |
544 | void | |
545 | store_data_long_abs(uint segment, uint offset, u32 val) | |
546 | { | |
547 | #ifdef DEBUG | |
548 | if (CHECK_DATA_ACCESS()) | |
549 | x86emu_check_data_access(segment, offset); | |
550 | #endif | |
551 | (*sys_wrl) (((u32) segment << 4) + offset, val); | |
552 | } | |
553 | ||
554 | /**************************************************************************** | |
555 | PARAMETERS: | |
556 | reg - Register to decode | |
557 | ||
558 | RETURNS: | |
559 | Pointer to the appropriate register | |
560 | ||
561 | REMARKS: | |
562 | Return a pointer to the register given by the R/RM field of the | |
563 | modrm byte, for byte operands. Also enables the decoding of instructions. | |
564 | ****************************************************************************/ | |
565 | u8 * | |
566 | decode_rm_byte_register(int reg) | |
567 | { | |
568 | switch (reg) { | |
569 | case 0: | |
570 | DECODE_PRINTF("AL"); | |
571 | return &M.x86.R_AL; | |
572 | case 1: | |
573 | DECODE_PRINTF("CL"); | |
574 | return &M.x86.R_CL; | |
575 | case 2: | |
576 | DECODE_PRINTF("DL"); | |
577 | return &M.x86.R_DL; | |
578 | case 3: | |
579 | DECODE_PRINTF("BL"); | |
580 | return &M.x86.R_BL; | |
581 | case 4: | |
582 | DECODE_PRINTF("AH"); | |
583 | return &M.x86.R_AH; | |
584 | case 5: | |
585 | DECODE_PRINTF("CH"); | |
586 | return &M.x86.R_CH; | |
587 | case 6: | |
588 | DECODE_PRINTF("DH"); | |
589 | return &M.x86.R_DH; | |
590 | case 7: | |
591 | DECODE_PRINTF("BH"); | |
592 | return &M.x86.R_BH; | |
593 | } | |
594 | HALT_SYS(); | |
595 | return NULL; /* NOT REACHED OR REACHED ON ERROR */ | |
596 | } | |
597 | ||
598 | /**************************************************************************** | |
599 | PARAMETERS: | |
600 | reg - Register to decode | |
601 | ||
602 | RETURNS: | |
603 | Pointer to the appropriate register | |
604 | ||
605 | REMARKS: | |
606 | Return a pointer to the register given by the R/RM field of the | |
607 | modrm byte, for word operands. Also enables the decoding of instructions. | |
608 | ****************************************************************************/ | |
609 | u16 * | |
610 | decode_rm_word_register(int reg) | |
611 | { | |
612 | switch (reg) { | |
613 | case 0: | |
614 | DECODE_PRINTF("AX"); | |
615 | return &M.x86.R_AX; | |
616 | case 1: | |
617 | DECODE_PRINTF("CX"); | |
618 | return &M.x86.R_CX; | |
619 | case 2: | |
620 | DECODE_PRINTF("DX"); | |
621 | return &M.x86.R_DX; | |
622 | case 3: | |
623 | DECODE_PRINTF("BX"); | |
624 | return &M.x86.R_BX; | |
625 | case 4: | |
626 | DECODE_PRINTF("SP"); | |
627 | return &M.x86.R_SP; | |
628 | case 5: | |
629 | DECODE_PRINTF("BP"); | |
630 | return &M.x86.R_BP; | |
631 | case 6: | |
632 | DECODE_PRINTF("SI"); | |
633 | return &M.x86.R_SI; | |
634 | case 7: | |
635 | DECODE_PRINTF("DI"); | |
636 | return &M.x86.R_DI; | |
637 | } | |
638 | HALT_SYS(); | |
639 | return NULL; /* NOTREACHED OR REACHED ON ERROR */ | |
640 | } | |
641 | ||
642 | /**************************************************************************** | |
643 | PARAMETERS: | |
644 | reg - Register to decode | |
645 | ||
646 | RETURNS: | |
647 | Pointer to the appropriate register | |
648 | ||
649 | REMARKS: | |
650 | Return a pointer to the register given by the R/RM field of the | |
651 | modrm byte, for dword operands. Also enables the decoding of instructions. | |
652 | ****************************************************************************/ | |
653 | u32 * | |
654 | decode_rm_long_register(int reg) | |
655 | { | |
656 | switch (reg) { | |
657 | case 0: | |
658 | DECODE_PRINTF("EAX"); | |
659 | return &M.x86.R_EAX; | |
660 | case 1: | |
661 | DECODE_PRINTF("ECX"); | |
662 | return &M.x86.R_ECX; | |
663 | case 2: | |
664 | DECODE_PRINTF("EDX"); | |
665 | return &M.x86.R_EDX; | |
666 | case 3: | |
667 | DECODE_PRINTF("EBX"); | |
668 | return &M.x86.R_EBX; | |
669 | case 4: | |
670 | DECODE_PRINTF("ESP"); | |
671 | return &M.x86.R_ESP; | |
672 | case 5: | |
673 | DECODE_PRINTF("EBP"); | |
674 | return &M.x86.R_EBP; | |
675 | case 6: | |
676 | DECODE_PRINTF("ESI"); | |
677 | return &M.x86.R_ESI; | |
678 | case 7: | |
679 | DECODE_PRINTF("EDI"); | |
680 | return &M.x86.R_EDI; | |
681 | } | |
682 | HALT_SYS(); | |
683 | return NULL; /* NOTREACHED OR REACHED ON ERROR */ | |
684 | } | |
685 | ||
686 | /**************************************************************************** | |
687 | PARAMETERS: | |
688 | reg - Register to decode | |
689 | ||
690 | RETURNS: | |
691 | Pointer to the appropriate register | |
692 | ||
693 | REMARKS: | |
694 | Return a pointer to the register given by the R/RM field of the | |
695 | modrm byte, for word operands, modified from above for the weirdo | |
696 | special case of segreg operands. Also enables the decoding of instructions. | |
697 | ****************************************************************************/ | |
698 | u16 * | |
699 | decode_rm_seg_register(int reg) | |
700 | { | |
701 | switch (reg) { | |
702 | case 0: | |
703 | DECODE_PRINTF("ES"); | |
704 | return &M.x86.R_ES; | |
705 | case 1: | |
706 | DECODE_PRINTF("CS"); | |
707 | return &M.x86.R_CS; | |
708 | case 2: | |
709 | DECODE_PRINTF("SS"); | |
710 | return &M.x86.R_SS; | |
711 | case 3: | |
712 | DECODE_PRINTF("DS"); | |
713 | return &M.x86.R_DS; | |
714 | case 4: | |
715 | DECODE_PRINTF("FS"); | |
716 | return &M.x86.R_FS; | |
717 | case 5: | |
718 | DECODE_PRINTF("GS"); | |
719 | return &M.x86.R_GS; | |
720 | case 6: | |
721 | case 7: | |
722 | DECODE_PRINTF("ILLEGAL SEGREG"); | |
723 | break; | |
724 | } | |
725 | HALT_SYS(); | |
726 | return NULL; /* NOT REACHED OR REACHED ON ERROR */ | |
727 | } | |
728 | ||
729 | /* | |
730 | * | |
731 | * return offset from the SIB Byte | |
732 | */ | |
733 | u32 | |
734 | decode_sib_address(int sib, int mod) | |
735 | { | |
736 | u32 base = 0, i = 0, scale = 1; | |
737 | ||
738 | switch (sib & 0x07) { | |
739 | case 0: | |
740 | DECODE_PRINTF("[EAX]"); | |
741 | base = M.x86.R_EAX; | |
742 | break; | |
743 | case 1: | |
744 | DECODE_PRINTF("[ECX]"); | |
745 | base = M.x86.R_ECX; | |
746 | break; | |
747 | case 2: | |
748 | DECODE_PRINTF("[EDX]"); | |
749 | base = M.x86.R_EDX; | |
750 | break; | |
751 | case 3: | |
752 | DECODE_PRINTF("[EBX]"); | |
753 | base = M.x86.R_EBX; | |
754 | break; | |
755 | case 4: | |
756 | DECODE_PRINTF("[ESP]"); | |
757 | base = M.x86.R_ESP; | |
758 | M.x86.mode |= SYSMODE_SEG_DS_SS; | |
759 | break; | |
760 | case 5: | |
761 | if (mod == 0) { | |
762 | base = fetch_long_imm(); | |
763 | DECODE_PRINTF2("%08x", base); | |
764 | } | |
765 | else { | |
766 | DECODE_PRINTF("[EBP]"); | |
767 | base = M.x86.R_ESP; | |
768 | M.x86.mode |= SYSMODE_SEG_DS_SS; | |
769 | } | |
770 | break; | |
771 | case 6: | |
772 | DECODE_PRINTF("[ESI]"); | |
773 | base = M.x86.R_ESI; | |
774 | break; | |
775 | case 7: | |
776 | DECODE_PRINTF("[EDI]"); | |
777 | base = M.x86.R_EDI; | |
778 | break; | |
779 | } | |
780 | switch ((sib >> 3) & 0x07) { | |
781 | case 0: | |
782 | DECODE_PRINTF("[EAX"); | |
783 | i = M.x86.R_EAX; | |
784 | break; | |
785 | case 1: | |
786 | DECODE_PRINTF("[ECX"); | |
787 | i = M.x86.R_ECX; | |
788 | break; | |
789 | case 2: | |
790 | DECODE_PRINTF("[EDX"); | |
791 | i = M.x86.R_EDX; | |
792 | break; | |
793 | case 3: | |
794 | DECODE_PRINTF("[EBX"); | |
795 | i = M.x86.R_EBX; | |
796 | break; | |
797 | case 4: | |
798 | i = 0; | |
799 | break; | |
800 | case 5: | |
801 | DECODE_PRINTF("[EBP"); | |
802 | i = M.x86.R_EBP; | |
803 | break; | |
804 | case 6: | |
805 | DECODE_PRINTF("[ESI"); | |
806 | i = M.x86.R_ESI; | |
807 | break; | |
808 | case 7: | |
809 | DECODE_PRINTF("[EDI"); | |
810 | i = M.x86.R_EDI; | |
811 | break; | |
812 | } | |
813 | scale = 1 << ((sib >> 6) & 0x03); | |
814 | if (((sib >> 3) & 0x07) != 4) { | |
815 | if (scale == 1) { | |
816 | DECODE_PRINTF("]"); | |
817 | } | |
818 | else { | |
819 | DECODE_PRINTF2("*%d]", scale); | |
820 | } | |
821 | } | |
822 | return base + (i * scale); | |
823 | } | |
824 | ||
825 | /**************************************************************************** | |
826 | PARAMETERS: | |
827 | rm - RM value to decode | |
828 | ||
829 | RETURNS: | |
830 | Offset in memory for the address decoding | |
831 | ||
832 | REMARKS: | |
833 | Return the offset given by mod=00 addressing. Also enables the | |
834 | decoding of instructions. | |
835 | ||
836 | NOTE: The code which specifies the corresponding segment (ds vs ss) | |
837 | below in the case of [BP+..]. The assumption here is that at the | |
838 | point that this subroutine is called, the bit corresponding to | |
839 | SYSMODE_SEG_DS_SS will be zero. After every instruction | |
840 | except the segment override instructions, this bit (as well | |
841 | as any bits indicating segment overrides) will be clear. So | |
842 | if a SS access is needed, set this bit. Otherwise, DS access | |
843 | occurs (unless any of the segment override bits are set). | |
844 | ****************************************************************************/ | |
845 | u32 | |
846 | decode_rm00_address(int rm) | |
847 | { | |
848 | u32 offset; | |
849 | int sib; | |
850 | ||
851 | if (M.x86.mode & SYSMODE_PREFIX_ADDR) { | |
852 | /* 32-bit addressing */ | |
853 | switch (rm) { | |
854 | case 0: | |
855 | DECODE_PRINTF("[EAX]"); | |
856 | return M.x86.R_EAX; | |
857 | case 1: | |
858 | DECODE_PRINTF("[ECX]"); | |
859 | return M.x86.R_ECX; | |
860 | case 2: | |
861 | DECODE_PRINTF("[EDX]"); | |
862 | return M.x86.R_EDX; | |
863 | case 3: | |
864 | DECODE_PRINTF("[EBX]"); | |
865 | return M.x86.R_EBX; | |
866 | case 4: | |
867 | sib = fetch_byte_imm(); | |
868 | return decode_sib_address(sib, 0); | |
869 | case 5: | |
870 | offset = fetch_long_imm(); | |
871 | DECODE_PRINTF2("[%08x]", offset); | |
872 | return offset; | |
873 | case 6: | |
874 | DECODE_PRINTF("[ESI]"); | |
875 | return M.x86.R_ESI; | |
876 | case 7: | |
877 | DECODE_PRINTF("[EDI]"); | |
878 | return M.x86.R_EDI; | |
879 | } | |
880 | HALT_SYS(); | |
881 | } | |
882 | else { | |
883 | /* 16-bit addressing */ | |
884 | switch (rm) { | |
885 | case 0: | |
886 | DECODE_PRINTF("[BX+SI]"); | |
887 | return (M.x86.R_BX + M.x86.R_SI) & 0xffff; | |
888 | case 1: | |
889 | DECODE_PRINTF("[BX+DI]"); | |
890 | return (M.x86.R_BX + M.x86.R_DI) & 0xffff; | |
891 | case 2: | |
892 | DECODE_PRINTF("[BP+SI]"); | |
893 | M.x86.mode |= SYSMODE_SEG_DS_SS; | |
894 | return (M.x86.R_BP + M.x86.R_SI) & 0xffff; | |
895 | case 3: | |
896 | DECODE_PRINTF("[BP+DI]"); | |
897 | M.x86.mode |= SYSMODE_SEG_DS_SS; | |
898 | return (M.x86.R_BP + M.x86.R_DI) & 0xffff; | |
899 | case 4: | |
900 | DECODE_PRINTF("[SI]"); | |
901 | return M.x86.R_SI; | |
902 | case 5: | |
903 | DECODE_PRINTF("[DI]"); | |
904 | return M.x86.R_DI; | |
905 | case 6: | |
906 | offset = fetch_word_imm(); | |
907 | DECODE_PRINTF2("[%04x]", offset); | |
908 | return offset; | |
909 | case 7: | |
910 | DECODE_PRINTF("[BX]"); | |
911 | return M.x86.R_BX; | |
912 | } | |
913 | HALT_SYS(); | |
914 | } | |
915 | return 0; | |
916 | } | |
917 | ||
918 | /**************************************************************************** | |
919 | PARAMETERS: | |
920 | rm - RM value to decode | |
921 | ||
922 | RETURNS: | |
923 | Offset in memory for the address decoding | |
924 | ||
925 | REMARKS: | |
926 | Return the offset given by mod=01 addressing. Also enables the | |
927 | decoding of instructions. | |
928 | ****************************************************************************/ | |
929 | u32 | |
930 | decode_rm01_address(int rm) | |
931 | { | |
932 | int displacement = 0; | |
933 | int sib; | |
934 | ||
935 | /* Fetch disp8 if no SIB byte */ | |
936 | if (!((M.x86.mode & SYSMODE_PREFIX_ADDR) && (rm == 4))) | |
937 | displacement = (s8) fetch_byte_imm(); | |
938 | ||
939 | if (M.x86.mode & SYSMODE_PREFIX_ADDR) { | |
940 | /* 32-bit addressing */ | |
941 | switch (rm) { | |
942 | case 0: | |
943 | DECODE_PRINTF2("%d[EAX]", displacement); | |
944 | return M.x86.R_EAX + displacement; | |
945 | case 1: | |
946 | DECODE_PRINTF2("%d[ECX]", displacement); | |
947 | return M.x86.R_ECX + displacement; | |
948 | case 2: | |
949 | DECODE_PRINTF2("%d[EDX]", displacement); | |
950 | return M.x86.R_EDX + displacement; | |
951 | case 3: | |
952 | DECODE_PRINTF2("%d[EBX]", displacement); | |
953 | return M.x86.R_EBX + displacement; | |
954 | case 4: | |
955 | sib = fetch_byte_imm(); | |
956 | displacement = (s8) fetch_byte_imm(); | |
957 | DECODE_PRINTF2("%d", displacement); | |
958 | return decode_sib_address(sib, 1) + displacement; | |
959 | case 5: | |
960 | DECODE_PRINTF2("%d[EBP]", displacement); | |
961 | return M.x86.R_EBP + displacement; | |
962 | case 6: | |
963 | DECODE_PRINTF2("%d[ESI]", displacement); | |
964 | return M.x86.R_ESI + displacement; | |
965 | case 7: | |
966 | DECODE_PRINTF2("%d[EDI]", displacement); | |
967 | return M.x86.R_EDI + displacement; | |
968 | } | |
969 | HALT_SYS(); | |
970 | } | |
971 | else { | |
972 | /* 16-bit addressing */ | |
973 | switch (rm) { | |
974 | case 0: | |
975 | DECODE_PRINTF2("%d[BX+SI]", displacement); | |
976 | return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff; | |
977 | case 1: | |
978 | DECODE_PRINTF2("%d[BX+DI]", displacement); | |
979 | return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff; | |
980 | case 2: | |
981 | DECODE_PRINTF2("%d[BP+SI]", displacement); | |
982 | M.x86.mode |= SYSMODE_SEG_DS_SS; | |
983 | return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff; | |
984 | case 3: | |
985 | DECODE_PRINTF2("%d[BP+DI]", displacement); | |
986 | M.x86.mode |= SYSMODE_SEG_DS_SS; | |
987 | return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff; | |
988 | case 4: | |
989 | DECODE_PRINTF2("%d[SI]", displacement); | |
990 | return (M.x86.R_SI + displacement) & 0xffff; | |
991 | case 5: | |
992 | DECODE_PRINTF2("%d[DI]", displacement); | |
993 | return (M.x86.R_DI + displacement) & 0xffff; | |
994 | case 6: | |
995 | DECODE_PRINTF2("%d[BP]", displacement); | |
996 | M.x86.mode |= SYSMODE_SEG_DS_SS; | |
997 | return (M.x86.R_BP + displacement) & 0xffff; | |
998 | case 7: | |
999 | DECODE_PRINTF2("%d[BX]", displacement); | |
1000 | return (M.x86.R_BX + displacement) & 0xffff; | |
1001 | } | |
1002 | HALT_SYS(); | |
1003 | } | |
1004 | return 0; /* SHOULD NOT HAPPEN */ | |
1005 | } | |
1006 | ||
1007 | /**************************************************************************** | |
1008 | PARAMETERS: | |
1009 | rm - RM value to decode | |
1010 | ||
1011 | RETURNS: | |
1012 | Offset in memory for the address decoding | |
1013 | ||
1014 | REMARKS: | |
1015 | Return the offset given by mod=10 addressing. Also enables the | |
1016 | decoding of instructions. | |
1017 | ****************************************************************************/ | |
1018 | u32 | |
1019 | decode_rm10_address(int rm) | |
1020 | { | |
1021 | u32 displacement = 0; | |
1022 | int sib; | |
1023 | ||
1024 | /* Fetch disp16 if 16-bit addr mode */ | |
1025 | if (!(M.x86.mode & SYSMODE_PREFIX_ADDR)) | |
1026 | displacement = (u16) fetch_word_imm(); | |
1027 | else { | |
1028 | /* Fetch disp32 if no SIB byte */ | |
1029 | if (rm != 4) | |
1030 | displacement = (u32) fetch_long_imm(); | |
1031 | } | |
1032 | ||
1033 | if (M.x86.mode & SYSMODE_PREFIX_ADDR) { | |
1034 | /* 32-bit addressing */ | |
1035 | switch (rm) { | |
1036 | case 0: | |
1037 | DECODE_PRINTF2("%08x[EAX]", displacement); | |
1038 | return M.x86.R_EAX + displacement; | |
1039 | case 1: | |
1040 | DECODE_PRINTF2("%08x[ECX]", displacement); | |
1041 | return M.x86.R_ECX + displacement; | |
1042 | case 2: | |
1043 | DECODE_PRINTF2("%08x[EDX]", displacement); | |
1044 | M.x86.mode |= SYSMODE_SEG_DS_SS; | |
1045 | return M.x86.R_EDX + displacement; | |
1046 | case 3: | |
1047 | DECODE_PRINTF2("%08x[EBX]", displacement); | |
1048 | return M.x86.R_EBX + displacement; | |
1049 | case 4: | |
1050 | sib = fetch_byte_imm(); | |
1051 | displacement = (u32) fetch_long_imm(); | |
1052 | DECODE_PRINTF2("%08x", displacement); | |
1053 | return decode_sib_address(sib, 2) + displacement; | |
1054 | break; | |
1055 | case 5: | |
1056 | DECODE_PRINTF2("%08x[EBP]", displacement); | |
1057 | return M.x86.R_EBP + displacement; | |
1058 | case 6: | |
1059 | DECODE_PRINTF2("%08x[ESI]", displacement); | |
1060 | return M.x86.R_ESI + displacement; | |
1061 | case 7: | |
1062 | DECODE_PRINTF2("%08x[EDI]", displacement); | |
1063 | return M.x86.R_EDI + displacement; | |
1064 | } | |
1065 | HALT_SYS(); | |
1066 | } | |
1067 | else { | |
1068 | /* 16-bit addressing */ | |
1069 | switch (rm) { | |
1070 | case 0: | |
1071 | DECODE_PRINTF2("%04x[BX+SI]", displacement); | |
1072 | return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff; | |
1073 | case 1: | |
1074 | DECODE_PRINTF2("%04x[BX+DI]", displacement); | |
1075 | return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff; | |
1076 | case 2: | |
1077 | DECODE_PRINTF2("%04x[BP+SI]", displacement); | |
1078 | M.x86.mode |= SYSMODE_SEG_DS_SS; | |
1079 | return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff; | |
1080 | case 3: | |
1081 | DECODE_PRINTF2("%04x[BP+DI]", displacement); | |
1082 | M.x86.mode |= SYSMODE_SEG_DS_SS; | |
1083 | return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff; | |
1084 | case 4: | |
1085 | DECODE_PRINTF2("%04x[SI]", displacement); | |
1086 | return (M.x86.R_SI + displacement) & 0xffff; | |
1087 | case 5: | |
1088 | DECODE_PRINTF2("%04x[DI]", displacement); | |
1089 | return (M.x86.R_DI + displacement) & 0xffff; | |
1090 | case 6: | |
1091 | DECODE_PRINTF2("%04x[BP]", displacement); | |
1092 | M.x86.mode |= SYSMODE_SEG_DS_SS; | |
1093 | return (M.x86.R_BP + displacement) & 0xffff; | |
1094 | case 7: | |
1095 | DECODE_PRINTF2("%04x[BX]", displacement); | |
1096 | return (M.x86.R_BX + displacement) & 0xffff; | |
1097 | } | |
1098 | HALT_SYS(); | |
1099 | } | |
1100 | return 0; | |
1101 | /*NOTREACHED */ | |
1102 | } |