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

Re: [PATCH 7/8] x86/mm: make code robust to future PAT changes



On Tue, Dec 06, 2022 at 12:06:24PM +0000, Andrew Cooper wrote:
> On 06/12/2022 04:33, Demi Marie Obenour wrote:
> > It may be desirable to change Xen's PAT for various reasons.  This
> > requires changes to several _PAGE_* macros as well.  Add static
> > assertions to check that XEN_MSR_PAT is consistent with the _PAGE_*
> > macros.
> >
> > Additionally, Xen has two unused entries in the PAT.  Currently these
> > are UC, but this will change if the hardware ever supports additional
> > memory types.  To avoid future problems, this adds a check in debug
> > builds that injects #GP into a guest that tries to use one of these
> > entries, along with returning -EINVAL from the hypercall.  Future
> > versions of Xen will refuse to use these entries even in release builds.
> >
> > Signed-off-by: Demi Marie Obenour <demi@xxxxxxxxxxxxxxxxxxxxxx>
> > ---
> >  xen/arch/x86/mm.c | 58 +++++++++++++++++++++++++++++++++++++++++++----
> >  1 file changed, 54 insertions(+), 4 deletions(-)
> >
> > diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
> > index 
> > 5d05399c3a841bf03991a3bed63df9a815c1e891..517fccee699b2a673ba537e47933aefc80017aa5
> >  100644
> > --- a/xen/arch/x86/mm.c
> > +++ b/xen/arch/x86/mm.c
> > @@ -849,6 +849,45 @@ static int cf_check print_mmio_emul_range(
> >  }
> >  #endif
> >  
> > +static void __init __maybe_unused build_assertions(void)
> 
> This wants to be at the very bottom of the file.  (And also in the
> previous patch to remove the _Static_assert())
> 
> > +{
> > +    /* A bunch of static assertions to check that the XEN_MSR_PAT is valid
> > +     * and consistent with the _PAGE_* macros */
> > +#define PAT_VALUE(v) (0xFF & (XEN_MSR_PAT >> (8 * (v))))
> > +#define BAD_VALUE(v) ((v) < 0 || (v) > 7 ||                                
> >     \
> > +                      (v) == MSR_PAT_RESERVED_1 || (v) == 
> > MSR_PAT_RESERVED_2)
> > +#define BAD_PAT_VALUE(v) BUILD_BUG_ON(BAD_VALUE(PAT_VALUE(v)))
> > +    BAD_PAT_VALUE(0);
> > +    BAD_PAT_VALUE(1);
> > +    BAD_PAT_VALUE(2);
> > +    BAD_PAT_VALUE(3);
> > +    BAD_PAT_VALUE(4);
> > +    BAD_PAT_VALUE(5);
> > +    BAD_PAT_VALUE(6);
> > +    BAD_PAT_VALUE(7);
> > +#undef BAD_PAT_VALUE
> > +#undef BAD_VALUE
> 
> Given that you've reworked the PAT declaration to be of the form (MT <<
> shift), I'm not sure how much value this check is.

One of my goals with this patch set is that it should be possible to
choose *any* value for XEN_MSR_PAT and for the PAT-related _PAGE_*, with
all bad values caught at compile-time.  This would allow making it a
Kconfig option.

> > +#define PAT_SHIFT(page_value) (((page_value) & _PAGE_PAT) >> 5 |           
> >     \
> > +                               ((page_value) & (_PAGE_PCD | _PAGE_PWT)) >> 
> > 3)
> 
> pte_flags_to_cacheattr()

That’s a function, not a macro (and for good reason), so it can’t be
used in BUILD_BUG_ON().

> > +#define CHECK_PAGE_VALUE(page_value) do {                                  
> >     \
> > +    /* Check that the _PAGE_* macros only use bits from PAGE_CACHE_ATTRS 
> > */    \
> > +    BUILD_BUG_ON(((_PAGE_##page_value) & PAGE_CACHE_ATTRS) !=              
> >     \
> > +                  (_PAGE_##page_value));                                   
> >     \
> > +    /* Check that the _PAGE_* are consistent with XEN_MSR_PAT */           
> >     \
> > +    BUILD_BUG_ON(PAT_VALUE(PAT_SHIFT(_PAGE_##page_value)) !=               
> >     \
> > +                 (MSR_PAT_##page_value));                                  
> >     \
> > +} while (0)
> > +    CHECK_PAGE_VALUE(WT);
> > +    CHECK_PAGE_VALUE(WB);
> > +    CHECK_PAGE_VALUE(WC);
> > +    CHECK_PAGE_VALUE(UC);
> > +    CHECK_PAGE_VALUE(UCM);
> > +    CHECK_PAGE_VALUE(WP);
> > +#undef CHECK_PAGE_VALUE
> > +#undef PAT_SHIFT
> > +#undef PAT_VALUE
> > +}
> > +
> >  /*
> >   * get_page_from_l1e returns:
> >   *   0  => success (page not present also counts as such)
> > @@ -961,13 +1000,24 @@ get_page_from_l1e(
> >  
> >          switch ( l1f & PAGE_CACHE_ATTRS )
> >          {
> > -        case _PAGE_WB:
> > +        default:
> > +#ifndef NDEBUG
> > +            printk(XENLOG_G_WARNING
> > +                   "d%d: Guest tried to use bad cachability attribute %u 
> > for MFN %lx\n",
> > +                   l1e_owner->domain_id, l1f & PAGE_CACHE_ATTRS, mfn);
> 
> %pd.  You absolutely want to convert the PTE bits to a PAT value before
> priniting (decimal on a PTE value is useless), and %PRI_mfn.

I’ll have to look at the rest of the Xen tree to see how to use this.

> > +            pv_inject_hw_exception(TRAP_gp_fault, 0);
> 
> As I said on IRC, we do want this, but I'm not certain if we can get
> away with just enabling it in debug builds.  _PAGE_GNTTAB was ok because
> it has always been like that, but there's a non-trivial chance that
> there are existing dom0 kernels which violate this constraint.

I chose this approach because it is very simple to implement.  Anything
more complex ought to be in a separate patch, IMO.

> > +            return -EINVAL;
> > +#endif
> >          case _PAGE_WT:
> >          case _PAGE_WP:
> > -            flip |= (l1f & PAGE_CACHE_ATTRS) ^ _PAGE_UC;
> > +        case _PAGE_WB:
> > +            /* Force this to be uncachable */
> > +            return flip | ( (l1f & PAGE_CACHE_ATTRS) ^ _PAGE_UC );
> > +        case _PAGE_WC:
> > +        case _PAGE_UC:
> > +        case _PAGE_UCM:
> > +            return flip;
> >          }
> > -
> > -        return flip;
> 
> This wants reworking over Jan's suggestion in patch 1, and modifying to
> reduce churn.  (Keep _PAGE_WB in the same order WRT _PAGE_WT, the
> uncached memory types should simply break, and default should be at the
> end.)

I put the default in the middle to keep the preprocessor conditionals
simple and avoid duplication.  I will have the default be treated as
cachable memory.
-- 
Sincerely,
Demi Marie Obenour (she/her/hers)
Invisible Things Lab

Attachment: signature.asc
Description: PGP signature


 


Rackspace

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