public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
From: David Daney <ddaney.cavm@gmail.com>
To: James Hogan <james.hogan@imgtec.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>,
	Gleb Natapov <gleb@kernel.org>,
	kvm@vger.kernel.org, Ralf Baechle <ralf@linux-mips.org>,
	linux-mips@linux-mips.org, Sanjay Lal <sanjayl@kymasys.com>
Subject: Re: [PATCH 09/21] MIPS: KVM: Fix timer race modifying guest CP0_Cause
Date: Fri, 25 Apr 2014 09:55:47 -0700	[thread overview]
Message-ID: <535A9393.9010907@gmail.com> (raw)
In-Reply-To: <1398439204-26171-10-git-send-email-james.hogan@imgtec.com>

On 04/25/2014 08:19 AM, James Hogan wrote:
> The hrtimer callback for guest timer timeouts sets the guest's
> CP0_Cause.TI bit to indicate to the guest that a timer interrupt is
> pending, however there is no mutual exclusion implemented to prevent
> this occurring while the guest's CP0_Cause register is being
> read-modify-written elsewhere.
>
> When this occurs the setting of the CP0_Cause.TI bit is undone and the
> guest misses the timer interrupt and doesn't reprogram the CP0_Compare
> register for the next timeout. Currently another timer interrupt will be
> triggered again in another 10ms anyway due to the way timers are
> emulated, but after the MIPS timer emulation is fixed this would result
> in Linux guest time standing still and the guest scheduler not being
> invoked until the guest CP0_Count has looped around again, which at
> 100MHz takes just under 43 seconds.
>
> Currently this is the only asynchronous modification of guest registers,
> therefore it is fixed by adjusting the implementations of the
> kvm_set_c0_guest_cause(), kvm_clear_c0_guest_cause(), and
> kvm_change_c0_guest_cause() macros which are used for modifying the
> guest CP0_Cause register to use ll/sc to ensure atomic modification.
> This should work in both UP and SMP cases without requiring interrupts
> to be disabled.
>
> Signed-off-by: James Hogan <james.hogan@imgtec.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Gleb Natapov <gleb@kernel.org>
> Cc: kvm@vger.kernel.org
> Cc: Ralf Baechle <ralf@linux-mips.org>
> Cc: linux-mips@linux-mips.org
> Cc: Sanjay Lal <sanjayl@kymasys.com>

NACK, I don't like the names of these functions.  They initially 
confused me too much...

> ---
>   arch/mips/include/asm/kvm_host.h | 71 ++++++++++++++++++++++++++++++++++++----
>   1 file changed, 65 insertions(+), 6 deletions(-)
>
> diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h
> index 3eedcb3015e5..90e1c0005ff4 100644
> --- a/arch/mips/include/asm/kvm_host.h
> +++ b/arch/mips/include/asm/kvm_host.h
> @@ -481,15 +481,74 @@ struct kvm_vcpu_arch {
>   #define kvm_read_c0_guest_errorepc(cop0)	(cop0->reg[MIPS_CP0_ERROR_PC][0])
>   #define kvm_write_c0_guest_errorepc(cop0, val)	(cop0->reg[MIPS_CP0_ERROR_PC][0] = (val))
>
> +/*
> + * Some of the guest registers may be modified asynchronously (e.g. from a
> + * hrtimer callback in hard irq context) and therefore need stronger atomicity
> + * guarantees than other registers.
> + */
> +
> +static inline void _kvm_atomic_set_c0_guest_reg(unsigned long *reg,
> +						unsigned long val)

The name of this function is too unclear.

It should be _kvm_atomic_or_c0_guest_reg, or 
_kvm_atomic_setbits_c0_guest_reg(unsigned long *reg, unsigned long mask)

> +{
> +	unsigned long temp;
> +	do {
> +		__asm__ __volatile__(
> +		"	.set	mips3				\n"
> +		"	" __LL "%0, %1				\n"
> +		"	or	%0, %2				\n"
> +		"	" __SC	"%0, %1				\n"
> +		"	.set	mips0				\n"
> +		: "=&r" (temp), "+m" (*reg)
> +		: "r" (val));
> +	} while (unlikely(!temp));
> +}
> +
> +static inline void _kvm_atomic_clear_c0_guest_reg(unsigned long *reg,
> +						  unsigned long val)

Same here.

Perhaps _kvm_atomic_clearbits_c0_guest_reg(unsigned long *reg, unsigned 
long mask)

> +{
> +	unsigned long temp;
> +	do {
> +		__asm__ __volatile__(
> +		"	.set	mips3				\n"
> +		"	" __LL "%0, %1				\n"
> +		"	and	%0, %2				\n"
> +		"	" __SC	"%0, %1				\n"
> +		"	.set	mips0				\n"
> +		: "=&r" (temp), "+m" (*reg)
> +		: "r" (~val));
> +	} while (unlikely(!temp));
> +}
> +
> +static inline void _kvm_atomic_change_c0_guest_reg(unsigned long *reg,
> +						   unsigned long change,
> +						   unsigned long val)

Same here.

Perhaps

_kvm_atomic_setbits_c0_guest_reg(unsigned long *reg,
				unsigned long mask,
				unsigned long bits)

> +{
> +	unsigned long temp;
> +	do {
> +		__asm__ __volatile__(
> +		"	.set	mips3				\n"
> +		"	" __LL "%0, %1				\n"
> +		"	and	%0, %2				\n"
> +		"	or	%0, %3				\n"
> +		"	" __SC	"%0, %1				\n"
> +		"	.set	mips0				\n"
> +		: "=&r" (temp), "+m" (*reg)
> +		: "r" (~change), "r" (val & change));
> +	} while (unlikely(!temp));
> +}
> +
>   #define kvm_set_c0_guest_status(cop0, val)	(cop0->reg[MIPS_CP0_STATUS][0] |= (val))
>   #define kvm_clear_c0_guest_status(cop0, val)	(cop0->reg[MIPS_CP0_STATUS][0] &= ~(val))
> -#define kvm_set_c0_guest_cause(cop0, val)	(cop0->reg[MIPS_CP0_CAUSE][0] |= (val))
> -#define kvm_clear_c0_guest_cause(cop0, val)	(cop0->reg[MIPS_CP0_CAUSE][0] &= ~(val))
> +
> +/* Cause can be modified asynchronously from hardirq hrtimer callback */
> +#define kvm_set_c0_guest_cause(cop0, val)				\
> +	_kvm_atomic_set_c0_guest_reg(&cop0->reg[MIPS_CP0_CAUSE][0], val)
> +#define kvm_clear_c0_guest_cause(cop0, val)				\
> +	_kvm_atomic_clear_c0_guest_reg(&cop0->reg[MIPS_CP0_CAUSE][0], val)
>   #define kvm_change_c0_guest_cause(cop0, change, val)			\
> -{									\
> -	kvm_clear_c0_guest_cause(cop0, change);				\
> -	kvm_set_c0_guest_cause(cop0, ((val) & (change)));		\
> -}
> +	_kvm_atomic_change_c0_guest_reg(&cop0->reg[MIPS_CP0_CAUSE][0],	\
> +					change, val)
> +
>   #define kvm_set_c0_guest_ebase(cop0, val)	(cop0->reg[MIPS_CP0_PRID][1] |= (val))
>   #define kvm_clear_c0_guest_ebase(cop0, val)	(cop0->reg[MIPS_CP0_PRID][1] &= ~(val))
>   #define kvm_change_c0_guest_ebase(cop0, change, val)			\
>


  reply	other threads:[~2014-04-25 16:55 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-04-25 15:19 [PATCH 00/21] MIPS: KVM: Fixes and guest timer rewrite James Hogan
2014-04-25 15:19 ` [PATCH 01/21] MIPS: KVM: Allocate at least 16KB for exception handlers James Hogan
2014-04-25 15:19 ` [PATCH 02/21] MIPS: KVM: Use local_flush_icache_range to fix RI on XBurst James Hogan
2014-04-25 15:19 ` [PATCH 03/21] MIPS: KVM: Use tlb_write_random James Hogan
2014-04-25 15:19 ` [PATCH 04/21] MIPS: KVM: Fix CP0_EBASE KVM register id James Hogan
2014-04-25 16:36   ` David Daney
2014-04-25 19:22     ` James Hogan
2014-04-25 15:19 ` [PATCH 05/21] MIPS: KVM: Add CP0_EPC KVM register access James Hogan
2014-04-25 16:44   ` David Daney
2014-04-25 20:29     ` James Hogan
2014-04-25 21:45       ` David Daney
2014-04-25 15:19 ` [PATCH 06/21] MIPS: KVM: Move KVM_{GET,SET}_ONE_REG definitions into kvm_host.h James Hogan
2014-04-25 15:19 ` [PATCH 07/21] MIPS: KVM: Add CP0_Count/Compare KVM register access James Hogan
2014-04-25 15:19 ` [PATCH 08/21] MIPS: KVM: Deliver guest interrupts after local_irq_disable() James Hogan
2014-04-25 15:19 ` [PATCH 09/21] MIPS: KVM: Fix timer race modifying guest CP0_Cause James Hogan
2014-04-25 16:55   ` David Daney [this message]
2014-04-25 20:42     ` James Hogan
2014-04-25 15:19 ` [PATCH 10/21] MIPS: KVM: Migrate hrtimer to follow VCPU James Hogan
2014-04-25 15:19 ` [PATCH 11/21] MIPS: KVM: Rewrite count/compare timer emulation James Hogan
2014-04-25 17:00   ` David Daney
2014-04-25 21:05     ` James Hogan
2014-04-25 15:19 ` [PATCH 12/21] MIPS: KVM: Override guest kernel timer frequency directly James Hogan
2014-04-25 15:19 ` [PATCH 13/21] MIPS: KVM: Add master disable count interface James Hogan
2014-04-25 15:19 ` [PATCH 14/21] MIPS: KVM: Add nanosecond count bias KVM register James Hogan
2014-04-25 17:27   ` David Daney
2014-04-25 22:34     ` James Hogan
2014-04-26  9:37       ` Paolo Bonzini
2014-05-28 14:21         ` James Hogan
2014-05-28 16:24           ` Paolo Bonzini
2014-04-28 12:01   ` Paolo Bonzini
2014-04-28 15:17     ` James Hogan
2014-04-28 15:42       ` Paolo Bonzini
2014-04-25 15:19 ` [PATCH 15/21] MIPS: KVM: Add count frequency " James Hogan
2014-04-25 15:19 ` [PATCH 16/21] MIPS: KVM: Make kvm_mips_comparecount_{func,wakeup} static James Hogan
2014-04-25 15:20 ` [PATCH 17/21] MIPS: KVM: Whitespace fixes in kvm_mips_callbacks James Hogan
2014-04-25 15:20 ` [PATCH 18/21] MIPS: KVM: Fix kvm_debug bit-rottage James Hogan
2014-04-25 15:20 ` [PATCH 19/21] MIPS: KVM: Remove ifdef DEBUG around kvm_debug James Hogan
2014-04-25 15:20 ` [PATCH 20/21] MIPS: KVM: Quieten kvm_info() logging James Hogan
2014-04-25 15:20 ` [PATCH 21/21] MIPS: KVM: Remove redundant NULL checks before kfree() James Hogan
2014-04-28 12:02 ` [PATCH 00/21] MIPS: KVM: Fixes and guest timer rewrite Paolo Bonzini

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=535A9393.9010907@gmail.com \
    --to=ddaney.cavm@gmail.com \
    --cc=gleb@kernel.org \
    --cc=james.hogan@imgtec.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-mips@linux-mips.org \
    --cc=pbonzini@redhat.com \
    --cc=ralf@linux-mips.org \
    --cc=sanjayl@kymasys.com \
    /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