[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH v2 04/10] x86/HVM/SVM: Add AVIC initialization code



>>> On 07.05.18 at 23:07, <Janakarajan.Natarajan@xxxxxxx> wrote:
> --- /dev/null
> +++ b/xen/arch/x86/hvm/svm/avic.c
> @@ -0,0 +1,190 @@
> +/*
> + * avic.c: implements AMD Advanced Virtual Interrupt Controller (AVIC) 
> support
> + * Copyright (c) 2018, Advanced Micro Devices, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along 
> with
> + * this program; If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <xen/domain_page.h>
> +#include <xen/sched.h>
> +#include <xen/stdbool.h>
> +#include <asm/acpi.h>
> +#include <asm/apicdef.h>
> +#include <asm/atomic.h>
> +#include <asm/event.h>
> +#include <asm/hvm/emulate.h>
> +#include <asm/hvm/nestedhvm.h>
> +#include <asm/hvm/support.h>
> +#include <asm/hvm/svm/avic.h>
> +#include <asm/hvm/vlapic.h>
> +#include <asm/p2m.h>
> +#include <asm/page.h>

Are all of these really needed? For example, xen/stdbool.h isn't commonly
included by non-header files, but is instead obtained from xen/types.h. That
header, in turn, is rarely required to be included explicitly by non-headers
because almost every header already includes it anyway.

In some cases I'm also not convinced you really mean asm/ (rather than
xen/).

> +/* Note: Current max index allowed for physical APIC ID table is 255. */
> +#define AVIC_PHY_APIC_ID_MAX    GET_xAPIC_ID(APIC_ID_MASK)

I think it was pointed out before that "max" generally means the last valid
value, rather than the first invalid one.

> +/*
> + * Note:
> + * Currently, svm-avic mode is not supported with nested virtualization.
> + * Therefore, it is not yet currently enabled by default. Once the support
> + * is in-place, this should be enabled by default.
> + */
> +bool svm_avic = false;
> +
> +static const char __section(".bss.page_aligned.const") __aligned(PAGE_SIZE)
> +    avic_backing_page[PAGE_SIZE];

So nothing ever writes to this page? I think it would be misleading if CPU side
writes were possible, yet this was marked const.

Also - does this really need allocating statically (rather than just on systems
actually needing it)?

> +static struct avic_physical_id_entry*
> +avic_get_physical_id_entry(struct svm_domain *d, unsigned int index)

I think the first parameter could be const.

> +int svm_avic_dom_init(struct domain *d)
> +{
> +    int ret = 0;
> +    struct page_info *pg;
> +
> +    if ( !svm_avic || !has_vlapic(d) )
> +        return 0;
> +
> +    /*
> +     * Note:
> +     * AVIC hardware walks the nested page table to check permissions,
> +     * but does not use the SPA address specified in the leaf page
> +     * table entry since it uses  address in the AVIC_BACKING_PAGE pointer
> +     * field of the VMCB. Therefore, we set up a dummy page for APIC.
> +     */
> +    set_mmio_p2m_entry(d, paddr_to_pfn(APIC_DEFAULT_PHYS_BASE),
> +                       _mfn(virt_to_mfn(avic_backing_page)), PAGE_ORDER_4K,
> +                       p2m_access_rw);
> +
> +    /* Init AVIC logical APIC ID table */
> +    pg = alloc_domheap_page(d, MEMF_no_owner);

Do you really mean d here (and below) rather than NULL?

> +    if ( !pg )
> +    {
> +        ret = -ENOMEM;
> +        goto err_out;
> +    }
> +    clear_domain_page(page_to_mfn(pg));
> +    d->arch.hvm_domain.svm.avic_logical_id_table_pg = pg;
> +    d->arch.hvm_domain.svm.avic_logical_id_table = 
> __map_domain_page_global(pg);

I think I have said before that I don't think you need to store both
virtual and physical address here, unless both are used frequently.
You establishing a global mapping suggests to me that it's the
virtual address you want to store (MFN and hence struct page_info
can be derived from the mapping via domain_page_map_to_mfn(),
like you already do further down).

> +bool svm_avic_vcpu_enabled(const struct vcpu *v)
> +{
> +    const struct arch_svm_struct *s = &v->arch.hvm_svm;
> +    const struct vmcb_struct *vmcb = s->vmcb;
> +
> +    return vmcb->_vintr.fields.avic_enable;

Please don't use excess local variables (both of them are used just once,
and I'm sure you could get away with just one of the two [or none at all]
without breaking the line length limit).

Also shouldn't this be vmcb_get_vintr()?

> +int svm_avic_init_vmcb(struct vcpu *v)
> +{
> +    u32 apic_id;
> +    struct arch_svm_struct *s = &v->arch.hvm_svm;
> +    struct vmcb_struct *vmcb = s->vmcb;
> +    struct svm_domain *d = &v->domain->arch.hvm_domain.svm;
> +    const struct vlapic *vlapic = vcpu_vlapic(v);
> +    struct avic_physical_id_entry *entry;
> +
> +    if ( !svm_avic || !has_vlapic(v->domain) )
> +        return 0;
> +
> +    if ( !vlapic || !vlapic->regs_page )
> +        return -EINVAL;
> +
> +    apic_id = vlapic_reg_read(vcpu_vlapic(v), APIC_ID);

Why can't this be vlapic_get_reg()?

> +    s->avic_last_phy_id = avic_get_physical_id_entry(d, 
> GET_xAPIC_ID(apic_id));

You don't appear to read this value outside of this function. Please store
values in struct domain / struct vcpu only if you in fact read them, and
if their calculation isn't trivial.

I also don't appear to understand the purpose of the "last" in the name.

> +    if ( !s->avic_last_phy_id )
> +        return -EINVAL;
> +
> +    vmcb->avic_bk_pg_pa = page_to_maddr(vlapic->regs_page);
> +    vmcb->avic_logical_id_table_pa = 
> mfn_to_maddr(domain_page_map_to_mfn(d->avic_logical_id_table));
> +    vmcb->avic_physical_id_table_pa = 
> mfn_to_maddr(domain_page_map_to_mfn(d->avic_physical_id_table));
> +
> +    /* Set Physical ID Table Pointer [7:0] to max apic id of the domain */
> +    vmcb->avic_physical_id_table_pa |= (v->domain->max_vcpus * 2) & 0xFF;
> +
> +    entry = s->avic_last_phy_id;
> +    entry->bk_pg_ptr_mfn = (vmcb->avic_bk_pg_pa) >> PAGE_SHIFT;

Please don't open-code paddr_to_pfn() / maddr_to_mfn().

> @@ -215,6 +216,8 @@ static int construct_vmcb(struct vcpu *v)
>              vmcb->_pause_filter_thresh = SVM_PAUSETHRESH_INIT;
>      }
>  
> +    svm_avic_init_vmcb(v);

This function may fail.

> --- a/xen/arch/x86/hvm/vlapic.c
> +++ b/xen/arch/x86/hvm/vlapic.c
> @@ -1597,6 +1597,10 @@ int vlapic_init(struct vcpu *v)
>  
>      if (vlapic->regs_page == NULL)
>      {
> +        /*
> +         * SVM AVIC depends on the vlapic->regs_page being a full
> +         * page allocation as it is also used for vAPIC backing page.
> +         */
>          vlapic->regs_page = alloc_domheap_page(v->domain, MEMF_no_owner);

I'm not convinced of the utility of this comment - iirc the same is true on the
VMX side (and there was no similar comment added here at the time).

> --- /dev/null
> +++ b/xen/include/asm-x86/hvm/svm/avic.h
> @@ -0,0 +1,39 @@
> +#ifndef _SVM_AVIC_H_
> +#define _SVM_AVIC_H_
> +
> +#include <xen/compiler.h>

You mean xen/types.h here, or else ...

> +enum avic_incmp_ipi_err_code {
> +    AVIC_INCMP_IPI_ERR_INVALID_INT_TYPE,
> +    AVIC_INCMP_IPI_ERR_TARGET_NOT_RUN,
> +    AVIC_INCMP_IPI_ERR_INV_TARGET,
> +    AVIC_INCMP_IPI_ERR_INV_BK_PAGE,
> +};
> +
> +typedef union avic_logical_id_entry {
> +    u32 raw;

... u32 (which really should be uint32_t - please replace thoughout the series)
may not be available here.

> +    struct __packed {
> +        u32 guest_phy_apic_id : 8;
> +        u32 res               : 23;
> +        u32 valid             : 1;
> +    };
> +} avic_logical_id_entry_t;
> +
> +struct __packed avic_physical_id_entry {
> +        u64 host_phy_apic_id  : 8;
> +        u64 res1              : 4;
> +        u64 bk_pg_ptr_mfn     : 40;
> +        u64 res2              : 10;
> +        u64 is_running        : 1;
> +        u64 valid             : 1;
> +};
> +
> +extern bool svm_avic;
> +
> +int svm_avic_dom_init(struct domain *d);
> +void svm_avic_dom_destroy(struct domain *d);
> +
> +bool svm_avic_vcpu_enabled(const struct vcpu *v);
> +int svm_avic_init_vmcb(struct vcpu *v);

These declarations even need xen/sched.h in place of (or together with)
xen/types.h.

Jan


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.