Update the user Makefrag to be more generic
[akaros.git] / user / vmm / vmxmsr.c
1 /*
2  * MSR emulation
3  *
4  * Copyright 2015 Google Inc.
5  *
6  * See LICENSE for details.
7  */
8
9 #include <stdio.h>
10 #include <sys/types.h>
11 #include <pthread.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <parlib/arch/arch.h>
15 #include <parlib/ros_debug.h>
16 #include <unistd.h>
17 #include <errno.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <sys/uio.h>
21 #include <stdint.h>
22 #include <err.h>
23 #include <sys/mman.h>
24 #include <ros/vmm.h>
25 #include <ros/arch/msr-index.h>
26 #include <vmm/virtio.h>
27 #include <vmm/virtio_mmio.h>
28 #include <vmm/virtio_ids.h>
29 #include <vmm/virtio_config.h>
30
31 struct emmsr {
32         uint32_t reg;
33         char *name;
34         int (*f) (struct vmctl * vcpu, struct emmsr *, uint32_t);
35         bool written;
36         uint32_t edx, eax;
37 };
38 // Might need to mfence rdmsr.  supposedly wrmsr serializes, but not for x2APIC
39 static inline uint64_t read_msr(uint32_t reg)
40 {
41         uint32_t edx, eax;
42         asm volatile("rdmsr; mfence" : "=d"(edx), "=a"(eax) : "c"(reg));
43         return (uint64_t)edx << 32 | eax;
44 }
45
46 static inline void write_msr(uint32_t reg, uint64_t val)
47 {
48         asm volatile("wrmsr" : : "d"((uint32_t)(val >> 32)),
49                                  "a"((uint32_t)(val & 0xFFFFFFFF)), 
50                                  "c"(reg));
51 }
52
53 int emsr_miscenable(struct vmctl *vcpu, struct emmsr *, uint32_t);
54 int emsr_mustmatch(struct vmctl *vcpu, struct emmsr *, uint32_t);
55 int emsr_readonly(struct vmctl *vcpu, struct emmsr *, uint32_t);
56 int emsr_readzero(struct vmctl *vcpu, struct emmsr *, uint32_t);
57 int emsr_fakewrite(struct vmctl *vcpu, struct emmsr *, uint32_t);
58 int emsr_ok(struct vmctl *vcpu, struct emmsr *, uint32_t);
59
60 struct emmsr emmsrs[] = {
61         {MSR_IA32_MISC_ENABLE, "MSR_IA32_MISC_ENABLE", emsr_miscenable},
62         {MSR_IA32_SYSENTER_CS, "MSR_IA32_SYSENTER_CS", emsr_ok},
63         {MSR_IA32_SYSENTER_EIP, "MSR_IA32_SYSENTER_EIP", emsr_ok},
64         {MSR_IA32_SYSENTER_ESP, "MSR_IA32_SYSENTER_ESP", emsr_ok},
65         {MSR_IA32_UCODE_REV, "MSR_IA32_UCODE_REV", emsr_fakewrite},
66         {MSR_CSTAR, "MSR_CSTAR", emsr_fakewrite},
67         {MSR_IA32_VMX_BASIC_MSR, "MSR_IA32_VMX_BASIC_MSR", emsr_fakewrite},
68         {MSR_IA32_VMX_PINBASED_CTLS_MSR, "MSR_IA32_VMX_PINBASED_CTLS_MSR",
69          emsr_fakewrite},
70         {MSR_IA32_VMX_PROCBASED_CTLS_MSR, "MSR_IA32_VMX_PROCBASED_CTLS_MSR",
71          emsr_fakewrite},
72         {MSR_IA32_VMX_PROCBASED_CTLS2, "MSR_IA32_VMX_PROCBASED_CTLS2",
73          emsr_fakewrite},
74         {MSR_IA32_VMX_EXIT_CTLS_MSR, "MSR_IA32_VMX_EXIT_CTLS_MSR",
75          emsr_fakewrite},
76         {MSR_IA32_VMX_ENTRY_CTLS_MSR, "MSR_IA32_VMX_ENTRY_CTLS_MSR",
77          emsr_fakewrite},
78         {MSR_IA32_ENERGY_PERF_BIAS, "MSR_IA32_ENERGY_PERF_BIAS",
79          emsr_fakewrite},
80         {MSR_LBR_SELECT, "MSR_LBR_SELECT", emsr_ok},
81         {MSR_LBR_TOS, "MSR_LBR_TOS", emsr_ok},
82         {MSR_LBR_NHM_FROM, "MSR_LBR_NHM_FROM", emsr_ok},
83         {MSR_LBR_NHM_TO, "MSR_LBR_NHM_TO", emsr_ok},
84         {MSR_LBR_CORE_FROM, "MSR_LBR_CORE_FROM", emsr_ok},
85         {MSR_LBR_CORE_TO, "MSR_LBR_CORE_TO", emsr_ok},
86
87         // grumble. 
88         {MSR_OFFCORE_RSP_0, "MSR_OFFCORE_RSP_0", emsr_ok},
89         {MSR_OFFCORE_RSP_1, "MSR_OFFCORE_RSP_1", emsr_ok},
90         // louder.
91         {MSR_PEBS_LD_LAT_THRESHOLD, "MSR_PEBS_LD_LAT_THRESHOLD", emsr_ok},
92         // aaaaaahhhhhhhhhhhhhhhhhhhhh
93         {MSR_ARCH_PERFMON_EVENTSEL0, "MSR_ARCH_PERFMON_EVENTSEL0", emsr_ok},
94         {MSR_ARCH_PERFMON_EVENTSEL1, "MSR_ARCH_PERFMON_EVENTSEL0", emsr_ok},
95         {MSR_IA32_PERF_CAPABILITIES, "MSR_IA32_PERF_CAPABILITIES", emsr_ok},
96         // unsafe.
97         {MSR_IA32_APICBASE, "MSR_IA32_APICBASE", emsr_fakewrite},
98
99         // mostly harmless.
100         {MSR_TSC_AUX, "MSR_TSC_AUX", emsr_fakewrite},
101         {MSR_RAPL_POWER_UNIT, "MSR_RAPL_POWER_UNIT", emsr_readzero},
102 };
103
104 static uint64_t set_low32(uint64_t hi, uint32_t lo)
105 {
106         return (hi & 0xffffffff00000000ULL) | lo;
107 }
108
109 static uint64_t set_low16(uint64_t hi, uint16_t lo)
110 {
111         return (hi & 0xffffffffffff0000ULL) | lo;
112 }
113
114 static uint64_t set_low8(uint64_t hi, uint8_t lo)
115 {
116         return (hi & 0xffffffffffffff00ULL) | lo;
117 }
118
119 /* this may be the only register that needs special handling.
120  * If there others then we might want to extend teh emmsr struct.
121  */
122 int emsr_miscenable(struct vmctl *vcpu, struct emmsr *msr,
123                     uint32_t opcode) {
124         uint32_t eax, edx;
125         rdmsr(msr->reg, eax, edx);
126         /* we just let them read the misc msr for now. */
127         if (opcode == EXIT_REASON_MSR_READ) {
128                 vcpu->regs.tf_rax = set_low32(vcpu->regs.tf_rax, eax);
129                 vcpu->regs.tf_rax |= MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL;
130                 vcpu->regs.tf_rdx = set_low32(vcpu->regs.tf_rdx, edx);
131                 return 0;
132         } else {
133                 /* if they are writing what is already written, that's ok. */
134                 if (((uint32_t) vcpu->regs.tf_rax == eax)
135                     && ((uint32_t) vcpu->regs.tf_rdx == edx))
136                         return 0;
137         }
138         fprintf(stderr, 
139                 "%s: Wanted to write 0x%x:0x%x, but could not; value was 0x%x:0x%x\n",
140                  msr->name, (uint32_t) vcpu->regs.tf_rdx,
141                  (uint32_t) vcpu->regs.tf_rax, edx, eax);
142         return SHUTDOWN_UNHANDLED_EXIT_REASON;
143 }
144
145 int emsr_mustmatch(struct vmctl *vcpu, struct emmsr *msr,
146                    uint32_t opcode) {
147         uint32_t eax, edx;
148         rdmsr(msr->reg, eax, edx);
149         /* we just let them read the misc msr for now. */
150         if (opcode == EXIT_REASON_MSR_READ) {
151                 vcpu->regs.tf_rax = set_low32(vcpu->regs.tf_rax, eax);
152                 vcpu->regs.tf_rdx = set_low32(vcpu->regs.tf_rdx, edx);
153                 return 0;
154         } else {
155                 /* if they are writing what is already written, that's ok. */
156                 if (((uint32_t) vcpu->regs.tf_rax == eax)
157                     && ((uint32_t) vcpu->regs.tf_rdx == edx))
158                         return 0;
159         }
160         fprintf(stderr,
161                 "%s: Wanted to write 0x%x:0x%x, but could not; value was 0x%x:0x%x\n",
162                  msr->name, (uint32_t) vcpu->regs.tf_rdx,
163                  (uint32_t) vcpu->regs.tf_rax, edx, eax);
164         return SHUTDOWN_UNHANDLED_EXIT_REASON;
165 }
166
167 int emsr_ok(struct vmctl *vcpu, struct emmsr *msr, uint32_t opcode)
168 {
169         if (opcode == EXIT_REASON_MSR_READ) {
170                 rdmsr(msr->reg, vcpu->regs.tf_rdx, vcpu->regs.tf_rax);
171         } else {
172                 uint64_t val =
173                         (uint64_t) vcpu->regs.tf_rdx << 32 | vcpu->regs.tf_rax;
174                 write_msr(msr->reg, val);
175         }
176         return 0;
177 }
178
179 int emsr_readonly(struct vmctl *vcpu, struct emmsr *msr, uint32_t opcode)
180 {
181         uint32_t eax, edx;
182         rdmsr((uint32_t) vcpu->regs.tf_rcx, eax, edx);
183         /* we just let them read the misc msr for now. */
184         if (opcode == EXIT_REASON_MSR_READ) {
185                 vcpu->regs.tf_rax = set_low32(vcpu->regs.tf_rax, eax);
186                 vcpu->regs.tf_rdx = set_low32(vcpu->regs.tf_rdx, edx);
187                 return 0;
188         }
189
190         fprintf(stderr,"%s: Tried to write a readonly register\n", msr->name);
191         return SHUTDOWN_UNHANDLED_EXIT_REASON;
192 }
193
194 int emsr_readzero(struct vmctl *vcpu, struct emmsr *msr, uint32_t opcode)
195 {
196         if (opcode == EXIT_REASON_MSR_READ) {
197                 vcpu->regs.tf_rax = 0;
198                 vcpu->regs.tf_rdx = 0;
199                 return 0;
200         }
201
202         fprintf(stderr,"%s: Tried to write a readonly register\n", msr->name);
203         return SHUTDOWN_UNHANDLED_EXIT_REASON;
204 }
205
206 /* pretend to write it, but don't write it. */
207 int emsr_fakewrite(struct vmctl *vcpu, struct emmsr *msr, uint32_t opcode)
208 {
209         uint32_t eax, edx;
210         if (!msr->written) {
211                 rdmsr(msr->reg, eax, edx);
212         } else {
213                 edx = msr->edx;
214                 eax = msr->eax;
215         }
216         /* we just let them read the misc msr for now. */
217         if (opcode == EXIT_REASON_MSR_READ) {
218                 vcpu->regs.tf_rax = set_low32(vcpu->regs.tf_rax, eax);
219                 vcpu->regs.tf_rdx = set_low32(vcpu->regs.tf_rdx, edx);
220                 return 0;
221         } else {
222                 /* if they are writing what is already written, that's ok. */
223                 if (((uint32_t) vcpu->regs.tf_rax == eax)
224                     && ((uint32_t) vcpu->regs.tf_rdx == edx))
225                         return 0;
226                 msr->edx = vcpu->regs.tf_rdx;
227                 msr->eax = vcpu->regs.tf_rax;
228                 msr->written = true;
229         }
230         return 0;
231 }
232
233 int
234 msrio(struct vmctl *vcpu, uint32_t opcode) {
235         int i;
236         for (i = 0; i < sizeof(emmsrs)/sizeof(emmsrs[0]); i++) {
237                 if (emmsrs[i].reg != vcpu->regs.tf_rcx)
238                         continue;
239                 return emmsrs[i].f(vcpu, &emmsrs[i], opcode);
240         }
241         fprintf(stderr,"msrio for 0x%lx failed\n", vcpu->regs.tf_rcx);
242         return SHUTDOWN_UNHANDLED_EXIT_REASON;
243 }
244