1 /* $OpenBSD: mmio.h,v 1.2 2024/07/09 09:31:37 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 24 /* Code segment bits */ 25 #define CS_L (1 << 13) 26 #define CS_D (1 << 14) 27 28 #define EFLAGS_VM (1 << 17) /* Virtual 8086 Mode enabled */ 29 30 /* Instruction Prefixes (SDM Vol 2, 2.1.1) */ 31 #define LEG_1_LOCK 0xF0 32 #define LEG_1_REPNE 0xF2 33 #define LEG_1_REP 0xF3 34 #define LEG_2_CS 0x2E 35 #define LEG_2_SS 0x36 36 #define LEG_2_DS 0x3E 37 #define LEG_2_ES 0x26 38 #define LEG_2_FS 0x64 39 #define LEG_2_GS 0x65 40 #define LEG_3_OPSZ 0x66 /* Operand size override */ 41 #define LEG_4_ADDRSZ 0x67 /* Address size override */ 42 43 /* REX prefix bit fields */ 44 #define REX_B 0x01 45 #define REX_X 0x02 46 #define REX_R 0x04 47 #define REX_W 0x08 48 #define REX_BASE 0x40 49 50 #define REX_NONE 0x00 51 52 /* VEX prefixes (unsupported) */ 53 #define VEX_2_BYTE 0xC5 54 #define VEX_3_BYTE 0xC4 55 56 #define ESCAPE 0x0F 57 58 struct x86_prefix { 59 uint8_t pfx_group1; /* LOCK, REP, or REPNE */ 60 uint8_t pfx_group2; /* Segment overrides */ 61 uint8_t pfx_group3; /* Operand size override */ 62 uint8_t pfx_group4; /* Address size override */ 63 uint8_t pfx_rex; /* REX prefix for long mode */ 64 }; 65 66 enum x86_opcode_type { 67 OP_UNKNOWN = 0, /* Default value when undecoded. */ 68 OP_IN, 69 OP_INS, 70 OP_MOV, 71 OP_MOVZX, 72 OP_OUT, 73 OP_OUTS, 74 OP_TWO_BYTE, /* Opcode is two bytes, not one. */ 75 OP_UNSUPPORTED, /* Valid decode, but no current support. */ 76 }; 77 78 /* Instruction Operand Encoding as described in the SDM Vol 2, Ch 3-5. */ 79 enum x86_operand_enc { 80 OP_ENC_UNKNOWN = 0, 81 OP_ENC_I, /* Only immediate operand */ 82 OP_ENC_MI, /* Immediate to ModRM */ 83 OP_ENC_MR, /* Register to ModRM */ 84 OP_ENC_RM, /* ModRm to Register */ 85 OP_ENC_FD, /* Value @ segment offset to RAX */ 86 OP_ENC_TD, /* RAX to segment offset */ 87 OP_ENC_OI, /* Immediate to Register (no emul. needed!) */ 88 OP_ENC_ZO, /* No ModRM byte. */ 89 }; 90 91 /* Displacement bytes */ 92 enum x86_disp_type { 93 DISP_NONE = 0, 94 DISP_0, 95 DISP_1, 96 DISP_2, /* Requires Legacy prefix LEG_4_ADDRSZ */ 97 DISP_4, 98 }; 99 100 struct x86_opcode { 101 uint8_t op_bytes[2]; /* VEX unsupported */ 102 uint8_t op_bytes_len; /* Length of opcode */ 103 enum x86_opcode_type op_type; /* Type of opcode */ 104 enum x86_operand_enc op_encoding; /* Operand encoding */ 105 }; 106 107 struct x86_insn { 108 uint8_t insn_bytes[15]; /* Original payload */ 109 uint8_t insn_bytes_len; /* Size of payload */ 110 int insn_cpu_mode; /* CPU mode */ 111 112 struct x86_prefix insn_prefix; /* Combined prefixes */ 113 struct x86_opcode insn_opcode; 114 115 uint8_t insn_modrm; /* ModR/M */ 116 #define MODRM_MOD(x) ((x >> 6) & 0x3) 117 #define MODRM_REGOP(x) ((x >> 3) & 0x7) 118 #define MODRM_RM(x) ((x >> 0) & 0x7) 119 uint8_t insn_modrm_valid; /* Is ModR/M set? */ 120 121 vaddr_t insn_gva; /* Guest Virtual Addr */ 122 int insn_reg; /* Register */ 123 124 uint8_t insn_sib; /* Scale-Index-Base */ 125 uint8_t insn_sib_valid; /* SIB byte set? */ 126 127 uint64_t insn_disp; /* Displacement */ 128 enum x86_disp_type insn_disp_type; 129 130 uint64_t insn_immediate; /* Immediate data */ 131 uint8_t insn_immediate_len; 132 }; 133 134 int insn_decode(struct vm_exit *, struct x86_insn *); 135 int insn_emulate(struct vm_exit *, struct x86_insn *); 136 137 #endif /* _MMIO_H_ */ 138