[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |