mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-22 05:30:24 +00:00
hv: support minimum set of TLFS
This patch implements the minimum set of TLFS functionality. It includes 6 vCPUID leaves and 3 vMSRs. - 0x40000001 Hypervisor Vendor-Neutral Interface Identification - 0x40000002 Hypervisor System Identity - 0x40000003 Hypervisor Feature Identification - 0x40000004 Implementation Recommendations - 0x40000005 Hypervisor Implementation Limits - 0x40000006 Implementation Hardware Features - HV_X64_MSR_GUEST_OS_ID Reporting the guest OS identity - HV_X64_MSR_HYPERCALL Establishing the hypercall interface - HV_X64_MSR_VP_INDEX Retrieve the vCPU ID from hypervisor Tracked-On: #3832 Signed-off-by: wenwumax <wenwux.ma@intel.com> Signed-off-by: Jian Jun Chen <jian.jun.chen@intel.com> Acked-by: Anthony Xu <anthony.xu@intel.com>
This commit is contained in:
parent
009d835bba
commit
048155d3d6
@ -250,6 +250,9 @@ VP_BASE_C_SRCS += arch/x86/guest/virtual_cr.c
|
|||||||
VP_BASE_C_SRCS += arch/x86/guest/vmexit.c
|
VP_BASE_C_SRCS += arch/x86/guest/vmexit.c
|
||||||
VP_BASE_C_SRCS += arch/x86/guest/ept.c
|
VP_BASE_C_SRCS += arch/x86/guest/ept.c
|
||||||
VP_BASE_C_SRCS += arch/x86/guest/ucode.c
|
VP_BASE_C_SRCS += arch/x86/guest/ucode.c
|
||||||
|
ifeq ($(CONFIG_HYPERV_ENABLED),y)
|
||||||
|
VP_BASE_C_SRCS += arch/x86/guest/hyperv.c
|
||||||
|
endif
|
||||||
VP_BASE_C_SRCS += boot/guest/vboot_info.c
|
VP_BASE_C_SRCS += boot/guest/vboot_info.c
|
||||||
VP_BASE_C_SRCS += common/hv_main.c
|
VP_BASE_C_SRCS += common/hv_main.c
|
||||||
VP_BASE_C_SRCS += common/vm_load.c
|
VP_BASE_C_SRCS += common/vm_load.c
|
||||||
|
@ -226,6 +226,13 @@ config ACPI_PARSE_ENABLED
|
|||||||
help
|
help
|
||||||
Whether to parse the ACPI tables at runtime.
|
Whether to parse the ACPI tables at runtime.
|
||||||
|
|
||||||
|
config HYPERV_ENABLED
|
||||||
|
bool "Enable Hyper-V enlightenment"
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
When set, the minimum set of TLFS functionality together with some
|
||||||
|
performance enlightenments are enabled.
|
||||||
|
|
||||||
config GPU_SBDF
|
config GPU_SBDF
|
||||||
hex "Segment, Bus, Device, and function of the GPU"
|
hex "Segment, Bus, Device, and function of the GPU"
|
||||||
depends on ACPI_PARSE_ENABLED
|
depends on ACPI_PARSE_ENABLED
|
||||||
|
160
hypervisor/arch/x86/guest/hyperv.c
Normal file
160
hypervisor/arch/x86/guest/hyperv.c
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* Microsoft Hyper-V emulation. See Microsoft's
|
||||||
|
* Hypervisor Top Level Functional Specification for more information.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
#include <vm.h>
|
||||||
|
#include <logmsg.h>
|
||||||
|
#include <hyperv.h>
|
||||||
|
|
||||||
|
#define ACRN_DBG_HYPERV 6U
|
||||||
|
|
||||||
|
/* Hypercall MSRs (HV_X64_MSR_GUEST_OS_ID and HV_X64_MSR_HYPERCALL) */
|
||||||
|
#define CPUID3A_HYPERCALL_MSR (1U << 5U)
|
||||||
|
/* Access virtual processor index MSR (HV_X64_MSR_VP_INDEX) */
|
||||||
|
#define CPUID3A_VP_INDEX_MSR (1U << 6U)
|
||||||
|
|
||||||
|
static void
|
||||||
|
hyperv_setup_hypercall_page(const struct acrn_vcpu *vcpu, uint64_t val)
|
||||||
|
{
|
||||||
|
union hyperv_hypercall_msr hypercall;
|
||||||
|
uint64_t page_gpa;
|
||||||
|
void *page_hva;
|
||||||
|
|
||||||
|
/* asm volatile ("mov $2,%%eax; mov $0,%%edx; ret":::"eax","edx"); */
|
||||||
|
const uint8_t inst[11] = {0xb8U, 0x02U, 0x0U, 0x0U, 0x0U, 0xbaU, 0x0U, 0x0U, 0x0U, 0x0U, 0xc3U};
|
||||||
|
|
||||||
|
hypercall.val64 = val;
|
||||||
|
|
||||||
|
if (hypercall.enabled != 0UL) {
|
||||||
|
page_gpa = hypercall.gpfn << PAGE_SHIFT;
|
||||||
|
page_hva = gpa2hva(vcpu->vm, page_gpa);
|
||||||
|
if (page_hva != NULL) {
|
||||||
|
stac();
|
||||||
|
(void)memset(page_hva, 0U, PAGE_SIZE);
|
||||||
|
(void)memcpy_s(page_hva, 11U, inst, 11U);
|
||||||
|
clac();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
hyperv_wrmsr(struct acrn_vcpu *vcpu, uint32_t msr, uint64_t wval)
|
||||||
|
{
|
||||||
|
int32_t ret = 0;
|
||||||
|
|
||||||
|
switch (msr) {
|
||||||
|
case HV_X64_MSR_GUEST_OS_ID:
|
||||||
|
vcpu->vm->arch_vm.hyperv.guest_os_id.val64 = wval;
|
||||||
|
if (wval == 0UL) {
|
||||||
|
vcpu->vm->arch_vm.hyperv.hypercall_page.enabled = 0UL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HV_X64_MSR_HYPERCALL:
|
||||||
|
if (vcpu->vm->arch_vm.hyperv.guest_os_id.val64 == 0UL) {
|
||||||
|
pr_warn("hv: %s: guest_os_id is 0", __func__);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
vcpu->vm->arch_vm.hyperv.hypercall_page.val64 = wval;
|
||||||
|
hyperv_setup_hypercall_page(vcpu, wval);
|
||||||
|
break;
|
||||||
|
case HV_X64_MSR_VP_INDEX:
|
||||||
|
/* read only */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pr_err("hv: %s: unexpected MSR[0x%x] write", __func__, msr);
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_dbg(ACRN_DBG_HYPERV, "hv: %s: MSR=0x%x wval=0x%llx vcpuid=%d vmid=%d",
|
||||||
|
__func__, msr, wval, vcpu->vcpu_id, vcpu->vm->vm_id);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
hyperv_rdmsr(struct acrn_vcpu *vcpu, uint32_t msr, uint64_t *rval)
|
||||||
|
{
|
||||||
|
int32_t ret = 0;
|
||||||
|
|
||||||
|
switch (msr) {
|
||||||
|
case HV_X64_MSR_GUEST_OS_ID:
|
||||||
|
*rval = vcpu->vm->arch_vm.hyperv.guest_os_id.val64;
|
||||||
|
break;
|
||||||
|
case HV_X64_MSR_HYPERCALL:
|
||||||
|
*rval = vcpu->vm->arch_vm.hyperv.hypercall_page.val64;
|
||||||
|
break;
|
||||||
|
case HV_X64_MSR_VP_INDEX:
|
||||||
|
*rval = vcpu->vcpu_id;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pr_err("hv: %s: unexpected MSR[0x%x] read", __func__, msr);
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_dbg(ACRN_DBG_HYPERV, "hv: %s: MSR=0x%x rval=0x%llx vcpuid=%d vmid=%d",
|
||||||
|
__func__, msr, *rval, vcpu->vcpu_id, vcpu->vm->vm_id);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hyperv_init_vcpuid_entry(uint32_t leaf, uint32_t subleaf, uint32_t flags,
|
||||||
|
struct vcpuid_entry *entry)
|
||||||
|
{
|
||||||
|
entry->leaf = leaf;
|
||||||
|
entry->subleaf = subleaf;
|
||||||
|
entry->flags = flags;
|
||||||
|
|
||||||
|
switch (leaf) {
|
||||||
|
case 0x40000001U: /* HV interface version */
|
||||||
|
entry->eax = 0x31237648U; /* "Hv#1" */
|
||||||
|
entry->ebx = 0U;
|
||||||
|
entry->ecx = 0U;
|
||||||
|
entry->edx = 0U;
|
||||||
|
break;
|
||||||
|
case 0x40000002U: /* HV system identity */
|
||||||
|
entry->eax = 0U;
|
||||||
|
entry->ebx = 0U;
|
||||||
|
entry->ecx = 0U;
|
||||||
|
entry->edx = 0U;
|
||||||
|
break;
|
||||||
|
case 0x40000003U: /* HV supported feature */
|
||||||
|
entry->eax = CPUID3A_HYPERCALL_MSR | CPUID3A_VP_INDEX_MSR;
|
||||||
|
entry->ebx = 0U;
|
||||||
|
entry->ecx = 0U;
|
||||||
|
entry->edx = 0U;
|
||||||
|
break;
|
||||||
|
case 0x40000004U: /* HV Recommended hypercall usage */
|
||||||
|
entry->eax = 0U;
|
||||||
|
entry->ebx = 0U;
|
||||||
|
entry->ecx = 0U;
|
||||||
|
entry->edx = 0U;
|
||||||
|
break;
|
||||||
|
case 0x40000005U: /* HV Maximum Supported Virtual & logical Processors */
|
||||||
|
entry->eax = CONFIG_MAX_VCPUS_PER_VM;
|
||||||
|
entry->ebx = 0U;
|
||||||
|
entry->ecx = 0U;
|
||||||
|
entry->edx = 0U;
|
||||||
|
break;
|
||||||
|
case 0x40000006U: /* Implementation Hardware Features */
|
||||||
|
entry->eax = 0U;
|
||||||
|
entry->ebx = 0U;
|
||||||
|
entry->ecx = 0U;
|
||||||
|
entry->edx = 0U;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* do nothing */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_dbg(ACRN_DBG_HYPERV, "hv: %s: leaf=%x subleaf=%x flags=%x eax=%x ebx=%x ecx=%x edx=%x",
|
||||||
|
__func__, leaf, subleaf, flags, entry->eax, entry->ebx, entry->ecx, entry->edx);
|
||||||
|
}
|
@ -263,9 +263,26 @@ static int32_t set_vcpuid_extended_function(struct acrn_vm *vm)
|
|||||||
if (is_sos_vm(vm)) {
|
if (is_sos_vm(vm)) {
|
||||||
entry.eax |= GUEST_CAPS_PRIVILEGE_VM;
|
entry.eax |= GUEST_CAPS_PRIVILEGE_VM;
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_HYPERV_ENABLED
|
||||||
|
else {
|
||||||
|
hyperv_init_vcpuid_entry(0x40000001U, 0U, 0U, &entry);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
result = set_vcpuid_entry(vm, &entry);
|
result = set_vcpuid_entry(vm, &entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_HYPERV_ENABLED
|
||||||
|
if (result == 0) {
|
||||||
|
for (i = 0x40000002U; i <= 0x40000006U; i++) {
|
||||||
|
hyperv_init_vcpuid_entry(i, 0U, 0U, &entry);
|
||||||
|
result = set_vcpuid_entry(vm, &entry);
|
||||||
|
if (result != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
init_vcpuid_entry(0x40000010U, 0U, 0U, &entry);
|
init_vcpuid_entry(0x40000010U, 0U, 0U, &entry);
|
||||||
result = set_vcpuid_entry(vm, &entry);
|
result = set_vcpuid_entry(vm, &entry);
|
||||||
|
@ -397,6 +397,15 @@ int32_t rdmsr_vmexit_handler(struct acrn_vcpu *vcpu)
|
|||||||
|
|
||||||
/* Do the required processing for each msr case */
|
/* Do the required processing for each msr case */
|
||||||
switch (msr) {
|
switch (msr) {
|
||||||
|
#ifdef CONFIG_HYPERV_ENABLED
|
||||||
|
case HV_X64_MSR_GUEST_OS_ID:
|
||||||
|
case HV_X64_MSR_HYPERCALL:
|
||||||
|
case HV_X64_MSR_VP_INDEX:
|
||||||
|
{
|
||||||
|
err = hyperv_rdmsr(vcpu, msr, &v);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
case MSR_IA32_TSC_DEADLINE:
|
case MSR_IA32_TSC_DEADLINE:
|
||||||
{
|
{
|
||||||
v = vlapic_get_tsc_deadline_msr(vcpu_vlapic(vcpu));
|
v = vlapic_get_tsc_deadline_msr(vcpu_vlapic(vcpu));
|
||||||
@ -676,6 +685,15 @@ int32_t wrmsr_vmexit_handler(struct acrn_vcpu *vcpu)
|
|||||||
|
|
||||||
/* Do the required processing for each msr case */
|
/* Do the required processing for each msr case */
|
||||||
switch (msr) {
|
switch (msr) {
|
||||||
|
#ifdef CONFIG_HYPERV_ENABLED
|
||||||
|
case HV_X64_MSR_GUEST_OS_ID:
|
||||||
|
case HV_X64_MSR_HYPERCALL:
|
||||||
|
case HV_X64_MSR_VP_INDEX:
|
||||||
|
{
|
||||||
|
err = hyperv_wrmsr(vcpu, msr, v);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
case MSR_IA32_TSC_DEADLINE:
|
case MSR_IA32_TSC_DEADLINE:
|
||||||
{
|
{
|
||||||
vlapic_set_tsc_deadline_msr(vcpu_vlapic(vcpu), v);
|
vlapic_set_tsc_deadline_msr(vcpu_vlapic(vcpu), v);
|
||||||
|
50
hypervisor/include/arch/x86/guest/hyperv.h
Normal file
50
hypervisor/include/arch/x86/guest/hyperv.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HYPERV_H
|
||||||
|
#define HYPERV_H
|
||||||
|
|
||||||
|
#include <vcpuid.h>
|
||||||
|
|
||||||
|
/* Hyper-V MSR numbers */
|
||||||
|
#define HV_X64_MSR_GUEST_OS_ID 0x40000000U
|
||||||
|
#define HV_X64_MSR_HYPERCALL 0x40000001U
|
||||||
|
#define HV_X64_MSR_VP_INDEX 0x40000002U
|
||||||
|
|
||||||
|
union hyperv_hypercall_msr {
|
||||||
|
uint64_t val64;
|
||||||
|
struct {
|
||||||
|
uint64_t enabled:1;
|
||||||
|
uint64_t locked:1;
|
||||||
|
uint64_t rsvdp:10;
|
||||||
|
uint64_t gpfn:52;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
union hyperv_guest_os_id_msr {
|
||||||
|
uint64_t val64;
|
||||||
|
struct {
|
||||||
|
uint64_t build_number:16;
|
||||||
|
uint64_t service_version:8;
|
||||||
|
uint64_t minor_version:8;
|
||||||
|
uint64_t major_version:8;
|
||||||
|
uint64_t os_id:8;
|
||||||
|
uint64_t vendor_id:15;
|
||||||
|
uint64_t os_type:1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct acrn_hyperv {
|
||||||
|
union hyperv_hypercall_msr hypercall_page;
|
||||||
|
union hyperv_guest_os_id_msr guest_os_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
int32_t hyperv_wrmsr(struct acrn_vcpu *vcpu, uint32_t msr, uint64_t wval);
|
||||||
|
int32_t hyperv_rdmsr(struct acrn_vcpu *vcpu, uint32_t msr, uint64_t *rval);
|
||||||
|
void hyperv_init_vcpuid_entry(uint32_t leaf, uint32_t subleaf, uint32_t flags,
|
||||||
|
struct vcpuid_entry *entry);
|
||||||
|
|
||||||
|
#endif
|
@ -26,6 +26,9 @@
|
|||||||
#include <cpu_caps.h>
|
#include <cpu_caps.h>
|
||||||
#include <e820.h>
|
#include <e820.h>
|
||||||
#include <vm_config.h>
|
#include <vm_config.h>
|
||||||
|
#ifdef CONFIG_HYPERV_ENABLED
|
||||||
|
#include <hyperv.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
struct vm_hw_info {
|
struct vm_hw_info {
|
||||||
/* vcpu array of this VM */
|
/* vcpu array of this VM */
|
||||||
@ -100,6 +103,9 @@ struct vm_arch {
|
|||||||
void *tmp_pg_array; /* Page array for tmp guest paging struct */
|
void *tmp_pg_array; /* Page array for tmp guest paging struct */
|
||||||
struct acrn_vioapic vioapic; /* Virtual IOAPIC base address */
|
struct acrn_vioapic vioapic; /* Virtual IOAPIC base address */
|
||||||
struct acrn_vpic vpic; /* Virtual PIC */
|
struct acrn_vpic vpic; /* Virtual PIC */
|
||||||
|
#ifdef CONFIG_HYPERV_ENABLED
|
||||||
|
struct acrn_hyperv hyperv;
|
||||||
|
#endif
|
||||||
enum vm_vlapic_state vlapic_state; /* Represents vLAPIC state across vCPUs*/
|
enum vm_vlapic_state vlapic_state; /* Represents vLAPIC state across vCPUs*/
|
||||||
|
|
||||||
/* reference to virtual platform to come here (as needed) */
|
/* reference to virtual platform to come here (as needed) */
|
||||||
|
Loading…
Reference in New Issue
Block a user