x86/hyperv: Add support for detecting nested hypervisor
Subsystems (4)
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH v10 1/5 x86/hyperv: Add support for detecting nested hypervisor
Detect if Linux is running as a nested hypervisor in the root partition for Microsoft Hypervisor, using flags provided by MSHV. Expose a new variable hv_nested that is used later for decisions specific to the nested use case.
--- arch/x86/include/asm/hyperv-tlfs.h | 3 +++ arch/x86/kernel/cpu/mshyperv.c | 7 +++++++ drivers/hv/hv_common.c | 9 ++++++--- include/asm-generic/mshyperv.h | 1 + 4 files changed, 17 insertions(+), 3 deletions(-)
arch/x86/include/asm/hyperv-tlfs.h +3 -0
@@ -114,6 +114,9 @@/* Recommend using the newer ExProcessorMasks interface */ #define HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED BIT(11) +/* Indicates that the hypervisor is nested within a Hyper-V partition. */ +#define HV_X64_HYPERV_NESTED BIT(12) +/* Recommend using enlightened VMCS */ #define HV_X64_ENLIGHTENED_VMCS_RECOMMENDED BIT(14)
arch/x86/kernel/cpu/mshyperv.c +7 -0
@@ -37,6 +37,8 @@/* Is Linux running as the root partition? */ bool hv_root_partition; +/* Is Linux running on nested Microsoft Hypervisor */ +bool hv_nested;struct ms_hyperv_info ms_hyperv;#if IS_ENABLED (CONFIG_HYPERV )
@@ -301,6 +303,11 @@ static void __init ms_hyperv_init_platform(void)pr_info ("Hyper-V: running as root partition\n" ); } +if (ms_hyperv.hints &HV_X64_HYPERV_NESTED ) { + hv_nested = true; +pr_info ("Hyper-V: running on a nested hypervisor\n" ); + } +/* * Extract host information. */
drivers/hv/hv_common.c +6 -3
@@ -25,17 +25,20 @@#include <asm/mshyperv.h> /* -* hv_root_partition and ms_hyperv are defined here with other Hyper-V -* specific globals so they are shared across all architectures and are +* hv_root_partition, ms_hyperv and hv_nested are defined here with other +* Hyper-V specific globals so they are shared across all architectures and are * built only when CONFIG_HYPERV is defined. But on x86, * ms_hyperv_init_platform() is built even when CONFIG_HYPERV is not -* defined, and it uses these two variables. So mark them as __weak +* defined, and it uses these three variables. So mark them as __weak * here, allowing for an overriding definition in the module containing * ms_hyperv_init_platform(). */ bool __weak hv_root_partition;EXPORT_SYMBOL_GPL (hv_root_partition); +bool __weak hv_nested; +EXPORT_SYMBOL_GPL (hv_nested); +struct ms_hyperv_info __weak ms_hyperv;EXPORT_SYMBOL_GPL (ms_hyperv);
include/asm-generic/mshyperv.h +1 -0
@@ -48,6 +48,7 @@ struct ms_hyperv_info {u64 shared_gpa_boundary; };extern struct ms_hyperv_info ms_hyperv; +extern bool hv_nested;extern void *__percpu *hyperv_pcpu_input_arg;extern void *__percpu *hyperv_pcpu_output_arg;
Signature · 1 line
2.25.1
From: Jinank Jain <[email protected]> Sent: Sunday, January 1, 2023 11:13 PM
Quoted 94 lines
Detect if Linux is running as a nested hypervisor in the root partition for Microsoft Hypervisor, using flags provided by MSHV. Expose a new variable
hv_nestedthat is used later for decisions specific to the nested use case.Signed-off-by Jinank Jain <[email protected]>--- arch/x86/include/asm/hyperv-tlfs.h | 3 +++ arch/x86/kernel/cpu/mshyperv.c | 7 +++++++ drivers/hv/hv_common.c | 9 ++++++--- include/asm-generic/mshyperv.h | 1 + 4 files changed, 17 insertions(+), 3 deletions(-)arch/x86/include/asm/hyperv-tlfs.h +3
-0@@ -114,6 +114,9 @@/* Recommend using the newer ExProcessorMasks interface */ #define HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED BIT(11) +/* Indicates that the hypervisor is nested within a Hyper-V partition. */ +#define HV_X64_HYPERV_NESTED BIT(12) +/* Recommend using enlightened VMCS */ #define HV_X64_ENLIGHTENED_VMCS_RECOMMENDED BIT(14)arch/x86/kernel/cpu/mshyperv.c +7
-0@@ -37,6 +37,8 @@/* Is Linux running as the root partition? */ bool hv_root_partition; +/* Is Linux running on nested Microsoft Hypervisor */ +bool hv_nested;struct ms_hyperv_info ms_hyperv;#if IS_ENABLED (CONFIG_HYPERV )@@ -301,6 +303,11 @@ static void __init ms_hyperv_init_platform(void)pr_info ("Hyper-V: running as root partition\n" ); } +if (ms_hyperv.hints &HV_X64_HYPERV_NESTED ) { + hv_nested = true; +pr_info ("Hyper-V: running on a nested hypervisor\n" ); + } +/* * Extract host information. */ drivers/hv/hv_common.c +6
-3@@ -25,17 +25,20 @@#include <asm/mshyperv.h> /* -* hv_root_partition and ms_hyperv are defined here with other Hyper-V -* specific globals so they are shared across all architectures and are +* hv_root_partition, ms_hyperv and hv_nested are defined here with other +* Hyper-V specific globals so they are shared across all architectures and are * built only when CONFIG_HYPERV is defined. But on x86, * ms_hyperv_init_platform() is built even when CONFIG_HYPERV is not -* defined, and it uses these two variables. So mark them as __weak +* defined, and it uses these three variables. So mark them as __weak * here, allowing for an overriding definition in the module containing * ms_hyperv_init_platform(). */ bool __weak hv_root_partition;EXPORT_SYMBOL_GPL (hv_root_partition); +bool __weak hv_nested; +EXPORT_SYMBOL_GPL (hv_nested); +struct ms_hyperv_info __weak ms_hyperv;EXPORT_SYMBOL_GPL (ms_hyperv);include/asm-generic/mshyperv.h +1
-1@@ -48,6 +48,7 @@ struct ms_hyperv_info {u64 shared_gpa_boundary; };extern struct ms_hyperv_info ms_hyperv; +extern bool hv_nested;extern void *__percpu *hyperv_pcpu_input_arg;extern void *__percpu *hyperv_pcpu_output_arg; --
Quoted 1 line
2.25.1
PATCH v10 2/5 Drivers: hv: Setup synic registers in case of nested root partition
In reply to a message not in the archiveChild partitions are free to allocate SynIC message and event page but in case of root partition it must use the pages allocated by Microsoft Hypervisor (MSHV). Base address for these pages can be found using synthetic MSRs exposed by MSHV. There is a slight difference in those MSRs for nested vs non-nested root partition.
--- arch/x86/include/asm/hyperv-tlfs.h | 11 +++++ arch/x86/include/asm/mshyperv.h | 30 +++----------- arch/x86/kernel/cpu/mshyperv.c | 65 ++++++++++++++++++++++++++++++ drivers/hv/hv.c | 18 +++++---- 4 files changed, 93 insertions(+), 31 deletions(-)
arch/x86/include/asm/hyperv-tlfs.h +11 -0
@@ -225,6 +225,17 @@ enum hv_isolation_type {#define HV_REGISTER_SINT14 0x4000009E#define HV_REGISTER_SINT15 0x4000009F +/* +* Define synthetic interrupt controller model specific registers for +* nested hypervisor. +*/ +#define HV_REGISTER_NESTED_SCONTROL 0x40001080 +#define HV_REGISTER_NESTED_SVERSION 0x40001081 +#define HV_REGISTER_NESTED_SIEFP 0x40001082 +#define HV_REGISTER_NESTED_SIMP 0x40001083 +#define HV_REGISTER_NESTED_EOM 0x40001084 +#define HV_REGISTER_NESTED_SINT0 0x40001090 +/* * Synthetic Timer MSRs. Four timers per vcpu. */
arch/x86/include/asm/mshyperv.h +6 -24
@@ -198,30 +198,10 @@ static inline bool hv_is_synic_reg(unsigned int reg) return false; } -static inline u64 hv_get_register (unsigned int reg) -{ -u64 value; - -if (hv_is_synic_reg (reg) &&hv_isolation_type_snp ()) -hv_ghcb_msr_read (reg, &value); -else -rdmsrl (reg, value); -return value; -} - -static inline void hv_set_register (unsigned int reg,u64 value) -{ -if (hv_is_synic_reg (reg) &&hv_isolation_type_snp ()) { -hv_ghcb_msr_write (reg, value); - -/* Write proxy bit via wrmsl instruction */ -if (reg >=HV_REGISTER_SINT0 && - reg <=HV_REGISTER_SINT15 ) -wrmsrl (reg, value |1 <<20 ); - }else { -wrmsrl (reg, value); - } -} +u64 hv_get_register (unsigned int reg); +void hv_set_register (unsigned int reg,u64 value); +u64 hv_get_non_nested_register (unsigned int reg); +void hv_set_non_nested_register (unsigned int reg,u64 value);#else /* CONFIG_HYPERV */ static inline void hyperv_init (void ) {}
@@ -241,6 +221,8 @@ static inline int hyperv_flush_guest_mapping_range(u64 as, }static inline void hv_set_register (unsigned int reg,u64 value) { }static inline u64 hv_get_register (unsigned int reg) {return 0 ; } +static inline void hv_set_non_nested_register (unsigned int reg,u64 value) { } +static inline u64 hv_get_non_nested_register (unsigned int reg) {return 0 ; }static inline int hv_set_mem_host_visibility (unsigned long addr,int numpages,bool visible) {
arch/x86/kernel/cpu/mshyperv.c +65 -0
72 lines not on this page · raw message
drivers/hv/hv.c +11 -7
@@ -147,7 +147,7 @@ int hv_synic_alloc(void)* Synic message and event pages are allocated by paravisor. * Skip these pages allocation here. */ -if (!hv_isolation_type_snp ()) { +if (!hv_isolation_type_snp () && !hv_root_partition) { hv_cpu->synic_message_page = (void *)get_zeroed_page (GFP_ATOMIC );if (hv_cpu->synic_message_page ==NULL ) {
@@ -216,7 +216,7 @@ void hv_synic_enable_regs(unsigned int cpu) simp.as_uint64 =hv_get_register (HV_REGISTER_SIMP ); simp.simp_enabled =1 ; -if (hv_isolation_type_snp ()) { +if (hv_isolation_type_snp () || hv_root_partition) { hv_cpu->synic_message_page =memremap (simp.base_simp_gpa <<HV_HYP_PAGE_SHIFT ,HV_HYP_PAGE_SIZE ,MEMREMAP_WB );
@@ -233,7 +233,7 @@ void hv_synic_enable_regs(unsigned int cpu) siefp.as_uint64 =hv_get_register (HV_REGISTER_SIEFP ); siefp.siefp_enabled =1 ; -if (hv_isolation_type_snp ()) { +if (hv_isolation_type_snp () || hv_root_partition) { hv_cpu->synic_event_page =memremap (siefp.base_siefp_gpa <<HV_HYP_PAGE_SHIFT ,HV_HYP_PAGE_SIZE ,MEMREMAP_WB );
@@ -315,20 +315,24 @@ void hv_synic_disable_regs(unsigned int cpu)* addresses. */ simp.simp_enabled =0 ; -if (hv_isolation_type_snp ()) +if (hv_isolation_type_snp () || hv_root_partition) {memunmap (hv_cpu->synic_message_page); -else + hv_cpu->synic_message_page =NULL ; + }else { simp.base_simp_gpa =0 ; + }hv_set_register (HV_REGISTER_SIMP , simp.as_uint64); siefp.as_uint64 =hv_get_register (HV_REGISTER_SIEFP ); siefp.siefp_enabled =0 ; -if (hv_isolation_type_snp ()) +if (hv_isolation_type_snp () || hv_root_partition) {memunmap (hv_cpu->synic_event_page); -else + hv_cpu->synic_event_page =NULL ; + }else { siefp.base_siefp_gpa =0 ; + }hv_set_register (HV_REGISTER_SIEFP , siefp.as_uint64);
Signature · 1 line
2.25.1
RE: [PATCH v10 2/5] Drivers: hv: Setup synic registers in case of nested root partition
From: Jinank Jain <[email protected]> Sent: Sunday, January 1, 2023 11:13 PM
Quoted 223 lines
Child partitions are free to allocate SynIC message and event page but in case of root partition it must use the pages allocated by Microsoft Hypervisor (MSHV). Base address for these pages can be found using synthetic MSRs exposed by MSHV. There is a slight difference in those MSRs for nested vs non-nested root partition.
Signed-off-by Jinank Jain <[email protected]>--- arch/x86/include/asm/hyperv-tlfs.h | 11 +++++ arch/x86/include/asm/mshyperv.h | 30 +++----------- arch/x86/kernel/cpu/mshyperv.c | 65 ++++++++++++++++++++++++++++++ drivers/hv/hv.c | 18 +++++---- 4 files changed, 93 insertions(+), 31 deletions(-)arch/x86/include/asm/hyperv-tlfs.h +11
-0@@ -225,6 +225,17 @@ enum hv_isolation_type {#define HV_REGISTER_SINT14 0x4000009E#define HV_REGISTER_SINT15 0x4000009F +/* +* Define synthetic interrupt controller model specific registers for +* nested hypervisor. +*/ +#define HV_REGISTER_NESTED_SCONTROL 0x40001080 +#define HV_REGISTER_NESTED_SVERSION 0x40001081 +#define HV_REGISTER_NESTED_SIEFP 0x40001082 +#define HV_REGISTER_NESTED_SIMP 0x40001083 +#define HV_REGISTER_NESTED_EOM 0x40001084 +#define HV_REGISTER_NESTED_SINT0 0x40001090 +/* * Synthetic Timer MSRs. Four timers per vcpu. */ arch/x86/include/asm/mshyperv.h +6
-24@@ -198,30 +198,10 @@ static inline bool hv_is_synic_reg(unsigned int reg) return false; } -static inline u64 hv_get_register (unsigned int reg) -{ -u64 value; - -if (hv_is_synic_reg (reg) &&hv_isolation_type_snp ()) -hv_ghcb_msr_read (reg, &value); -else -rdmsrl (reg, value); -return value; -} - -static inline void hv_set_register (unsigned int reg,u64 value) -{ -if (hv_is_synic_reg (reg) &&hv_isolation_type_snp ()) { -hv_ghcb_msr_write (reg, value); - -/* Write proxy bit via wrmsl instruction */ -if (reg >=HV_REGISTER_SINT0 && - reg <=HV_REGISTER_SINT15 ) -wrmsrl (reg, value |1 <<20 ); - }else { -wrmsrl (reg, value); - } -} +u64 hv_get_register (unsigned int reg); +void hv_set_register (unsigned int reg,u64 value); +u64 hv_get_non_nested_register (unsigned int reg); +void hv_set_non_nested_register (unsigned int reg,u64 value);#else /* CONFIG_HYPERV */ static inline void hyperv_init (void ) {}@@ -241,6 +221,8 @@ static inline int hyperv_flush_guest_mapping_range(u64 as, }static inline void hv_set_register (unsigned int reg,u64 value) { }static inline u64 hv_get_register (unsigned int reg) {return 0 ; } +static inline void hv_set_non_nested_register (unsigned int reg,u64 value) { } +static inline u64 hv_get_non_nested_register (unsigned int reg) {return 0 ; }static inline int hv_set_mem_host_visibility (unsigned long addr,int numpages,bool visible) {arch/x86/kernel/cpu/mshyperv.c +65
-0@@ -41,7 +41,72 @@ bool hv_root_partition;bool hv_nested;struct ms_hyperv_info ms_hyperv; +static inline unsigned int hv_get_nested_reg (unsigned int reg) +{ +switch (reg) { +case HV_REGISTER_SIMP : +return HV_REGISTER_NESTED_SIMP ; +case HV_REGISTER_SIEFP : +return HV_REGISTER_NESTED_SIEFP ; +case HV_REGISTER_SVERSION : +return HV_REGISTER_NESTED_SVERSION ; +case HV_REGISTER_SCONTROL : +return HV_REGISTER_NESTED_SCONTROL ; +case HV_REGISTER_SINT0 : +return HV_REGISTER_NESTED_SINT0 ; +case HV_REGISTER_EOM : +return HV_REGISTER_NESTED_EOM ; +default : +return reg; + } +} +#if IS_ENABLED (CONFIG_HYPERV ) +u64 hv_get_non_nested_register (unsigned int reg) +{ +u64 value; + +if (hv_is_synic_reg (reg) &&hv_isolation_type_snp ()) +hv_ghcb_msr_read (reg, &value); +else +rdmsrl (reg, value); +return value; +} +EXPORT_SYMBOL_GPL (hv_get_non_nested_register); + +void hv_set_non_nested_register (unsigned int reg,u64 value) +{ +if (hv_is_synic_reg (reg) &&hv_isolation_type_snp ()) { +hv_ghcb_msr_write (reg, value); + +/* Write proxy bit via wrmsl instruction */ +if (reg >=HV_REGISTER_SINT0 && + reg <=HV_REGISTER_SINT15 ) +wrmsrl (reg, value |1 <<20 ); + }else { +wrmsrl (reg, value); + } +} +EXPORT_SYMBOL_GPL (hv_set_non_nested_register); + +u64 hv_get_register (unsigned int reg) +{ +if (hv_nested) + reg =hv_get_nested_reg (reg); + +return hv_get_non_nested_register (reg); +} +EXPORT_SYMBOL_GPL (hv_get_register); + +void hv_set_register (unsigned int reg,u64 value) +{ +if (hv_nested) + reg =hv_get_nested_reg (reg); + +hv_set_non_nested_register (reg, value); +} +EXPORT_SYMBOL_GPL (hv_set_register); +static void (*vmbus_handler)(void );static void (*hv_stimer0_handler)(void );static void (*hv_kexec_handler)(void );drivers/hv/hv.c +11
-8@@ -147,7 +147,7 @@ int hv_synic_alloc(void)* Synic message and event pages are allocated by paravisor. * Skip these pages allocation here. */ -if (!hv_isolation_type_snp ()) { +if (!hv_isolation_type_snp () && !hv_root_partition) { hv_cpu->synic_message_page = (void *)get_zeroed_page (GFP_ATOMIC );if (hv_cpu->synic_message_page ==NULL ) {@@ -216,7 +216,7 @@ void hv_synic_enable_regs(unsigned int cpu) simp.as_uint64 =hv_get_register (HV_REGISTER_SIMP ); simp.simp_enabled =1 ; -if (hv_isolation_type_snp ()) { +if (hv_isolation_type_snp () || hv_root_partition) { hv_cpu->synic_message_page =memremap (simp.base_simp_gpa <<HV_HYP_PAGE_SHIFT ,HV_HYP_PAGE_SIZE ,MEMREMAP_WB );@@ -233,7 +233,7 @@ void hv_synic_enable_regs(unsigned int cpu) siefp.as_uint64 =hv_get_register (HV_REGISTER_SIEFP ); siefp.siefp_enabled =1 ; -if (hv_isolation_type_snp ()) { +if (hv_isolation_type_snp () || hv_root_partition) { hv_cpu->synic_event_page =memremap (siefp.base_siefp_gpa <<HV_HYP_PAGE_SHIFT ,HV_HYP_PAGE_SIZE ,MEMREMAP_WB );@@ -315,20 +315,24 @@ void hv_synic_disable_regs(unsigned int cpu)* addresses. */ simp.simp_enabled =0 ; -if (hv_isolation_type_snp ()) +if (hv_isolation_type_snp () || hv_root_partition) {memunmap (hv_cpu->synic_message_page); -else + hv_cpu->synic_message_page =NULL ; + }else { simp.base_simp_gpa =0 ; + }hv_set_register (HV_REGISTER_SIMP , simp.as_uint64); siefp.as_uint64 =hv_get_register (HV_REGISTER_SIEFP ); siefp.siefp_enabled =0 ; -if (hv_isolation_type_snp ()) +if (hv_isolation_type_snp () || hv_root_partition) {memunmap (hv_cpu->synic_event_page); -else + hv_cpu->synic_event_page =NULL ; + }else { siefp.base_siefp_gpa =0 ; + }hv_set_register (HV_REGISTER_SIEFP , siefp.as_uint64); --
Quoted 1 line
2.25.1
Looks good! Thanks for persisting and addressing my concerns.
Re: [PATCH v10 2/5] Drivers: hv: Setup synic registers in case of nested root partition
In reply to Jinank JainQuoted 211 lines · Jinank Jain
Child partitions are free to allocate SynIC message and event page but in case of root partition it must use the pages allocated by Microsoft Hypervisor (MSHV). Base address for these pages can be found using synthetic MSRs exposed by MSHV. There is a slight difference in those MSRs for nested vs non-nested root partition.
Signed-off-by Jinank Jain <[email protected]>--- arch/x86/include/asm/hyperv-tlfs.h | 11 +++++ arch/x86/include/asm/mshyperv.h | 30 +++----------- arch/x86/kernel/cpu/mshyperv.c | 65 ++++++++++++++++++++++++++++++ drivers/hv/hv.c | 18 +++++---- 4 files changed, 93 insertions(+), 31 deletions(-)arch/x86/include/asm/hyperv-tlfs.h +11
-0@@ -225,6 +225,17 @@ enum hv_isolation_type {#define HV_REGISTER_SINT14 0x4000009E#define HV_REGISTER_SINT15 0x4000009F +/* +* Define synthetic interrupt controller model specific registers for +* nested hypervisor. +*/ +#define HV_REGISTER_NESTED_SCONTROL 0x40001080 +#define HV_REGISTER_NESTED_SVERSION 0x40001081 +#define HV_REGISTER_NESTED_SIEFP 0x40001082 +#define HV_REGISTER_NESTED_SIMP 0x40001083 +#define HV_REGISTER_NESTED_EOM 0x40001084 +#define HV_REGISTER_NESTED_SINT0 0x40001090 +/* * Synthetic Timer MSRs. Four timers per vcpu. */ arch/x86/include/asm/mshyperv.h +6
-24@@ -198,30 +198,10 @@ static inline bool hv_is_synic_reg(unsigned int reg) return false; } -static inline u64 hv_get_register (unsigned int reg) -{ -u64 value; - -if (hv_is_synic_reg (reg) &&hv_isolation_type_snp ()) -hv_ghcb_msr_read (reg, &value); -else -rdmsrl (reg, value); -return value; -} - -static inline void hv_set_register (unsigned int reg,u64 value) -{ -if (hv_is_synic_reg (reg) &&hv_isolation_type_snp ()) { -hv_ghcb_msr_write (reg, value); - -/* Write proxy bit via wrmsl instruction */ -if (reg >=HV_REGISTER_SINT0 && - reg <=HV_REGISTER_SINT15 ) -wrmsrl (reg, value |1 <<20 ); - }else { -wrmsrl (reg, value); - } -} +u64 hv_get_register (unsigned int reg); +void hv_set_register (unsigned int reg,u64 value); +u64 hv_get_non_nested_register (unsigned int reg); +void hv_set_non_nested_register (unsigned int reg,u64 value);#else /* CONFIG_HYPERV */ static inline void hyperv_init (void ) {}@@ -241,6 +221,8 @@ static inline int hyperv_flush_guest_mapping_range(u64 as, }static inline void hv_set_register (unsigned int reg,u64 value) { }static inline u64 hv_get_register (unsigned int reg) {return 0 ; } +static inline void hv_set_non_nested_register (unsigned int reg,u64 value) { } +static inline u64 hv_get_non_nested_register (unsigned int reg) {return 0 ; }static inline int hv_set_mem_host_visibility (unsigned long addr,int numpages,bool visible) {arch/x86/kernel/cpu/mshyperv.c +65
-0@@ -41,7 +41,72 @@ bool hv_root_partition;bool hv_nested;struct ms_hyperv_info ms_hyperv; +static inline unsigned int hv_get_nested_reg (unsigned int reg) +{ +switch (reg) { +case HV_REGISTER_SIMP : +return HV_REGISTER_NESTED_SIMP ; +case HV_REGISTER_SIEFP : +return HV_REGISTER_NESTED_SIEFP ; +case HV_REGISTER_SVERSION : +return HV_REGISTER_NESTED_SVERSION ; +case HV_REGISTER_SCONTROL : +return HV_REGISTER_NESTED_SCONTROL ; +case HV_REGISTER_SINT0 : +return HV_REGISTER_NESTED_SINT0 ; +case HV_REGISTER_EOM : +return HV_REGISTER_NESTED_EOM ; +default : +return reg; + } +} +#if IS_ENABLED (CONFIG_HYPERV ) +u64 hv_get_non_nested_register (unsigned int reg) +{ +u64 value; + +if (hv_is_synic_reg (reg) &&hv_isolation_type_snp ()) +hv_ghcb_msr_read (reg, &value); +else +rdmsrl (reg, value); +return value; +} +EXPORT_SYMBOL_GPL (hv_get_non_nested_register); + +void hv_set_non_nested_register (unsigned int reg,u64 value) +{ +if (hv_is_synic_reg (reg) &&hv_isolation_type_snp ()) { +hv_ghcb_msr_write (reg, value); + +/* Write proxy bit via wrmsl instruction */ +if (reg >=HV_REGISTER_SINT0 && + reg <=HV_REGISTER_SINT15 ) +wrmsrl (reg, value |1 <<20 ); + }else { +wrmsrl (reg, value); + } +} +EXPORT_SYMBOL_GPL (hv_set_non_nested_register); + +u64 hv_get_register (unsigned int reg) +{ +if (hv_nested) + reg =hv_get_nested_reg (reg); + +return hv_get_non_nested_register (reg); +} +EXPORT_SYMBOL_GPL (hv_get_register); + +void hv_set_register (unsigned int reg,u64 value) +{ +if (hv_nested) + reg =hv_get_nested_reg (reg); + +hv_set_non_nested_register (reg, value); +} +EXPORT_SYMBOL_GPL (hv_set_register); +static void (*vmbus_handler)(void );static void (*hv_stimer0_handler)(void );static void (*hv_kexec_handler)(void );drivers/hv/hv.c +7
-6@@ -147,7 +147,7 @@ int hv_synic_alloc(void)* Synic message and event pages are allocated by paravisor. * Skip these pages allocation here. */ -if (!hv_isolation_type_snp ()) { +if (!hv_isolation_type_snp () && !hv_root_partition) { hv_cpu->synic_message_page = (void *)get_zeroed_page (GFP_ATOMIC );if (hv_cpu->synic_message_page ==NULL ) {@@ -216,7 +216,7 @@ void hv_synic_enable_regs(unsigned int cpu) simp.as_uint64 =hv_get_register (HV_REGISTER_SIMP ); simp.simp_enabled =1 ; -if (hv_isolation_type_snp ()) { +if (hv_isolation_type_snp () || hv_root_partition) { hv_cpu->synic_message_page =memremap (simp.base_simp_gpa <<HV_HYP_PAGE_SHIFT ,HV_HYP_PAGE_SIZE ,MEMREMAP_WB );@@ -233,7 +233,7 @@ void hv_synic_enable_regs(unsigned int cpu) siefp.as_uint64 =hv_get_register (HV_REGISTER_SIEFP ); siefp.siefp_enabled =1 ; -if (hv_isolation_type_snp ()) { +if (hv_isolation_type_snp () || hv_root_partition) { hv_cpu->synic_event_page =memremap (siefp.base_siefp_gpa <<HV_HYP_PAGE_SHIFT ,HV_HYP_PAGE_SIZE ,MEMREMAP_WB );@@ -315,20 +315,24 @@ void hv_synic_disable_regs(unsigned int cpu)* addresses. */ simp.simp_enabled =0 ; -if (hv_isolation_type_snp ()) +if (hv_isolation_type_snp () || hv_root_partition) {memunmap (hv_cpu->synic_message_page); -else + hv_cpu->synic_message_page =NULL ; + }else { simp.base_simp_gpa =0 ; + }hv_set_register (HV_REGISTER_SIMP , simp.as_uint64); siefp.as_uint64 =hv_get_register (HV_REGISTER_SIEFP ); siefp.siefp_enabled =0 ; -if (hv_isolation_type_snp ())
drivers/hv/hv.c void hv_synic_disable_regs(unsigned int cpu) · line 338
Quoted 10 lines
drivers/hv/hv.c +4
-1+if (hv_isolation_type_snp () || hv_root_partition) {memunmap (hv_cpu->synic_event_page); - else + hv_cpu->synic_event_page =NULL ; + }else { siefp.base_siefp_gpa =0 ; + }hv_set_register (HV_REGISTER_SIEFP , siefp.as_uint64);
PATCH v10 3/5 x86/hyperv: Add an interface to do nested hypercalls
In reply to a message not in the archiveAccording to TLFS, in order to communicate to L0 hypervisor there needs to be an additional bit set in the control register. This communication is required to perform privileged instructions which can only be performed by L0 hypervisor. An example of that could be setting up the VMBus infrastructure.
--- arch/x86/include/asm/hyperv-tlfs.h | 3 ++- arch/x86/include/asm/mshyperv.h | 42 +++++++++++++++++++++++++++--- include/asm-generic/hyperv-tlfs.h | 1 + 3 files changed, 41 insertions(+), 5 deletions(-)
arch/x86/include/asm/hyperv-tlfs.h +2 -1
@@ -380,7 +380,8 @@ struct hv_nested_enlightenments_control { __u32 reserved:31; } features;struct { -__u32 reserved; +__u32 inter_partition_comm:1 ; +__u32 reserved:31 ; } hypercallControls; } __packed;
arch/x86/include/asm/mshyperv.h +38 -4
64 lines not on this page · raw message
include/asm-generic/hyperv-tlfs.h +1 -0
@@ -194,6 +194,7 @@ enum HV_GENERIC_SET_FORMAT {#define HV_HYPERCALL_VARHEAD_OFFSET 17#define HV_HYPERCALL_VARHEAD_MASK GENMASK_ULL(26, 17)#define HV_HYPERCALL_RSVD0_MASK GENMASK_ULL(31, 27) +#define HV_HYPERCALL_NESTED BIT_ULL(31)#define HV_HYPERCALL_REP_COMP_OFFSET 32#define HV_HYPERCALL_REP_COMP_1 BIT_ULL(32)#define HV_HYPERCALL_REP_COMP_MASK GENMASK_ULL(43, 32)
Signature · 1 line
2.25.1
RE: [PATCH v10 3/5] x86/hyperv: Add an interface to do nested hypercalls
From: Jinank Jain <[email protected]> Sent: Sunday, January 1, 2023 11:13 PM
Quoted 115 lines
According to TLFS, in order to communicate to L0 hypervisor there needs to be an additional bit set in the control register. This communication is required to perform privileged instructions which can only be performed by L0 hypervisor. An example of that could be setting up the VMBus infrastructure.
Signed-off-by Jinank Jain <[email protected]>--- arch/x86/include/asm/hyperv-tlfs.h | 3 ++- arch/x86/include/asm/mshyperv.h | 42 +++++++++++++++++++++++++++--- include/asm-generic/hyperv-tlfs.h | 1 + 3 files changed, 41 insertions(+), 5 deletions(-)arch/x86/include/asm/hyperv-tlfs.h +2
-1@@ -380,7 +380,8 @@ struct hv_nested_enlightenments_control { __u32 reserved:31; } features;struct { -__u32 reserved; +__u32 inter_partition_comm:1 ; +__u32 reserved:31 ; } hypercallControls; } __packed;arch/x86/include/asm/mshyperv.h +8
-2@@ -74,10 +74,16 @@ static inline u64 hv_do_hypercall(u64 control, void *input, void *output)return hv_status; } +/* Hypercall to the L0 hypervisor */ +static inline u64 hv_do_nested_hypercall (u64 control,void *input,void *output) +{ +return hv_do_hypercall (control |HV_HYPERCALL_NESTED , input, output); +} +/* Fast hypercall with 8 bytes of input and no output */ -static inline u64 hv_do_fast_hypercall8 (u16 code,u64 input1) +static inline u64 _hv_do_fast_hypercall8 (u64 control,u64 input1) { -u64 hv_status, control = (u64 )code |HV_HYPERCALL_FAST_BIT ; +u64 hv_status;#ifdef CONFIG_X86_64 arch/x86/include/asm/mshyperv.h +16
-2{@@ -105,10 +111,24 @@ static inline u64 hv_do_fast_hypercall8(u16 code, u64 input1)return hv_status; } +static inline u64 hv_do_fast_hypercall8 (u16 code,u64 input1) +{ +u64 control = (u64 )code |HV_HYPERCALL_FAST_BIT ; + +return _hv_do_fast_hypercall8 (control, input1); +} + +static inline u64 hv_do_fast_nested_hypercall8 (u16 code,u64 input1) +{ +u64 control = (u64 )code |HV_HYPERCALL_FAST_BIT |HV_HYPERCALL_NESTED ; + +return _hv_do_fast_hypercall8 (control, input1); +} +/* Fast hypercall with 16 bytes of input */ -static inline u64 hv_do_fast_hypercall16 (u16 code,u64 input1,u64 input2) +static inline u64 _hv_do_fast_hypercall16 (u64 control,u64 input1,u64 input2) { -u64 hv_status, control = (u64 )code |HV_HYPERCALL_FAST_BIT ; +u64 hv_status;#ifdef CONFIG_X86_64 arch/x86/include/asm/mshyperv.h +14
-0{@@ -139,6 +159,20 @@ static inline u64 hv_do_fast_hypercall16(u16 code, u64 input1, u64 input2)return hv_status; } +static inline u64 hv_do_fast_hypercall16 (u16 code,u64 input1,u64 input2) +{ +u64 control = (u64 )code |HV_HYPERCALL_FAST_BIT ; + +return _hv_do_fast_hypercall16 (control, input1, input2); +} + +static inline u64 hv_do_fast_nested_hypercall16 (u16 code,u64 input1,u64 input2) +{ +u64 control = (u64 )code |HV_HYPERCALL_FAST_BIT |HV_HYPERCALL_NESTED ; + +return _hv_do_fast_hypercall16 (control, input1, input2); +} +extern struct hv_vp_assist_page **hv_vp_assist_page;static inline struct
hv_vp_assist_page*hv_get_vp_assist_page(unsigned int cpu)include/asm-generic/hyperv-tlfs.h +1
-1@@ -194,6 +194,7 @@ enum HV_GENERIC_SET_FORMAT {#define HV_HYPERCALL_VARHEAD_OFFSET 17#define HV_HYPERCALL_VARHEAD_MASK GENMASK_ULL(26, 17)#define HV_HYPERCALL_RSVD0_MASK GENMASK_ULL(31, 27) +#define HV_HYPERCALL_NESTED BIT_ULL(31)#define HV_HYPERCALL_REP_COMP_OFFSET 32#define HV_HYPERCALL_REP_COMP_1 BIT_ULL(32)#define HV_HYPERCALL_REP_COMP_MASK GENMASK_ULL(43, 32) --
Quoted 1 line
2.25.1
PATCH v10 4/5 Drivers: hv: Enable vmbus driver for nested root partition
In reply to a message not in the archiveCurrently VMBus driver is not initialized for root partition but we need to enable the VMBus driver for nested root partition. This is required, so that L2 root can use the VMBus devices.
--- drivers/hv/vmbus_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hv/vmbus_drv.c +1 -1
@@ -2745,7 +2745,7 @@ static int __init hv_acpi_init(void)if (!hv_is_hyperv_initialized ())return -ENODEV ; -if (hv_root_partition) +if (hv_root_partition && !hv_nested)return 0 ;/*
Signature · 1 line
2.25.1
RE: [PATCH v10 4/5] Drivers: hv: Enable vmbus driver for nested root partition
From: Jinank Jain <[email protected]> Sent: Sunday, January 1, 2023 11:13 PM
Quoted 24 lines
Currently VMBus driver is not initialized for root partition but we need to enable the VMBus driver for nested root partition. This is required, so that L2 root can use the VMBus devices.
Signed-off-by Jinank Jain <[email protected]>--- drivers/hv/vmbus_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/hv/vmbus_drv.c +1
-2@@ -2745,7 +2745,7 @@ static int __init hv_acpi_init(void)if (!hv_is_hyperv_initialized ())return -ENODEV ; -if (hv_root_partition) +if (hv_root_partition && !hv_nested)return 0 ;/* --
Quoted 1 line
2.25.1
PATCH v10 5/5 x86/hyperv: Change interrupt vector for nested root partition
In reply to a message not in the archiveTraditionally we have been using the HYPERVISOR_CALLBACK_VECTOR to relay the VMBus interrupt. But this does not work in case of nested hypervisor. Microsoft Hypervisor reserves 0x31 to 0x34 as the interrupt vector range for VMBus and thus we have to use one of the vectors from that range and setup the IDT accordingly.
--- arch/x86/include/asm/idtentry.h | 2 ++ arch/x86/include/asm/irq_vectors.h | 6 ++++++ arch/x86/kernel/cpu/mshyperv.c | 15 +++++++++++++++ arch/x86/kernel/idt.c | 10 ++++++++++ drivers/hv/vmbus_drv.c | 3 ++- 5 files changed, 35 insertions(+), 1 deletion(-)
arch/x86/include/asm/idtentry.h +2 -0
@@ -686,6 +686,8 @@ DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_NESTED_VECTOR, sysvec_kvm_posted_intr_nestedDECLARE_IDTENTRY_SYSVEC (HYPERVISOR_CALLBACK_VECTOR , sysvec_hyperv_callback);DECLARE_IDTENTRY_SYSVEC (HYPERV_REENLIGHTENMENT_VECTOR , sysvec_hyperv_reenlightenment);DECLARE_IDTENTRY_SYSVEC (HYPERV_STIMER0_VECTOR , sysvec_hyperv_stimer0); +DECLARE_IDTENTRY_SYSVEC (HYPERV_INTR_NESTED_VMBUS_VECTOR , + sysvec_hyperv_nested_vmbus_intr);#endif #if IS_ENABLED (CONFIG_ACRN_GUEST )
arch/x86/include/asm/irq_vectors.h +6 -0
@@ -102,6 +102,12 @@#if IS_ENABLED (CONFIG_HYPERV )#define HYPERV_REENLIGHTENMENT_VECTOR 0xee#define HYPERV_STIMER0_VECTOR 0xed +/* +* FIXME: Change this, once Microsoft Hypervisor changes its assumption +* around VMBus interrupt vector allocation for nested root partition. +* Or provides a better interface to detect this instead of hardcoding. +*/ +#define HYPERV_INTR_NESTED_VMBUS_VECTOR 0x31#endif #define LOCAL_TIMER_VECTOR 0xec
arch/x86/kernel/cpu/mshyperv.c +15 -0
@@ -126,6 +126,21 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_hyperv_callback)set_irq_regs (old_regs); } +DEFINE_IDTENTRY_SYSVEC (sysvec_hyperv_nested_vmbus_intr) +{ +struct pt_regs *old_regs =set_irq_regs (regs); + +inc_irq_stat (irq_hv_callback_count); + +if (vmbus_handler) +vmbus_handler (); + +if (ms_hyperv.hints &HV_DEPRECATING_AEOI_RECOMMENDED ) +ack_APIC_irq (); + +set_irq_regs (old_regs); +} +void hv_setup_vmbus_handler (void (*handler)(void )) { vmbus_handler = handler;
arch/x86/kernel/idt.c +10 -0
@@ -160,6 +160,16 @@ static const __initconst struct idt_data apic_idts[] = {# endif INTG (SPURIOUS_APIC_VECTOR , asm_sysvec_spurious_apic_interrupt),INTG (ERROR_APIC_VECTOR , asm_sysvec_error_interrupt), +#ifdef CONFIG_HYPERV +/* +* This is a hack because we cannot install this interrupt handler +* via alloc_intr_gate as it does not allow interrupt vector less +* than FIRST_SYSTEM_VECTORS. And hyperv does not want anything other +* than 0x31-0x34 as the interrupt vector for vmbus interrupt in case +* of nested setup. + */ + INTG(HYPERV_INTR_NESTED_VMBUS_VECTOR, asm_sysvec_hyperv_nested_vmbus_intr), +#endif #endif };
drivers/hv/vmbus_drv.c +2 -1
@@ -2768,7 +2768,8 @@ static int __init hv_acpi_init(void)* normal Linux IRQ mechanism is not used in this case. */ #ifdef HYPERVISOR_CALLBACK_VECTOR - vmbus_interrupt =HYPERVISOR_CALLBACK_VECTOR ; + vmbus_interrupt = hv_nested ?HYPERV_INTR_NESTED_VMBUS_VECTOR : +HYPERVISOR_CALLBACK_VECTOR ; vmbus_irq =-1 ;#endif
Signature · 1 line
2.25.1
RE: [PATCH v10 5/5] x86/hyperv: Change interrupt vector for nested root partition
From: Jinank Jain <[email protected]> Sent: Sunday, January 1, 2023 11:13 PM
Quoted 114 lines
Traditionally we have been using the
HYPERVISOR_CALLBACK_VECTORto relay the VMBus interrupt. But this does not work in case of nested hypervisor. Microsoft Hypervisor reserves0x31to0x34as the interrupt vector range for VMBus and thus we have to use one of the vectors from that range and setup the IDT accordingly.Signed-off-by Jinank Jain <[email protected]>--- arch/x86/include/asm/idtentry.h | 2 ++ arch/x86/include/asm/irq_vectors.h | 6 ++++++ arch/x86/kernel/cpu/mshyperv.c | 15 +++++++++++++++ arch/x86/kernel/idt.c | 10 ++++++++++ drivers/hv/vmbus_drv.c | 3 ++- 5 files changed, 35 insertions(+), 1 deletion(-)arch/x86/include/asm/idtentry.h +0
-0@@ -686,6 +686,8 @@ DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_NESTED_VECTOR,sysvec_kvm_posted_intr_nested DECLARE_IDTENTRY_SYSVEC (HYPERVISOR_CALLBACK_VECTOR ,sysvec_hyperv_callback );DECLARE_IDTENTRY_SYSVEC (HYPERV_REENLIGHTENMENT_VECTOR , sysvec_hyperv_reenlightenment); DECLARE_IDTENTRY_SYSVEC(HYPERV_STIMER0_VECTOR,sysvec_hyperv_stimer0);arch/x86/include/asm/idtentry.h +2
-0+DECLARE_IDTENTRY_SYSVEC (HYPERV_INTR_NESTED_VMBUS_VECTOR , + sysvec_hyperv_nested_vmbus_intr);#endif #if IS_ENABLED (CONFIG_ACRN_GUEST )arch/x86/include/asm/irq_vectors.h +6
-0@@ -102,6 +102,12 @@#if IS_ENABLED (CONFIG_HYPERV )#define HYPERV_REENLIGHTENMENT_VECTOR 0xee#define HYPERV_STIMER0_VECTOR 0xed +/* +* FIXME: Change this, once Microsoft Hypervisor changes its assumption +* around VMBus interrupt vector allocation for nested root partition. +* Or provides a better interface to detect this instead of hardcoding. +*/ +#define HYPERV_INTR_NESTED_VMBUS_VECTOR 0x31#endif #define LOCAL_TIMER_VECTOR 0xecarch/x86/kernel/cpu/mshyperv.c +15
-0@@ -126,6 +126,21 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_hyperv_callback)set_irq_regs (old_regs); } +DEFINE_IDTENTRY_SYSVEC (sysvec_hyperv_nested_vmbus_intr) +{ +struct pt_regs *old_regs =set_irq_regs (regs); + +inc_irq_stat (irq_hv_callback_count); + +if (vmbus_handler) +vmbus_handler (); + +if (ms_hyperv.hints &HV_DEPRECATING_AEOI_RECOMMENDED ) +ack_APIC_irq (); + +set_irq_regs (old_regs); +} +void hv_setup_vmbus_handler (void (*handler)(void )) { vmbus_handler = handler;arch/x86/kernel/idt.c +10
-0@@ -160,6 +160,16 @@ static const __initconst struct idt_data apic_idts[] = {# endif INTG (SPURIOUS_APIC_VECTOR , asm_sysvec_spurious_apic_interrupt),INTG (ERROR_APIC_VECTOR , asm_sysvec_error_interrupt), +#ifdef CONFIG_HYPERV +/* +* This is a hack because we cannot install this interrupt handler +* via alloc_intr_gate as it does not allow interrupt vector less +* than FIRST_SYSTEM_VECTORS. And hyperv does not want anything other +* than 0x31-0x34 as the interrupt vector for vmbus interrupt in case +* of nested setup. + */ + INTG(HYPERV_INTR_NESTED_VMBUS_VECTOR, asm_sysvec_hyperv_nested_vmbus_intr), +#endif #endif };
drivers/hv/vmbus_drv.c +2
-2@@ -2768,7 +2768,8 @@ static int __init hv_acpi_init(void)* normal Linux IRQ mechanism is not used in this case. */ #ifdef HYPERVISOR_CALLBACK_VECTOR - vmbus_interrupt =HYPERVISOR_CALLBACK_VECTOR ; + vmbus_interrupt = hv_nested ?HYPERV_INTR_NESTED_VMBUS_VECTOR : +HYPERVISOR_CALLBACK_VECTOR ; vmbus_irq =-1 ;#endif --
Quoted 1 line
2.25.1
I'm giving my "Reviewed-by" based on what I know, but I'm unsure about the validity of grabbing vector 0x31 out of the middle of the range versus at the end like all the other fixed vectors. Getting this changed on the MSHV side would really be a better solution.
Re: [PATCH v10 5/5] x86/hyperv: Change interrupt vector for nested root partition
In reply to Jinank JainQuoted 7 lines · Jinank Jain
Traditionally we have been using the
HYPERVISOR_CALLBACK_VECTORto relay the VMBus interrupt. But this does not work in case of nested hypervisor. Microsoft Hypervisor reserves0x31to0x34as the interrupt vector range for VMBus and thus we have to use one of the vectors from that range and setup the IDT accordingly.Signed-off-by Jinank Jain <[email protected]>
I've applied all but this patch to hyperv-next.
This patch still needs an ack or nack from x86 maintainers to proceed.
Thanks,
Wei.
Quoted 102 lines
--- arch/x86/include/asm/idtentry.h | 2 ++ arch/x86/include/asm/irq_vectors.h | 6 ++++++ arch/x86/kernel/cpu/mshyperv.c | 15 +++++++++++++++ arch/x86/kernel/idt.c | 10 ++++++++++ drivers/hv/vmbus_drv.c | 3 ++- 5 files changed, 35 insertions(+), 1 deletion(-)arch/x86/include/asm/idtentry.h +2
-0@@ -686,6 +686,8 @@ DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_NESTED_VECTOR, sysvec_kvm_posted_intr_nestedDECLARE_IDTENTRY_SYSVEC (HYPERVISOR_CALLBACK_VECTOR , sysvec_hyperv_callback);DECLARE_IDTENTRY_SYSVEC (HYPERV_REENLIGHTENMENT_VECTOR , sysvec_hyperv_reenlightenment);DECLARE_IDTENTRY_SYSVEC (HYPERV_STIMER0_VECTOR , sysvec_hyperv_stimer0); +DECLARE_IDTENTRY_SYSVEC (HYPERV_INTR_NESTED_VMBUS_VECTOR , + sysvec_hyperv_nested_vmbus_intr);#endif #if IS_ENABLED (CONFIG_ACRN_GUEST )arch/x86/include/asm/irq_vectors.h +6
-0@@ -102,6 +102,12 @@#if IS_ENABLED (CONFIG_HYPERV )#define HYPERV_REENLIGHTENMENT_VECTOR 0xee#define HYPERV_STIMER0_VECTOR 0xed +/* +* FIXME: Change this, once Microsoft Hypervisor changes its assumption +* around VMBus interrupt vector allocation for nested root partition. +* Or provides a better interface to detect this instead of hardcoding. +*/ +#define HYPERV_INTR_NESTED_VMBUS_VECTOR 0x31#endif #define LOCAL_TIMER_VECTOR 0xecarch/x86/kernel/cpu/mshyperv.c +15
-0@@ -126,6 +126,21 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_hyperv_callback)set_irq_regs (old_regs); } +DEFINE_IDTENTRY_SYSVEC (sysvec_hyperv_nested_vmbus_intr) +{ +struct pt_regs *old_regs =set_irq_regs (regs); + +inc_irq_stat (irq_hv_callback_count); + +if (vmbus_handler) +vmbus_handler (); + +if (ms_hyperv.hints &HV_DEPRECATING_AEOI_RECOMMENDED ) +ack_APIC_irq (); + +set_irq_regs (old_regs); +} +void hv_setup_vmbus_handler (void (*handler)(void )) { vmbus_handler = handler;arch/x86/kernel/idt.c +10
-0@@ -160,6 +160,16 @@ static const __initconst struct idt_data apic_idts[] = {# endif INTG (SPURIOUS_APIC_VECTOR , asm_sysvec_spurious_apic_interrupt),INTG (ERROR_APIC_VECTOR , asm_sysvec_error_interrupt), +#ifdef CONFIG_HYPERV +/* +* This is a hack because we cannot install this interrupt handler +* via alloc_intr_gate as it does not allow interrupt vector less +* than FIRST_SYSTEM_VECTORS. And hyperv does not want anything other +* than 0x31-0x34 as the interrupt vector for vmbus interrupt in case +* of nested setup. + */ + INTG(HYPERV_INTR_NESTED_VMBUS_VECTOR, asm_sysvec_hyperv_nested_vmbus_intr), +#endif #endif };drivers/hv/vmbus_drv.c +2
-1@@ -2768,7 +2768,8 @@ static int __init hv_acpi_init(void)* normal Linux IRQ mechanism is not used in this case. */ #ifdef HYPERVISOR_CALLBACK_VECTOR - vmbus_interrupt =HYPERVISOR_CALLBACK_VECTOR ; + vmbus_interrupt = hv_nested ?HYPERV_INTR_NESTED_VMBUS_VECTOR : +HYPERVISOR_CALLBACK_VECTOR ; vmbus_irq =-1 ;#endif Signature · 1 line
2.25.1
Borislav Petkov
maintainerRe: [PATCH v10 5/5] x86/hyperv: Change interrupt vector for nested root partition
In reply to Jinank JainQuoted 1 line · Jinank Jain
Traditionally we have been using the
HYPERVISOR_CALLBACK_VECTORto relay
Who's "we"?
Please use passive voice in your commit message: no "we" or "I", etc, and describe your changes in imperative mood.
Also, pls read section "2) Describe your changes" in Documentation/process/submitting-patches.rst for more details.
Also, see section "Changelog" inDocumentation/process/maintainer-tip.rst
Bottom line is: personal pronouns are ambiguous in text, especially with so many parties/companies/etc developing the kernel so let's avoid them please.
Quoted 32 lines
the VMBus interrupt. But this does not work in case of nested hypervisor. Microsoft Hypervisor reserves
0x31to0x34as the interrupt vector range for VMBus and thus we have to use one of the vectors from that range and setup the IDT accordingly.Signed-off-by Jinank Jain <[email protected]>--- arch/x86/include/asm/idtentry.h | 2 ++ arch/x86/include/asm/irq_vectors.h | 6 ++++++ arch/x86/kernel/cpu/mshyperv.c | 15 +++++++++++++++ arch/x86/kernel/idt.c | 10 ++++++++++ drivers/hv/vmbus_drv.c | 3 ++- 5 files changed, 35 insertions(+), 1 deletion(-)arch/x86/include/asm/idtentry.h +2
-0@@ -686,6 +686,8 @@ DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_NESTED_VECTOR, sysvec_kvm_posted_intr_nestedDECLARE_IDTENTRY_SYSVEC (HYPERVISOR_CALLBACK_VECTOR , sysvec_hyperv_callback);DECLARE_IDTENTRY_SYSVEC (HYPERV_REENLIGHTENMENT_VECTOR , sysvec_hyperv_reenlightenment);DECLARE_IDTENTRY_SYSVEC (HYPERV_STIMER0_VECTOR , sysvec_hyperv_stimer0); +DECLARE_IDTENTRY_SYSVEC (HYPERV_INTR_NESTED_VMBUS_VECTOR , + sysvec_hyperv_nested_vmbus_intr);#endif #if IS_ENABLED (CONFIG_ACRN_GUEST )arch/x86/include/asm/irq_vectors.h +0
-0
arch/x86/include/asm/irq_vectors.h line 106
Quoted 5 lines
arch/x86/include/asm/irq_vectors.h +2
-0@@ -102,6 +102,12 @@#if IS_ENABLED (CONFIG_HYPERV )#define HYPERV_REENLIGHTENMENT_VECTOR 0xee#define HYPERV_STIMER0_VECTOR 0xed +/* +* FIXME: Change this, once Microsoft Hypervisor changes its assumption
^^^^^^
This patch looks like it is not ready to go anywhere yet...
arch/x86/include/asm/irq_vectors.h line 107
Quoted 1 line
arch/x86/include/asm/irq_vectors.h +1
-0+* around VMBus interrupt vector allocation for nested root partition.
When is that going to happen? If at all...
Quoted 37 lines
arch/x86/include/asm/irq_vectors.h +3
-0+* Or provides a better interface to detect this instead of hardcoding. +*/ +#define HYPERV_INTR_NESTED_VMBUS_VECTOR 0x31#endif #define LOCAL_TIMER_VECTOR 0xecarch/x86/kernel/cpu/mshyperv.c +15
-0@@ -126,6 +126,21 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_hyperv_callback)set_irq_regs (old_regs); } +DEFINE_IDTENTRY_SYSVEC (sysvec_hyperv_nested_vmbus_intr) +{ +struct pt_regs *old_regs =set_irq_regs (regs); + +inc_irq_stat (irq_hv_callback_count); + +if (vmbus_handler) +vmbus_handler (); + +if (ms_hyperv.hints &HV_DEPRECATING_AEOI_RECOMMENDED ) +ack_APIC_irq (); + +set_irq_regs (old_regs); +} +void hv_setup_vmbus_handler (void (*handler)(void )) { vmbus_handler = handler;arch/x86/kernel/idt.c +0
-0
arch/x86/kernel/idt.c static const __initconst struct idt_data apic_idts[] = { · line 168
Quoted 9 lines
arch/x86/kernel/idt.c +6
-0@@ -160,6 +160,16 @@ static const __initconst struct idt_data apic_idts[] = {# endif INTG (SPURIOUS_APIC_VECTOR , asm_sysvec_spurious_apic_interrupt),INTG (ERROR_APIC_VECTOR , asm_sysvec_error_interrupt), +#ifdef CONFIG_HYPERV +/* +* This is a hack because we cannot install this interrupt handler +* via alloc_intr_gate as it does not allow interrupt vector less +* than FIRST_SYSTEM_VECTORS. And hyperv does not want anything other +* than 0x31-0x34 as the interrupt vector for vmbus interrupt in case
Well:
/*
* IDT vectors usable for external interrupt sources start at 0x20.
* (0x80 is the syscall vector, 0x30-0x3f are for ISA)
^^^^^^^^^^^^^^^^^^^^^^
*/
#define FIRST_EXTERNAL_VECTOR 0x20
I guess HyperV decided to reuse those...?
Signature · 4 lines
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquetteRe: [PATCH v10 5/5] x86/hyperv: Change interrupt vector for nested root partition
In reply to Jinank JainJinank!
arch/x86/include/asm/irq_vectors.h line 110
Quoted 8 lines · Jinank Jain
arch/x86/include/asm/irq_vectors.h +6
-0+/* +* FIXME: Change this, once Microsoft Hypervisor changes its assumption +* around VMBus interrupt vector allocation for nested root partition. +* Or provides a better interface to detect this instead of hardcoding. +*/ +#define HYPERV_INTR_NESTED_VMBUS_VECTOR 0x31
arch/x86/include/asm/irq_vectors.h line 47:
/*
* Vectors 0x30-0x3f are used for ISA interrupts.
* round up to the next 16-vector boundary
*/
#define ISA_IRQ_VECTOR(irq) (((FIRST_EXTERNAL_VECTOR + 16) & ~15) + irq)
So this overlaps with the legacy interrupt vector space.
arch/x86/include/asm/irq_vectors.h
Quoted 10 lines
arch/x86/include/asm/irq_vectors.h +10
-0+#ifdef CONFIG_HYPERV +/* +* This is a hack because we cannot install this interrupt handler +* via alloc_intr_gate as it does not allow interrupt vector less +* than FIRST_SYSTEM_VECTORS. And hyperv does not want anything other +* than 0x31-0x34 as the interrupt vector for vmbus interrupt in case +* of nested setup. +*/ + INTG(HYPERV_INTR_NESTED_VMBUS_VECTOR, asm_sysvec_hyperv_nested_vmbus_intr), +#endif
I agree, that this is a hack, but that puts it mildly: It's a completely broken hack.
Quoted 1 line
+DECLARE_IDTENTRY_SYSVEC(HYPERV_INTR_NESTED_VMBUS_VECTOR,
sysvec_hyperv_nested_vmbus_intr);
This generates the low level entry stub for vector 0x31 at compile time, which competes with the interrupt stub for external interrupts generated by:
SYM_CODE_START(irq_entries_start)
Now the above INTG() hard-codes the IDT entry for vector 0x31 into the apic_idts table. That marks it as system vector which in turn prevents idt_setup_apic_and_irq_gates() to install the IDT entry for the external vector on _ALL_ systems unconditionally.
IOW, you broke world except for systems which do not use the legacy interrupt space. Congrats!
That legacy space is hardcoded and that's clearly documented so.
0x31 becomes IRQ1 - usually the i8042 - which makes it pretty much guaranteed that this collides and fails. The worst case consequence is a fully uncontrolled interrupt storm which is not even detectable.
So this patch is /dev/null material and either the hypervisor side makes it possible to use a different vector space or this needs some very careful modifications to the legacy ISA vector assignment.
Thanks,
tglx