1221828Sgrehan/*-
2221828Sgrehan * Copyright (c) 2011 NetApp, Inc.
3221828Sgrehan * All rights reserved.
4221828Sgrehan *
5221828Sgrehan * Redistribution and use in source and binary forms, with or without
6221828Sgrehan * modification, are permitted provided that the following conditions
7221828Sgrehan * are met:
8221828Sgrehan * 1. Redistributions of source code must retain the above copyright
9221828Sgrehan *    notice, this list of conditions and the following disclaimer.
10221828Sgrehan * 2. Redistributions in binary form must reproduce the above copyright
11221828Sgrehan *    notice, this list of conditions and the following disclaimer in the
12221828Sgrehan *    documentation and/or other materials provided with the distribution.
13221828Sgrehan *
14221828Sgrehan * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15221828Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16221828Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17221828Sgrehan * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18221828Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19221828Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20221828Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21221828Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22221828Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23221828Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24221828Sgrehan * SUCH DAMAGE.
25221828Sgrehan *
26221828Sgrehan * $FreeBSD$
27221828Sgrehan */
28221828Sgrehan
29221828Sgrehan#include <sys/cdefs.h>
30221828Sgrehan__FBSDID("$FreeBSD$");
31221828Sgrehan
32221828Sgrehan#include <sys/param.h>
33221828Sgrehan#include <sys/systm.h>
34223621Sgrehan#include <sys/smp.h>
35221828Sgrehan
36240772Sneel#include <x86/specialreg.h>
37243640Sneel#include <x86/apicreg.h>
38240772Sneel
39221828Sgrehan#include <machine/vmm.h>
40221828Sgrehan#include "vmm_ipi.h"
41262350Sjhb#include "vmm_ktr.h"
42221828Sgrehan#include "vmm_lapic.h"
43221828Sgrehan#include "vlapic.h"
44221828Sgrehan
45262350Sjhb/*
46262350Sjhb * Some MSI message definitions
47262350Sjhb */
48262350Sjhb#define	MSI_X86_ADDR_MASK	0xfff00000
49262350Sjhb#define	MSI_X86_ADDR_BASE	0xfee00000
50262350Sjhb#define	MSI_X86_ADDR_RH		0x00000008	/* Redirection Hint */
51262350Sjhb#define	MSI_X86_ADDR_LOG	0x00000004	/* Destination Mode */
52262350Sjhb
53221828Sgrehanint
54261088Sjhblapic_set_intr(struct vm *vm, int cpu, int vector, bool level)
55221828Sgrehan{
56221828Sgrehan	struct vlapic *vlapic;
57221828Sgrehan
58221828Sgrehan	if (cpu < 0 || cpu >= VM_MAXCPU)
59221828Sgrehan		return (EINVAL);
60221828Sgrehan
61284899Sneel	/*
62284899Sneel	 * According to section "Maskable Hardware Interrupts" in Intel SDM
63284899Sneel	 * vectors 16 through 255 can be delivered through the local APIC.
64284899Sneel	 */
65284899Sneel	if (vector < 16 || vector > 255)
66221828Sgrehan		return (EINVAL);
67221828Sgrehan
68221828Sgrehan	vlapic = vm_lapic(vm, cpu);
69266339Sjhb	if (vlapic_set_intr_ready(vlapic, vector, level))
70266339Sjhb		vcpu_notify_event(vm, cpu, true);
71221828Sgrehan	return (0);
72221828Sgrehan}
73221828Sgrehan
74241766Sneelint
75262350Sjhblapic_set_local_intr(struct vm *vm, int cpu, int vector)
76221828Sgrehan{
77221828Sgrehan	struct vlapic *vlapic;
78262350Sjhb	cpuset_t dmask;
79262350Sjhb	int error;
80221828Sgrehan
81262350Sjhb	if (cpu < -1 || cpu >= VM_MAXCPU)
82262350Sjhb		return (EINVAL);
83221828Sgrehan
84262350Sjhb	if (cpu == -1)
85262350Sjhb		dmask = vm_active_cpus(vm);
86262350Sjhb	else
87262350Sjhb		CPU_SETOF(cpu, &dmask);
88262350Sjhb	error = 0;
89262350Sjhb	while ((cpu = CPU_FFS(&dmask)) != 0) {
90262350Sjhb		cpu--;
91262350Sjhb		CPU_CLR(cpu, &dmask);
92262350Sjhb		vlapic = vm_lapic(vm, cpu);
93262350Sjhb		error = vlapic_trigger_lvt(vlapic, vector);
94262350Sjhb		if (error)
95262350Sjhb			break;
96262350Sjhb	}
97262350Sjhb
98262350Sjhb	return (error);
99221828Sgrehan}
100240772Sneel
101262350Sjhbint
102262350Sjhblapic_intr_msi(struct vm *vm, uint64_t addr, uint64_t msg)
103262350Sjhb{
104262350Sjhb	int delmode, vec;
105262350Sjhb	uint32_t dest;
106262350Sjhb	bool phys;
107262350Sjhb
108262350Sjhb	VM_CTR2(vm, "lapic MSI addr: %#lx msg: %#lx", addr, msg);
109262350Sjhb
110262350Sjhb	if ((addr & MSI_X86_ADDR_MASK) != MSI_X86_ADDR_BASE) {
111262350Sjhb		VM_CTR1(vm, "lapic MSI invalid addr %#lx", addr);
112262350Sjhb		return (-1);
113262350Sjhb	}
114262350Sjhb
115262350Sjhb	/*
116262350Sjhb	 * Extract the x86-specific fields from the MSI addr/msg
117262350Sjhb	 * params according to the Intel Arch spec, Vol3 Ch 10.
118262350Sjhb	 *
119262350Sjhb	 * The PCI specification does not support level triggered
120262350Sjhb	 * MSI/MSI-X so ignore trigger level in 'msg'.
121262350Sjhb	 *
122262350Sjhb	 * The 'dest' is interpreted as a logical APIC ID if both
123262350Sjhb	 * the Redirection Hint and Destination Mode are '1' and
124262350Sjhb	 * physical otherwise.
125262350Sjhb	 */
126262350Sjhb	dest = (addr >> 12) & 0xff;
127262350Sjhb	phys = ((addr & (MSI_X86_ADDR_RH | MSI_X86_ADDR_LOG)) !=
128262350Sjhb	    (MSI_X86_ADDR_RH | MSI_X86_ADDR_LOG));
129262350Sjhb	delmode = msg & APIC_DELMODE_MASK;
130262350Sjhb	vec = msg & 0xff;
131262350Sjhb
132262350Sjhb	VM_CTR3(vm, "lapic MSI %s dest %#x, vec %d",
133262350Sjhb	    phys ? "physical" : "logical", dest, vec);
134262350Sjhb
135262350Sjhb	vlapic_deliver_intr(vm, LAPIC_TRIG_EDGE, dest, phys, delmode, vec);
136262350Sjhb	return (0);
137262350Sjhb}
138262350Sjhb
139240772Sneelstatic boolean_t
140240772Sneelx2apic_msr(u_int msr)
141240772Sneel{
142240772Sneel	if (msr >= 0x800 && msr <= 0xBFF)
143240772Sneel		return (TRUE);
144240772Sneel	else
145240772Sneel		return (FALSE);
146240772Sneel}
147240772Sneel
148240772Sneelstatic u_int
149240772Sneelx2apic_msr_to_regoff(u_int msr)
150240772Sneel{
151240772Sneel
152240772Sneel	return ((msr - 0x800) << 4);
153240772Sneel}
154240772Sneel
155240772Sneelboolean_t
156240772Sneellapic_msr(u_int msr)
157240772Sneel{
158240772Sneel
159240772Sneel	if (x2apic_msr(msr) || (msr == MSR_APICBASE))
160240772Sneel		return (TRUE);
161240772Sneel	else
162240772Sneel		return (FALSE);
163240772Sneel}
164240772Sneel
165240772Sneelint
166262350Sjhblapic_rdmsr(struct vm *vm, int cpu, u_int msr, uint64_t *rval, bool *retu)
167240772Sneel{
168243650Sneel	int error;
169243650Sneel	u_int offset;
170240772Sneel	struct vlapic *vlapic;
171240772Sneel
172240772Sneel	vlapic = vm_lapic(vm, cpu);
173240772Sneel
174240772Sneel	if (msr == MSR_APICBASE) {
175240772Sneel		*rval = vlapic_get_apicbase(vlapic);
176243650Sneel		error = 0;
177243650Sneel	} else {
178243650Sneel		offset = x2apic_msr_to_regoff(msr);
179267447Sjhb		error = vlapic_read(vlapic, 0, offset, rval, retu);
180243650Sneel	}
181240772Sneel
182243650Sneel	return (error);
183240772Sneel}
184240772Sneel
185240772Sneelint
186262350Sjhblapic_wrmsr(struct vm *vm, int cpu, u_int msr, uint64_t val, bool *retu)
187240772Sneel{
188243650Sneel	int error;
189243650Sneel	u_int offset;
190240772Sneel	struct vlapic *vlapic;
191240772Sneel
192240772Sneel	vlapic = vm_lapic(vm, cpu);
193240772Sneel
194240772Sneel	if (msr == MSR_APICBASE) {
195267447Sjhb		error = vlapic_set_apicbase(vlapic, val);
196243650Sneel	} else {
197243650Sneel		offset = x2apic_msr_to_regoff(msr);
198267447Sjhb		error = vlapic_write(vlapic, 0, offset, val, retu);
199243650Sneel	}
200240772Sneel
201243650Sneel	return (error);
202240772Sneel}
203240941Sneel
204240941Sneelint
205243640Sneellapic_mmio_write(void *vm, int cpu, uint64_t gpa, uint64_t wval, int size,
206243640Sneel		 void *arg)
207240941Sneel{
208243640Sneel	int error;
209243640Sneel	uint64_t off;
210240941Sneel	struct vlapic *vlapic;
211240941Sneel
212243640Sneel	off = gpa - DEFAULT_APIC_BASE;
213240941Sneel
214240941Sneel	/*
215243640Sneel	 * Memory mapped local apic accesses must be 4 bytes wide and
216243640Sneel	 * aligned on a 16-byte boundary.
217240941Sneel	 */
218243640Sneel	if (size != 4 || off & 0xf)
219243640Sneel		return (EINVAL);
220240941Sneel
221243640Sneel	vlapic = vm_lapic(vm, cpu);
222267447Sjhb	error = vlapic_write(vlapic, 1, off, wval, arg);
223243640Sneel	return (error);
224243640Sneel}
225240941Sneel
226243640Sneelint
227243640Sneellapic_mmio_read(void *vm, int cpu, uint64_t gpa, uint64_t *rval, int size,
228243640Sneel		void *arg)
229243640Sneel{
230243640Sneel	int error;
231243640Sneel	uint64_t off;
232243640Sneel	struct vlapic *vlapic;
233240941Sneel
234243640Sneel	off = gpa - DEFAULT_APIC_BASE;
235240941Sneel
236243640Sneel	/*
237268953Sjhb	 * Memory mapped local apic accesses should be aligned on a
238268953Sjhb	 * 16-byte boundary.  They are also suggested to be 4 bytes
239268953Sjhb	 * wide, alas not all OSes follow suggestions.
240243640Sneel	 */
241268953Sjhb	off &= ~3;
242268953Sjhb	if (off & 0xf)
243243640Sneel		return (EINVAL);
244240941Sneel
245243640Sneel	vlapic = vm_lapic(vm, cpu);
246267447Sjhb	error = vlapic_read(vlapic, 1, off, rval, arg);
247243640Sneel	return (error);
248240941Sneel}
249