mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-05-17 21:00:37 +00:00
internal commit: 14ac2bc2299032fa6714d1fefa7cf0987b3e3085 Signed-off-by: Eddie Dong <eddie.dong@intel.com>
196 lines
5.1 KiB
C
196 lines
5.1 KiB
C
/*
|
|
* Copyright (C) 2018 Intel Corporation. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* * Neither the name of Intel Corporation nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <hypervisor.h>
|
|
#include <hv_lib.h>
|
|
#include <acrn_common.h>
|
|
#include <hv_arch.h>
|
|
#include <cpu.h>
|
|
|
|
void emulate_cpuid(struct vcpu *vcpu, uint32_t src_op, uint32_t *eax_ptr,
|
|
uint32_t *ebx_ptr, uint32_t *ecx_ptr, uint32_t *edx_ptr)
|
|
{
|
|
uint32_t apicid = vlapic_get_id(vcpu->arch_vcpu.vlapic);
|
|
static const char sig[12] = "ACRNACRNACRN";
|
|
const uint32_t *sigptr = (const uint32_t *)sig;
|
|
uint32_t count = *ecx_ptr;
|
|
|
|
if ((src_op != 0x40000000) && (src_op != 0x40000010))
|
|
cpuid_count(src_op, count, eax_ptr, ebx_ptr, ecx_ptr, edx_ptr);
|
|
|
|
switch (src_op) {
|
|
/* Virtualize cpuid 0x01 */
|
|
case 0x01:
|
|
/* Patching initial APIC ID */
|
|
*ebx_ptr &= ~APIC_ID_MASK;
|
|
*ebx_ptr |= (apicid & APIC_ID_MASK);
|
|
|
|
/* mask mtrr */
|
|
*edx_ptr &= ~CPUID_EDX_MTRR;
|
|
|
|
/* Patching X2APIC, X2APIC mode is disabled by default. */
|
|
if (x2apic_enabled)
|
|
*ecx_ptr |= CPUID_ECX_x2APIC;
|
|
else
|
|
*ecx_ptr &= ~CPUID_ECX_x2APIC;
|
|
|
|
/* mask pcid */
|
|
*ecx_ptr &= ~CPUID_ECX_PCID;
|
|
|
|
/*mask vmx to guest os */
|
|
*ecx_ptr &= ~CPUID_ECX_VMX;
|
|
|
|
break;
|
|
|
|
/* Virtualize cpuid 0x07 */
|
|
case 0x07:
|
|
/* mask invpcid */
|
|
*ebx_ptr &= ~CPUID_EBX_INVPCID;
|
|
|
|
break;
|
|
|
|
case 0x0a:
|
|
/* not support pmu */
|
|
*eax_ptr &= ~0xff;
|
|
break;
|
|
|
|
/* Virtualize cpuid 0x0b */
|
|
case 0x0b:
|
|
/* Patching X2APIC */
|
|
if (!x2apic_enabled) {
|
|
*eax_ptr = 0;
|
|
*ebx_ptr = 0;
|
|
*ecx_ptr = 0;
|
|
*edx_ptr = 0;
|
|
}
|
|
break;
|
|
|
|
/*
|
|
* Leaf 0x40000000
|
|
* This leaf returns the CPUID leaf range supported by the
|
|
* hypervisor and the hypervisor vendor signature.
|
|
*
|
|
* EAX: The maximum input value for CPUID supported by the
|
|
* hypervisor.
|
|
* EBX, ECX, EDX: Hypervisor vendor ID signature.
|
|
*/
|
|
case 0x40000000:
|
|
*eax_ptr = 0x40000010;
|
|
*ebx_ptr = sigptr[0];
|
|
*ecx_ptr = sigptr[1];
|
|
*edx_ptr = sigptr[2];
|
|
break;
|
|
|
|
/*
|
|
* Leaf 0x40000010 - Timing Information.
|
|
* This leaf returns the current TSC frequency and
|
|
* current Bus frequency in kHz.
|
|
*
|
|
* EAX: (Virtual) TSC frequency in kHz.
|
|
* TSC frequency is calculated from PIT in ACRN
|
|
* EBX: (Virtual) Bus (local apic timer) frequency in kHz.
|
|
* Bus (local apic timer) frequency is hardcoded as
|
|
* (128 * 1024 * 1024) in ACRN
|
|
* ECX, EDX: RESERVED (reserved fields are set to zero).
|
|
*/
|
|
case 0x40000010:
|
|
*eax_ptr = (uint32_t)(tsc_clock_freq / 1000);
|
|
*ebx_ptr = (128 * 1024 * 1024) / 1000;
|
|
*ecx_ptr = 0;
|
|
*edx_ptr = 0;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static DEFINE_CPU_DATA(struct cpuid_cache_entry[CPUID_EXTEND_FEATURE_CACHE_MAX],
|
|
cpuid_cache);
|
|
|
|
static inline struct cpuid_cache_entry *find_cpuid_cache_entry(uint32_t op,
|
|
uint32_t count)
|
|
{
|
|
int pcpu_id = get_cpu_id();
|
|
enum cpuid_cache_idx idx = CPUID_EXTEND_FEATURE_CACHE_MAX;
|
|
|
|
if ((count != 0))
|
|
return NULL;
|
|
|
|
switch (op) {
|
|
case CPUID_VENDORSTRING:
|
|
idx = CPUID_VENDORSTRING_CACHE_IDX;
|
|
break;
|
|
|
|
case CPUID_FEATURES:
|
|
idx = CPUID_FEATURES_CACHE_IDX;
|
|
break;
|
|
|
|
case CPUID_EXTEND_FEATURE:
|
|
idx = CPUID_EXTEND_FEATURE_CACHE_IDX;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (idx == CPUID_EXTEND_FEATURE_CACHE_MAX)
|
|
return NULL;
|
|
|
|
return &per_cpu(cpuid_cache, pcpu_id)[idx];
|
|
}
|
|
|
|
inline void cpuid_count(uint32_t op, uint32_t count,
|
|
uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
|
|
{
|
|
struct cpuid_cache_entry *entry;
|
|
|
|
entry = find_cpuid_cache_entry(op, count);
|
|
|
|
if (entry == NULL) {
|
|
native_cpuid_count(op, count, a, b, c, d);
|
|
} else if (entry->inited) {
|
|
*a = entry->a;
|
|
*b = entry->b;
|
|
*c = entry->c;
|
|
*d = entry->d;
|
|
} else {
|
|
native_cpuid_count(op, count, a, b, c, d);
|
|
|
|
entry->a = *a;
|
|
entry->b = *b;
|
|
entry->c = *c;
|
|
entry->d = *d;
|
|
|
|
entry->inited = 1;
|
|
}
|
|
}
|
|
|