summaryrefslogtreecommitdiff
path: root/usr.sbin/vmd/mmio.h
blob: b3f3fa40c2526ea7080c6b94c6c1d7461136f54b (plain)
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_ */