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

Re: [Xen-devel] [PATCH v2] tools: libxc: flush data cache after loading images into guest memory



On Thu, 2013-12-12 at 14:23 +0000, Ian Campbell wrote:

Ian,

Since this is a tool patch more than and ARM one I should have CCd you,
sorry.

Ian.

> On ARM guest OSes are started with MMU and Caches disables (as they are on
> native) however caching is enabled in the domain running the builder and
> therefore we must flush the cache as we load the blobs, otherwise when the
> guest starts running it may not see them. The dom0 build in the hypervisor has
> the same requirements and already does the right thing.
> 
> The mechanism for performing a cache flush from userspace is OS specific, so
> implement this as a new osdep hook:
> 
>  - On 32-bit ARM Linux provides a system call to flush the cache.
>  - On 64-bit ARM Linux the processor is configured to allow cache flushes
>    directly from userspace.
>  - Non-Linux platforms will need to provide their own implementation. If
>    similar mechanisms are not available then a new privcmd ioctl should be a
>    suitable alternative.
> 
> No cache maintenance is required on x86, so provide a stub for all non-Linux
> platforms which returns success on x86 only and log an error otherwise.
> 
> This fixes guest building on Xgene which has a very large L3 cache and so is
> particularly susceptible to this problem. It has also been observed
> sporadically on midway.
> 
> Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
> Cc: Andre Przywara <andre.przywara@xxxxxxxxxxx>
> Cc: Pranavkumar Sawargaonkar <psawargaonkar@xxxxxxx>
> Cc: Anup Patel <apatel@xxxxxxx>
> ---
> v2: Add IPRINTF to ENOSYS debug module.
> Freeze: Bugfix.
> ---
>  tools/libxc/xc_dom_armzimageloader.c |    1 +
>  tools/libxc/xc_dom_binloader.c       |    1 +
>  tools/libxc/xc_dom_core.c            |    2 ++
>  tools/libxc/xc_linux_osdep.c         |   39 
> ++++++++++++++++++++++++++++++++++
>  tools/libxc/xc_minios.c              |   11 ++++++++++
>  tools/libxc/xc_netbsd.c              |   12 +++++++++++
>  tools/libxc/xc_private.c             |    5 +++++
>  tools/libxc/xc_private.h             |    3 +++
>  tools/libxc/xc_solaris.c             |   12 +++++++++++
>  tools/libxc/xenctrl_osdep_ENOSYS.c   |    9 ++++++++
>  tools/libxc/xenctrlosdep.h           |    1 +
>  11 files changed, 96 insertions(+)
> 
> diff --git a/tools/libxc/xc_dom_armzimageloader.c 
> b/tools/libxc/xc_dom_armzimageloader.c
> index e6516a1..508f74b 100644
> --- a/tools/libxc/xc_dom_armzimageloader.c
> +++ b/tools/libxc/xc_dom_armzimageloader.c
> @@ -229,6 +229,7 @@ static int xc_dom_load_zimage_kernel(struct xc_dom_image 
> *dom)
>                __func__, dom->kernel_size, dom->kernel_blob, dst);
>  
>      memcpy(dst, dom->kernel_blob, dom->kernel_size);
> +    xc_cache_flush(dom->xch, dst, dom->kernel_size);
>  
>      return 0;
>  }
> diff --git a/tools/libxc/xc_dom_binloader.c b/tools/libxc/xc_dom_binloader.c
> index e1de5b5..aa0463c 100644
> --- a/tools/libxc/xc_dom_binloader.c
> +++ b/tools/libxc/xc_dom_binloader.c
> @@ -301,6 +301,7 @@ static int xc_dom_load_bin_kernel(struct xc_dom_image 
> *dom)
>  
>      memcpy(dest, image + skip, text_size);
>      memset(dest + text_size, 0, bss_size);
> +    xc_cache_flush(dom->xch, dest, text_size+bss_size);
>  
>      return 0;
>  }
> diff --git a/tools/libxc/xc_dom_core.c b/tools/libxc/xc_dom_core.c
> index 77a4e64..d46ac22 100644
> --- a/tools/libxc/xc_dom_core.c
> +++ b/tools/libxc/xc_dom_core.c
> @@ -978,6 +978,7 @@ int xc_dom_build_image(struct xc_dom_image *dom)
>          }
>          else
>              memcpy(ramdiskmap, dom->ramdisk_blob, dom->ramdisk_size);
> +        xc_cache_flush(dom->xch, ramdiskmap, ramdisklen);
>      }
>  
>      /* load devicetree */
> @@ -997,6 +998,7 @@ int xc_dom_build_image(struct xc_dom_image *dom)
>              goto err;
>          }
>          memcpy(devicetreemap, dom->devicetree_blob, dom->devicetree_size);
> +        xc_cache_flush(dom->xch, devicetreemap, dom->devicetree_size);
>      }
>  
>      /* allocate other pages */
> diff --git a/tools/libxc/xc_linux_osdep.c b/tools/libxc/xc_linux_osdep.c
> index 73860a2..8362495 100644
> --- a/tools/libxc/xc_linux_osdep.c
> +++ b/tools/libxc/xc_linux_osdep.c
> @@ -30,6 +30,7 @@
>  
>  #include <sys/mman.h>
>  #include <sys/ioctl.h>
> +#include <sys/syscall.h>
>  
>  #include <xen/memory.h>
>  #include <xen/sys/evtchn.h>
> @@ -416,6 +417,42 @@ static void 
> *linux_privcmd_map_foreign_ranges(xc_interface *xch, xc_osdep_handle
>      return ret;
>  }
>  
> +static void linux_privcmd_cache_flush(xc_interface *xch,
> +                                   const void *ptr, size_t nr)
> +{
> +#if defined(__arm__)
> +    unsigned long start = (unsigned long)ptr;
> +    unsigned long end = start + nr;
> +    /* cacheflush(unsigned long start, unsigned long end, int flags) */
> +    int rc = syscall(__ARM_NR_cacheflush, start, end, 0);
> +    if ( rc < 0 )
> +         PERROR("cache flush operation failed: %d\n", errno);
> +#elif defined(__aarch64__)
> +    unsigned long start = (unsigned long)ptr;
> +    unsigned long end = start + nr;
> +    unsigned long p, ctr;
> +    int stride;
> +
> +    /* Flush cache using direct DC CVAC instructions. This is
> +     * available to EL0 when SCTLR_EL1.UCI is set, which Linux does.
> +     *
> +     * Bits 19:16 of CTR_EL0 are log2 of the minimum dcache line size
> +     * in words, which we use as our stride length. This is readable
> +     * with SCTLR_EL1.UCT is set, which Linux does.
> +     */
> +    asm volatile ("mrs %0, ctr_el0" : "=r" (ctr));
> +
> +    stride = 4 * (1 << ((ctr & 0xf0000UL) >> 16));
> +
> +    for ( p = start ; p < end ; p += stride )
> +        asm volatile ("dc cvac, %0" :  : "r" (p));
> +#elif defined(__i386__) || defined(__x86_64__)
> +    /* No need for cache maintenance on x86 */
> +#else
> +    PERROR("No cache flush operation defined for architecture");
> +#endif
> +}
> +
>  static struct xc_osdep_ops linux_privcmd_ops = {
>      .open = &linux_privcmd_open,
>      .close = &linux_privcmd_close,
> @@ -430,6 +467,8 @@ static struct xc_osdep_ops linux_privcmd_ops = {
>          .map_foreign_bulk = &linux_privcmd_map_foreign_bulk,
>          .map_foreign_range = &linux_privcmd_map_foreign_range,
>          .map_foreign_ranges = &linux_privcmd_map_foreign_ranges,
> +
> +        .cache_flush = &linux_privcmd_cache_flush,
>      },
>  };
>  
> diff --git a/tools/libxc/xc_minios.c b/tools/libxc/xc_minios.c
> index dec4d73..3b2f553 100644
> --- a/tools/libxc/xc_minios.c
> +++ b/tools/libxc/xc_minios.c
> @@ -181,6 +181,15 @@ static void 
> *minios_privcmd_map_foreign_ranges(xc_interface *xch, xc_osdep_handl
>      return ret;
>  }
>  
> +static void minios_privcmd_cache_flush(xc_interface *xch,
> +                                       const void *ptr, size_t nr)
> +{
> +#if defined(__i386__) || defined(__x86_64__)
> +    /* No need for cache maintenance on x86 */
> +#else
> +    PERROR("No cache flush operation defined for architecture");
> +#endif
> +}
>  
>  static struct xc_osdep_ops minios_privcmd_ops = {
>      .open = &minios_privcmd_open,
> @@ -196,6 +205,8 @@ static struct xc_osdep_ops minios_privcmd_ops = {
>          .map_foreign_bulk = &minios_privcmd_map_foreign_bulk,
>          .map_foreign_range = &minios_privcmd_map_foreign_range,
>          .map_foreign_ranges = &minios_privcmd_map_foreign_ranges,
> +
> +        .cache_flush = &minios_privcmd_cache_flush,
>      },
>  };
>  
> diff --git a/tools/libxc/xc_netbsd.c b/tools/libxc/xc_netbsd.c
> index 8a90ef3..11e1027 100644
> --- a/tools/libxc/xc_netbsd.c
> +++ b/tools/libxc/xc_netbsd.c
> @@ -207,6 +207,16 @@ mmap_failed:
>       return NULL;
>  }
>  
> +static void netbsd_privcmd_cache_flush(xc_interface *xch,
> +                                       const void *ptr, size_t nr)
> +{
> +#if defined(__i386__) || defined(__x86_64__)
> +    /* No need for cache maintenance on x86 */
> +#else
> +    PERROR("No cache flush operation defined for architecture");
> +#endif
> +}
> +
>  static struct xc_osdep_ops netbsd_privcmd_ops = {
>      .open = &netbsd_privcmd_open,
>      .close = &netbsd_privcmd_close,
> @@ -221,6 +231,8 @@ static struct xc_osdep_ops netbsd_privcmd_ops = {
>          .map_foreign_bulk = &xc_map_foreign_bulk_compat,
>          .map_foreign_range = &netbsd_privcmd_map_foreign_range,
>          .map_foreign_ranges = &netbsd_privcmd_map_foreign_ranges,
> +
> +        .cache_flush = &netbsd_privcmd_cache_flush,
>      },
>  };
>  
> diff --git a/tools/libxc/xc_private.c b/tools/libxc/xc_private.c
> index 838fd21..3ccee2b 100644
> --- a/tools/libxc/xc_private.c
> +++ b/tools/libxc/xc_private.c
> @@ -249,6 +249,11 @@ int do_xen_hypercall(xc_interface *xch, 
> privcmd_hypercall_t *hypercall)
>      return xch->ops->u.privcmd.hypercall(xch, xch->ops_handle, hypercall);
>  }
>  
> +void xc_cache_flush(xc_interface *xch, const void *p, size_t n)
> +{
> +    xch->ops->u.privcmd.cache_flush(xch, p, n);
> +}
> +
>  xc_evtchn *xc_evtchn_open(xentoollog_logger *logger,
>                               unsigned open_flags)
>  {
> diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h
> index 92271c9..50a0aa7 100644
> --- a/tools/libxc/xc_private.h
> +++ b/tools/libxc/xc_private.h
> @@ -304,6 +304,9 @@ void bitmap_byte_to_64(uint64_t *lp, const uint8_t *bp, 
> int nbits);
>  /* Optionally flush file to disk and discard page cache */
>  void discard_file_cache(xc_interface *xch, int fd, int flush);
>  
> +/* Flush data cache */
> +void xc_cache_flush(xc_interface *xch, const void *p, size_t n);
> +
>  #define MAX_MMU_UPDATES 1024
>  struct xc_mmu {
>      mmu_update_t updates[MAX_MMU_UPDATES];
> diff --git a/tools/libxc/xc_solaris.c b/tools/libxc/xc_solaris.c
> index 7257a54..83c3777 100644
> --- a/tools/libxc/xc_solaris.c
> +++ b/tools/libxc/xc_solaris.c
> @@ -178,6 +178,16 @@ mmap_failed:
>      return NULL;
>  }
>  
> +static void solaris_privcmd_cache_flush(xc_interface *xch,
> +                                        const void *ptr, size_t nr)
> +{
> +#if defined(__i386__) || defined(__x86_64__)
> +    /* No need for cache maintenance on x86 */
> +#else
> +    PERROR("No cache flush operation defined for architecture");
> +#endif
> +}
> +
>  static struct xc_osdep_ops solaris_privcmd_ops = {
>      .open = &solaris_privcmd_open,
>      .close = &solaris_privcmd_close,
> @@ -192,6 +202,8 @@ static struct xc_osdep_ops solaris_privcmd_ops = {
>          .map_foreign_bulk = &xc_map_foreign_bulk_compat,
>          .map_foreign_range = &solaris_privcmd_map_foreign_range,
>          .map_foreign_ranges = &solaris_privcmd_map_foreign_ranges,
> +
> +        .cache_flush = &solaris_privcmd_cache_flush,
>      },
>  };
>  
> diff --git a/tools/libxc/xenctrl_osdep_ENOSYS.c 
> b/tools/libxc/xenctrl_osdep_ENOSYS.c
> index 4821342..d911b10 100644
> --- a/tools/libxc/xenctrl_osdep_ENOSYS.c
> +++ b/tools/libxc/xenctrl_osdep_ENOSYS.c
> @@ -63,6 +63,13 @@ static void 
> *ENOSYS_privcmd_map_foreign_ranges(xc_interface *xch, xc_osdep_handl
>      return MAP_FAILED;
>  }
>  
> +static void ENOSYS_privcmd_cache_flush(xc_interface *xch, const void *p, 
> size_t n)
> +{
> +    unsigned long start = (unsigned long)p;
> +    unsigned long end = start + n;
> +    IPRINTF(xch, "ENOSYS_privcmd: cache_flush: %#lx-%#lx\n", start, end);
> +}
> +
>  static struct xc_osdep_ops ENOSYS_privcmd_ops =
>  {
>      .open      = &ENOSYS_privcmd_open,
> @@ -74,6 +81,8 @@ static struct xc_osdep_ops ENOSYS_privcmd_ops =
>          .map_foreign_bulk = &ENOSYS_privcmd_map_foreign_bulk,
>          .map_foreign_range = &ENOSYS_privcmd_map_foreign_range,
>          .map_foreign_ranges = &ENOSYS_privcmd_map_foreign_ranges,
> +
> +        .cache_flush = &ENOSYS_privcmd_cache_flush,
>      }
>  };
>  
> diff --git a/tools/libxc/xenctrlosdep.h b/tools/libxc/xenctrlosdep.h
> index e610a24..6c9a005 100644
> --- a/tools/libxc/xenctrlosdep.h
> +++ b/tools/libxc/xenctrlosdep.h
> @@ -89,6 +89,7 @@ struct xc_osdep_ops
>              void *(*map_foreign_ranges)(xc_interface *xch, xc_osdep_handle 
> h, uint32_t dom, size_t size, int prot,
>                                          size_t chunksize, 
> privcmd_mmap_entry_t entries[],
>                                          int nentries);
> +            void (*cache_flush)(xc_interface *xch, const void *p, size_t n);
>          } privcmd;
>          struct {
>              int (*fd)(xc_evtchn *xce, xc_osdep_handle h);



_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

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