#define PROT_SECT_NORMAL      (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL))
  #define PROT_SECT_NORMAL_EXEC (PROT_SECT_DEFAULT | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL))
  
 -#define _PAGE_DEFAULT         (PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL))
 +#define _PAGE_DEFAULT         (_PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL))
 +#define _HYP_PAGE_DEFAULT     _PAGE_DEFAULT
  
 -#define PAGE_KERNEL           __pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE)
 -#define PAGE_KERNEL_RO                __pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_RDONLY)
 -#define PAGE_KERNEL_ROX               __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_RDONLY)
 -#define PAGE_KERNEL_EXEC      __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE)
 -#define PAGE_KERNEL_EXEC_CONT __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_CONT)
 +#define PAGE_KERNEL           __pgprot(PROT_NORMAL)
 +#define PAGE_KERNEL_RO                __pgprot((PROT_NORMAL & ~PTE_WRITE) | PTE_RDONLY)
 +#define PAGE_KERNEL_ROX               __pgprot((PROT_NORMAL & ~(PTE_WRITE | PTE_PXN)) | PTE_RDONLY)
 +#define PAGE_KERNEL_EXEC      __pgprot(PROT_NORMAL & ~PTE_PXN)
 +#define PAGE_KERNEL_EXEC_CONT __pgprot((PROT_NORMAL & ~PTE_PXN) | PTE_CONT)
  
 -#define PAGE_HYP              __pgprot(_PAGE_DEFAULT | PTE_HYP | PTE_HYP_XN)
 -#define PAGE_HYP_EXEC         __pgprot(_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY)
 -#define PAGE_HYP_RO           __pgprot(_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY | PTE_HYP_XN)
 +#define PAGE_HYP              __pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_HYP_XN)
 +#define PAGE_HYP_EXEC         __pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY)
 +#define PAGE_HYP_RO           __pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY | PTE_HYP_XN)
  #define PAGE_HYP_DEVICE               __pgprot(PROT_DEVICE_nGnRE | PTE_HYP)
  
- #define PAGE_S2                       __pgprot(_PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_NORMAL) | PTE_S2_RDONLY)
- #define PAGE_S2_DEVICE                __pgprot(_PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_DEVICE_nGnRE) | PTE_S2_RDONLY | PTE_UXN)
 -#define PAGE_S2                       __pgprot(PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_NORMAL) | PTE_S2_RDONLY | PTE_S2_XN)
 -#define PAGE_S2_DEVICE                __pgprot(PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_DEVICE_nGnRE) | PTE_S2_RDONLY | PTE_S2_XN)
++#define PAGE_S2                       __pgprot(_PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_NORMAL) | PTE_S2_RDONLY | PTE_S2_XN)
++#define PAGE_S2_DEVICE                __pgprot(_PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_DEVICE_nGnRE) | PTE_S2_RDONLY | PTE_S2_XN)
  
 -#define PAGE_NONE             __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_RDONLY | PTE_PXN | PTE_UXN)
 +#define PAGE_NONE             __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN)
  #define PAGE_SHARED           __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE)
  #define PAGE_SHARED_EXEC      __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_WRITE)
  #define PAGE_READONLY         __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN)
 
  void hyperv_setup_mmu_ops(void);
  void hyper_alloc_mmu(void);
  void hyperv_report_panic(struct pt_regs *regs, long err);
 -bool hv_is_hypercall_page_setup(void);
 +bool hv_is_hyperv_initialized(void);
  void hyperv_cleanup(void);
+ 
+ void hyperv_reenlightenment_intr(struct pt_regs *regs);
+ void set_hv_tscchange_cb(void (*cb)(void));
+ void clear_hv_tscchange_cb(void);
+ void hyperv_stop_tsc_emulation(void);
  #else /* CONFIG_HYPERV */
  static inline void hyperv_init(void) {}
 -static inline bool hv_is_hypercall_page_setup(void) { return false; }
 +static inline bool hv_is_hyperv_initialized(void) { return false; }
  static inline void hyperv_cleanup(void) {}
  static inline void hyperv_setup_mmu_ops(void) {}
+ static inline void set_hv_tscchange_cb(void (*cb)(void)) {}
+ static inline void clear_hv_tscchange_cb(void) {}
+ static inline void hyperv_stop_tsc_emulation(void) {};
  #endif /* CONFIG_HYPERV */
  
  #ifdef CONFIG_HYPERV_TSCPAGE
 
  
  static inline short vmcs_field_to_offset(unsigned long field)
  {
 +      const size_t size = ARRAY_SIZE(vmcs_field_to_offset_table);
 +      unsigned short offset;
+       unsigned index;
+ 
+       if (field >> 15)
+               return -ENOENT;
  
-       BUILD_BUG_ON(size > SHRT_MAX);
-       if (field >= size)
+       index = ROL16(field, 6);
 -      if (index >= ARRAY_SIZE(vmcs_field_to_offset_table))
++      if (index >= size)
                return -ENOENT;
  
-       field = array_index_nospec(field, size);
-       offset = vmcs_field_to_offset_table[field];
 -      /*
 -       * FIXME: Mitigation for CVE-2017-5753.  To be replaced with a
 -       * generic mechanism.
 -       */
 -      asm("lfence");
 -
 -      if (vmcs_field_to_offset_table[index] == 0)
++      index = array_index_nospec(index, size);
++      offset = vmcs_field_to_offset_table[index];
 +      if (offset == 0)
                return -ENOENT;
 -
 -      return vmcs_field_to_offset_table[index];
 +      return offset;
  }
  
  static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)
        struct page *page;
        unsigned long *msr_bitmap_l1;
        unsigned long *msr_bitmap_l0 = to_vmx(vcpu)->nested.vmcs02.msr_bitmap;
 +      /*
 +       * pred_cmd & spec_ctrl are trying to verify two things:
 +       *
 +       * 1. L0 gave a permission to L1 to actually passthrough the MSR. This
 +       *    ensures that we do not accidentally generate an L02 MSR bitmap
 +       *    from the L12 MSR bitmap that is too permissive.
 +       * 2. That L1 or L2s have actually used the MSR. This avoids
 +       *    unnecessarily merging of the bitmap if the MSR is unused. This
 +       *    works properly because we only update the L01 MSR bitmap lazily.
 +       *    So even if L0 should pass L1 these MSRs, the L01 bitmap is only
 +       *    updated to reflect this when L1 (or its L2s) actually write to
 +       *    the MSR.
 +       */
 +      bool pred_cmd = msr_write_intercepted_l01(vcpu, MSR_IA32_PRED_CMD);
 +      bool spec_ctrl = msr_write_intercepted_l01(vcpu, MSR_IA32_SPEC_CTRL);
  
 -      /* This shortcut is ok because we support only x2APIC MSRs so far. */
 -      if (!nested_cpu_has_virt_x2apic_mode(vmcs12))
+       /* Nothing to do if the MSR bitmap is not in use.  */
+       if (!cpu_has_vmx_msr_bitmap() ||
+           !nested_cpu_has(vmcs12, CPU_BASED_USE_MSR_BITMAPS))
+               return false;
+ 
 +      if (!nested_cpu_has_virt_x2apic_mode(vmcs12) &&
 +          !pred_cmd && !spec_ctrl)
                return false;
  
        page = kvm_vcpu_gpa_to_page(vcpu, vmcs12->msr_bitmap);
        if (is_error_page(page))
                return false;
-       msr_bitmap_l1 = (unsigned long *)kmap(page);
  
-       memset(msr_bitmap_l0, 0xff, PAGE_SIZE);
+       msr_bitmap_l1 = (unsigned long *)kmap(page);
+       if (nested_cpu_has_apic_reg_virt(vmcs12)) {
+               /*
+                * L0 need not intercept reads for MSRs between 0x800 and 0x8ff, it
+                * just lets the processor take the value from the virtual-APIC page;
+                * take those 256 bits directly from the L1 bitmap.
+                */
+               for (msr = 0x800; msr <= 0x8ff; msr += BITS_PER_LONG) {
+                       unsigned word = msr / BITS_PER_LONG;
+                       msr_bitmap_l0[word] = msr_bitmap_l1[word];
+                       msr_bitmap_l0[word + (0x800 / sizeof(long))] = ~0;
+               }
+       } else {
+               for (msr = 0x800; msr <= 0x8ff; msr += BITS_PER_LONG) {
+                       unsigned word = msr / BITS_PER_LONG;
+                       msr_bitmap_l0[word] = ~0;
+                       msr_bitmap_l0[word + (0x800 / sizeof(long))] = ~0;
+               }
+       }
  
-       if (nested_cpu_has_virt_x2apic_mode(vmcs12)) {
-               if (nested_cpu_has_apic_reg_virt(vmcs12))
-                       for (msr = 0x800; msr <= 0x8ff; msr++)
-                               nested_vmx_disable_intercept_for_msr(
-                                       msr_bitmap_l1, msr_bitmap_l0,
-                                       msr, MSR_TYPE_R);
+       nested_vmx_disable_intercept_for_msr(
+               msr_bitmap_l1, msr_bitmap_l0,
+               X2APIC_MSR(APIC_TASKPRI),
+               MSR_TYPE_W);
  
+       if (nested_cpu_has_vid(vmcs12)) {
                nested_vmx_disable_intercept_for_msr(
-                               msr_bitmap_l1, msr_bitmap_l0,
-                               APIC_BASE_MSR + (APIC_TASKPRI >> 4),
-                               MSR_TYPE_R | MSR_TYPE_W);
- 
-               if (nested_cpu_has_vid(vmcs12)) {
-                       nested_vmx_disable_intercept_for_msr(
-                               msr_bitmap_l1, msr_bitmap_l0,
-                               APIC_BASE_MSR + (APIC_EOI >> 4),
-                               MSR_TYPE_W);
-                       nested_vmx_disable_intercept_for_msr(
-                               msr_bitmap_l1, msr_bitmap_l0,
-                               APIC_BASE_MSR + (APIC_SELF_IPI >> 4),
-                               MSR_TYPE_W);
-               }
+                       msr_bitmap_l1, msr_bitmap_l0,
+                       X2APIC_MSR(APIC_EOI),
+                       MSR_TYPE_W);
+               nested_vmx_disable_intercept_for_msr(
+                       msr_bitmap_l1, msr_bitmap_l0,
+                       X2APIC_MSR(APIC_SELF_IPI),
+                       MSR_TYPE_W);
        }
 +
 +      if (spec_ctrl)
 +              nested_vmx_disable_intercept_for_msr(
 +                                      msr_bitmap_l1, msr_bitmap_l0,
 +                                      MSR_IA32_SPEC_CTRL,
 +                                      MSR_TYPE_R | MSR_TYPE_W);
 +
 +      if (pred_cmd)
 +              nested_vmx_disable_intercept_for_msr(
 +                                      msr_bitmap_l1, msr_bitmap_l0,
 +                                      MSR_IA32_PRED_CMD,
 +                                      MSR_TYPE_W);
 +
        kunmap(page);
        kvm_release_page_clean(page);