From: Andrew Cooper <andrew.cooper3@citrix.com>
To: Jan Beulich <JBeulich@suse.com>,
xen-devel <xen-devel@lists.xenproject.org>
Cc: Keir Fraser <keir@xen.org>, Tim Deegan <tim@xen.org>
Subject: Re: [PATCH v4 2/4] x86/HVM: fix ID handling of x2APIC emulation
Date: Mon, 22 Sep 2014 15:30:48 +0100 [thread overview]
Message-ID: <54203298.7090700@citrix.com> (raw)
In-Reply-To: <541B0BEB02000078000363C3@mail.emea.novell.com>
[-- Attachment #1.1: Type: text/plain, Size: 10017 bytes --]
On 18/09/14 15:44, Jan Beulich wrote:
> - properly change ID when switching into x2APIC mode (instead of
> mimicking necessary behavior in hvm_x2apic_msr_read())
> - correctly (meaningfully) set LDR (so far it ended up being 1 on all
> vCPU-s)
> - even if we don't support more than 128 vCPU-s in a HVM guest for now,
> we should properly handle IDs as 32-bit values (i.e. not ignore the
> top 24 bits)
> - with that, properly do cluster ID and bit mask check in
> vlapic_match_logical_addr()
> - slightly adjust other parameter types of vlapic_match_dest() and
> vlapic_lowest_prio() (and related local variable ones)
>
> Signed-off-by: Jan Beulich <jbeulich@suse.com>
> ---
> v4: Replace unpause-based approach with one latching most recently
> loaded values.
> v2: Some changes broken out to separate patch. Correct ID and
> LDR after domain restore (if necessary); as stated previously the
> only compatibility problem this creates is when migrating a VM _to_
> an unfixed (i.e. old) hypervisor, a scenario which supposedly isn't
> supported.
>
> --- a/xen/arch/x86/hvm/vlapic.c
> +++ b/xen/arch/x86/hvm/vlapic.c
> @@ -173,18 +173,17 @@ uint32_t vlapic_set_ppr(struct vlapic *v
> return ppr;
> }
>
> -static int vlapic_match_logical_addr(struct vlapic *vlapic, uint8_t mda)
> +static int vlapic_match_logical_addr(struct vlapic *vlapic, uint32_t mda)
> {
> int result = 0;
> - uint32_t logical_id;
> + uint32_t logical_id = vlapic_get_reg(vlapic, APIC_LDR);
>
> if ( vlapic_x2apic_mode(vlapic) )
> - {
> - logical_id = vlapic_get_reg(vlapic, APIC_LDR);
> - return !!(logical_id & mda);
> - }
> + return ((logical_id >> 16) == (mda >> 16)) &&
> + (uint16_t)(logical_id & mda);
>
> - logical_id = GET_xAPIC_LOGICAL_ID(vlapic_get_reg(vlapic, APIC_LDR));
> + logical_id = GET_xAPIC_LOGICAL_ID(logical_id);
> + mda = (uint8_t)mda;
>
> switch ( vlapic_get_reg(vlapic, APIC_DFR) )
> {
> @@ -207,8 +206,8 @@ static int vlapic_match_logical_addr(str
> }
>
> bool_t vlapic_match_dest(
> - struct vlapic *target, struct vlapic *source,
> - int short_hand, uint8_t dest, uint8_t dest_mode)
> + struct vlapic *target, const struct vlapic *source,
This constification of source could move to patch 3 (if there are
sufficient other changes to warrent a respin of the series). Here and
elsewhere.
> + int short_hand, uint32_t dest, bool_t dest_mode)
> {
> HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "target %p, source %p, dest %#x, "
> "dest_mode %#x, short_hand %#x",
> @@ -219,7 +218,8 @@ bool_t vlapic_match_dest(
> case APIC_DEST_NOSHORT:
> if ( dest_mode )
> return vlapic_match_logical_addr(target, dest);
> - return ((dest == 0xFF) || (dest == VLAPIC_ID(target)));
> + return (dest == _VLAPIC_ID(target, 0xffffffff)) ||
> + (dest == VLAPIC_ID(target));
>
> case APIC_DEST_SELF:
> return (target == source);
> @@ -286,7 +286,7 @@ static void vlapic_init_sipi_action(unsi
> uint32_t icr = vcpu_vlapic(origin)->init_sipi.icr;
> uint32_t dest = vcpu_vlapic(origin)->init_sipi.dest;
> uint32_t short_hand = icr & APIC_SHORT_MASK;
> - uint32_t dest_mode = !!(icr & APIC_DEST_MASK);
> + bool_t dest_mode = !!(icr & APIC_DEST_MASK);
This could also move to patch 3.
> struct vcpu *v;
>
> if ( icr == 0 )
> @@ -352,8 +352,8 @@ static void vlapic_accept_irq(struct vcp
> }
>
> struct vlapic *vlapic_lowest_prio(
> - struct domain *d, struct vlapic *source,
> - int short_hand, uint8_t dest, uint8_t dest_mode)
> + struct domain *d, const struct vlapic *source,
> + int short_hand, uint32_t dest, bool_t dest_mode)
> {
> int old = d->arch.hvm_domain.irq.round_robin_prev_vcpu;
> uint32_t ppr, target_ppr = UINT_MAX;
> @@ -434,13 +434,11 @@ void vlapic_ipi(
> {
> unsigned int dest;
> unsigned int short_hand = icr_low & APIC_SHORT_MASK;
> - unsigned int dest_mode = !!(icr_low & APIC_DEST_MASK);
> + bool_t dest_mode = !!(icr_low & APIC_DEST_MASK);
>
> HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "icr = 0x%08x:%08x", icr_high, icr_low);
>
> - dest = (vlapic_x2apic_mode(vlapic)
> - ? icr_high
> - : GET_xAPIC_DEST_FIELD(icr_high));
> + dest = _VLAPIC_ID(vlapic, icr_high);
>
> switch ( icr_low & APIC_MODE_MASK )
> {
> @@ -619,10 +617,6 @@ int hvm_x2apic_msr_read(struct vcpu *v,
> vlapic_read_aligned(vlapic, offset, &low);
> switch ( offset )
> {
> - case APIC_ID:
> - low = GET_xAPIC_ID(low);
> - break;
> -
> case APIC_ICR:
> vlapic_read_aligned(vlapic, APIC_ICR2, &high);
> break;
> @@ -656,6 +650,8 @@ static int vlapic_reg_write(struct vcpu
> struct vlapic *vlapic = vcpu_vlapic(v);
> int rc = X86EMUL_OKAY;
>
> + memset(&vlapic->loaded, 0, sizeof(vlapic->loaded));
This is slightly expensive to do for each register write. Why does this
clobbering need to be here? Could it not be....
> +
> switch ( offset )
> {
> case APIC_ID:
> @@ -924,6 +920,15 @@ const struct hvm_mmio_handler vlapic_mmi
> .write_handler = vlapic_write
> };
>
> +static void set_x2apic_id(struct vlapic *vlapic)
> +{
> + u32 id = vlapic_vcpu(vlapic)->vcpu_id;
> + u32 ldr = ((id & ~0xf) << 12) | (1 << (id & 0xf));
> +
> + vlapic_set_reg(vlapic, APIC_ID, id * 2);
> + vlapic_set_reg(vlapic, APIC_LDR, ldr);
> +}
> +
> bool_t vlapic_msr_set(struct vlapic *vlapic, uint64_t value)
> {
> if ( (vlapic->hw.apic_base_msr ^ value) & MSR_IA32_APICBASE_ENABLE )
> @@ -949,13 +954,10 @@ bool_t vlapic_msr_set(struct vlapic *vla
> return 0;
>
> vlapic->hw.apic_base_msr = value;
> + memset(&vlapic->loaded, 0, sizeof(vlapic->loaded));
(Similarly here...)
>
> if ( vlapic_x2apic_mode(vlapic) )
> - {
> - u32 id = vlapic_get_reg(vlapic, APIC_ID);
> - u32 ldr = ((id & ~0xf) << 16) | (1 << (id & 0xf));
> - vlapic_set_reg(vlapic, APIC_LDR, ldr);
> - }
> + set_x2apic_id(vlapic);
>
> vmx_vlapic_msr_changed(vlapic_vcpu(vlapic));
>
> @@ -1227,6 +1229,22 @@ static int lapic_save_regs(struct domain
> return rc;
> }
>
> +/*
> + * Following lapic_load_hidden()/lapic_load_regs() we may need to
> + * correct ID and LDR when they come from an old, broken hypervisor.
> + */
> +static void lapic_load_fixup(struct vlapic *vlapic)
> +{
> + uint32_t id = vlapic->loaded.id;
> +
> + if ( vlapic_x2apic_mode(vlapic) &&
> + id && vlapic->loaded.ldr == 1 &&
> + /* Further checks are optional: ID != 0 contradicts LDR == 1. */
> + GET_xAPIC_ID(id) == vlapic_vcpu(vlapic)->vcpu_id * 2 &&
> + id == SET_xAPIC_ID(GET_xAPIC_ID(id)) )
> + set_x2apic_id(vlapic);
... in here, where we have positively identified whether fixup is needed
or not.
~Andrew
> +}
> +
> static int lapic_load_hidden(struct domain *d, hvm_domain_context_t *h)
> {
> uint16_t vcpuid;
> @@ -1246,6 +1264,10 @@ static int lapic_load_hidden(struct doma
> if ( hvm_load_entry_zeroextend(LAPIC, h, &s->hw) != 0 )
> return -EINVAL;
>
> + s->loaded.hw = 1;
> + if ( s->loaded.regs )
> + lapic_load_fixup(s);
> +
> if ( !(s->hw.apic_base_msr & MSR_IA32_APICBASE_ENABLE) &&
> unlikely(vlapic_x2apic_mode(s)) )
> return -EINVAL;
> @@ -1274,6 +1296,12 @@ static int lapic_load_regs(struct domain
> if ( hvm_load_entry(LAPIC_REGS, h, s->regs) != 0 )
> return -EINVAL;
>
> + s->loaded.id = vlapic_get_reg(s, APIC_ID);
> + s->loaded.ldr = vlapic_get_reg(s, APIC_LDR);
> + s->loaded.regs = 1;
> + if ( s->loaded.hw )
> + lapic_load_fixup(s);
> +
> if ( hvm_funcs.process_isr )
> hvm_funcs.process_isr(vlapic_find_highest_isr(s), v);
>
> --- a/xen/include/asm-x86/hvm/vlapic.h
> +++ b/xen/include/asm-x86/hvm/vlapic.h
> @@ -30,8 +30,9 @@
> #define vlapic_vcpu(x) (container_of((x), struct vcpu, arch.hvm_vcpu.vlapic))
> #define vlapic_domain(x) (vlapic_vcpu(x)->domain)
>
> -#define VLAPIC_ID(vlapic) \
> - (GET_xAPIC_ID(vlapic_get_reg((vlapic), APIC_ID)))
> +#define _VLAPIC_ID(vlapic, id) (vlapic_x2apic_mode(vlapic) \
> + ? (id) : GET_xAPIC_ID(id))
> +#define VLAPIC_ID(vlapic) _VLAPIC_ID(vlapic, vlapic_get_reg(vlapic, APIC_ID))
>
> /*
> * APIC can be disabled in two ways:
> @@ -70,6 +71,10 @@
> struct vlapic {
> struct hvm_hw_lapic hw;
> struct hvm_hw_lapic_regs *regs;
> + struct {
> + bool_t hw, regs;
> + uint32_t id, ldr;
> + } loaded;
> struct periodic_time pt;
> s_time_t timer_last_update;
> struct page_info *regs_page;
> @@ -123,11 +128,11 @@ void vlapic_ipi(struct vlapic *vlapic, u
> int vlapic_apicv_write(struct vcpu *v, unsigned int offset);
>
> struct vlapic *vlapic_lowest_prio(
> - struct domain *d, struct vlapic *source,
> - int short_hand, uint8_t dest, uint8_t dest_mode);
> + struct domain *d, const struct vlapic *source,
> + int short_hand, uint32_t dest, bool_t dest_mode);
>
> bool_t vlapic_match_dest(
> - struct vlapic *target, struct vlapic *source,
> - int short_hand, uint8_t dest, uint8_t dest_mode);
> + struct vlapic *target, const struct vlapic *source,
> + int short_hand, uint32_t dest, bool_t dest_mode);
>
> #endif /* __ASM_X86_HVM_VLAPIC_H__ */
>
>
>
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> http://lists.xen.org/xen-devel
[-- Attachment #1.2: Type: text/html, Size: 11010 bytes --]
[-- Attachment #2: Type: text/plain, Size: 126 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel
next prev parent reply other threads:[~2014-09-22 14:30 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-09-18 14:35 [PATCH v4 0/4] x86/HVM: fix various aspects of APIC emulation Jan Beulich
2014-09-18 14:43 ` [PATCH v4 1/4] x86/HVM: fix miscellaneous aspects of x2APIC emulation Jan Beulich
2014-09-22 13:14 ` Andrew Cooper
2014-09-22 13:40 ` Jan Beulich
2014-09-23 16:56 ` Andrew Cooper
2014-09-24 8:02 ` Jan Beulich
2014-09-18 14:44 ` [PATCH v4 2/4] x86/HVM: fix ID handling " Jan Beulich
2014-09-19 6:09 ` Jan Beulich
2014-09-22 14:30 ` Andrew Cooper [this message]
2014-09-22 15:19 ` Jan Beulich
2014-09-24 10:42 ` Andrew Cooper
2014-09-24 11:41 ` Jan Beulich
2014-09-24 12:10 ` Andrew Cooper
2014-09-18 14:44 ` [PATCH v4 3/4] x86/HVM: a few type adjustments Jan Beulich
2014-09-18 14:45 ` [PATCH v4 4/4] x86/vlapic: don't silently accept bad vectors Jan Beulich
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=54203298.7090700@citrix.com \
--to=andrew.cooper3@citrix.com \
--cc=JBeulich@suse.com \
--cc=keir@xen.org \
--cc=tim@xen.org \
--cc=xen-devel@lists.xenproject.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).