1 /* $OpenBSD: mmio.h,v 1.1 2022/11/10 11:46:39 dv Exp $ */ 2 3 /* 4 * Copyright (c) 2022 Dave Voutila <dv@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #ifndef _MMIO_H_ 20 #define _MMIO_H_ 21 22 #include <sys/types.h> 23 #include <machine/vmmvar.h> 24 25 /* Code segment bits */ 26 #define CS_L (1 << 13) 27 #define CS_D (1 << 14) 28 29 #define EFLAGS_VM (1 << 17) /* Virtual 8086 Mode enabled */ 30 31 /* Instruction Prefixes (SDM Vol 2, 2.1.1) */ 32 #define LEG_1_LOCK 0xF0 33 #define LEG_1_REPNE 0xF2 34 #define LEG_1_REP 0xF3 35 #define LEG_2_CS 0x2E 36 #define LEG_2_SS 0x36 37 #define LEG_2_DS 0x3E 38 #define LEG_2_ES 0x26 39 #define LEG_2_FS 0x64 40 #define LEG_2_GS 0x65 41 #define LEG_3_OPSZ 0x66 /* Operand size override */ 42 #define LEG_4_ADDRSZ 0x67 /* Address size override */ 43 44 /* REX prefix bit fields */ 45 #define REX_B 0x01 46 #define REX_X 0x02 47 #define REX_R 0x04 48 #define REX_W 0x08 49 #define REX_BASE 0x40 50 51 #define REX_NONE 0x00 52 53 /* VEX prefixes (unsupported) */ 54 #define VEX_2_BYTE 0xC5 55 #define VEX_3_BYTE 0xC4 56 57 #define ESCAPE 0x0F 58 59 struct x86_prefix { 60 uint8_t pfx_group1; /* LOCK, REP, or REPNE */ 61 uint8_t pfx_group2; /* Segment overrides */ 62 uint8_t pfx_group3; /* Operand size override */ 63 uint8_t pfx_group4; /* Address size override */ 64 uint8_t pfx_rex; /* REX prefix for long mode */ 65 }; 66 67 enum x86_opcode_type { 68 OP_UNKNOWN = 0, /* Default value when undecoded. */ 69 OP_IN, 70 OP_INS, 71 OP_MOV, 72 OP_MOVZX, 73 OP_OUT, 74 OP_OUTS, 75 OP_TWO_BYTE, /* Opcode is two bytes, not one. */ 76 OP_UNSUPPORTED, /* Valid decode, but no current support. */ 77 }; 78 79 /* Instruction Operand Encoding as described in the SDM Vol 2, Ch 3-5. */ 80 enum x86_operand_enc { 81 OP_ENC_UNKNOWN = 0, 82 OP_ENC_I, /* Only immediate operand */ 83 OP_ENC_MI, /* Immediate to ModRM */ 84 OP_ENC_MR, /* Register to ModRM */ 85 OP_ENC_RM, /* ModRm to Register */ 86 OP_ENC_FD, /* Value @ segment offset to RAX */ 87 OP_ENC_TD, /* RAX to segment offset */ 88 OP_ENC_OI, /* Immediate to Register (no emul. needed!) */ 89 OP_ENC_ZO, /* No ModRM byte. */ 90 }; 91 92 /* Displacement bytes */ 93 enum x86_disp_type { 94 DISP_NONE = 0, 95 DISP_0, 96 DISP_1, 97 DISP_2, /* Requires Legacy prefix LEG_4_ADDRSZ */ 98 DISP_4, 99 }; 100 101 struct x86_opcode { 102 uint8_t op_bytes[2]; /* VEX unsupported */ 103 uint8_t op_bytes_len; /* Length of opcode */ 104 enum x86_opcode_type op_type; /* Type of opcode */ 105 enum x86_operand_enc op_encoding; /* Operand encoding */ 106 }; 107 108 struct x86_insn { 109 uint8_t insn_bytes[15]; /* Original payload */ 110 uint8_t insn_bytes_len; /* Size of payload */ 111 int insn_cpu_mode; /* CPU mode */ 112 113 struct x86_prefix insn_prefix; /* Combined prefixes */ 114 struct x86_opcode insn_opcode; 115 116 uint8_t insn_modrm; /* ModR/M */ 117 #define MODRM_MOD(x) ((x >> 6) & 0x3) 118 #define MODRM_REGOP(x) ((x >> 3) & 0x7) 119 #define MODRM_RM(x) ((x >> 0) & 0x7) 120 uint8_t insn_modrm_valid; /* Is ModR/M set? */ 121 122 vaddr_t insn_gva; /* Guest Virtual Addr */ 123 int insn_reg; /* Register */ 124 125 uint8_t insn_sib; /* Scale-Index-Base */ 126 uint8_t insn_sib_valid; /* SIB byte set? */ 127 128 uint64_t insn_disp; /* Displacement */ 129 enum x86_disp_type insn_disp_type; 130 131 uint64_t insn_immediate; /* Immediate data */ 132 uint8_t insn_immediate_len; 133 }; 134 135 int insn_decode(struct vm_exit *, struct x86_insn *); 136 int insn_emulate(struct vm_exit *, struct x86_insn *); 137 138 #endif /* _MMIO_H_ */ 139