linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: cdall@kernel.org (Christoffer Dall)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 25/37] KVM: arm64: Prepare to handle traps on remaining deferred EL1 sysregs
Date: Sun, 3 Dec 2017 21:29:37 +0100	[thread overview]
Message-ID: <20171203202937.GA32397@cbox> (raw)
In-Reply-To: <20171113185614.6d6xwpyxcnqjfs7w@hawk.localdomain>

On Mon, Nov 13, 2017 at 07:56:14PM +0100, Andrew Jones wrote:
> On Thu, Oct 12, 2017 at 12:41:29PM +0200, Christoffer Dall wrote:
> > Handle accesses during traps to any remaining EL1 registers which can be
> > deferred to vcpu_load and vcpu_put, by either accessing them directly on
> > the physical CPU when the latest version is stored there, or by
> > synchronizing the memory representation with the CPU state.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> >  arch/arm64/include/asm/kvm_emulate.h | 14 -------
> >  arch/arm64/kvm/inject_fault.c        | 79 ++++++++++++++++++++++++++++++++----
> >  arch/arm64/kvm/sys_regs.c            |  6 ++-
> >  3 files changed, 76 insertions(+), 23 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> > index 630dd60..69bb40d 100644
> > --- a/arch/arm64/include/asm/kvm_emulate.h
> > +++ b/arch/arm64/include/asm/kvm_emulate.h
> > @@ -66,11 +66,6 @@ static inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu)
> >  	return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pc;
> >  }
> >  
> > -static inline unsigned long *vcpu_elr_el1(const struct kvm_vcpu *vcpu)
> > -{
> > -	return (unsigned long *)&vcpu_gp_regs(vcpu)->elr_el1;
> > -}
> > -
> >  static inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu)
> >  {
> >  	return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pstate;
> > @@ -120,15 +115,6 @@ static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
> >  		vcpu_gp_regs(vcpu)->regs.regs[reg_num] = val;
> >  }
> >  
> > -/* Get vcpu SPSR for current mode */
> > -static inline unsigned long *vcpu_spsr(const struct kvm_vcpu *vcpu)
> > -{
> > -	if (vcpu_mode_is_32bit(vcpu))
> > -		return vcpu_spsr32(vcpu);
> > -
> > -	return (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
> > -}
> > -
> >  static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
> >  {
> >  	u32 mode;
> > diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
> > index 45c7026..f4513fc 100644
> > --- a/arch/arm64/kvm/inject_fault.c
> > +++ b/arch/arm64/kvm/inject_fault.c
> > @@ -23,6 +23,7 @@
> >  
> >  #include <linux/kvm_host.h>
> >  #include <asm/kvm_emulate.h>
> > +#include <asm/kvm_hyp.h>
> >  #include <asm/esr.h>
> >  
> >  #define PSTATE_FAULT_BITS_64 	(PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | \
> > @@ -33,13 +34,55 @@
> >  #define LOWER_EL_AArch64_VECTOR		0x400
> >  #define LOWER_EL_AArch32_VECTOR		0x600
> >  
> > +static u64 vcpu_get_vbar_el1(struct kvm_vcpu *vcpu)
> > +{
> > +	unsigned long vbar;
> > +
> > +	if (vcpu->arch.sysregs_loaded_on_cpu)
> > +		vbar = read_sysreg_el1(vbar);
> > +	else
> > +		vbar = vcpu_sys_reg(vcpu, VBAR_EL1);
> > +
> > +	if (vcpu_el1_is_32bit(vcpu))
> > +		return lower_32_bits(vbar);
> > +	return vbar;
> > +}
> > +
> > +static void vcpu_set_elr_el1(struct kvm_vcpu *vcpu, u64 val)
> > +{
> > +	if (vcpu->arch.sysregs_loaded_on_cpu)
> > +		write_sysreg_el1(val, elr);
> > +	else
> > +		vcpu_gp_regs(vcpu)->elr_el1 = val;
> > +}
> > +
> > +/* Set the SPSR for the current mode */
> > +static void vcpu_set_spsr(struct kvm_vcpu *vcpu, u64 val)
> > +{
> > +	if (vcpu_mode_is_32bit(vcpu))
> > +		*vcpu_spsr32(vcpu) = val;
> > +
> > +	if (vcpu->arch.sysregs_loaded_on_cpu)
> > +		write_sysreg_el1(val, spsr);
> > +	else
> > +		vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1] = val;
> > +}
> > +
> > +static u32 vcpu_get_c1_sctlr(struct kvm_vcpu *vcpu)
> > +{
> > +	if (vcpu->arch.sysregs_loaded_on_cpu)
> > +		return lower_32_bits(read_sysreg_el1(sctlr));
> > +	else
> > +		return vcpu_cp15(vcpu, c1_SCTLR);
> > +}
> > +
> >  static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
> >  {
> >  	unsigned long cpsr;
> >  	unsigned long new_spsr_value = *vcpu_cpsr(vcpu);
> >  	bool is_thumb = (new_spsr_value & COMPAT_PSR_T_BIT);
> >  	u32 return_offset = (is_thumb) ? 4 : 0;
> > -	u32 sctlr = vcpu_cp15(vcpu, c1_SCTLR);
> > +	u32 sctlr = vcpu_get_c1_sctlr(vcpu);
> >  
> >  	cpsr = mode | COMPAT_PSR_I_BIT;
> >  
> > @@ -51,14 +94,14 @@ static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
> >  	*vcpu_cpsr(vcpu) = cpsr;
> >  
> >  	/* Note: These now point to the banked copies */
> > -	*vcpu_spsr(vcpu) = new_spsr_value;
> > +	vcpu_set_spsr(vcpu, new_spsr_value);
> >  	*vcpu_reg32(vcpu, 14) = *vcpu_pc(vcpu) + return_offset;
> >  
> >  	/* Branch to exception vector */
> >  	if (sctlr & (1 << 13))
> >  		vect_offset += 0xffff0000;
> >  	else /* always have security exceptions */
> > -		vect_offset += vcpu_cp15(vcpu, c12_VBAR);
> > +		vect_offset += vcpu_get_vbar_el1(vcpu);
> >  
> >  	*vcpu_pc(vcpu) = vect_offset;
> >  }
> > @@ -79,6 +122,20 @@ static void inject_abt32(struct kvm_vcpu *vcpu, bool is_pabt,
> >  	u32 *far, *fsr;
> >  	bool is_lpae;
> >  
> > +	/*
> > +	 * We are going to need the latest values of the following system
> > +	 * regiters:
> 
> registers
> 
> > +	 *   DFAR:  mapped to FAR_EL1
> 
> FAR_EL1[31:0]
> 
> > +	 *   IFAR:  mapped to FAR_EL1
> 
> FAR_EL1[63:32]
> 

I had to rework this after the 32-bit fault injection code has been
reworked, so I got rid of this comment (as it's now being shared with
the 32-bit side, and I use a bigger hammer to solve the problem).

> > +	 *   DFSR:  mapped to ESR_EL1
> > +	 *   TTBCR: mapped to TCR_EL1
> > +	 */
> > +	if (vcpu->arch.sysregs_loaded_on_cpu) {
> > +		vcpu->arch.ctxt.sys_regs[FAR_EL1] = read_sysreg_el1(far);
> > +		vcpu->arch.ctxt.sys_regs[ESR_EL1] = read_sysreg_el1(esr);
> > +		vcpu->arch.ctxt.sys_regs[TCR_EL1] = read_sysreg_el1(tcr);
> > +	}
> > +
> >  	if (is_pabt) {
> >  		vect_offset = 12;
> >  		far = &vcpu_cp15(vcpu, c6_IFAR);
> > @@ -99,6 +156,12 @@ static void inject_abt32(struct kvm_vcpu *vcpu, bool is_pabt,
> >  		*fsr = 1 << 9 | 0x34;
> >  	else
> >  		*fsr = 0x14;
> > +
> > +	/* Sync back any registers we may have changed */
> > +	if (vcpu->arch.sysregs_loaded_on_cpu) {
> > +		write_sysreg_el1(vcpu->arch.ctxt.sys_regs[FAR_EL1], far);
> > +		write_sysreg_el1(vcpu->arch.ctxt.sys_regs[ESR_EL1], esr);
> > +	}
> >  }
> >  
> >  enum exception_type {
> > @@ -126,7 +189,7 @@ static u64 get_except_vector(struct kvm_vcpu *vcpu, enum exception_type type)
> >  		exc_offset = LOWER_EL_AArch32_VECTOR;
> >  	}
> >  
> > -	return vcpu_sys_reg(vcpu, VBAR_EL1) + exc_offset + type;
> > +	return vcpu_get_vbar_el1(vcpu) + exc_offset + type;
> >  }
> >  
> >  static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
> > @@ -135,11 +198,11 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
> >  	bool is_aarch32 = vcpu_mode_is_32bit(vcpu);
> >  	u32 esr = 0;
> >  
> > -	*vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
> > +	vcpu_set_elr_el1(vcpu, *vcpu_pc(vcpu));
> >  	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
> >  
> >  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
> > -	*vcpu_spsr(vcpu) = cpsr;
> > +	vcpu_set_spsr(vcpu, cpsr);
> >  
> >  	vcpu_sys_reg(vcpu, FAR_EL1) = addr;
> >  
> > @@ -170,11 +233,11 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
> >  	unsigned long cpsr = *vcpu_cpsr(vcpu);
> >  	u32 esr = (ESR_ELx_EC_UNKNOWN << ESR_ELx_EC_SHIFT);
> >  
> > -	*vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
> > +	vcpu_set_elr_el1(vcpu, *vcpu_pc(vcpu));
> >  	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
> >  
> >  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
> > -	*vcpu_spsr(vcpu) = cpsr;
> > +	vcpu_set_spsr(vcpu, cpsr);
> >  
> 
> I'm concerned the maintenance of emulation code will become more
> difficult now that some registers have special accessors, while
> others don't, and some functions have save/restore lists, that
> will need to stay maintained with the emulation. The only alternative
> that pops to mind, though, is adding get/set members to the register
> descriptors and encapsulating the decision in them, but that might be
> overkill.
> 

I was concerned initially as well, and had rewritten the entire code to
use get/set accessors everywhere, and that was not a pretty set of
patches to review, and in fact seemed less intuitive and easy to
maintain.

This is an interesting discussion; my original standpoint was very
similar to yours and I had similar concernes, but this rework has left
me feeling that maintaining this code base requires an intimate
understanding of the flow and state the CPU/VM can be in at any one
point, and it's therefore actually easier to maintain something that
does the required things in the right places, as opposed to creating
larger abstractions, at least to some degree.

I'm curious what Marc thinks here, and I'm willing to produce an
alternative patch with everything abstracted as get/set functions, with
giant switch statements to access hardware registers (which will only
actually hit in a few of the cases), but I think I know what the final
answer will be already.

> >  	/*
> >  	 * Build an unknown exception, depending on the instruction
> > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> > index f7887dd..60d1660 100644
> > --- a/arch/arm64/kvm/sys_regs.c
> > +++ b/arch/arm64/kvm/sys_regs.c
> > @@ -86,12 +86,16 @@ static u32 cache_levels;
> >  static u32 get_ccsidr(u32 csselr)
> >  {
> >  	u32 ccsidr;
> > +	u32 csselr_preserve;
> >  
> > -	/* Make sure noone else changes CSSELR during this! */
> > +	/* Make sure noone else changes CSSELR during this and preserve any
> > +	 * existing value in the CSSELR! */
> >  	local_irq_disable();
> > +	csselr_preserve = read_sysreg(csselr_el1);
> >  	write_sysreg(csselr, csselr_el1);
> >  	isb();
> >  	ccsidr = read_sysreg(ccsidr_el1);
> > +	write_sysreg(csselr_preserve, csselr_el1);
> >  	local_irq_enable();
> >  
> >  	return ccsidr;
> 
> This looks like an unrelated fix.
> 

Not really.  The point is that the host kernel doesn't make any
assumptions about the csselr and will set it to select the value it
wants to read when using this feature.

Until we start deferring el1 registers for the guest, we can therefore
do the same, as the guest will always get its values restore.

However, when we introduce lazy save/restore of guest state, we cannot
just step on the guest state, but we have to preserve the guest state.

We could make it conditional on the sysregs loaded flag, but that
doesn't get us much, and we might as well do this.

Thanks,
-Christoffer

  reply	other threads:[~2017-12-03 20:29 UTC|newest]

Thread overview: 127+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-10-12 10:41 [PATCH 00/37] Optimize KVM/ARM for VHE systems Christoffer Dall
2017-10-12 10:41 ` [PATCH 01/37] KVM: arm64: Avoid storing the vcpu pointer on the stack Christoffer Dall
2017-10-12 15:49   ` Marc Zyngier
2017-10-12 17:02     ` Christoffer Dall
2017-10-13 11:31       ` Marc Zyngier
2017-11-23 20:59     ` Christoffer Dall
2017-11-27 11:11       ` James Morse
2017-11-29 18:20         ` Christoffer Dall
2017-11-06 17:22   ` Andrew Jones
2017-11-07  8:24     ` Christoffer Dall
2017-10-12 10:41 ` [PATCH 02/37] KVM: arm64: Rework hyp_panic for VHE and non-VHE Christoffer Dall
2017-10-12 15:55   ` Marc Zyngier
2017-10-12 17:06     ` Christoffer Dall
2017-10-12 10:41 ` [PATCH 03/37] KVM: arm64: Move HCR_INT_OVERRIDE to default HCR_EL2 guest flag Christoffer Dall
2017-10-12 16:20   ` Marc Zyngier
2017-10-12 10:41 ` [PATCH 04/37] KVM: arm/arm64: Get rid of vcpu->arch.irq_lines Christoffer Dall
2017-10-12 16:24   ` Marc Zyngier
2017-11-06 17:58   ` Andrew Jones
2017-11-14 12:17   ` Julien Thierry
2017-11-16 16:11     ` Julien Thierry
2017-11-26 16:04     ` Christoffer Dall
2017-10-12 10:41 ` [PATCH 05/37] KVM: Record the executing ioctl number on the vcpu struct Christoffer Dall
2017-10-13 17:13   ` Radim Krčmář
2017-10-13 17:31     ` Christoffer Dall
2017-10-13 18:38       ` Radim Krčmář
2017-10-13 18:51         ` Christoffer Dall
2017-11-07 10:45   ` Andrew Jones
2017-11-22 20:28     ` Christoffer Dall
2017-10-12 10:41 ` [PATCH 06/37] KVM: arm/arm64: Only load/put VCPU state for KVM_RUN Christoffer Dall
2017-10-12 10:41 ` [PATCH 07/37] KVM: arm/arm64: Add kvm_vcpu_load_sysregs and kvm_vcpu_put_sysregs Christoffer Dall
2017-11-07 10:56   ` Andrew Jones
2017-11-07 11:10   ` Andrew Jones
2017-11-22 20:34     ` Christoffer Dall
2017-11-23 11:08       ` Andrew Jones
2017-10-12 10:41 ` [PATCH 08/37] KVM: arm64: Defer restoring host VFP state to vcpu_put Christoffer Dall
2017-11-07 13:15   ` Andrew Jones
2017-11-26 16:24     ` Christoffer Dall
2017-11-15 16:04   ` Andrew Jones
2017-11-26 16:17     ` Christoffer Dall
2017-11-27  8:32       ` Andrew Jones
2017-11-25  7:52   ` Yury Norov
2017-11-26 16:17     ` Christoffer Dall
2017-11-26 18:58       ` Yury Norov
2017-11-26 19:18         ` Christoffer Dall
2017-11-27  6:25           ` Yury Norov
2017-11-30 19:07         ` Marc Zyngier
2017-10-12 10:41 ` [PATCH 09/37] KVM: arm64: Move debug dirty flag calculation out of world switch Christoffer Dall
2017-11-07 14:09   ` Andrew Jones
2017-11-25  8:09     ` Yury Norov
2017-12-01 17:25     ` Christoffer Dall
2017-12-03 13:17       ` Andrew Jones
2017-10-12 10:41 ` [PATCH 10/37] KVM: arm64: Slightly improve debug save/restore functions Christoffer Dall
2017-11-07 14:22   ` Andrew Jones
2017-12-01 17:51     ` Christoffer Dall
2017-11-14 16:42   ` Julien Thierry
2017-12-01 15:19     ` Christoffer Dall
2017-12-06 15:38       ` Julien Thierry
2017-10-12 10:41 ` [PATCH 11/37] KVM: arm64: Improve debug register save/restore flow Christoffer Dall
2017-11-07 14:48   ` Andrew Jones
2017-12-01 17:52     ` Christoffer Dall
2017-12-03 13:49       ` Andrew Jones
2017-12-03 20:47         ` Christoffer Dall
2017-10-12 10:41 ` [PATCH 12/37] KVM: arm64: Factor out fault info population and gic workarounds Christoffer Dall
2017-11-07 15:12   ` Andrew Jones
2017-10-12 10:41 ` [PATCH 13/37] KVM: arm64: Introduce VHE-specific kvm_vcpu_run Christoffer Dall
2017-11-07 15:25   ` Andrew Jones
2017-12-01 18:10     ` Christoffer Dall
2017-10-12 10:41 ` [PATCH 14/37] KVM: arm64: Remove kern_hyp_va() use in VHE switch function Christoffer Dall
2017-11-07 16:07   ` Andrew Jones
2017-10-12 10:41 ` [PATCH 15/37] KVM: arm64: Don't deactivate VM on VHE systems Christoffer Dall
2017-11-07 16:14   ` Andrew Jones
2017-12-03 19:27     ` Christoffer Dall
2017-10-12 10:41 ` [PATCH 16/37] KVM: arm64: Remove noop calls to timer save/restore from VHE switch Christoffer Dall
2017-11-07 16:25   ` Andrew Jones
2017-12-03 19:27     ` Christoffer Dall
2017-10-12 10:41 ` [PATCH 17/37] KVM: arm64: Move userspace system registers into separate function Christoffer Dall
2017-11-08  9:32   ` Andrew Jones
2017-12-03 19:36     ` Christoffer Dall
2017-10-12 10:41 ` [PATCH 18/37] KVM: arm64: Rewrite sysreg alternatives to static keys Christoffer Dall
2017-10-12 10:41 ` [PATCH 19/37] KVM: arm64: Introduce separate VHE/non-VHE sysreg save/restore functions Christoffer Dall
2017-11-08 10:31   ` Andrew Jones
2017-10-12 10:41 ` [PATCH 20/37] KVM: arm64: Unify non-VHE host/guest sysreg save and restore functions Christoffer Dall
2017-11-08 10:39   ` Andrew Jones
2017-12-03 19:41     ` Christoffer Dall
2017-10-12 10:41 ` [PATCH 21/37] KVM: arm64: Don't save the host ELR_EL2 and SPSR_EL2 on VHE systems Christoffer Dall
2017-11-08 17:03   ` Andrew Jones
2017-12-03 19:45     ` Christoffer Dall
2017-10-12 10:41 ` [PATCH 22/37] KVM: arm64: Change 32-bit handling of VM system registers Christoffer Dall
2017-11-13 16:25   ` Andrew Jones
2017-10-12 10:41 ` [PATCH 23/37] KVM: arm64: Prepare to handle traps on deferred VM sysregs Christoffer Dall
2017-11-13 17:54   ` Andrew Jones
2017-12-03 19:50     ` Christoffer Dall
2017-12-04 10:05       ` Andrew Jones
2017-10-12 10:41 ` [PATCH 24/37] KVM: arm64: Prepare to handle traps on deferred EL0 sysregs Christoffer Dall
2017-11-15  9:25   ` Julien Thierry
2017-12-03 19:51     ` Christoffer Dall
2017-10-12 10:41 ` [PATCH 25/37] KVM: arm64: Prepare to handle traps on remaining deferred EL1 sysregs Christoffer Dall
2017-11-13 18:56   ` Andrew Jones
2017-12-03 20:29     ` Christoffer Dall [this message]
2017-10-12 10:41 ` [PATCH 26/37] KVM: arm64: Prepare to handle traps on deferred AArch32 sysregs Christoffer Dall
2017-11-13 19:07   ` Andrew Jones
2017-12-03 20:35     ` Christoffer Dall
2017-10-12 10:41 ` [PATCH 27/37] KVM: arm64: Defer saving/restoring system registers to vcpu load/put on VHE Christoffer Dall
2017-10-12 10:41 ` [PATCH 28/37] KVM: arm64: Move common VHE/non-VHE trap config in separate functions Christoffer Dall
2017-11-25 10:43   ` Yury Norov
2017-11-25 10:49     ` Russell King - ARM Linux
2017-10-12 10:41 ` [PATCH 29/37] KVM: arm64: Configure FPSIMD traps on vcpu load/put for VHE Christoffer Dall
2017-10-12 10:41 ` [PATCH 30/37] KVM: arm64: Configure c15, PMU, and debug register traps on cpu " Christoffer Dall
2017-10-12 10:41 ` [PATCH 31/37] KVM: arm64: Separate activate_traps and deactive_traps for VHE and non-VHE Christoffer Dall
2017-10-12 10:41 ` [PATCH 32/37] KVM: arm/arm64: Handle VGICv2 save/restore from the main VGIC code Christoffer Dall
2017-11-15 17:50   ` Andre Przywara
2017-11-26 10:29     ` Yury Norov
2017-11-26 19:46       ` Christoffer Dall
2017-11-30 12:09         ` Yury Norov
2017-11-26 19:37     ` Christoffer Dall
2017-10-12 10:41 ` [PATCH 33/37] KVM: arm/arm64: Move arm64-only vgic-v2-sr.c file to arm64 Christoffer Dall
2017-11-15 17:52   ` Andre Przywara
2017-10-12 10:41 ` [PATCH 34/37] KVM: arm/arm64: Handle VGICv3 save/restore from the main VGIC code on VHE Christoffer Dall
2017-10-12 10:41 ` [PATCH 35/37] KVM: arm/arm64: Get rid of vgic_elrsr Christoffer Dall
2017-11-26 14:39   ` Yury Norov
2017-11-26 19:53     ` Christoffer Dall
2017-10-12 10:41 ` [PATCH 36/37] KVM: arm/arm64: Move VGIC APR save/restore to vgic put/load Christoffer Dall
2017-11-26 15:09   ` Yury Norov
2017-11-26 19:55     ` Christoffer Dall
2017-10-12 10:41 ` [PATCH 37/37] KVM: arm/arm64: Avoid VGICv3 save/restore on VHE with no IRQs Christoffer Dall
2017-11-30 18:33   ` Yury Norov
2017-12-03 20:38     ` Christoffer Dall

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=20171203202937.GA32397@cbox \
    --to=cdall@kernel.org \
    --cc=linux-arm-kernel@lists.infradead.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).