From ac61ae0ae5d686b5a7689abb27cdc4502e64372e Mon Sep 17 00:00:00 2001 From: Junjie Mao Date: Wed, 4 Apr 2018 00:07:21 +0800 Subject: [PATCH] hv: cpu: use the physical address limit from CPUID when available Per SDM Vol. 2: If CPUID.80000008H:EAX[7:0] is supported, the maximum physical address number supported should come from this field. This patch gets the maximum physical address number from CPUID leaf 0x80000008 and calculates the physical address mask when the leaf is available. Currently ACRN does not support platforms w/o this leaf and will panic on such platforms. Also call get_cpu_capabilities() earlier since the physical address mask is required for initializing paging. Signed-off-by: Junjie Mao Acked-by: Eddie Dong --- arch/x86/cpu.c | 25 +++++++++++++++++++++++-- include/arch/x86/cpu.h | 2 ++ include/arch/x86/cpuid.h | 1 + include/arch/x86/mmu.h | 5 ++++- 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/arch/x86/cpu.c b/arch/x86/cpu.c index 389f2e7a1..1e326a26b 100644 --- a/arch/x86/cpu.c +++ b/arch/x86/cpu.c @@ -125,6 +125,11 @@ inline bool get_vmx_cap(void) return !!(boot_cpu_data.cpuid_leaves[FEAT_1_ECX] & CPUID_ECX_VMX); } +static uint64_t get_address_mask(uint8_t limit) +{ + return ((1ULL << limit) - 1) & CPU_PAGE_MASK; +} + static void get_cpu_capabilities(void) { uint32_t eax, unused; @@ -156,10 +161,23 @@ static void get_cpu_capabilities(void) boot_cpu_data.cpuid_leaves[FEAT_8000_0000_EAX] = max_extended_function_idx; + if (max_extended_function_idx < CPUID_EXTEND_ADDRESS_SIZE) { + panic("CPU w/o CPUID.80000008H is not supported"); + } + cpuid(CPUID_EXTEND_FUNCTION_1, &unused, &unused, &boot_cpu_data.cpuid_leaves[FEAT_8000_0001_ECX], &boot_cpu_data.cpuid_leaves[FEAT_8000_0001_EDX]); + cpuid(CPUID_EXTEND_ADDRESS_SIZE, + &eax, &unused, &unused, &unused); + boot_cpu_data.cpuid_leaves[FEAT_8000_0008_EAX] = eax; + /* EAX bits 07-00: #Physical Address Bits + * bits 15-08: #Linear Address Bits + */ + boot_cpu_data.physical_address_mask = + get_address_mask(eax & 0xff); + /* For speculation defence. * The default way is to set IBRS at vmexit and then do IBPB at vcpu * context switch(ibrs_type == IBRS_RAW). @@ -352,6 +370,11 @@ void bsp_boot_init(void) VMX_MACHINE_T_GUEST_SPEC_CTRL_OFFSET, "run_context ia32_spec_ctrl offset not match"); + /* Get CPU capabilities thru CPUID, including the physical address bit + * limit which is required for initializing paging. + */ + get_cpu_capabilities(); + /* Initialize the hypervisor paging */ init_paging(); @@ -368,8 +391,6 @@ void bsp_boot_init(void) set_fs_base(); #endif - get_cpu_capabilities(); - vapic_cap_detect(); cpu_xsave_init(); diff --git a/include/arch/x86/cpu.h b/include/arch/x86/cpu.h index dde5acf99..744da1cc9 100644 --- a/include/arch/x86/cpu.h +++ b/include/arch/x86/cpu.h @@ -228,11 +228,13 @@ enum feature_word { FEAT_8000_0000_EAX, /* CPUID[8000_0000].EAX */ FEAT_8000_0001_ECX, /* CPUID[8000_0001].ECX */ FEAT_8000_0001_EDX, /* CPUID[8000_0001].EDX */ + FEAT_8000_0008_EAX, /* CPUID[8000_0008].EAX */ FEATURE_WORDS, }; struct cpuinfo_x86 { uint8_t x86, x86_model; + uint64_t physical_address_mask; uint32_t cpuid_leaves[FEATURE_WORDS]; }; diff --git a/include/arch/x86/cpuid.h b/include/arch/x86/cpuid.h index a842fb4b9..be0702cd4 100644 --- a/include/arch/x86/cpuid.h +++ b/include/arch/x86/cpuid.h @@ -115,6 +115,7 @@ #define CPUID_EXTEND_FEATURE 7 #define CPUID_MAX_EXTENDED_FUNCTION 0x80000000 #define CPUID_EXTEND_FUNCTION_1 0x80000001 +#define CPUID_EXTEND_ADDRESS_SIZE 0x80000008 static inline void __cpuid(uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) diff --git a/include/arch/x86/mmu.h b/include/arch/x86/mmu.h index 08fbb6410..bb340a2ec 100644 --- a/include/arch/x86/mmu.h +++ b/include/arch/x86/mmu.h @@ -157,6 +157,8 @@ #ifndef ASSEMBLER +#include + /* Define cache line size (in bytes) */ #define CACHE_LINE_SIZE 64 @@ -167,7 +169,8 @@ #define IA32E_INDEX_MASK_BITS 9 #define IA32E_NUM_ENTRIES 512 #define IA32E_INDEX_MASK (uint64_t)(IA32E_NUM_ENTRIES - 1) -#define IA32E_REF_MASK 0x000FFFFFFFFFF000 +#define IA32E_REF_MASK \ + (boot_cpu_data.physical_address_mask) #define IA32E_FIRST_BLOCK_INDEX 1 /* Macro to get PML4 index given an address */