| /* |
| * Emulation of priviledged instructions |
| * |
| * Copyright 1995 Alexandre Julliard |
| */ |
| |
| #include <stdio.h> |
| #include "windows.h" |
| #include "dos_fs.h" |
| #include "ldt.h" |
| #include "miscemu.h" |
| #include "registers.h" |
| |
| |
| static int do_int(int intnum, struct sigcontext_struct *context) |
| { |
| switch(intnum) |
| { |
| case 0x10: return do_int10(context); |
| |
| case 0x11: |
| AX = DOS_GetEquipment(); |
| return 1; |
| |
| case 0x12: |
| AX = 640; |
| return 1; /* get base mem size */ |
| |
| case 0x13: return do_int13(context); |
| case 0x15: return do_int15(context); |
| case 0x16: return do_int16(context); |
| case 0x1a: return do_int1a(context); |
| case 0x21: return do_int21(context); |
| |
| case 0x22: |
| AX = 0x1234; |
| BX = 0x5678; |
| CX = 0x9abc; |
| DX = 0xdef0; |
| return 1; |
| |
| case 0x25: return do_int25(context); |
| case 0x26: return do_int26(context); |
| case 0x2a: return do_int2a(context); |
| case 0x2f: return do_int2f(context); |
| case 0x31: return do_int31(context); |
| case 0x3d: return 1; |
| case 0x5c: return do_int5c(context); |
| |
| default: |
| fprintf(stderr,"int%02x: Unimplemented!\n", intnum); |
| break; |
| } |
| return 0; |
| } |
| |
| |
| /*********************************************************************** |
| * INSTR_EmulateInstruction |
| * |
| * Emulate a priviledged instruction. Returns TRUE if emulation successful. |
| */ |
| BOOL INSTR_EmulateInstruction( struct sigcontext_struct *context ) |
| { |
| int prefix, segprefix, long_op, long_addr; |
| BYTE *instr = (BYTE *) PTR_SEG_OFF_TO_LIN( CS, IP ); |
| |
| /* First handle any possible prefix */ |
| |
| long_op = long_addr = (GET_SEL_FLAGS(CS) & LDT_FLAGS_32BIT) != 0; |
| segprefix = 0; /* no prefix */ |
| prefix = 1; |
| while(prefix) |
| { |
| switch(*instr) |
| { |
| case 0x2e: |
| segprefix = 1; /* CS */ |
| break; |
| case 0x36: |
| segprefix = 2; /* SS */ |
| break; |
| case 0x3e: |
| segprefix = 3; /* DS */ |
| break; |
| case 0x26: |
| segprefix = 4; /* ES */ |
| break; |
| case 0x64: |
| segprefix = 5; /* FS */ |
| break; |
| case 0x65: |
| segprefix = 6; /* GS */ |
| break; |
| case 0x66: |
| long_op = !long_op; /* opcode size prefix */ |
| break; |
| case 0x67: |
| long_addr = !long_addr; /* addr size prefix */ |
| break; |
| default: |
| prefix = 0; /* no more prefixes */ |
| break; |
| } |
| if (prefix) |
| { |
| instr++; |
| EIP++; |
| } |
| } |
| |
| /* Now look at the actual instruction */ |
| |
| switch(*instr) |
| { |
| case 0xcd: /* int <XX> */ |
| instr++; |
| if (!do_int(*instr, context)) |
| { |
| fprintf(stderr,"Unexpected Windows interrupt %x\n", *instr); |
| return FALSE; |
| } |
| EIP += 2; /* Bypass the int instruction */ |
| break; |
| |
| case 0xcf: /* iret */ |
| if (long_op) |
| { |
| /* FIXME: should check the stack 'big' bit */ |
| DWORD *stack = (WORD *)PTR_SEG_OFF_TO_LIN( SS, SP ); |
| EIP = *stack++; |
| CS = *stack++; |
| EFL = *stack; |
| SP += 3*sizeof(DWORD); /* Pop the return address and flags */ |
| } |
| else |
| { |
| /* FIXME: should check the stack 'big' bit */ |
| WORD *stack = (WORD *)PTR_SEG_OFF_TO_LIN( SS, SP ); |
| EIP = *stack++; |
| CS = *stack++; |
| EFL = (EFL & 0xffff0000) | *stack; |
| SP += 3*sizeof(WORD); /* Pop the return address and flags */ |
| } |
| break; |
| |
| case 0xe4: /* inb al,XX */ |
| inportb_abs(context); |
| EIP += 2; |
| break; |
| |
| case 0xe5: /* in ax,XX */ |
| inport_abs( context, long_op ); |
| EIP += 2; |
| break; |
| |
| case 0xe6: /* outb XX,al */ |
| outportb_abs(context); |
| EIP += 2; |
| break; |
| |
| case 0xe7: /* out XX,ax */ |
| outport_abs( context, long_op ); |
| EIP += 2; |
| break; |
| |
| case 0xec: /* inb al,dx */ |
| inportb(context); |
| EIP++; |
| break; |
| |
| case 0xed: /* in ax,dx */ |
| inport( context, long_op ); |
| EIP++; |
| break; |
| |
| case 0xee: /* outb dx,al */ |
| outportb(context); |
| EIP++; |
| break; |
| |
| case 0xef: /* out dx,ax */ |
| outport( context, long_op ); |
| EIP++; |
| break; |
| |
| case 0xfa: /* cli, ignored */ |
| EIP++; |
| break; |
| |
| case 0xfb: /* sti, ignored */ |
| EIP++; |
| break; |
| |
| default: |
| fprintf(stderr, "Unexpected Windows program segfault" |
| " - opcode = %x\n", *instr); |
| return FALSE; /* Unable to emulate it */ |
| } |
| return TRUE; |
| } |