Overview   API Reference  

io_page_fault_udis86.hpp

00001 #if !defined(__IO_PAGE_FAULT_UDIS86_HPP__)
00002 #define __IO_PAGE_FAULT_UDIS86_HPP__
00003 
00004 //
00005 // local includes
00006 //
00007 #include "core/machine/arch/x86/emulation/in_out.hpp"
00008 #include "udis86-1.4/udis86.h"
00009 
00010 //
00011 // handle x86 in & out instructions
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     // determine I/O port
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         // always byte immediate
00026         case UD_OP_IMM: port=port_op.lval.ubyte; break;
00027         // or always register DX
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     // with opsize prefix it is a 16-bit access, so call handler
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     // otherwise determine access size and call handler
00043     //
00044     const ud_operand &size_op=ud.operand[(mnemonic == UD_Iin) ? 0 : 1];
00045 
00046     if (L4VMM_DEBUG_X86)
00047         // always register operand: AL, AX or EAX
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 // handle all x86 I/O space instructions
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     // replaces ud_init(&ud)
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     // decode instruction
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     // get REP prefix
00088     const bool rep=ud.pfx_rep || ud.pfx_repe || ud.pfx_repne;
00089 
00090     //
00091     // call handler functions
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     // skip instruction
00113     ctx.ip()+=ins_size;
00114     return 0;
00115 }
00116 
00117 #endif
00118 
00119 // ***** end of source ***** //
00120 

L4vmm Reference Manual, written by Mario Schwalbe  © 2006-2008