extern int kernel_set_to_readonly;
 
 #ifdef CONFIG_X86_64
-static inline int set_mce_nospec(unsigned long pfn)
+/*
+ * Prevent speculative access to the page by either unmapping
+ * it (if we do not require access to any part of the page) or
+ * marking it uncacheable (if we want to try to retrieve data
+ * from non-poisoned lines in the page).
+ */
+static inline int set_mce_nospec(unsigned long pfn, bool unmap)
 {
        unsigned long decoy_addr;
        int rc;
 
        /*
-        * Mark the linear address as UC to make sure we don't log more
-        * errors because of speculative access to the page.
         * We would like to just call:
-        *      set_memory_uc((unsigned long)pfn_to_kaddr(pfn), 1);
+        *      set_memory_XX((unsigned long)pfn_to_kaddr(pfn), 1);
         * but doing that would radically increase the odds of a
         * speculative access to the poison page because we'd have
         * the virtual address of the kernel 1:1 mapping sitting
         * around in registers.
         * Instead we get tricky.  We create a non-canonical address
         * that looks just like the one we want, but has bit 63 flipped.
-        * This relies on set_memory_uc() properly sanitizing any __pa()
+        * This relies on set_memory_XX() properly sanitizing any __pa()
         * results with __PHYSICAL_MASK or PTE_PFN_MASK.
         */
        decoy_addr = (pfn << PAGE_SHIFT) + (PAGE_OFFSET ^ BIT(63));
 
-       rc = set_memory_uc(decoy_addr, 1);
+       if (unmap)
+               rc = set_memory_np(decoy_addr, 1);
+       else
+               rc = set_memory_uc(decoy_addr, 1);
        if (rc)
                pr_warn("Could not invalidate pfn=0x%lx from 1:1 map\n", pfn);
        return rc;
 
 }
 EXPORT_SYMBOL_GPL(mce_is_memory_error);
 
+static bool whole_page(struct mce *m)
+{
+       if (!mca_cfg.ser || !(m->status & MCI_STATUS_MISCV))
+               return true;
+
+       return MCI_MISC_ADDR_LSB(m->misc) >= PAGE_SHIFT;
+}
+
 bool mce_is_correctable(struct mce *m)
 {
        if (m->cpuvendor == X86_VENDOR_AMD && m->status & MCI_STATUS_DEFERRED)
 
        pfn = mce->addr >> PAGE_SHIFT;
        if (!memory_failure(pfn, 0)) {
-               set_mce_nospec(pfn);
+               set_mce_nospec(pfn, whole_page(mce));
                mce->kflags |= MCE_HANDLED_UC;
        }
 
        int flags = MF_ACTION_REQUIRED;
 
        pr_err("Uncorrected hardware memory error in user-access at %llx", p->mce_addr);
-       if (!(p->mce_status & MCG_STATUS_RIPV))
+
+       if (!p->mce_ripv)
                flags |= MF_MUST_KILL;
 
        if (!memory_failure(p->mce_addr >> PAGE_SHIFT, flags)) {
-               set_mce_nospec(p->mce_addr >> PAGE_SHIFT);
+               set_mce_nospec(p->mce_addr >> PAGE_SHIFT, p->mce_whole_page);
                return;
        }
 
                BUG_ON(!on_thread_stack() || !user_mode(regs));
 
                current->mce_addr = m.addr;
-               current->mce_status = m.mcgstatus;
+               current->mce_ripv = !!(m.mcgstatus & MCG_STATUS_RIPV);
+               current->mce_whole_page = whole_page(&m);
                current->mce_kill_me.func = kill_me_maybe;
                if (kill_it)
                        current->mce_kill_me.func = kill_me_now;