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