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 59struct 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 67enum 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. */ 80enum 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 */ 93enum 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 101struct 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 108struct 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 135int insn_decode(struct vm_exit *, struct x86_insn *); 136int insn_emulate(struct vm_exit *, struct x86_insn *); 137 138#endif /* _MMIO_H_ */ 139