All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrew Jones <drjones@redhat.com>
To: Marc Zyngier <marc.zyngier@arm.com>
Cc: Christoffer Dall <christoffer.dall@linaro.org>,
	Shannon Zhao <shannon.zhao@linaro.org>,
	Peter Maydell <peter.maydell@linaro.org>,
	linux-arm-kernel@lists.infradead.org, kvm@vger.kernel.org,
	kvmarm@lists.cs.columbia.edu
Subject: Re: [PATCH] arm64: KVM: Fix AArch64 guest userspace exception injection
Date: Tue, 12 Jan 2016 19:23:59 +0100	[thread overview]
Message-ID: <20160112182359.GA5795@hawk.localdomain> (raw)
In-Reply-To: <1452157416-9435-1-git-send-email-marc.zyngier@arm.com>

On Thu, Jan 07, 2016 at 09:03:36AM +0000, Marc Zyngier wrote:
> At the moment, our fault injection is pretty limited. We always
> generate a SYNC exception into EL1, as if the fault was actually
> from EL1h, no matter how it was generated.
> 
> This is obviously wrong, as EL0 can generate faults of its own
> (not to mention the pretty-much unused EL1t mode).
> 
> This patch fixes it by implementing section D1.10.2 of the ARMv8 ARM,
> and in particular table D1-7 ("Vector offsets from vector table base
> address"), which describes which vector to use depending on the source
> exception level and type (synchronous, IRQ, FIQ or SError).
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  arch/arm64/kvm/inject_fault.c | 38 +++++++++++++++++++++++++++++++++++---
>  1 file changed, 35 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
> index 648112e..4d1ac81 100644
> --- a/arch/arm64/kvm/inject_fault.c
> +++ b/arch/arm64/kvm/inject_fault.c
> @@ -27,7 +27,11 @@
>  
>  #define PSTATE_FAULT_BITS_64 	(PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | \
>  				 PSR_I_BIT | PSR_D_BIT)
> -#define EL1_EXCEPT_SYNC_OFFSET	0x200
> +
> +#define CURRENT_EL_SP_EL0_VECTOR	0x0
> +#define CURRENT_EL_SP_ELx_VECTOR	0x200
> +#define LOWER_EL_AArch64_VECTOR		0x400
> +#define LOWER_EL_AArch32_VECTOR		0x600
>  
>  static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
>  {
> @@ -97,6 +101,34 @@ static void inject_abt32(struct kvm_vcpu *vcpu, bool is_pabt,
>  		*fsr = 0x14;
>  }
>  
> +enum exception_type {
> +	except_type_sync	= 0,
> +	except_type_irq		= 0x80,
> +	except_type_fiq		= 0x100,
> +	except_type_serror	= 0x180,
> +};
> +
> +static u64 get_except_vector(struct kvm_vcpu *vcpu, enum exception_type type)
> +{
> +	u64 exc_offset;
> +
> +	switch (*vcpu_cpsr(vcpu) & (PSR_MODE_MASK | PSR_MODE32_BIT)) {
> +	case PSR_MODE_EL1t:
> +		exc_offset = CURRENT_EL_SP_EL0_VECTOR;
> +		break;
> +	case PSR_MODE_EL1h:
> +		exc_offset = CURRENT_EL_SP_ELx_VECTOR;
> +		break;
> +	case PSR_MODE_EL0t:
> +		exc_offset = LOWER_EL_AArch64_VECTOR;
> +		break;
> +	default:
> +		exc_offset = LOWER_EL_AArch32_VECTOR;
> +	}
> +
> +	return vcpu_sys_reg(vcpu, VBAR_EL1) + exc_offset + type;
> +}
> +
>  static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
>  {
>  	unsigned long cpsr = *vcpu_cpsr(vcpu);
> @@ -108,8 +140,8 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
>  	*vcpu_spsr(vcpu) = cpsr;
>  	*vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
>  
> +	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
>  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
> -	*vcpu_pc(vcpu) = vcpu_sys_reg(vcpu, VBAR_EL1) + EL1_EXCEPT_SYNC_OFFSET;
>  
>  	vcpu_sys_reg(vcpu, FAR_EL1) = addr;
>  
> @@ -143,8 +175,8 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
>  	*vcpu_spsr(vcpu) = cpsr;
>  	*vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
>  
> +	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
>  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
> -	*vcpu_pc(vcpu) = vcpu_sys_reg(vcpu, VBAR_EL1) + EL1_EXCEPT_SYNC_OFFSET;
>  
>  	/*
>  	 * Build an unknown exception, depending on the instruction

Hi Marc,

Please shoot me if the following statement is false.

Without this patch, if a guest that is running in, e.g. PSR_MODE_EL0t,
tries to do, e.g. 'smc #0', then KVM will inject an undef exception,
which should lead to the guest resuming at VBAR_EL1 + 0x400, but instead
it resumes at VBAR_EL1 + 0x200.

Now, if you haven't started loading your gun to shoot me yet, then I'm
quite confused as to why the unit test[1] I wrote for this works just
fine without this patch.

(If you're suspicious of the vector table in kvm-unit-tests, take a
 look at the bottom of [2] to see it.)

Thanks,
drew

[1] https://github.com/rhdrjones/kvm-unit-tests/blob/arm64/test-exinj/arm/test-exinj.c
[2] https://github.com/rhdrjones/kvm-unit-tests/blob/arm64/test-exinj/arm/cstart64.S

WARNING: multiple messages have this Message-ID (diff)
From: drjones@redhat.com (Andrew Jones)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH] arm64: KVM: Fix AArch64 guest userspace exception injection
Date: Tue, 12 Jan 2016 19:23:59 +0100	[thread overview]
Message-ID: <20160112182359.GA5795@hawk.localdomain> (raw)
In-Reply-To: <1452157416-9435-1-git-send-email-marc.zyngier@arm.com>

On Thu, Jan 07, 2016 at 09:03:36AM +0000, Marc Zyngier wrote:
> At the moment, our fault injection is pretty limited. We always
> generate a SYNC exception into EL1, as if the fault was actually
> from EL1h, no matter how it was generated.
> 
> This is obviously wrong, as EL0 can generate faults of its own
> (not to mention the pretty-much unused EL1t mode).
> 
> This patch fixes it by implementing section D1.10.2 of the ARMv8 ARM,
> and in particular table D1-7 ("Vector offsets from vector table base
> address"), which describes which vector to use depending on the source
> exception level and type (synchronous, IRQ, FIQ or SError).
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  arch/arm64/kvm/inject_fault.c | 38 +++++++++++++++++++++++++++++++++++---
>  1 file changed, 35 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
> index 648112e..4d1ac81 100644
> --- a/arch/arm64/kvm/inject_fault.c
> +++ b/arch/arm64/kvm/inject_fault.c
> @@ -27,7 +27,11 @@
>  
>  #define PSTATE_FAULT_BITS_64 	(PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | \
>  				 PSR_I_BIT | PSR_D_BIT)
> -#define EL1_EXCEPT_SYNC_OFFSET	0x200
> +
> +#define CURRENT_EL_SP_EL0_VECTOR	0x0
> +#define CURRENT_EL_SP_ELx_VECTOR	0x200
> +#define LOWER_EL_AArch64_VECTOR		0x400
> +#define LOWER_EL_AArch32_VECTOR		0x600
>  
>  static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
>  {
> @@ -97,6 +101,34 @@ static void inject_abt32(struct kvm_vcpu *vcpu, bool is_pabt,
>  		*fsr = 0x14;
>  }
>  
> +enum exception_type {
> +	except_type_sync	= 0,
> +	except_type_irq		= 0x80,
> +	except_type_fiq		= 0x100,
> +	except_type_serror	= 0x180,
> +};
> +
> +static u64 get_except_vector(struct kvm_vcpu *vcpu, enum exception_type type)
> +{
> +	u64 exc_offset;
> +
> +	switch (*vcpu_cpsr(vcpu) & (PSR_MODE_MASK | PSR_MODE32_BIT)) {
> +	case PSR_MODE_EL1t:
> +		exc_offset = CURRENT_EL_SP_EL0_VECTOR;
> +		break;
> +	case PSR_MODE_EL1h:
> +		exc_offset = CURRENT_EL_SP_ELx_VECTOR;
> +		break;
> +	case PSR_MODE_EL0t:
> +		exc_offset = LOWER_EL_AArch64_VECTOR;
> +		break;
> +	default:
> +		exc_offset = LOWER_EL_AArch32_VECTOR;
> +	}
> +
> +	return vcpu_sys_reg(vcpu, VBAR_EL1) + exc_offset + type;
> +}
> +
>  static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
>  {
>  	unsigned long cpsr = *vcpu_cpsr(vcpu);
> @@ -108,8 +140,8 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
>  	*vcpu_spsr(vcpu) = cpsr;
>  	*vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
>  
> +	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
>  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
> -	*vcpu_pc(vcpu) = vcpu_sys_reg(vcpu, VBAR_EL1) + EL1_EXCEPT_SYNC_OFFSET;
>  
>  	vcpu_sys_reg(vcpu, FAR_EL1) = addr;
>  
> @@ -143,8 +175,8 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
>  	*vcpu_spsr(vcpu) = cpsr;
>  	*vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
>  
> +	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
>  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
> -	*vcpu_pc(vcpu) = vcpu_sys_reg(vcpu, VBAR_EL1) + EL1_EXCEPT_SYNC_OFFSET;
>  
>  	/*
>  	 * Build an unknown exception, depending on the instruction

Hi Marc,

Please shoot me if the following statement is false.

Without this patch, if a guest that is running in, e.g. PSR_MODE_EL0t,
tries to do, e.g. 'smc #0', then KVM will inject an undef exception,
which should lead to the guest resuming at VBAR_EL1 + 0x400, but instead
it resumes at VBAR_EL1 + 0x200.

Now, if you haven't started loading your gun to shoot me yet, then I'm
quite confused as to why the unit test[1] I wrote for this works just
fine without this patch.

(If you're suspicious of the vector table in kvm-unit-tests, take a
 look at the bottom of [2] to see it.)

Thanks,
drew

[1] https://github.com/rhdrjones/kvm-unit-tests/blob/arm64/test-exinj/arm/test-exinj.c
[2] https://github.com/rhdrjones/kvm-unit-tests/blob/arm64/test-exinj/arm/cstart64.S

  parent reply	other threads:[~2016-01-12 18:24 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-01-07  9:03 [PATCH] arm64: KVM: Fix AArch64 guest userspace exception injection Marc Zyngier
2016-01-07  9:03 ` Marc Zyngier
2016-01-08  8:36 ` Shannon Zhao
2016-01-08  8:36   ` Shannon Zhao
2016-01-08  8:36   ` Shannon Zhao
2016-01-08  8:56   ` Marc Zyngier
2016-01-08  8:56     ` Marc Zyngier
2016-01-11  1:36     ` Shannon Zhao
2016-01-11  1:36       ` Shannon Zhao
2016-01-11  1:36       ` Shannon Zhao
2016-01-10 19:45 ` Christoffer Dall
2016-01-10 19:45   ` Christoffer Dall
2016-01-11 10:06   ` Marc Zyngier
2016-01-11 10:06     ` Marc Zyngier
2016-01-12 18:23 ` Andrew Jones [this message]
2016-01-12 18:23   ` Andrew Jones
2016-01-12 18:44   ` Marc Zyngier
2016-01-12 18:44     ` Marc Zyngier
2016-01-12 19:13     ` Andrew Jones
2016-01-12 19:13       ` Andrew Jones

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20160112182359.GA5795@hawk.localdomain \
    --to=drjones@redhat.com \
    --cc=christoffer.dall@linaro.org \
    --cc=kvm@vger.kernel.org \
    --cc=kvmarm@lists.cs.columbia.edu \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=marc.zyngier@arm.com \
    --cc=peter.maydell@linaro.org \
    --cc=shannon.zhao@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.