x86/kvm: Enable MCE injection in the guest
Borislav Petkov
maintainercover x86/kvm: Enable MCE injection in the guest
From: Borislav Petkov <[email protected]>
Hi all,
there's this mce-inject.ko module in the kernel which allows for injecting real MCEs and thus test the MCE handling code.
It is doubly useful to be able to inject same MCEs in a guest so that testing of the MCE handling code can happen even easier/faster. In order to be able to do that on an AMD guest, we need to emulate some bits and pieces like the HWCR[McStatusWrEn] bit which allows writes to the MCi_STATUS registers without a #GP.
The below does that and with it I'm able to properly inject MCEs in said guest.
Thx.
Borislav Petkov (3):
kvm/x86: Move MSR_K7_HWCR to svm.c
x86/kvm: Implement MSR_HWCR support
x86/kvm: Handle all MCA banks
arch/x86/kvm/svm.c | 20 ++++++++++++++++++ arch/x86/kvm/x86.c | 51 ++++++++++++++++++++++++++++++---------------- 2 files changed, 54 insertions(+), 17 deletions(-)
Signature · 1 line
2.17.0.582.gccdcbd54c
Borislav Petkov
maintainerPATCH 1/3 kvm/x86: Move MSR_K7_HWCR to svm.c
From: Borislav Petkov <[email protected]>
This is an AMD-specific MSR. Put it where it belongs.
--- arch/x86/kvm/svm.c | 14 ++++++++++++++ arch/x86/kvm/x86.c | 12 ------------ 2 files changed, 14 insertions(+), 12 deletions(-)
arch/x86/kvm/svm.c +14 -0
@@ -4153,6 +4153,9 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)case MSR_F10H_DECFG : msr_info->data = svm->msr_decfg;break ; +case MSR_K7_HWCR : + msr_info->data =0 ; +break ;default :return kvm_get_msr_common (vcpu, msr_info); }
@@ -4357,6 +4360,17 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) svm->msr_decfg = data;break ; } +case MSR_K7_HWCR : + data &= ~(u64 )0x40 ;/* ignore flush filter disable */ + data &= ~(u64 )0x100 ;/* ignore ignne emulation enable */ + data &= ~(u64 )0x8 ;/* ignore TLB cache disable */ + data &= ~(u64 )0x40000 ;/* ignore Mc status write enable */ +if (data !=0 ) { +vcpu_unimpl (vcpu,"unimplemented HWCR wrmsr: 0x%llx\n" , + data); +return 1 ; + } +break ;case MSR_IA32_APICBASE :if (kvm_vcpu_apicv_active (vcpu))avic_update_vapic_bar (to_svm (vcpu), data);
arch/x86/kvm/x86.c +0 -12
@@ -2317,17 +2317,6 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)break ;case MSR_EFER :return set_efer (vcpu, data); -case MSR_K7_HWCR : - data &= ~(u64 )0x40 ;/* ignore flush filter disable */ - data &= ~(u64 )0x100 ;/* ignore ignne emulation enable */ - data &= ~(u64 )0x8 ;/* ignore TLB cache disable */ - data &= ~(u64 )0x40000 ;/* ignore Mc status write enable */ -if (data !=0 ) { -vcpu_unimpl (vcpu,"unimplemented HWCR wrmsr: 0x%llx\n" , - data); -return 1 ; - } -break ;case MSR_FAM10H_MMIO_CONF_BASE :if (data !=0 ) { vcpu_unimpl(vcpu, "unimplemented MMIO_CONF_BASE wrmsr: "
@@ -2597,7 +2586,6 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)case MSR_K8_SYSCFG :case MSR_K8_TSEG_ADDR :case MSR_K8_TSEG_MASK : -case MSR_K7_HWCR :case MSR_VM_HSAVE_PA :case MSR_K8_INT_PENDING_MSG :case MSR_AMD64_NB_CFG :
Signature · 1 line
2.17.0.582.gccdcbd54c
Borislav Petkov
maintainerPATCH 2/3 x86/kvm: Implement MSR_HWCR support
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
The hardware configuration register has some useful bits which can be used by guests. Implement McStatusWrEn which can be used by guests when injecting MCEs with the in-kernel mce-inject module.
For that, we need to set bit 18 - McStatusWrEn - first, before writing the MCi_STATUS registers (otherwise we #GP).
Add the required machinery to do so.
--- arch/x86/kvm/svm.c | 12 +++++++++--- arch/x86/kvm/x86.c | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 6 deletions(-)
arch/x86/kvm/svm.c +9 -3
@@ -251,6 +251,9 @@ struct vcpu_svm {/* which host CPU was used for running this vcpu */ unsigned int last_cpu; + +/* MSRC001_0015 Hardware Configuration */ +u64 msr_hwcr; };/*
@@ -4154,7 +4157,7 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) msr_info->data = svm->msr_decfg;break ;case MSR_K7_HWCR : - msr_info->data =0 ; + msr_info->data = svm->msr_hwcr;break ;default :return kvm_get_msr_common (vcpu, msr_info);
@@ -4364,8 +4367,11 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) data &= ~(u64 )0x40 ;/* ignore flush filter disable */ data &= ~(u64 )0x100 ;/* ignore ignne emulation enable */ data &= ~(u64 )0x8 ;/* ignore TLB cache disable */ - data &= ~(u64 )0x40000 ;/* ignore Mc status write enable */ -if (data !=0 ) { + +/* Handle McStatusWrEn */ +if (data ==BIT_ULL (18 )) { + svm->msr_hwcr = data; + }else if (data !=0 ) {vcpu_unimpl (vcpu,"unimplemented HWCR wrmsr: 0x%llx\n" , data);return 1 ;
arch/x86/kvm/x86.c +31 -3
@@ -2146,6 +2146,30 @@ static void kvmclock_sync_fn(struct work_struct *work) KVMCLOCK_SYNC_PERIOD); } +/* +* On AMD, HWCR[McStatusWrEn] controls whether setting MCi_STATUS results in #GP. +*/ +static bool __set_mci_status (struct kvm_vcpu *vcpu,struct msr_data *msr_info) +{ +if (guest_cpuid_is_amd (vcpu)) { +struct msr_data tmp; + + tmp.index =MSR_K7_HWCR ; + +if (kvm_x86_ops->get_msr (vcpu, &tmp)) +return false; + +/* McStatusWrEn enabled? */ +if (tmp.data &BIT_ULL (18 )) +return true; + } + +if (!msr_info->host_initiated && msr_info->data !=0 ) +return false; + +return true; +} +static int set_msr_mce (struct kvm_vcpu *vcpu,struct msr_data *msr_info) {u64 mcg_cap = vcpu->arch.mcg_cap;
@@ -2176,9 +2200,13 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info)if ((offset &0x3 ) ==0 && data !=0 && (data | (1 <<10 )) != ~(u64 )0 )return -1 ; -if (!msr_info->host_initiated && - (offset &0x3 ) ==1 && data !=0 ) -return -1 ; + +/* MCi_STATUS */ +if ((offset &0x3 ) ==1 ) { +if (!__set_mci_status (vcpu, msr_info)) +return -1 ; + } + vcpu->arch.mce_banks[offset] = data;break ; }
Signature · 1 line
2.17.0.582.gccdcbd54c
Re: [PATCH 2/3] x86/kvm: Implement MSR_HWCR support
2018-06-22 11:51+0200, Borislav Petkov:
Quoted 28 lines
From: Borislav Petkov <[email protected]>
The hardware configuration register has some useful bits which can be used by guests. Implement McStatusWrEn which can be used by guests when injecting MCEs with the in-kernel mce-inject module.
For that, we need to set bit 18 - McStatusWrEn - first, before writing the
MCi_STATUSregisters (otherwise we #GP).Add the required machinery to do so.
Signed-off-by Borislav Petkov <[email protected]>---
arch/x86/kvm/x86.c +10
-0@@ -2146,6 +2146,30 @@ static void kvmclock_sync_fn(struct work_struct *work) KVMCLOCK_SYNC_PERIOD); } +/* +* On AMD, HWCR[McStatusWrEn] controls whether setting MCi_STATUS results in #GP. +*/ +static bool __set_mci_status (struct kvm_vcpu *vcpu,struct msr_data *msr_info) +{ +if (guest_cpuid_is_amd (vcpu)) { +struct msr_data tmp; + + tmp.index =MSR_K7_HWCR ; +
arch/x86/kvm/x86.c static void kvmclock_sync_fn(struct work_struct *work) · line 2168
Quoted 10 lines
arch/x86/kvm/x86.c +10
-0+if (kvm_x86_ops->get_msr (vcpu, &tmp)) +return false; + +/* McStatusWrEn enabled? */ +if (tmp.data &BIT_ULL (18 )) +return true; + } + +if (!msr_info->host_initiated && msr_info->data !=0 ) +return false;
msr_info->host_initiated is always going to return true, so it would be better to put it outside of __set_mci_status.
Maybe we could just write the whole logic inline, otherwise I'd call it something like mci_status_is_writeable.
Quoted 6 lines
arch/x86/kvm/x86.c +0
-0static int set_msr_mce (struct kvm_vcpu *vcpu,struct msr_data *msr_info) {u64 mcg_cap = vcpu->arch.mcg_cap;@@ -2176,9 +2200,13 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info)if ((offset &0x3 ) ==0 && data !=0 && (data | (1 <<10 )) != ~(u64 )0 )
arch/x86/kvm/x86.c static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 2208
Quoted 10 lines
arch/x86/kvm/x86.c +6
-3return -1 ; -if (!msr_info->host_initiated && - (offset &0x3 ) ==1 && data !=0 ) -return -1 ; + +/* MCi_STATUS */ +if ((offset &0x3 ) ==1 ) { +if (!__set_mci_status (vcpu, msr_info)) +return -1 ; + }
if (!msr_info->host_initiated &&
(offset & 0x3) == 1 && data != 0) {
struct msr_data tmp = {.index = MSR_K7_HWCR};
if (!guest_cpuid_is_amd(vcpu) ||
!kvm_x86_ops->get_msr(vcpu, &tmp) ||
!(tmp.data & BIT_ULL(18)))
return -1;
}Quoted 7 lines
arch/x86/kvm/x86.c +1
-0+ vcpu->arch.mce_banks[offset] = data;break ; }Signature · 1 line
2.17.0.582.gccdcbd54c
Borislav Petkov
maintainerRe: [PATCH 2/3] x86/kvm: Implement MSR_HWCR support
Quoted 23 lines · Radim Krčmář
msr_info->host_initiatedis always going to return true, so it would be better to put it outside of__set_mci_status.Maybe we could just write the whole logic inline, otherwise I'd call it something like
mci_status_is_writeable.Quoted 6 lines
static int
set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info){arch/x86/kvm/x86.c +0
-0u64 mcg_cap = vcpu->arch.mcg_cap;@@ -2176,9 +2200,13 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info)if ((offset &0x3 ) ==0 && data !=0 && (data | (1 <<10 )) != ~(u64 )0 )arch/x86/kvm/x86.c static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 2208
Quoted 10 lines
arch/x86/kvm/x86.c +6
-3return -1 ; -if (!msr_info->host_initiated && - (offset &0x3 ) ==1 && data !=0 ) -return -1 ; + +/* MCi_STATUS */ +if ((offset &0x3 ) ==1 ) { +if (!__set_mci_status (vcpu, msr_info)) +return -1 ; + }
Quoted 8 lines
if (!msr_info->host_initiated &&
(offset & 0x3) == 1 && data != 0) {
struct msr_data tmp = {.index = MSR_K7_HWCR};
if (!guest_cpuid_is_amd(vcpu) ||
!kvm_x86_ops->get_msr(vcpu, &tmp) ||
!(tmp.data & BIT_ULL(18)))
return -1;Don't you feel it is cleaner if all the MCi_STATUS checking is done in a separate function? The indentation level and the bunch of checks in set_msr_mce() make it hard to read while having a separate function separates it and makes it easier to follow.
I mean, you're the maintainer but if I may give a suggestion, moving the whole logic into a separate function would be more readable.
And then do:
if (!msr_info->host_initiated) {
if (check_mci_status(...))
return -1;
}Something like that...
Signature · 4 lines
Regards/Gruss,
Boris.
Good mailing practices for 400: avoid top-posting and trim the reply.Re: [PATCH 2/3] x86/kvm: Implement MSR_HWCR support
2018-06-22 21:09+0200, Borislav Petkov:
Quoted 33 lines · Radim Krčmář
Quoted 23 lines
msr_info->host_initiatedis always going to return true, so it would be better to put it outside of__set_mci_status.Maybe we could just write the whole logic inline, otherwise I'd call it something like
mci_status_is_writeable.Quoted 6 lines
static int
set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info){arch/x86/kvm/x86.c +0
-0u64 mcg_cap = vcpu->arch.mcg_cap;@@ -2176,9 +2200,13 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info)if ((offset &0x3 ) ==0 && data !=0 && (data | (1 <<10 )) != ~(u64 )0 )arch/x86/kvm/x86.c static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 2208
Quoted 10 lines
arch/x86/kvm/x86.c +6
-3return -1 ; -if (!msr_info->host_initiated && - (offset &0x3 ) ==1 && data !=0 ) -return -1 ; + +/* MCi_STATUS */ +if ((offset &0x3 ) ==1 ) { +if (!__set_mci_status (vcpu, msr_info)) +return -1 ; + }Quoted 8 lines
if (!msr_info->host_initiated && (offset & 0x3) == 1 && data != 0) { struct msr_data tmp = {.index = MSR_K7_HWCR}; if (!guest_cpuid_is_amd(vcpu) || !kvm_x86_ops->get_msr(vcpu, &tmp) || !(tmp.data & BIT_ULL(18))) return -1;
Quoted 4 lines
Don't you feel it is cleaner if all the
MCi_STATUSchecking is done in a separate function? The indentation level and the bunch of checks inset_msr_mce()make it hard to read while having a separate function separates it and makes it easier to follow.
Yes, I feel the same.
Quoted 11 lines
I mean, you're the maintainer but if I may give a suggestion, moving the whole logic into a separate function would be more readable.
And then do:
if (!msr_info->host_initiated) { if (check_mci_status(...)) return -1; }Something like that...
Much better, thanks.
Borislav Petkov
maintainerPATCH 3/3 x86/kvm: Handle all MCA banks
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
Extend the range of MCA banks which get passed to set/get_msr_mce() to include all the MSRs of the last bank too.
--- arch/x86/kvm/x86.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
arch/x86/kvm/x86.c +3 -2
@@ -2466,7 +2466,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)case MSR_IA32_MCG_CTL :case MSR_IA32_MCG_STATUS : - case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS) - 1: + case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_MISC(KVM_MAX_MCE_BANKS) - 1:return set_msr_mce (vcpu, msr_info); case MSR_K7_PERFCTR0 ... MSR_K7_PERFCTR3:
@@ -2588,9 +2588,10 @@ static int get_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)case MSR_IA32_MCG_STATUS : data = vcpu->arch.mcg_status;break ; +default :if (msr >=MSR_IA32_MC0_CTL && - msr <MSR_IA32_MCx_CTL (bank_num)) { + msr <MSR_IA32_MCx_MISC (bank_num)) {u32 offset = msr -MSR_IA32_MC0_CTL ; data = vcpu->arch.mce_banks[offset];break ;
Signature · 1 line
2.17.0.582.gccdcbd54c
Re: [PATCH 3/3] x86/kvm: Handle all MCA banks
2018-06-22 11:51+0200, Borislav Petkov:
Quoted 15 lines
From: Borislav Petkov <[email protected]>
Extend the range of MCA banks which get passed to set/get_msr_mce() to include all the MSRs of the last bank too.
Signed-off-by Borislav Petkov <[email protected]>--- arch/x86/kvm/x86.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)arch/x86/kvm/x86.c +0
-0
arch/x86/kvm/x86.c int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 2469
Quoted 5 lines
arch/x86/kvm/x86.c +1
-1@@ -2466,7 +2466,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)case MSR_IA32_MCG_CTL :case MSR_IA32_MCG_STATUS : - case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS) - 1: + case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_MISC(KVM_MAX_MCE_BANKS) - 1:
It was correct before. We have 32 banks (KVM_MAX_MCE_BANKS), so the last useable has index 31 and the "- 1" is going to roll over from first MSR of bank 32 to the last MSR of the last bank.
Another way of writing it would be:
case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_MISC(KVM_MAX_MCE_BANKS - 1):
arch/x86/kvm/x86.c static int get_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) · line 2594
Quoted 12 lines
arch/x86/kvm/x86.c +2
-1return set_msr_mce (vcpu, msr_info); case MSR_K7_PERFCTR0 ... MSR_K7_PERFCTR3:@@ -2588,9 +2588,10 @@ static int get_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)case MSR_IA32_MCG_STATUS : data = vcpu->arch.mcg_status;break ; +default :if (msr >=MSR_IA32_MC0_CTL && - msr <MSR_IA32_MCx_CTL (bank_num)) { + msr <MSR_IA32_MCx_MISC (bank_num)) {
Similar logic here.
I think it would be best just to keep the current code,
thanks.
Borislav Petkov
maintainerRe: [PATCH 3/3] x86/kvm: Handle all MCA banks
Quoted 26 lines · Radim Krčmář
2018-06-22 11:51+0200, Borislav Petkov:
Quoted 15 lines
From: Borislav Petkov <[email protected]>
Extend the range of MCA banks which get passed to set/get_msr_mce() to include all the MSRs of the last bank too.
Signed-off-by Borislav Petkov <[email protected]>--- arch/x86/kvm/x86.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)arch/x86/kvm/x86.c +0
-0arch/x86/kvm/x86.c int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 2469
Quoted 5 lines
arch/x86/kvm/x86.c +1
-1@@ -2466,7 +2466,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)case MSR_IA32_MCG_CTL :case MSR_IA32_MCG_STATUS : - case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS) - 1: + case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_MISC(KVM_MAX_MCE_BANKS) - 1:It was correct before. We have 32 banks (
KVM_MAX_MCE_BANKS), so the last useable has index 31 and the "- 1" is going to roll over from first MSR of bank 32 to the last MSR of the last bank.
Quoted 3 lines
Another way of writing it would be:
case
MSR_IA32_MC0_CTL...MSR_IA32_MCx_MISC(KVM_MAX_MCE_BANKS - 1):
Huh?
This is what I did:
+ case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_MISC(KVM_MAX_MCE_BANKS) - 1:
It needs to be MISC because it is the last MSR in the MCA bank and thus the highest.
Signature · 4 lines
Regards/Gruss,
Boris.
Good mailing practices for 400: avoid top-posting and trim the reply.Re: [PATCH 3/3] x86/kvm: Handle all MCA banks
2018-06-22 20:24+0200, Borislav Petkov:
Quoted 31 lines · Radim Krčmář
Quoted 26 lines
2018-06-22 11:51+0200, Borislav Petkov:
Quoted 15 lines
From: Borislav Petkov <[email protected]>
Extend the range of MCA banks which get passed to set/get_msr_mce() to include all the MSRs of the last bank too.
Signed-off-by Borislav Petkov <[email protected]>--- arch/x86/kvm/x86.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)arch/x86/kvm/x86.c +0
-0arch/x86/kvm/x86.c int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 2469
Quoted 5 lines
arch/x86/kvm/x86.c +1
-1@@ -2466,7 +2466,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)case MSR_IA32_MCG_CTL :case MSR_IA32_MCG_STATUS : - case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS) - 1: + case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_MISC(KVM_MAX_MCE_BANKS) - 1:It was correct before. We have 32 banks (
KVM_MAX_MCE_BANKS), so the last useable has index 31 and the "- 1" is going to roll over from first MSR of bank 32 to the last MSR of the last bank.Quoted 3 lines
Another way of writing it would be:
case
MSR_IA32_MC0_CTL...MSR_IA32_MCx_MISC(KVM_MAX_MCE_BANKS - 1):
Quoted 8 lines
Huh?
This is what I did:
+ case
MSR_IA32_MC0_CTL...MSR_IA32_MCx_MISC(KVM_MAX_MCE_BANKS)- 1:It needs to be MISC because it is the last MSR in the MCA bank and thus the highest.
The last MSR is the original "MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS) - 1".
"MSR_IA32_MCx_MISC(KVM_MAX_MCE_BANKS) - 1" also covers
MSR_IA32_MC32_CTL, MSR_IA32_MC32_STATUS, and MSR_IA32_MC32_ADDR
but the maximal valid MSR is MSR_IA32_MC31_MISC.
Borislav Petkov
maintainerRe: [PATCH 3/3] x86/kvm: Handle all MCA banks
Quoted 7 lines · Radim Krčmář
The last MSR is the original "
MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS)- 1"."
MSR_IA32_MCx_MISC(KVM_MAX_MCE_BANKS)- 1" also covers
MSR_IA32_MC32_CTL,MSR_IA32_MC32_STATUS, andMSR_IA32_MC32_ADDRbut the maximal valid MSR is
MSR_IA32_MC31_MISC.
Bah, right you are, MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS) - 1 *is* the last MSR of bank 31, yes.
Pls ignore this patch.
Signature · 4 lines
Regards/Gruss,
Boris.
Good mailing practices for 400: avoid top-posting and trim the reply.