00001 #if !defined(__IO_PAGE_FAULT_UDIS86_HPP__)
00002 #define __IO_PAGE_FAULT_UDIS86_HPP__
00003
00004
00005
00006
00007 #include "core/machine/arch/x86/emulation/in_out.hpp"
00008 #include "udis86-1.4/udis86.h"
00009
00010
00011
00012
00013 template <enum ud_mnemonic_code mnemonic>
00014 inline int x86_handle_in_out(x86_machine &machine, x86_context &ctx, const ud_t &ud)
00015 {
00016 static_assert((mnemonic == UD_Iin) || (mnemonic == UD_Iout), "invalid mnemonic");
00017
00018
00019
00020
00021 const ud_operand &port_op=ud.operand[(mnemonic == UD_Iin) ? 1 : 0];
00022 l4_port_t port=0;
00023
00024 switch (port_op.type) {
00025
00026 case UD_OP_IMM: port=port_op.lval.ubyte; break;
00027
00028 case UD_OP_REG: port=ctx.edx() & 0xffff; break;
00029
00030 default:
00031 log::error("bad operand for instruction at "l4_gva_fmt", expected DX or immediate\n", ctx.ip());
00032 return -L4_ENOTFOUND;
00033 }
00034
00035
00036
00037
00038 if (ud.pfx_opr)
00039 return (mnemonic == UD_Iin) ? x86_in<uint16_t>(machine, ctx, port) : x86_out<uint16_t>(machine, ctx, port);
00040
00041
00042
00043
00044 const ud_operand &size_op=ud.operand[(mnemonic == UD_Iin) ? 0 : 1];
00045
00046 if (L4VMM_DEBUG_X86)
00047
00048 if (size_op.type != UD_OP_REG) {
00049 log::error("bad operand for instruction at "l4_gva_fmt", expected AL, AX or EAX\n", ctx.ip());
00050 return -L4_EINVAL;
00051 }
00052
00053 switch (size_op.base) {
00054 case UD_R_AL:
00055 return (mnemonic == UD_Iin) ? x86_in<uint8_t>(machine, ctx, port) : x86_out<uint8_t>(machine, ctx, port);
00056 case UD_R_AX:
00057 return (mnemonic == UD_Iin) ? x86_in<uint16_t>(machine, ctx, port) : x86_out<uint16_t>(machine, ctx, port);
00058 case UD_R_EAX:
00059 return (mnemonic == UD_Iin) ? x86_in<uint32_t>(machine, ctx, port) : x86_out<uint32_t>(machine, ctx, port);
00060
00061 default:
00062 log::error("bad operand for instruction at "l4_gva_fmt", expected AL, AX or EAX\n", ctx.ip());
00063 return -L4_ENOTFOUND;
00064 }
00065 }
00066
00067
00068
00069
00070 inline int x86_machine::handle_io_page_fault(x86_context &ctx)
00071 {
00072 logd(L4VMM_DEBUG_X86 >= 2, L4VMM_DEBUG": emulating I/O space instruction at "l4_gva_fmt"\n", ctx.ip());
00073
00074
00075 ud_t ud;
00076 memset(&ud, 0, sizeof(ud));
00077 ud_set_mode(&ud, 32);
00078 ud_set_input_buffer(&ud, reinterpret_cast<uint8_t *>(ctx.ip()), 32);
00079
00080
00081 const uint8_t ins_size=ud_disassemble(&ud);
00082 if (unlikely(ud.mnemonic == UD_Idb)) {
00083 log::error("error decoding instruction at "l4_gva_fmt"\n", ctx.ip());
00084 return -L4_EINVAL;
00085 }
00086
00087
00088 const bool rep=ud.pfx_rep || ud.pfx_repe || ud.pfx_repne;
00089
00090
00091
00092
00093 int err=0;
00094 switch (ud.mnemonic) {
00095 case UD_Iin: err=x86_handle_in_out<UD_Iin>(*this, ctx, ud); break;
00096 case UD_Iout: err=x86_handle_in_out<UD_Iout>(*this, ctx, ud); break;
00097
00098 case UD_Iinsb: err=x86_ins<uint8_t>(*this, ctx, rep); break;
00099 case UD_Iinsw: err=x86_ins<uint16_t>(*this, ctx, rep); break;
00100 case UD_Iinsd: err=x86_ins<uint32_t>(*this, ctx, rep); break;
00101 case UD_Ioutsb: err=x86_outs<uint8_t>(*this, ctx, rep); break;
00102 case UD_Ioutsw: err=x86_outs<uint16_t>(*this, ctx, rep); break;
00103 case UD_Ioutsd: err=x86_outs<uint32_t>(*this, ctx, rep); break;
00104
00105 default:
00106 log::error("bad instruction at "l4_gva_fmt" [%d]\n"
00107 " expected in/out or ins/outs\n", ctx.ip(), ins_size);
00108 return -L4_ENOTSUPP;
00109 }
00110
00111 if (err) return err;
00112
00113 ctx.ip()+=ins_size;
00114 return 0;
00115 }
00116
00117 #endif
00118
00119
00120