Skip to content
  • Dexuan Cui's avatar
    x86/hyper-v: Zero out the VP ASSIST PAGE on allocation · e320ab3c
    Dexuan Cui authored
    The VP ASSIST PAGE is an "overlay" page (see Hyper-V TLFS's Section
    5.2.1 "GPA Overlay Pages" for the details) and here is an excerpt:
    
    "The hypervisor defines several special pages that "overlay" the guest's
     Guest Physical Addresses (GPA) space. Overlays are addressed GPA but are
     not included in the normal GPA map maintained internally by the hypervisor.
     Conceptually, they exist in a separate map that overlays the GPA map.
    
     If a page within the GPA space is overlaid, any SPA page mapped to the
     GPA page is effectively "obscured" and generally unreachable by the
     virtual processor through processor memory accesses.
    
     If an overlay page is disabled, the underlying GPA page is "uncovered",
     and an existing mapping becomes accessible to the guest."
    
    SPA = System Physical Address = the final real physical address.
    
    When a CPU (e.g. CPU1) is onlined, hv_cpu_init() allocates the VP ASSIST
    PAGE and enables the EOI optimization for this CPU by writing the MSR
    HV_X64_MSR_VP_ASSIST_PAGE. From now on, hvp->apic_assist belongs to the
    special SPA page, and this CPU *always* uses hvp->apic_assist (which is
    shared with the hypervisor) to decide if it needs to write the EOI MSR.
    
    When a CPU is offlined then on the outgoing CPU:
    1. hv_cpu_die() disables the EOI optimizaton for this CPU, and from
       now on hvp->apic_assist belongs to the original "normal" SPA page;
    2. the remaining work of stopping this CPU is done
    3. this CPU is completely stopped.
    
    Between 1 and 3, this CPU can still receive interrupts (e.g. reschedule
    IPIs from CPU0, and Local APIC timer interrupts), and this CPU *must* write
    the EOI MSR for every interrupt received, otherwise the hypervisor may not
    deliver further interrupts, which may be needed to completely stop the CPU.
    
    So, after the EOI optimization is disabled in hv_cpu_die(), it's required
    that the hvp->apic_assist's bit0 is zero, which is not guaranteed by the
    current allocation mode because it lacks __GFP_ZERO. As a consequence the
    bit might be set and interrupt handling would not write the EOI MSR causing
    interrupt delivery to become stuck.
    
    Add the missing __GFP_ZERO to the allocation.
    
    Note 1: after the "normal" SPA page is allocted and zeroed out, neither the
    hypervisor nor the guest writes into the page, so the page remains with
    zeros.
    
    Note 2: see Section 10.3.5 "EOI Assist" for the details of the EOI
    optimization. When the optimization is enabled, the guest can still write
    the EOI MSR register irrespective of the "No EOI required" value, but
    that's slower than the optimized assist based variant.
    
    Fixes: ba696429
    
     ("x86/hyper-v: Implement EOI assist")
    Signed-off-by: default avatarDexuan Cui <decui@microsoft.com>
    Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
    Cc: stable@vger.kernel.org
    Link: https://lkml.kernel.org/r/ <PU1P153MB0169B716A637FABF07433C04BFCB0@PU1P153MB0169.APCP153.PROD.OUTLOOK.COM
    e320ab3c