Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Step:15-SP4
xen.25152
62a1e60e-x86-split-cache_flush-out-of-cache_wri...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 62a1e60e-x86-split-cache_flush-out-of-cache_writeback.patch of Package xen.25152
# Commit 9a67ffee3371506e1cbfdfff5b90658d4828f6a2 # Date 2022-06-09 14:22:38 +0200 # Author Andrew Cooper <andrew.cooper3@citrix.com> # Committer Jan Beulich <jbeulich@suse.com> x86: Split cache_flush() out of cache_writeback() Subsequent changes will want a fully flushing version. Use the new helper rather than opencoding it in flush_area_local(). This resolves an outstanding issue where the conditional sfence is on the wrong side of the clflushopt loop. clflushopt is ordered with respect to older stores, not to younger stores. Rename gnttab_cache_flush()'s helper to avoid colliding in name. grant_table.c can see the prototype from cache.h so the build fails otherwise. This is part of XSA-402. Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com> Reviewed-by: Jan Beulich <jbeulich@suse.com> Xen 4.16 and earlier: * Also backport half of c/s 3330013e67396 "VT-d / x86: re-arrange cache syncing" to split cache_writeback() out of the IOMMU logic, but without the associated hooks changes. --- a/xen/arch/x86/flushtlb.c +++ b/xen/arch/x86/flushtlb.c @@ -234,7 +234,7 @@ unsigned int flush_area_local(const void if ( flags & FLUSH_CACHE ) { const struct cpuinfo_x86 *c = ¤t_cpu_data; - unsigned long i, sz = 0; + unsigned long sz = 0; if ( order < (BITS_PER_LONG - PAGE_SHIFT) ) sz = 1UL << (order + PAGE_SHIFT); @@ -244,13 +244,7 @@ unsigned int flush_area_local(const void c->x86_clflush_size && c->x86_cache_size && sz && ((sz >> 10) < c->x86_cache_size) ) { - alternative("", "sfence", X86_FEATURE_CLFLUSHOPT); - for ( i = 0; i < sz; i += c->x86_clflush_size ) - alternative_input(".byte " __stringify(NOP_DS_PREFIX) ";" - " clflush %0", - "data16 clflush %0", /* clflushopt */ - X86_FEATURE_CLFLUSHOPT, - "m" (((const char *)va)[i])); + cache_flush(va, sz); flags &= ~FLUSH_CACHE; } else @@ -265,6 +259,80 @@ unsigned int flush_area_local(const void return flags; } +void cache_flush(const void *addr, unsigned int size) +{ + /* + * This function may be called before current_cpu_data is established. + * Hence a fallback is needed to prevent the loop below becoming infinite. + */ + unsigned int clflush_size = current_cpu_data.x86_clflush_size ?: 16; + const void *end = addr + size; + + addr -= (unsigned long)addr & (clflush_size - 1); + for ( ; addr < end; addr += clflush_size ) + { + /* + * Note regarding the "ds" prefix use: it's faster to do a clflush + * + prefix than a clflush + nop, and hence the prefix is added instead + * of letting the alternative framework fill the gap by appending nops. + */ + alternative_io("ds; clflush %[p]", + "data16 clflush %[p]", /* clflushopt */ + X86_FEATURE_CLFLUSHOPT, + /* no outputs */, + [p] "m" (*(const char *)(addr))); + } + + alternative("", "sfence", X86_FEATURE_CLFLUSHOPT); +} + +void cache_writeback(const void *addr, unsigned int size) +{ + unsigned int clflush_size; + const void *end = addr + size; + + /* Fall back to CLFLUSH{,OPT} when CLWB isn't available. */ + if ( !boot_cpu_has(X86_FEATURE_CLWB) ) + return cache_flush(addr, size); + + /* + * This function may be called before current_cpu_data is established. + * Hence a fallback is needed to prevent the loop below becoming infinite. + */ + clflush_size = current_cpu_data.x86_clflush_size ?: 16; + addr -= (unsigned long)addr & (clflush_size - 1); + for ( ; addr < end; addr += clflush_size ) + { +/* + * The arguments to a macro must not include preprocessor directives. Doing so + * results in undefined behavior, so we have to create some defines here in + * order to avoid it. + */ +#if defined(HAVE_AS_CLWB) +# define CLWB_ENCODING "clwb %[p]" +#elif defined(HAVE_AS_XSAVEOPT) +# define CLWB_ENCODING "data16 xsaveopt %[p]" /* clwb */ +#else +# define CLWB_ENCODING ".byte 0x66, 0x0f, 0xae, 0x30" /* clwb (%%rax) */ +#endif + +#define BASE_INPUT(addr) [p] "m" (*(const char *)(addr)) +#if defined(HAVE_AS_CLWB) || defined(HAVE_AS_XSAVEOPT) +# define INPUT BASE_INPUT +#else +# define INPUT(addr) "a" (addr), BASE_INPUT(addr) +#endif + + asm volatile (CLWB_ENCODING :: INPUT(addr)); + +#undef INPUT +#undef BASE_INPUT +#undef CLWB_ENCODING + } + + asm volatile ("sfence" ::: "memory"); +} + unsigned int guest_flush_tlb_flags(const struct domain *d) { bool shadow = paging_mode_shadow(d); --- a/xen/common/grant_table.c +++ b/xen/common/grant_table.c @@ -3440,7 +3440,7 @@ gnttab_swap_grant_ref(XEN_GUEST_HANDLE_P return 0; } -static int cache_flush(const gnttab_cache_flush_t *cflush, grant_ref_t *cur_ref) +static int _cache_flush(const gnttab_cache_flush_t *cflush, grant_ref_t *cur_ref) { struct domain *d, *owner; struct page_info *page; @@ -3534,7 +3534,7 @@ gnttab_cache_flush(XEN_GUEST_HANDLE_PARA return -EFAULT; for ( ; ; ) { - int ret = cache_flush(&op, cur_ref); + int ret = _cache_flush(&op, cur_ref); if ( ret < 0 ) return ret; --- a/xen/drivers/passthrough/vtd/extern.h +++ b/xen/drivers/passthrough/vtd/extern.h @@ -77,7 +77,6 @@ int __must_check qinval_device_iotlb_syn struct pci_dev *pdev, u16 did, u16 size, u64 addr); -unsigned int get_cache_line_size(void); void flush_all_cache(void); uint64_t alloc_pgtable_maddr(unsigned long npages, nodeid_t node); --- a/xen/drivers/passthrough/vtd/iommu.c +++ b/xen/drivers/passthrough/vtd/iommu.c @@ -31,6 +31,7 @@ #include <xen/pci.h> #include <xen/pci_regs.h> #include <xen/keyhandler.h> +#include <asm/cache.h> #include <asm/msi.h> #include <asm/nops.h> #include <asm/irq.h> @@ -207,53 +208,10 @@ static int iommus_incoherent; static void sync_cache(const void *addr, unsigned int size) { - static unsigned long clflush_size = 0; - const void *end = addr + size; - if ( !iommus_incoherent ) return; - if ( clflush_size == 0 ) - clflush_size = get_cache_line_size(); - - addr -= (unsigned long)addr & (clflush_size - 1); - for ( ; addr < end; addr += clflush_size ) -/* - * The arguments to a macro must not include preprocessor directives. Doing so - * results in undefined behavior, so we have to create some defines here in - * order to avoid it. - */ -#if defined(HAVE_AS_CLWB) -# define CLWB_ENCODING "clwb %[p]" -#elif defined(HAVE_AS_XSAVEOPT) -# define CLWB_ENCODING "data16 xsaveopt %[p]" /* clwb */ -#else -# define CLWB_ENCODING ".byte 0x66, 0x0f, 0xae, 0x30" /* clwb (%%rax) */ -#endif - -#define BASE_INPUT(addr) [p] "m" (*(const char *)(addr)) -#if defined(HAVE_AS_CLWB) || defined(HAVE_AS_XSAVEOPT) -# define INPUT BASE_INPUT -#else -# define INPUT(addr) "a" (addr), BASE_INPUT(addr) -#endif - /* - * Note regarding the use of NOP_DS_PREFIX: it's faster to do a clflush - * + prefix than a clflush + nop, and hence the prefix is added instead - * of letting the alternative framework fill the gap by appending nops. - */ - alternative_io_2(".byte " __stringify(NOP_DS_PREFIX) "; clflush %[p]", - "data16 clflush %[p]", /* clflushopt */ - X86_FEATURE_CLFLUSHOPT, - CLWB_ENCODING, - X86_FEATURE_CLWB, /* no outputs */, - INPUT(addr)); -#undef INPUT -#undef BASE_INPUT -#undef CLWB_ENCODING - - alternative_2("", "sfence", X86_FEATURE_CLFLUSHOPT, - "sfence", X86_FEATURE_CLWB); + cache_writeback(addr, size); } /* Allocate page table, return its machine address */ --- a/xen/drivers/passthrough/vtd/x86/vtd.c +++ b/xen/drivers/passthrough/vtd/x86/vtd.c @@ -47,11 +47,6 @@ void unmap_vtd_domain_page(void *va) unmap_domain_page(va); } -unsigned int get_cache_line_size(void) -{ - return ((cpuid_ebx(1) >> 8) & 0xff) * 8; -} - void flush_all_cache() { wbinvd(); --- a/xen/include/asm-x86/cache.h +++ b/xen/include/asm-x86/cache.h @@ -11,4 +11,11 @@ #define __read_mostly __section(".data.read_mostly") +#ifndef __ASSEMBLY__ + +void cache_flush(const void *addr, unsigned int size); +void cache_writeback(const void *addr, unsigned int size); + +#endif + #endif
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor