diff --git a/tools/libxc/xc_dom_armzimageloader.c b/tools/libxc/xc_dom_armzimageloader.c index e6516a1c92..508f74b2a6 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 e1de5b5c21..aa0463c5a5 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 77a4e64e42..d46ac22bcc 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 73860a2699..e219b2491f 100644 --- a/tools/libxc/xc_linux_osdep.c +++ b/tools/libxc/xc_linux_osdep.c @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -416,6 +417,44 @@ 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)); + asm volatile ("dsb sy"); +#elif defined(__i386__) || defined(__x86_64__) + /* No need for cache maintenance on x86 */ +#else + PERROR("No cache flush operation defined for architecture"); + abort(); +#endif +} + static struct xc_osdep_ops linux_privcmd_ops = { .open = &linux_privcmd_open, .close = &linux_privcmd_close, @@ -430,6 +469,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 dec4d73f60..5026b2b196 100644 --- a/tools/libxc/xc_minios.c +++ b/tools/libxc/xc_minios.c @@ -181,6 +181,16 @@ 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 + printf("No cache flush operation defined for architecture"); + BUG(); +#endif +} static struct xc_osdep_ops minios_privcmd_ops = { .open = &minios_privcmd_open, @@ -196,6 +206,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 8a90ef3d63..0143305036 100644 --- a/tools/libxc/xc_netbsd.c +++ b/tools/libxc/xc_netbsd.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -207,6 +208,17 @@ 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"); + abort(); +#endif +} + static struct xc_osdep_ops netbsd_privcmd_ops = { .open = &netbsd_privcmd_open, .close = &netbsd_privcmd_close, @@ -221,6 +233,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 838fd21f23..3ccee2b571 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 92271c9b47..50a0aa7013 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 7257a54be1..edffab1514 100644 --- a/tools/libxc/xc_solaris.c +++ b/tools/libxc/xc_solaris.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -178,6 +179,17 @@ 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"); + abort(); +#endif +} + static struct xc_osdep_ops solaris_privcmd_ops = { .open = &solaris_privcmd_open, .close = &solaris_privcmd_close, @@ -192,6 +204,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 4821342a48..d911b101bd 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 e610a245ed..6c9a00569f 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);