aboutsummaryrefslogtreecommitdiff
path: root/sys/amd64/vmm/io/vlapic_priv.h
blob: ccae4b748880c99c673c75279ba804e7005d8691 (plain) (blame)
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*-
 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
 *
 * Copyright (c) 2013 Neel Natu <neel@freebsd.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD$
 */

#ifndef _VLAPIC_PRIV_H_
#define	_VLAPIC_PRIV_H_

#include <x86/apicreg.h>

/*
 * APIC Register:		Offset	   Description
 */
#define APIC_OFFSET_ID		0x20	/* Local APIC ID		*/
#define APIC_OFFSET_VER		0x30	/* Local APIC Version		*/
#define APIC_OFFSET_TPR		0x80	/* Task Priority Register	*/
#define APIC_OFFSET_APR		0x90	/* Arbitration Priority		*/
#define APIC_OFFSET_PPR		0xA0	/* Processor Priority Register	*/
#define APIC_OFFSET_EOI		0xB0	/* EOI Register			*/
#define APIC_OFFSET_RRR		0xC0	/* Remote read			*/
#define APIC_OFFSET_LDR		0xD0	/* Logical Destination		*/
#define APIC_OFFSET_DFR		0xE0	/* Destination Format Register	*/
#define APIC_OFFSET_SVR		0xF0	/* Spurious Vector Register	*/
#define APIC_OFFSET_ISR0	0x100	/* In Service Register		*/
#define APIC_OFFSET_ISR1	0x110
#define APIC_OFFSET_ISR2	0x120
#define APIC_OFFSET_ISR3	0x130
#define APIC_OFFSET_ISR4	0x140
#define APIC_OFFSET_ISR5	0x150
#define APIC_OFFSET_ISR6	0x160
#define APIC_OFFSET_ISR7	0x170
#define APIC_OFFSET_TMR0	0x180	/* Trigger Mode Register	*/
#define APIC_OFFSET_TMR1	0x190
#define APIC_OFFSET_TMR2	0x1A0
#define APIC_OFFSET_TMR3	0x1B0
#define APIC_OFFSET_TMR4	0x1C0
#define APIC_OFFSET_TMR5	0x1D0
#define APIC_OFFSET_TMR6	0x1E0
#define APIC_OFFSET_TMR7	0x1F0
#define APIC_OFFSET_IRR0	0x200	/* Interrupt Request Register	*/
#define APIC_OFFSET_IRR1	0x210
#define APIC_OFFSET_IRR2	0x220
#define APIC_OFFSET_IRR3	0x230
#define APIC_OFFSET_IRR4	0x240
#define APIC_OFFSET_IRR5	0x250
#define APIC_OFFSET_IRR6	0x260
#define APIC_OFFSET_IRR7	0x270
#define APIC_OFFSET_ESR		0x280	/* Error Status Register	*/
#define APIC_OFFSET_CMCI_LVT	0x2F0	/* Local Vector Table (CMCI)	*/
#define APIC_OFFSET_ICR_LOW	0x300	/* Interrupt Command Register	*/
#define APIC_OFFSET_ICR_HI	0x310
#define APIC_OFFSET_TIMER_LVT	0x320	/* Local Vector Table (Timer)	*/
#define APIC_OFFSET_THERM_LVT	0x330	/* Local Vector Table (Thermal)	*/
#define APIC_OFFSET_PERF_LVT	0x340	/* Local Vector Table (PMC)	*/
#define APIC_OFFSET_LINT0_LVT	0x350	/* Local Vector Table (LINT0)	*/
#define APIC_OFFSET_LINT1_LVT	0x360	/* Local Vector Table (LINT1)	*/
#define APIC_OFFSET_ERROR_LVT	0x370	/* Local Vector Table (ERROR)	*/
#define APIC_OFFSET_TIMER_ICR	0x380	/* Timer's Initial Count	*/
#define APIC_OFFSET_TIMER_CCR	0x390	/* Timer's Current Count	*/
#define APIC_OFFSET_TIMER_DCR	0x3E0	/* Timer's Divide Configuration	*/
#define	APIC_OFFSET_SELF_IPI	0x3F0	/* Self IPI register */

#define	VLAPIC_CTR0(vlapic, format)					\
	VCPU_CTR0((vlapic)->vm, (vlapic)->vcpuid, format)

#define	VLAPIC_CTR1(vlapic, format, p1)					\
	VCPU_CTR1((vlapic)->vm, (vlapic)->vcpuid, format, p1)

#define	VLAPIC_CTR2(vlapic, format, p1, p2)				\
	VCPU_CTR2((vlapic)->vm, (vlapic)->vcpuid, format, p1, p2)

#define	VLAPIC_CTR3(vlapic, format, p1, p2, p3)				\
	VCPU_CTR3((vlapic)->vm, (vlapic)->vcpuid, format, p1, p2, p3)

#define	VLAPIC_CTR_IRR(vlapic, msg)					\
do {									\
	uint32_t *irrptr = &(vlapic)->apic_page->irr0;			\
	irrptr[0] = irrptr[0];	/* silence compiler */			\
	VLAPIC_CTR1((vlapic), msg " irr0 0x%08x", irrptr[0 << 2]);	\
	VLAPIC_CTR1((vlapic), msg " irr1 0x%08x", irrptr[1 << 2]);	\
	VLAPIC_CTR1((vlapic), msg " irr2 0x%08x", irrptr[2 << 2]);	\
	VLAPIC_CTR1((vlapic), msg " irr3 0x%08x", irrptr[3 << 2]);	\
	VLAPIC_CTR1((vlapic), msg " irr4 0x%08x", irrptr[4 << 2]);	\
	VLAPIC_CTR1((vlapic), msg " irr5 0x%08x", irrptr[5 << 2]);	\
	VLAPIC_CTR1((vlapic), msg " irr6 0x%08x", irrptr[6 << 2]);	\
	VLAPIC_CTR1((vlapic), msg " irr7 0x%08x", irrptr[7 << 2]);	\
} while (0)

#define	VLAPIC_CTR_ISR(vlapic, msg)					\
do {									\
	uint32_t *isrptr = &(vlapic)->apic_page->isr0;			\
	isrptr[0] = isrptr[0];	/* silence compiler */			\
	VLAPIC_CTR1((vlapic), msg " isr0 0x%08x", isrptr[0 << 2]);	\
	VLAPIC_CTR1((vlapic), msg " isr1 0x%08x", isrptr[1 << 2]);	\
	VLAPIC_CTR1((vlapic), msg " isr2 0x%08x", isrptr[2 << 2]);	\
	VLAPIC_CTR1((vlapic), msg " isr3 0x%08x", isrptr[3 << 2]);	\
	VLAPIC_CTR1((vlapic), msg " isr4 0x%08x", isrptr[4 << 2]);	\
	VLAPIC_CTR1((vlapic), msg " isr5 0x%08x", isrptr[5 << 2]);	\
	VLAPIC_CTR1((vlapic), msg " isr6 0x%08x", isrptr[6 << 2]);	\
	VLAPIC_CTR1((vlapic), msg " isr7 0x%08x", isrptr[7 << 2]);	\
} while (0)

/*
 * 16 priority levels with at most one vector injected per level.
 */
#define	ISRVEC_STK_SIZE		(16 + 1)

#define VLAPIC_MAXLVT_INDEX	APIC_LVT_CMCI

struct vcpu;
struct vlapic;

struct vlapic_ops {
	int (*set_intr_ready)(struct vlapic *vlapic, int vector, bool level);
	int (*pending_intr)(struct vlapic *vlapic, int *vecptr);
	void (*intr_accepted)(struct vlapic *vlapic, int vector);
	void (*post_intr)(struct vlapic *vlapic, int hostcpu);
	void (*set_tmr)(struct vlapic *vlapic, int vector, bool level);
	void (*enable_x2apic_mode)(struct vlapic *vlapic);
};

struct vlapic {
	struct vm		*vm;
	struct vcpu		*vcpu;
	int			vcpuid;
	struct LAPIC		*apic_page;
	struct vlapic_ops	ops;

	uint32_t		esr_pending;

	struct callout	callout;	/* vlapic timer */
	struct bintime	timer_fire_bt;	/* callout expiry time */
	struct bintime	timer_freq_bt;	/* timer frequency */
	struct bintime	timer_period_bt; /* timer period */
	struct mtx	timer_mtx;

	/*
	 * The 'isrvec_stk' is a stack of vectors injected by the local apic.
	 * A vector is popped from the stack when the processor does an EOI.
	 * The vector on the top of the stack is used to compute the
	 * Processor Priority in conjunction with the TPR.
	 */
	uint8_t		isrvec_stk[ISRVEC_STK_SIZE];
	int		isrvec_stk_top;

	uint64_t	msr_apicbase;

	/*
	 * Copies of some registers in the virtual APIC page. We do this for
	 * a couple of different reasons:
	 * - to be able to detect what changed (e.g. svr_last)
	 * - to maintain a coherent snapshot of the register (e.g. lvt_last)
	 */
	uint32_t	svr_last;
	uint32_t	lvt_last[VLAPIC_MAXLVT_INDEX + 1];

	bool		ipi_exit;
};

void vlapic_init(struct vlapic *vlapic);
void vlapic_cleanup(struct vlapic *vlapic);

#endif	/* _VLAPIC_PRIV_H_ */