vmm_lapic.c revision 261088
1/*-
2 * Copyright (c) 2011 NetApp, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: stable/10/sys/amd64/vmm/vmm_lapic.c 261088 2014-01-23 20:21:39Z jhb $
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/10/sys/amd64/vmm/vmm_lapic.c 261088 2014-01-23 20:21:39Z jhb $");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/smp.h>
35
36#include <x86/specialreg.h>
37#include <x86/apicreg.h>
38
39#include <machine/vmm.h>
40#include "vmm_ipi.h"
41#include "vmm_lapic.h"
42#include "vlapic.h"
43
44int
45lapic_pending_intr(struct vm *vm, int cpu)
46{
47	struct vlapic *vlapic;
48
49	vlapic = vm_lapic(vm, cpu);
50
51	return (vlapic_pending_intr(vlapic));
52}
53
54void
55lapic_intr_accepted(struct vm *vm, int cpu, int vector)
56{
57	struct vlapic *vlapic;
58
59	vlapic = vm_lapic(vm, cpu);
60
61	vlapic_intr_accepted(vlapic, vector);
62}
63
64int
65lapic_set_intr(struct vm *vm, int cpu, int vector, bool level)
66{
67	struct vlapic *vlapic;
68
69	if (cpu < 0 || cpu >= VM_MAXCPU)
70		return (EINVAL);
71
72	if (vector < 32 || vector > 255)
73		return (EINVAL);
74
75	vlapic = vm_lapic(vm, cpu);
76	vlapic_set_intr_ready(vlapic, vector, level);
77
78	vm_interrupt_hostcpu(vm, cpu);
79
80	return (0);
81}
82
83int
84lapic_timer_tick(struct vm *vm, int cpu)
85{
86	struct vlapic *vlapic;
87
88	vlapic = vm_lapic(vm, cpu);
89
90	return (vlapic_timer_tick(vlapic));
91}
92
93static boolean_t
94x2apic_msr(u_int msr)
95{
96	if (msr >= 0x800 && msr <= 0xBFF)
97		return (TRUE);
98	else
99		return (FALSE);
100}
101
102static u_int
103x2apic_msr_to_regoff(u_int msr)
104{
105
106	return ((msr - 0x800) << 4);
107}
108
109boolean_t
110lapic_msr(u_int msr)
111{
112
113	if (x2apic_msr(msr) || (msr == MSR_APICBASE))
114		return (TRUE);
115	else
116		return (FALSE);
117}
118
119int
120lapic_rdmsr(struct vm *vm, int cpu, u_int msr, uint64_t *rval)
121{
122	int error;
123	u_int offset;
124	struct vlapic *vlapic;
125
126	vlapic = vm_lapic(vm, cpu);
127
128	if (msr == MSR_APICBASE) {
129		*rval = vlapic_get_apicbase(vlapic);
130		error = 0;
131	} else {
132		offset = x2apic_msr_to_regoff(msr);
133		error = vlapic_read(vlapic, offset, rval);
134	}
135
136	return (error);
137}
138
139int
140lapic_wrmsr(struct vm *vm, int cpu, u_int msr, uint64_t val)
141{
142	int error;
143	u_int offset;
144	struct vlapic *vlapic;
145
146	vlapic = vm_lapic(vm, cpu);
147
148	if (msr == MSR_APICBASE) {
149		vlapic_set_apicbase(vlapic, val);
150		error = 0;
151	} else {
152		offset = x2apic_msr_to_regoff(msr);
153		error = vlapic_write(vlapic, offset, val);
154	}
155
156	return (error);
157}
158
159int
160lapic_mmio_write(void *vm, int cpu, uint64_t gpa, uint64_t wval, int size,
161		 void *arg)
162{
163	int error;
164	uint64_t off;
165	struct vlapic *vlapic;
166
167	off = gpa - DEFAULT_APIC_BASE;
168
169	/*
170	 * Memory mapped local apic accesses must be 4 bytes wide and
171	 * aligned on a 16-byte boundary.
172	 */
173	if (size != 4 || off & 0xf)
174		return (EINVAL);
175
176	vlapic = vm_lapic(vm, cpu);
177	error = vlapic_write(vlapic, off, wval);
178	return (error);
179}
180
181int
182lapic_mmio_read(void *vm, int cpu, uint64_t gpa, uint64_t *rval, int size,
183		void *arg)
184{
185	int error;
186	uint64_t off;
187	struct vlapic *vlapic;
188
189	off = gpa - DEFAULT_APIC_BASE;
190
191	/*
192	 * Memory mapped local apic accesses must be 4 bytes wide and
193	 * aligned on a 16-byte boundary.
194	 */
195	if (size != 4 || off & 0xf)
196		return (EINVAL);
197
198	vlapic = vm_lapic(vm, cpu);
199	error = vlapic_read(vlapic, off, rval);
200	return (error);
201}
202