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 <machine/specialreg.h>
37
38#include <machine/vmm.h>
39#include "vmm_lapic.h"
40#include "vmm_msr.h"
41
42#define	VMM_MSR_F_EMULATE	0x01
43#define	VMM_MSR_F_READONLY	0x02
44#define VMM_MSR_F_INVALID	0x04  /* guest_msr_valid() can override this */
45
46struct vmm_msr {
47	int		num;
48	int		flags;
49	uint64_t	hostval;
50};
51
52static struct vmm_msr vmm_msr[] = {
53	{ MSR_LSTAR,	0 },
54	{ MSR_CSTAR,	0 },
55	{ MSR_STAR,	0 },
56	{ MSR_SF_MASK,	0 },
57	{ MSR_PAT,      VMM_MSR_F_EMULATE | VMM_MSR_F_INVALID },
58	{ MSR_BIOS_SIGN,VMM_MSR_F_EMULATE },
59	{ MSR_MCG_CAP,	VMM_MSR_F_EMULATE | VMM_MSR_F_READONLY },
60	{ MSR_IA32_PLATFORM_ID, VMM_MSR_F_EMULATE | VMM_MSR_F_READONLY },
61	{ MSR_IA32_MISC_ENABLE, VMM_MSR_F_EMULATE | VMM_MSR_F_READONLY },
62};
63
64#define	vmm_msr_num	(sizeof(vmm_msr) / sizeof(vmm_msr[0]))
65CTASSERT(VMM_MSR_NUM >= vmm_msr_num);
66
67#define	readonly_msr(idx)	\
68	((vmm_msr[(idx)].flags & VMM_MSR_F_READONLY) != 0)
69
70#define	emulated_msr(idx)	\
71	((vmm_msr[(idx)].flags & VMM_MSR_F_EMULATE) != 0)
72
73#define invalid_msr(idx)	\
74	((vmm_msr[(idx)].flags & VMM_MSR_F_INVALID) != 0)
75
76void
77vmm_msr_init(void)
78{
79	int i;
80
81	for (i = 0; i < vmm_msr_num; i++) {
82		if (emulated_msr(i))
83			continue;
84		/*
85		 * XXX this assumes that the value of the host msr does not
86		 * change after we have cached it.
87		 */
88		vmm_msr[i].hostval = rdmsr(vmm_msr[i].num);
89	}
90}
91
92void
93guest_msrs_init(struct vm *vm, int cpu)
94{
95	int i;
96	uint64_t *guest_msrs, misc;
97
98	guest_msrs = vm_guest_msrs(vm, cpu);
99
100	for (i = 0; i < vmm_msr_num; i++) {
101		switch (vmm_msr[i].num) {
102		case MSR_LSTAR:
103		case MSR_CSTAR:
104		case MSR_STAR:
105		case MSR_SF_MASK:
106		case MSR_BIOS_SIGN:
107		case MSR_MCG_CAP:
108			guest_msrs[i] = 0;
109			break;
110		case MSR_PAT:
111			guest_msrs[i] = PAT_VALUE(0, PAT_WRITE_BACK)      |
112				PAT_VALUE(1, PAT_WRITE_THROUGH)   |
113				PAT_VALUE(2, PAT_UNCACHED)        |
114				PAT_VALUE(3, PAT_UNCACHEABLE)     |
115				PAT_VALUE(4, PAT_WRITE_BACK)      |
116				PAT_VALUE(5, PAT_WRITE_THROUGH)   |
117				PAT_VALUE(6, PAT_UNCACHED)        |
118				PAT_VALUE(7, PAT_UNCACHEABLE);
119			break;
120		case MSR_IA32_MISC_ENABLE:
121			misc = rdmsr(MSR_IA32_MISC_ENABLE);
122			/*
123			 * Set mandatory bits
124			 *  11:   branch trace disabled
125			 *  12:   PEBS unavailable
126			 * Clear unsupported features
127			 *  16:   SpeedStep enable
128			 *  18:   enable MONITOR FSM
129                         */
130			misc |= (1 << 12) | (1 << 11);
131			misc &= ~((1 << 18) | (1 << 16));
132			guest_msrs[i] = misc;
133			break;
134		case MSR_IA32_PLATFORM_ID:
135			guest_msrs[i] = 0;
136			break;
137		default:
138			panic("guest_msrs_init: missing initialization for msr "
139			      "0x%0x", vmm_msr[i].num);
140		}
141	}
142}
143
144static int
145msr_num_to_idx(u_int num)
146{
147	int i;
148
149	for (i = 0; i < vmm_msr_num; i++)
150		if (vmm_msr[i].num == num)
151			return (i);
152
153	return (-1);
154}
155
156int
157emulate_wrmsr(struct vm *vm, int cpu, u_int num, uint64_t val, bool *retu)
158{
159	int idx;
160	uint64_t *guest_msrs;
161
162	if (lapic_msr(num))
163		return (lapic_wrmsr(vm, cpu, num, val, retu));
164
165	idx = msr_num_to_idx(num);
166	if (idx < 0 || invalid_msr(idx))
167		return (EINVAL);
168
169	if (!readonly_msr(idx)) {
170		guest_msrs = vm_guest_msrs(vm, cpu);
171
172		/* Stash the value */
173		guest_msrs[idx] = val;
174
175		/* Update processor state for non-emulated MSRs */
176		if (!emulated_msr(idx))
177			wrmsr(vmm_msr[idx].num, val);
178	}
179
180	return (0);
181}
182
183int
184emulate_rdmsr(struct vm *vm, int cpu, u_int num, bool *retu)
185{
186	int error, idx;
187	uint32_t eax, edx;
188	uint64_t result, *guest_msrs;
189
190	if (lapic_msr(num)) {
191		error = lapic_rdmsr(vm, cpu, num, &result, retu);
192		goto done;
193	}
194
195	idx = msr_num_to_idx(num);
196	if (idx < 0 || invalid_msr(idx)) {
197		error = EINVAL;
198		goto done;
199	}
200
201	guest_msrs = vm_guest_msrs(vm, cpu);
202	result = guest_msrs[idx];
203
204	/*
205	 * If this is not an emulated msr register make sure that the processor
206	 * state matches our cached state.
207	 */
208	if (!emulated_msr(idx) && (rdmsr(num) != result)) {
209		panic("emulate_rdmsr: msr 0x%0x has inconsistent cached "
210		      "(0x%016lx) and actual (0x%016lx) values", num,
211		      result, rdmsr(num));
212	}
213
214	error = 0;
215
216done:
217	if (error == 0) {
218		eax = result;
219		edx = result >> 32;
220		error = vm_set_register(vm, cpu, VM_REG_GUEST_RAX, eax);
221		if (error)
222			panic("vm_set_register(rax) error %d", error);
223		error = vm_set_register(vm, cpu, VM_REG_GUEST_RDX, edx);
224		if (error)
225			panic("vm_set_register(rdx) error %d", error);
226	}
227	return (error);
228}
229
230void
231restore_guest_msrs(struct vm *vm, int cpu)
232{
233	int i;
234	uint64_t *guest_msrs;
235
236	guest_msrs = vm_guest_msrs(vm, cpu);
237
238	for (i = 0; i < vmm_msr_num; i++) {
239		if (emulated_msr(i))
240			continue;
241		else
242			wrmsr(vmm_msr[i].num, guest_msrs[i]);
243	}
244}
245
246void
247restore_host_msrs(struct vm *vm, int cpu)
248{
249	int i;
250
251	for (i = 0; i < vmm_msr_num; i++) {
252		if (emulated_msr(i))
253			continue;
254		else
255			wrmsr(vmm_msr[i].num, vmm_msr[i].hostval);
256	}
257}
258
259/*
260 * Must be called by the CPU-specific code before any guests are
261 * created
262 */
263void
264guest_msr_valid(int msr)
265{
266	int i;
267
268	for (i = 0; i < vmm_msr_num; i++) {
269		if (vmm_msr[i].num == msr && invalid_msr(i)) {
270			vmm_msr[i].flags &= ~VMM_MSR_F_INVALID;
271		}
272	}
273}
274