parlib: have 2LS libraries #include parlib/stdio.h
[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 <parlib/stdio.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 #include <parlib/arch/arch.h>
14 #include <parlib/ros_debug.h>
15 #include <unistd.h>
16 #include <errno.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/uio.h>
20 #include <stdint.h>
21 #include <err.h>
22 #include <sys/mman.h>
23 #include <ros/vmm.h>
24 #include <ros/arch/msr-index.h>
25 #include <vmm/virtio.h>
26 #include <vmm/virtio_mmio.h>
27 #include <vmm/virtio_ids.h>
28 #include <vmm/virtio_config.h>
29 #include <vmm/sched.h>
30 #include <vmm/vmm.h>
31 #include <ros/arch/trapframe.h>
32 #include <parlib/alarm.h>
33
34 struct emmsr {
35         uint32_t reg;
36         char *name;
37         int (*f)(struct guest_thread *vm_thread, struct emmsr *, uint32_t);
38         bool written;
39         uint32_t edx, eax;
40 };
41
42 static inline uint64_t read_msr(uint32_t reg)
43 {
44         panic("Not implemented for userspace");
45 }
46
47 static inline void write_msr(uint32_t reg, uint64_t val)
48 {
49         panic("Not implemented for userspace");
50 }
51
52 static int emsr_readonly(struct guest_thread *vm_thread, struct emmsr *,
53                          uint32_t);
54 static int emsr_readzero(struct guest_thread *vm_thread, struct emmsr *,
55                          uint32_t);
56 static int emsr_fakewrite(struct guest_thread *vm_thread, struct emmsr *,
57                           uint32_t);
58 static int emsr_ok(struct guest_thread *vm_thread, struct emmsr *, uint32_t);
59
60 struct emmsr emmsrs[] = {
61         {MSR_RAPL_POWER_UNIT, "MSR_RAPL_POWER_UNIT", emsr_readzero},
62 };
63
64 static inline uint32_t low32(uint64_t val)
65 {
66         return val & 0xffffffff;
67 }
68
69 static inline uint32_t high32(uint64_t val)
70 {
71         return val >> 32;
72 }
73
74 static int emsr_ok(struct guest_thread *vm_thread, struct emmsr *msr,
75                    uint32_t opcode)
76 {
77         struct vm_trapframe *vm_tf = &(vm_thread->uthread.u_ctx.tf.vm_tf);
78         uint64_t msr_val;
79
80         if (opcode == EXIT_REASON_MSR_READ) {
81                 msr_val = read_msr(msr->reg);
82                 vm_tf->tf_rax = low32(msr_val);
83                 vm_tf->tf_rdx = high32(msr_val);
84         } else {
85                 msr_val = (vm_tf->tf_rdx << 32) | vm_tf->tf_rax;
86                 write_msr(msr->reg, msr_val);
87         }
88         return 0;
89 }
90
91 static int emsr_readonly(struct guest_thread *vm_thread, struct emmsr *msr,
92                          uint32_t opcode)
93 {
94         struct vm_trapframe *vm_tf = &(vm_thread->uthread.u_ctx.tf.vm_tf);
95         uint64_t msr_val;
96
97         msr_val = read_msr(msr->reg);
98         if (opcode == EXIT_REASON_MSR_READ) {
99                 vm_tf->tf_rax = low32(msr_val);
100                 vm_tf->tf_rdx = high32(msr_val);
101                 return 0;
102         }
103
104         fprintf(stderr,"%s: Tried to write a readonly register\n", msr->name);
105         return SHUTDOWN_UNHANDLED_EXIT_REASON;
106 }
107
108 static int emsr_readzero(struct guest_thread *vm_thread, struct emmsr *msr,
109                          uint32_t opcode)
110 {
111         struct vm_trapframe *vm_tf = &(vm_thread->uthread.u_ctx.tf.vm_tf);
112
113         if (opcode == EXIT_REASON_MSR_READ) {
114                 vm_tf->tf_rax = 0;
115                 vm_tf->tf_rdx = 0;
116                 return 0;
117         }
118
119         fprintf(stderr,"%s: Tried to write a readonly register\n", msr->name);
120         return SHUTDOWN_UNHANDLED_EXIT_REASON;
121 }
122
123 /* pretend to write it, but don't write it. */
124 static int emsr_fakewrite(struct guest_thread *vm_thread, struct emmsr *msr,
125                           uint32_t opcode)
126 {
127         uint32_t eax, edx;
128         uint64_t msr_val;
129         struct vm_trapframe *vm_tf = &(vm_thread->uthread.u_ctx.tf.vm_tf);
130
131         if (!msr->written) {
132                 msr_val = read_msr(msr->reg);
133                 eax = low32(msr_val);
134                 edx = high32(msr_val);
135         } else {
136                 eax = msr->eax;
137                 edx = msr->edx;
138         }
139         if (opcode == EXIT_REASON_MSR_READ) {
140                 vm_tf->tf_rax = eax;
141                 vm_tf->tf_rdx = edx;
142                 return 0;
143         } else {
144                 msr->edx = vm_tf->tf_rdx;
145                 msr->eax = vm_tf->tf_rax;
146                 msr->written = true;
147         }
148         return 0;
149 }
150
151 static int apic_icr_write(struct guest_thread *vm_thread,
152                           struct vmm_gpcore_init *gpci)
153 {
154         /* We currently only handle physical destinations.
155          * TODO(ganshun): Support logical destinations if needed. */
156         struct virtual_machine *vm = gth_to_vm(vm_thread);
157         struct vm_trapframe *vm_tf = gth_to_vmtf(vm_thread);
158         uint32_t destination = vm_tf->tf_rdx & 0xffffffff;
159         uint8_t vector = vm_tf->tf_rax & 0xff;
160         uint8_t type = (vm_tf->tf_rax >> 8) & 0x7;
161         int apic_offset = vm_tf->tf_rcx & 0xff;
162
163         if (destination >= vm->nr_gpcs && destination != 0xffffffff) {
164                 fprintf(stderr, "UNSUPPORTED DESTINATION 0x%02x!\n",
165                                 destination);
166                 return SHUTDOWN_UNHANDLED_EXIT_REASON;
167         }
168         switch (type) {
169         case 0:
170                 /* Send IPI */
171                 if (destination == 0xffffffff) {
172                         /* Broadcast */
173                         for (int i = 0; i < vm->nr_gpcs; i++)
174                                 vmm_interrupt_guest(vm, i, vector);
175                 } else {
176                         /* Send individual IPI */
177                         vmm_interrupt_guest(vm, destination, vector);
178                 }
179                 break;
180         case 0x5:       /* INIT */
181         case 0x6:       /* SIPI */
182                 /* We don't use INIT/SIPI for SMP boot.  The guest is still
183                  * allowed to try to make them for now. */
184                 break;
185         default:
186                 fprintf(stderr, "Unsupported IPI type %d!\n", type);
187                 break;
188         }
189
190         ((uint32_t *)(gpci->vapic_addr))[apic_offset] =
191                                                (uint32_t)(vm_tf->tf_rax);
192         ((uint32_t *)(gpci->vapic_addr))[apic_offset + 1] =
193                                                (uint32_t)(vm_tf->tf_rdx);
194         return 0;
195 }
196
197 static int apic_timer_write(struct guest_thread *gth,
198                             struct vmm_gpcore_init *gpci)
199 {
200         uint32_t multiplier;
201         uint8_t vector;
202         uint32_t initial_count;
203         uint32_t divide_config_reg;
204         struct alarm_waiter *timer_waiter;
205         struct vm_trapframe *vm_tf = gth_to_vmtf(gth);
206         int apic_offset = vm_tf->tf_rcx & 0xff;
207
208         ((uint32_t *)(gpci->vapic_addr))[apic_offset] =
209                                        (uint32_t)(vm_tf->tf_rax);
210
211         /* See if we can set the timer. */
212         vector = ((uint32_t *)gpci->vapic_addr)[0x32] & 0xff;
213         initial_count = ((uint32_t *)gpci->vapic_addr)[0x38];
214         divide_config_reg = ((uint32_t *)gpci->vapic_addr)[0x3E];
215         timer_waiter = (struct alarm_waiter*)gth->user_data;
216
217         /* This is a precaution on my part, in case the guest tries to look at
218          * the current count on the lapic. I wanted it to be something other
219          * than 0 just in case. The current count will never be right short of
220          * us properly emulating it. */
221         ((uint32_t *)(gpci->vapic_addr))[0x39] = initial_count;
222
223         if (!timer_waiter)
224                 panic("NO WAITER");
225
226         /* Look at the intel manual Vol 3 10.5.4 APIC Timer */
227         multiplier = (((divide_config_reg & 0x08) >> 1) |
228                       (divide_config_reg & 0x03)) + 1;
229         multiplier &= 0x07;
230
231         unset_alarm(timer_waiter);
232
233         if (vector && initial_count) {
234                 set_awaiter_rel(timer_waiter, initial_count << multiplier);
235                 set_alarm(timer_waiter);
236         }
237         return 0;
238 }
239
240 static int emsr_apic(struct guest_thread *vm_thread,
241                      struct vmm_gpcore_init *gpci, uint32_t opcode)
242 {
243         struct vm_trapframe *vm_tf = &(vm_thread->uthread.u_ctx.tf.vm_tf);
244         int apic_offset = vm_tf->tf_rcx & 0xff;
245         uint64_t value;
246         int error;
247
248         if (opcode == EXIT_REASON_MSR_READ) {
249                 if (vm_tf->tf_rcx != MSR_LAPIC_ICR) {
250                         vm_tf->tf_rax =
251                                 ((uint32_t*)(gpci->vapic_addr))[apic_offset];
252                         vm_tf->tf_rdx = 0;
253                 } else {
254                         vm_tf->tf_rax =
255                                 ((uint32_t*)(gpci->vapic_addr))[apic_offset];
256                         vm_tf->tf_rdx =
257                                 ((uint32_t*)(gpci->vapic_addr))[apic_offset +1];
258                 }
259         } else {
260                 switch (vm_tf->tf_rcx) {
261                 case MSR_LAPIC_ICR:
262                         error = apic_icr_write(vm_thread, gpci);
263                         if (error != 0)
264                                 return error;
265                         break;
266                 case MSR_LAPIC_DIVIDE_CONFIG_REG:
267                 case MSR_LAPIC_LVT_TIMER:
268                 case MSR_LAPIC_INITIAL_COUNT:
269                         apic_timer_write(vm_thread, gpci);
270                         break;
271                 default:
272                         ((uint32_t *)(gpci->vapic_addr))[apic_offset] =
273                                 (uint32_t)(vm_tf->tf_rax);
274                 }
275         }
276         return 0;
277 }
278
279 int msrio(struct guest_thread *vm_thread, struct vmm_gpcore_init *gpci,
280           uint32_t opcode)
281 {
282         int i;
283         struct vm_trapframe *vm_tf = &(vm_thread->uthread.u_ctx.tf.vm_tf);
284
285         if (vm_tf->tf_rcx >= MSR_LAPIC_ID && vm_tf->tf_rcx < MSR_LAPIC_END)
286                 return emsr_apic(vm_thread, gpci, opcode);
287
288         for (i = 0; i < sizeof(emmsrs)/sizeof(emmsrs[0]); i++) {
289                 if (emmsrs[i].reg != vm_tf->tf_rcx)
290                         continue;
291                 return emmsrs[i].f(vm_thread, &emmsrs[i], opcode);
292         }
293         printd("msrio for 0x%lx failed\n", vm_tf->tf_rcx);
294         return SHUTDOWN_UNHANDLED_EXIT_REASON;
295 }
296