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