blob: 235732e1d29dd78ede757c0e76d9acc32c98fee3 [file] [log] [blame]
/*
* Copyright 2017, Data61
* Commonwealth Scientific and Industrial Research Organisation (CSIRO)
* ABN 41 687 119 230.
*
* This software may be distributed and modified according to the terms of
* the GNU General Public License version 2. Note that NO WARRANTY is provided.
* See "LICENSE_GPLv2.txt" for details.
*
* @TAG(DATA61_GPL)
*/
/*handling msr read & write exceptions*/
#include <stdio.h>
#include <stdlib.h>
#include <sel4/sel4.h>
#include "vmm/debug.h"
#include "vmm/vmm.h"
#include "vmm/processor/msr.h"
int vmm_rdmsr_handler(vmm_vcpu_t *vcpu) {
int ret = 0;
unsigned int msr_no = vmm_read_user_context(&vcpu->guest_state, USER_CONTEXT_ECX);
uint64_t data = 0;
DPRINTF(4, "rdmsr ecx 0x%x\n", msr_no);
// src reference: Linux kernel 3.11 kvm arch/x86/kvm/x86.c
switch (msr_no) {
case MSR_IA32_PLATFORM_ID:
case MSR_IA32_EBL_CR_POWERON:
case MSR_IA32_DEBUGCTLMSR:
case MSR_IA32_LASTBRANCHFROMIP:
case MSR_IA32_LASTBRANCHTOIP:
case MSR_IA32_LASTINTFROMIP:
case MSR_IA32_LASTINTTOIP:
case MSR_IA32_MISC_ENABLE:
data = 0;
break;
case MSR_IA32_UCODE_REV:
data = 0x100000000ULL;
break;
case MSR_P6_PERFCTR0:
case MSR_P6_PERFCTR1:
case MSR_P6_EVNTSEL0:
case MSR_P6_EVNTSEL1:
case MSR_IA32_PERF_GLOBAL_STATUS_SET:
/* performance counters not supported. */
data = 0;
break;
case 0xcd: /* fsb frequency */
data = 3;
break;
case MSR_EBC_FREQUENCY_ID:
data = 1 << 24;
break;
case MSR_IA32_APICBASE:
data = vmm_lapic_get_base_msr(vcpu);
break;
default:
DPRINTF(1, "rdmsr WARNING unsupported msr_no 0x%x\n", msr_no);
// generate a GP fault
vmm_inject_exception(vcpu, 13, 1, 0);
return 0;
}
if (!ret) {
vmm_set_user_context(&vcpu->guest_state, USER_CONTEXT_EAX, (uint32_t)(data & 0xffffffff));
vmm_set_user_context(&vcpu->guest_state, USER_CONTEXT_EDX, (uint32_t)(data >> 32));
vmm_guest_exit_next_instruction(&vcpu->guest_state, vcpu->guest_vcpu);
}
return ret;
}
int vmm_wrmsr_handler(vmm_vcpu_t *vcpu) {
int ret = 0;
unsigned int msr_no = vmm_read_user_context(&vcpu->guest_state, USER_CONTEXT_ECX);
unsigned int val_high = vmm_read_user_context(&vcpu->guest_state, USER_CONTEXT_EDX);
unsigned int val_low = vmm_read_user_context(&vcpu->guest_state, USER_CONTEXT_EAX);
DPRINTF(4, "wrmsr ecx 0x%x value: 0x%x 0x%x\n", msr_no, val_high, val_low);
// src reference: Linux kernel 3.11 kvm arch/x86/kvm/x86.c
switch (msr_no) {
case MSR_IA32_UCODE_REV:
case MSR_IA32_UCODE_WRITE:
break;
case MSR_P6_PERFCTR0:
case MSR_P6_PERFCTR1:
case MSR_P6_EVNTSEL0:
case MSR_P6_EVNTSEL1:
case MSR_IA32_PERF_GLOBAL_STATUS_SET:
/* performance counters not supported. */
break;
case MSR_IA32_APICBASE:
vmm_lapic_set_base_msr(vcpu, val_low);
break;
default:
DPRINTF(1, "wrmsr WARNING unsupported msr_no 0x%x\n", msr_no);
// generate a GP fault
vmm_inject_exception(vcpu, 13, 1, 0);
return 0;
}
if (!ret)
vmm_guest_exit_next_instruction(&vcpu->guest_state, vcpu->guest_vcpu);
return ret;
}