|
[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 |