xref: /freebsd/sys/amd64/vmm/vmm_lapic.c (revision ddd5b8e9b4d8957fce018c520657cdfa4ecffad3)
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$
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
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 
44 int
45 lapic_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 
54 void
55 lapic_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 
64 int
65 lapic_set_intr(struct vm *vm, int cpu, int vector)
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);
77 
78 	vm_interrupt_hostcpu(vm, cpu);
79 
80 	return (0);
81 }
82 
83 int
84 lapic_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 
93 static boolean_t
94 x2apic_msr(u_int msr)
95 {
96 	if (msr >= 0x800 && msr <= 0xBFF)
97 		return (TRUE);
98 	else
99 		return (FALSE);
100 }
101 
102 static u_int
103 x2apic_msr_to_regoff(u_int msr)
104 {
105 
106 	return ((msr - 0x800) << 4);
107 }
108 
109 boolean_t
110 lapic_msr(u_int msr)
111 {
112 
113 	if (x2apic_msr(msr) || (msr == MSR_APICBASE))
114 		return (TRUE);
115 	else
116 		return (FALSE);
117 }
118 
119 int
120 lapic_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_op_mem_read(vlapic, offset, DWORD, rval);
134 	}
135 
136 	return (error);
137 }
138 
139 int
140 lapic_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_op_mem_write(vlapic, offset, DWORD, val);
154 	}
155 
156 	return (error);
157 }
158 
159 int
160 lapic_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_op_mem_write(vlapic, off, DWORD, wval);
178 	return (error);
179 }
180 
181 int
182 lapic_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_op_mem_read(vlapic, off, DWORD, rval);
200 	return (error);
201 }
202