1/*
2 * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7/*handling msr read & write exceptions*/
8
9#include <stdio.h>
10#include <stdlib.h>
11
12#include <sel4/sel4.h>
13
14#include <sel4vm/guest_vm.h>
15#include <sel4vm/arch/guest_x86_context.h>
16
17#include "vm.h"
18#include "guest_state.h"
19#include "processor/msr.h"
20#include "processor/lapic.h"
21#include "interrupt.h"
22
23int vm_rdmsr_handler(vm_vcpu_t *vcpu)
24{
25
26    int ret = 0;
27    unsigned int msr_no;
28    if (vm_get_thread_context_reg(vcpu, VCPU_CONTEXT_ECX, &msr_no)) {
29        return VM_EXIT_HANDLE_ERROR;
30    }
31    uint64_t data = 0;
32
33    ZF_LOGD("rdmsr ecx 0x%x\n", msr_no);
34
35    // src reference: Linux kernel 3.11 kvm arch/x86/kvm/x86.c
36    switch (msr_no) {
37    case MSR_IA32_PLATFORM_ID:
38    case MSR_IA32_EBL_CR_POWERON:
39    case MSR_IA32_DEBUGCTLMSR:
40    case MSR_IA32_LASTBRANCHFROMIP:
41    case MSR_IA32_LASTBRANCHTOIP:
42    case MSR_IA32_LASTINTFROMIP:
43    case MSR_IA32_LASTINTTOIP:
44    case MSR_IA32_MISC_ENABLE:
45        data = 0;
46        break;
47
48    case MSR_IA32_UCODE_REV:
49        data = 0x100000000ULL;
50        break;
51
52    case MSR_P6_PERFCTR0:
53    case MSR_P6_PERFCTR1:
54    case MSR_P6_EVNTSEL0:
55    case MSR_P6_EVNTSEL1:
56    case MSR_IA32_PERF_GLOBAL_STATUS_SET:
57        /* performance counters not supported. */
58        data = 0;
59        break;
60
61    case 0xcd: /* fsb frequency */
62        data = 3;
63        break;
64
65    case MSR_EBC_FREQUENCY_ID:
66        data = 1 << 24;
67        break;
68
69    case MSR_IA32_APICBASE:
70        data = vm_lapic_get_base_msr(vcpu);
71        break;
72
73    default:
74        ZF_LOGW("rdmsr WARNING unsupported msr_no 0x%x\n", msr_no);
75        // generate a GP fault
76        vm_inject_exception(vcpu, 13, 1, 0);
77        return VM_EXIT_HANDLED;
78
79    }
80
81    if (!ret) {
82        vm_set_thread_context_reg(vcpu, VCPU_CONTEXT_EAX, (uint32_t)(data & 0xffffffff));
83        vm_set_thread_context_reg(vcpu, VCPU_CONTEXT_EDX, (uint32_t)(data >> 32));
84        vm_guest_exit_next_instruction(vcpu->vcpu_arch.guest_state, vcpu->vcpu.cptr);
85        return VM_EXIT_HANDLED;
86    }
87
88    return VM_EXIT_HANDLE_ERROR;
89}
90
91int vm_wrmsr_handler(vm_vcpu_t *vcpu)
92{
93
94    int ret = 0;
95
96    unsigned int msr_no;
97    if (vm_get_thread_context_reg(vcpu, VCPU_CONTEXT_ECX, &msr_no)) {
98        return VM_EXIT_HANDLE_ERROR;
99    }
100    unsigned int val_high, val_low;
101
102    if (vm_get_thread_context_reg(vcpu, VCPU_CONTEXT_EDX, &val_high)
103        || vm_get_thread_context_reg(vcpu, VCPU_CONTEXT_EAX, &val_low)) {
104        return VM_EXIT_HANDLE_ERROR;
105    }
106
107    ZF_LOGD("wrmsr ecx 0x%x   value: 0x%x  0x%x\n", msr_no, val_high, val_low);
108
109    // src reference: Linux kernel 3.11 kvm arch/x86/kvm/x86.c
110    switch (msr_no) {
111    case MSR_IA32_UCODE_REV:
112    case MSR_IA32_UCODE_WRITE:
113        break;
114
115    case MSR_P6_PERFCTR0:
116    case MSR_P6_PERFCTR1:
117    case MSR_P6_EVNTSEL0:
118    case MSR_P6_EVNTSEL1:
119    case MSR_IA32_PERF_GLOBAL_STATUS_SET:
120        /* performance counters not supported. */
121        break;
122
123    case MSR_IA32_APICBASE:
124        vm_lapic_set_base_msr(vcpu, val_low);
125        break;
126
127    default:
128        ZF_LOGW("wrmsr WARNING unsupported msr_no 0x%x\n", msr_no);
129        // generate a GP fault
130        vm_inject_exception(vcpu, 13, 1, 0);
131        return VM_EXIT_HANDLED;
132    }
133
134    vm_guest_exit_next_instruction(vcpu->vcpu_arch.guest_state, vcpu->vcpu.cptr);
135    return VM_EXIT_HANDLED;
136
137}
138