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