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