All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/2] mem/nvdimm: ensure persistence of QEMU writes to real NVDIMM device
@ 2017-12-25  1:06 Haozhong Zhang
  2017-12-25  1:06 ` [Qemu-devel] [PATCH 1/2] util/pmem: add function to make writes to pmem persistent Haozhong Zhang
  2017-12-25  1:06 ` [Qemu-devel] [PATCH 2/2] mem/nvdimm: ensure persistence of QEMU writes to real NVDIMM device Haozhong Zhang
  0 siblings, 2 replies; 5+ messages in thread
From: Haozhong Zhang @ 2017-12-25  1:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: mst, Igor Mammedov, Xiao Guangrong, Stefan Hajnoczi, Dan Williams,
	Haozhong Zhang

QEMU intercepts guest writes to vNVDIMM labels, and then stores them
to the backend. When the backend is a real NVDIMM device, QEMU needs
to ensure the write persistence before returning to guest, so that the
guest labels will not be lost if QEMU exits abnormally.

Haozhong Zhang (2):
  util/pmem: add function to make writes to pmem persistent
  mem/nvdimm: ensure persistence of QEMU writes to real NVDIMM device

 hw/mem/nvdimm.c     |   3 ++
 include/qemu/pmem.h |  25 ++++++++++
 util/Makefile.objs  |   1 +
 util/pmem.c         | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 161 insertions(+)
 create mode 100644 include/qemu/pmem.h
 create mode 100644 util/pmem.c

-- 
2.14.1

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Qemu-devel] [PATCH 1/2] util/pmem: add function to make writes to pmem persistent
  2017-12-25  1:06 [Qemu-devel] [PATCH 0/2] mem/nvdimm: ensure persistence of QEMU writes to real NVDIMM device Haozhong Zhang
@ 2017-12-25  1:06 ` Haozhong Zhang
  2017-12-31 15:55   ` Michael S. Tsirkin
  2017-12-25  1:06 ` [Qemu-devel] [PATCH 2/2] mem/nvdimm: ensure persistence of QEMU writes to real NVDIMM device Haozhong Zhang
  1 sibling, 1 reply; 5+ messages in thread
From: Haozhong Zhang @ 2017-12-25  1:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: mst, Igor Mammedov, Xiao Guangrong, Stefan Hajnoczi, Dan Williams,
	Haozhong Zhang

The new function pmem_persistent() flushes the previous cached writes
on the specified memory buffer, which ensures the write persistence if
the buffer is in persistent memory.

Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
---
 include/qemu/pmem.h |  25 ++++++++++
 util/Makefile.objs  |   1 +
 util/pmem.c         | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 158 insertions(+)
 create mode 100644 include/qemu/pmem.h
 create mode 100644 util/pmem.c

diff --git a/include/qemu/pmem.h b/include/qemu/pmem.h
new file mode 100644
index 0000000000..6593ae1d5c
--- /dev/null
+++ b/include/qemu/pmem.h
@@ -0,0 +1,25 @@
+/*
+ * Helper functions to operate on persistent memory.
+ *
+ * Copyright (c) 2017 Intel Corporation.
+ *
+ * Author: Haozhong Zhang <haozhong.zhang@intel.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_PMEM_H
+#define QEMU_PMEM_H
+
+/**
+ * Flush previous cached writes to the specified memory buffer. If the
+ * buffer is in persistent memory, this function will ensure the write
+ * persistence.
+ *
+ * @p: the pointer to the memory buffer
+ * @len: the length in bytes of the memory buffer
+ */
+void pmem_persistent(void *p, unsigned long len);
+
+#endif /* QEMU_PMEM_H */
diff --git a/util/Makefile.objs b/util/Makefile.objs
index 2973b0a323..2614a84a9e 100644
--- a/util/Makefile.objs
+++ b/util/Makefile.objs
@@ -41,6 +41,7 @@ util-obj-y += timed-average.o
 util-obj-y += base64.o
 util-obj-y += log.o
 util-obj-y += pagesize.o
+util-obj-y += pmem.o
 util-obj-y += qdist.o
 util-obj-y += qht.o
 util-obj-y += range.o
diff --git a/util/pmem.c b/util/pmem.c
new file mode 100644
index 0000000000..44be1dde58
--- /dev/null
+++ b/util/pmem.c
@@ -0,0 +1,132 @@
+/*
+ * Helper functions to operate on persistent memory.
+ *
+ * Copyright (c) 2017 Intel Corporation.
+ *
+ * Author: Haozhong Zhang <haozhong.zhang@intel.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qemu/pmem.h"
+
+static size_t cache_line_size;
+
+typedef void (*cache_flush_func_t)(void *p);
+typedef void (*store_fence_func_t)(void);
+
+static cache_flush_func_t cache_flush_func;
+static store_fence_func_t store_fence_func;
+
+#if defined(__x86_64__) || defined(__i386__)
+
+#define CPUID_1_0_EBX_CLSIZE_MASK   0x0000ff00
+#define CPUID_1_0_EBX_CLSIZE_SHIFT  8
+#define CPUID_1_0_EDX_CLFLUSH       (1U << 19)
+#define CPUID_7_0_EBX_CLFLUSHOPT    (1U << 23)
+#define CPUID_7_0_EBX_CLWB          (1U << 24)
+
+static inline void cpuid(uint32_t function, uint32_t count,
+                         uint32_t *eax, uint32_t *ebx,
+                         uint32_t *ecx, uint32_t *edx)
+{
+    uint32_t vec[4];
+
+#ifdef __x86_64__
+    asm volatile("cpuid"
+                 : "=a"(vec[0]), "=b"(vec[1]),
+                   "=c"(vec[2]), "=d"(vec[3])
+                 : "0"(function), "c"(count) : "cc");
+#else
+    asm volatile("pusha\n\t"
+                 "cpuid\n\t"
+                 "mov %%eax, 0(%2)\n\t"
+                 "mov %%ebx, 4(%2)\n\t"
+                 "mov %%ecx, 8(%2)\n\t"
+                 "mov %%edx, 12(%2)\n\t"
+                 "popa"
+                 : : "a"(function), "c"(count), "S"(vec)
+                 : "memory", "cc");
+#endif
+
+    if (eax) {
+        *eax = vec[0];
+    }
+    if (ebx) {
+        *ebx = vec[1];
+    }
+    if (ecx) {
+        *ecx = vec[2];
+    }
+    if (edx) {
+        *edx = vec[3];
+    }
+}
+
+static void clflush(void *p)
+{
+    asm volatile("clflush %0" : "+m" (*(volatile char *)p));
+}
+
+static void clflushopt(void *p)
+{
+    asm volatile(".byte 0x66; clflush %0" : "+m" (*(volatile char *)p));
+}
+
+static void clwb(void *p)
+{
+    asm volatile(".byte 0x66; xsaveopt %0" : "+m" (*(volatile char *)p));
+}
+
+static void sfence(void)
+{
+    asm volatile("sfence" : : : "memory");
+}
+
+static void __attribute__((constructor)) init_funcs(void)
+{
+    uint32_t ebx, edx;
+
+    cpuid(0x1, 0x0, NULL, &ebx, NULL, &edx);
+
+    cache_line_size = ((ebx & CPUID_1_0_EBX_CLSIZE_MASK) >>
+                       CPUID_1_0_EBX_CLSIZE_SHIFT) * 8;
+    assert(cache_line_size && !(cache_line_size & (cache_line_size - 1)));
+
+    cpuid(0x7, 0x0, NULL, &ebx, NULL, NULL);
+    if (ebx & CPUID_7_0_EBX_CLWB) {
+        cache_flush_func = clwb;
+    } else if (ebx & CPUID_7_0_EBX_CLFLUSHOPT) {
+        cache_flush_func = clflushopt;
+    } else {
+        if (edx & CPUID_1_0_EDX_CLFLUSH) {
+            cache_flush_func = clflush;
+        }
+    }
+
+    store_fence_func = sfence;
+}
+
+#endif /* __x86_64__ || __i386__ */
+
+void pmem_persistent(void *p, unsigned long len)
+{
+    uintptr_t s, e;
+
+    if (!cache_flush_func || !store_fence_func) {
+        return;
+    }
+
+    s = (uintptr_t)p & ~(cache_line_size - 1);
+    e = (uintptr_t)p + len;
+
+    while (s < e) {
+        cache_flush_func((void *)s);
+        s +=  cache_line_size;
+    }
+
+    store_fence_func();
+}
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [Qemu-devel] [PATCH 2/2] mem/nvdimm: ensure persistence of QEMU writes to real NVDIMM device
  2017-12-25  1:06 [Qemu-devel] [PATCH 0/2] mem/nvdimm: ensure persistence of QEMU writes to real NVDIMM device Haozhong Zhang
  2017-12-25  1:06 ` [Qemu-devel] [PATCH 1/2] util/pmem: add function to make writes to pmem persistent Haozhong Zhang
@ 2017-12-25  1:06 ` Haozhong Zhang
  1 sibling, 0 replies; 5+ messages in thread
From: Haozhong Zhang @ 2017-12-25  1:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: mst, Igor Mammedov, Xiao Guangrong, Stefan Hajnoczi, Dan Williams,
	Haozhong Zhang

QEMU intercepts guest writes to vNVDIMM labels, and then stores them
to the backend. When the backend is a real NVDIMM device, QEMU needs
to ensure the write persistence before returning to guest, so that the
guest labels will not be lost if QEMU exits abnormally.

Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
---
 hw/mem/nvdimm.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c
index 952fce5ec8..b644876eb1 100644
--- a/hw/mem/nvdimm.c
+++ b/hw/mem/nvdimm.c
@@ -23,6 +23,7 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/pmem.h"
 #include "qapi/error.h"
 #include "qapi/visitor.h"
 #include "hw/mem/nvdimm.h"
@@ -135,6 +136,8 @@ static void nvdimm_write_label_data(NVDIMMDevice *nvdimm, const void *buf,
     nvdimm_validate_rw_label_data(nvdimm, size, offset);
 
     memcpy(nvdimm->label_data + offset, buf, size);
+    /* Make QEMU writes persistent in case the backend is a real NVDIMM. */
+    pmem_persistent(nvdimm->label_data + offset, size);
 
     mr = host_memory_backend_get_memory(dimm->hostmem, &error_abort);
     backend_offset = memory_region_size(mr) - nvdimm->label_size + offset;
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [Qemu-devel] [PATCH 1/2] util/pmem: add function to make writes to pmem persistent
  2017-12-25  1:06 ` [Qemu-devel] [PATCH 1/2] util/pmem: add function to make writes to pmem persistent Haozhong Zhang
@ 2017-12-31 15:55   ` Michael S. Tsirkin
  2018-01-03  2:04     ` Haozhong Zhang
  0 siblings, 1 reply; 5+ messages in thread
From: Michael S. Tsirkin @ 2017-12-31 15:55 UTC (permalink / raw)
  To: Haozhong Zhang
  Cc: qemu-devel, Igor Mammedov, Xiao Guangrong, Stefan Hajnoczi,
	Dan Williams

On Mon, Dec 25, 2017 at 09:06:10AM +0800, Haozhong Zhang wrote:
> The new function pmem_persistent() flushes the previous cached writes
> on the specified memory buffer, which ensures the write persistence if
> the buffer is in persistent memory.
> 
> Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
> ---
>  include/qemu/pmem.h |  25 ++++++++++
>  util/Makefile.objs  |   1 +
>  util/pmem.c         | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 158 insertions(+)
>  create mode 100644 include/qemu/pmem.h
>  create mode 100644 util/pmem.c
> 
> diff --git a/include/qemu/pmem.h b/include/qemu/pmem.h
> new file mode 100644
> index 0000000000..6593ae1d5c
> --- /dev/null
> +++ b/include/qemu/pmem.h
> @@ -0,0 +1,25 @@
> +/*
> + * Helper functions to operate on persistent memory.
> + *
> + * Copyright (c) 2017 Intel Corporation.
> + *
> + * Author: Haozhong Zhang <haozhong.zhang@intel.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#ifndef QEMU_PMEM_H
> +#define QEMU_PMEM_H
> +
> +/**
> + * Flush previous cached writes to the specified memory buffer. If the
> + * buffer is in persistent memory, this function will ensure the write
> + * persistence.
> + *
> + * @p: the pointer to the memory buffer
> + * @len: the length in bytes of the memory buffer
> + */
> +void pmem_persistent(void *p, unsigned long len);
> +
> +#endif /* QEMU_PMEM_H */
> diff --git a/util/Makefile.objs b/util/Makefile.objs
> index 2973b0a323..2614a84a9e 100644
> --- a/util/Makefile.objs
> +++ b/util/Makefile.objs
> @@ -41,6 +41,7 @@ util-obj-y += timed-average.o
>  util-obj-y += base64.o
>  util-obj-y += log.o
>  util-obj-y += pagesize.o
> +util-obj-y += pmem.o
>  util-obj-y += qdist.o
>  util-obj-y += qht.o
>  util-obj-y += range.o
> diff --git a/util/pmem.c b/util/pmem.c
> new file mode 100644
> index 0000000000..44be1dde58
> --- /dev/null
> +++ b/util/pmem.c
> @@ -0,0 +1,132 @@
> +/*
> + * Helper functions to operate on persistent memory.
> + *
> + * Copyright (c) 2017 Intel Corporation.
> + *
> + * Author: Haozhong Zhang <haozhong.zhang@intel.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu-common.h"
> +#include "qemu/pmem.h"
> +
> +static size_t cache_line_size;
> +
> +typedef void (*cache_flush_func_t)(void *p);
> +typedef void (*store_fence_func_t)(void);
> +
> +static cache_flush_func_t cache_flush_func;
> +static store_fence_func_t store_fence_func;
> +
> +#if defined(__x86_64__) || defined(__i386__)
> +
> +#define CPUID_1_0_EBX_CLSIZE_MASK   0x0000ff00
> +#define CPUID_1_0_EBX_CLSIZE_SHIFT  8
> +#define CPUID_1_0_EDX_CLFLUSH       (1U << 19)
> +#define CPUID_7_0_EBX_CLFLUSHOPT    (1U << 23)
> +#define CPUID_7_0_EBX_CLWB          (1U << 24)
> +
> +static inline void cpuid(uint32_t function, uint32_t count,
> +                         uint32_t *eax, uint32_t *ebx,
> +                         uint32_t *ecx, uint32_t *edx)
> +{
> +    uint32_t vec[4];
> +
> +#ifdef __x86_64__
> +    asm volatile("cpuid"
> +                 : "=a"(vec[0]), "=b"(vec[1]),
> +                   "=c"(vec[2]), "=d"(vec[3])
> +                 : "0"(function), "c"(count) : "cc");
> +#else
> +    asm volatile("pusha\n\t"
> +                 "cpuid\n\t"
> +                 "mov %%eax, 0(%2)\n\t"
> +                 "mov %%ebx, 4(%2)\n\t"
> +                 "mov %%ecx, 8(%2)\n\t"
> +                 "mov %%edx, 12(%2)\n\t"
> +                 "popa"
> +                 : : "a"(function), "c"(count), "S"(vec)
> +                 : "memory", "cc");
> +#endif
> +
> +    if (eax) {
> +        *eax = vec[0];
> +    }
> +    if (ebx) {
> +        *ebx = vec[1];
> +    }
> +    if (ecx) {
> +        *ecx = vec[2];
> +    }
> +    if (edx) {
> +        *edx = vec[3];
> +    }
> +}
> +
> +static void clflush(void *p)
> +{
> +    asm volatile("clflush %0" : "+m" (*(volatile char *)p));
> +}
> +
> +static void clflushopt(void *p)
> +{
> +    asm volatile(".byte 0x66; clflush %0" : "+m" (*(volatile char *)p));
> +}
> +
> +static void clwb(void *p)
> +{
> +    asm volatile(".byte 0x66; xsaveopt %0" : "+m" (*(volatile char *)p));
> +}
> +
> +static void sfence(void)
> +{
> +    asm volatile("sfence" : : : "memory");
> +}
> +
> +static void __attribute__((constructor)) init_funcs(void)
> +{
> +    uint32_t ebx, edx;
> +
> +    cpuid(0x1, 0x0, NULL, &ebx, NULL, &edx);
> +
> +    cache_line_size = ((ebx & CPUID_1_0_EBX_CLSIZE_MASK) >>
> +                       CPUID_1_0_EBX_CLSIZE_SHIFT) * 8;
> +    assert(cache_line_size && !(cache_line_size & (cache_line_size - 1)));
> +
> +    cpuid(0x7, 0x0, NULL, &ebx, NULL, NULL);
> +    if (ebx & CPUID_7_0_EBX_CLWB) {
> +        cache_flush_func = clwb;
> +    } else if (ebx & CPUID_7_0_EBX_CLFLUSHOPT) {
> +        cache_flush_func = clflushopt;
> +    } else {
> +        if (edx & CPUID_1_0_EDX_CLFLUSH) {
> +            cache_flush_func = clflush;
> +        }
> +    }
> +
> +    store_fence_func = sfence;
> +}
> +
> +#endif /* __x86_64__ || __i386__ */
> +
> +void pmem_persistent(void *p, unsigned long len)
> +{
> +    uintptr_t s, e;
> +
> +    if (!cache_flush_func || !store_fence_func) {
> +        return;
> +    }
> +
> +    s = (uintptr_t)p & ~(cache_line_size - 1);
> +    e = (uintptr_t)p + len;
> +
> +    while (s < e) {
> +        cache_flush_func((void *)s);
> +        s +=  cache_line_size;
> +    }
> +
> +    store_fence_func();
> +}


Shouldn't something be done for non x86 platforms?

> -- 
> 2.14.1

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Qemu-devel] [PATCH 1/2] util/pmem: add function to make writes to pmem persistent
  2017-12-31 15:55   ` Michael S. Tsirkin
@ 2018-01-03  2:04     ` Haozhong Zhang
  0 siblings, 0 replies; 5+ messages in thread
From: Haozhong Zhang @ 2018-01-03  2:04 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: qemu-devel, Igor Mammedov, Xiao Guangrong, Stefan Hajnoczi,
	Dan Williams

On 12/31/17 17:55 +0200, Michael S. Tsirkin wrote:
> On Mon, Dec 25, 2017 at 09:06:10AM +0800, Haozhong Zhang wrote:
> > The new function pmem_persistent() flushes the previous cached writes
> > on the specified memory buffer, which ensures the write persistence if
> > the buffer is in persistent memory.
> > 
> > Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
> > ---
> >  include/qemu/pmem.h |  25 ++++++++++
> >  util/Makefile.objs  |   1 +
> >  util/pmem.c         | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 158 insertions(+)
> >  create mode 100644 include/qemu/pmem.h
> >  create mode 100644 util/pmem.c
> > 
> > diff --git a/include/qemu/pmem.h b/include/qemu/pmem.h
> > new file mode 100644
> > index 0000000000..6593ae1d5c
> > --- /dev/null
> > +++ b/include/qemu/pmem.h
> > @@ -0,0 +1,25 @@
> > +/*
> > + * Helper functions to operate on persistent memory.
> > + *
> > + * Copyright (c) 2017 Intel Corporation.
> > + *
> > + * Author: Haozhong Zhang <haozhong.zhang@intel.com>
> > + *
> > + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> > + * See the COPYING file in the top-level directory.
> > + */
> > +
> > +#ifndef QEMU_PMEM_H
> > +#define QEMU_PMEM_H
> > +
> > +/**
> > + * Flush previous cached writes to the specified memory buffer. If the
> > + * buffer is in persistent memory, this function will ensure the write
> > + * persistence.
> > + *
> > + * @p: the pointer to the memory buffer
> > + * @len: the length in bytes of the memory buffer
> > + */
> > +void pmem_persistent(void *p, unsigned long len);
> > +
> > +#endif /* QEMU_PMEM_H */
> > diff --git a/util/Makefile.objs b/util/Makefile.objs
> > index 2973b0a323..2614a84a9e 100644
> > --- a/util/Makefile.objs
> > +++ b/util/Makefile.objs
> > @@ -41,6 +41,7 @@ util-obj-y += timed-average.o
> >  util-obj-y += base64.o
> >  util-obj-y += log.o
> >  util-obj-y += pagesize.o
> > +util-obj-y += pmem.o
> >  util-obj-y += qdist.o
> >  util-obj-y += qht.o
> >  util-obj-y += range.o
> > diff --git a/util/pmem.c b/util/pmem.c
> > new file mode 100644
> > index 0000000000..44be1dde58
> > --- /dev/null
> > +++ b/util/pmem.c
> > @@ -0,0 +1,132 @@
> > +/*
> > + * Helper functions to operate on persistent memory.
> > + *
> > + * Copyright (c) 2017 Intel Corporation.
> > + *
> > + * Author: Haozhong Zhang <haozhong.zhang@intel.com>
> > + *
> > + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> > + * See the COPYING file in the top-level directory.
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "qemu-common.h"
> > +#include "qemu/pmem.h"
> > +
> > +static size_t cache_line_size;
> > +
> > +typedef void (*cache_flush_func_t)(void *p);
> > +typedef void (*store_fence_func_t)(void);
> > +
> > +static cache_flush_func_t cache_flush_func;
> > +static store_fence_func_t store_fence_func;
> > +
> > +#if defined(__x86_64__) || defined(__i386__)
> > +
> > +#define CPUID_1_0_EBX_CLSIZE_MASK   0x0000ff00
> > +#define CPUID_1_0_EBX_CLSIZE_SHIFT  8
> > +#define CPUID_1_0_EDX_CLFLUSH       (1U << 19)
> > +#define CPUID_7_0_EBX_CLFLUSHOPT    (1U << 23)
> > +#define CPUID_7_0_EBX_CLWB          (1U << 24)
> > +
> > +static inline void cpuid(uint32_t function, uint32_t count,
> > +                         uint32_t *eax, uint32_t *ebx,
> > +                         uint32_t *ecx, uint32_t *edx)
> > +{
> > +    uint32_t vec[4];
> > +
> > +#ifdef __x86_64__
> > +    asm volatile("cpuid"
> > +                 : "=a"(vec[0]), "=b"(vec[1]),
> > +                   "=c"(vec[2]), "=d"(vec[3])
> > +                 : "0"(function), "c"(count) : "cc");
> > +#else
> > +    asm volatile("pusha\n\t"
> > +                 "cpuid\n\t"
> > +                 "mov %%eax, 0(%2)\n\t"
> > +                 "mov %%ebx, 4(%2)\n\t"
> > +                 "mov %%ecx, 8(%2)\n\t"
> > +                 "mov %%edx, 12(%2)\n\t"
> > +                 "popa"
> > +                 : : "a"(function), "c"(count), "S"(vec)
> > +                 : "memory", "cc");
> > +#endif
> > +
> > +    if (eax) {
> > +        *eax = vec[0];
> > +    }
> > +    if (ebx) {
> > +        *ebx = vec[1];
> > +    }
> > +    if (ecx) {
> > +        *ecx = vec[2];
> > +    }
> > +    if (edx) {
> > +        *edx = vec[3];
> > +    }
> > +}
> > +
> > +static void clflush(void *p)
> > +{
> > +    asm volatile("clflush %0" : "+m" (*(volatile char *)p));
> > +}
> > +
> > +static void clflushopt(void *p)
> > +{
> > +    asm volatile(".byte 0x66; clflush %0" : "+m" (*(volatile char *)p));
> > +}
> > +
> > +static void clwb(void *p)
> > +{
> > +    asm volatile(".byte 0x66; xsaveopt %0" : "+m" (*(volatile char *)p));
> > +}
> > +
> > +static void sfence(void)
> > +{
> > +    asm volatile("sfence" : : : "memory");
> > +}
> > +
> > +static void __attribute__((constructor)) init_funcs(void)
> > +{
> > +    uint32_t ebx, edx;
> > +
> > +    cpuid(0x1, 0x0, NULL, &ebx, NULL, &edx);
> > +
> > +    cache_line_size = ((ebx & CPUID_1_0_EBX_CLSIZE_MASK) >>
> > +                       CPUID_1_0_EBX_CLSIZE_SHIFT) * 8;
> > +    assert(cache_line_size && !(cache_line_size & (cache_line_size - 1)));
> > +
> > +    cpuid(0x7, 0x0, NULL, &ebx, NULL, NULL);
> > +    if (ebx & CPUID_7_0_EBX_CLWB) {
> > +        cache_flush_func = clwb;
> > +    } else if (ebx & CPUID_7_0_EBX_CLFLUSHOPT) {
> > +        cache_flush_func = clflushopt;
> > +    } else {
> > +        if (edx & CPUID_1_0_EDX_CLFLUSH) {
> > +            cache_flush_func = clflush;
> > +        }
> > +    }
> > +
> > +    store_fence_func = sfence;
> > +}
> > +
> > +#endif /* __x86_64__ || __i386__ */
> > +
> > +void pmem_persistent(void *p, unsigned long len)
> > +{
> > +    uintptr_t s, e;
> > +
> > +    if (!cache_flush_func || !store_fence_func) {
> > +        return;
> > +    }
> > +
> > +    s = (uintptr_t)p & ~(cache_line_size - 1);
> > +    e = (uintptr_t)p + len;
> > +
> > +    while (s < e) {
> > +        cache_flush_func((void *)s);
> > +        s +=  cache_line_size;
> > +    }
> > +
> > +    store_fence_func();
> > +}
> 
> 
> Shouldn't something be done for non x86 platforms?

This patch basically follows what pmdk [1] does. Recently there is an
initial AARCH64 port to pmdk [2]. I can add those instruction changes
to this patch series as well.

For other platforms, pmem_persistent() currently does nothing, and we
can add their support later when it's clear what changes are needed.

[1] Formerly known as nvml, http://pmem.io/pmdk/
[2] https://github.com/vvenkates27/nvml/commit/aeabe1d4bf9fc88c2b645d45ebce3de969e13a31


Haozhong

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2018-01-03  2:04 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-12-25  1:06 [Qemu-devel] [PATCH 0/2] mem/nvdimm: ensure persistence of QEMU writes to real NVDIMM device Haozhong Zhang
2017-12-25  1:06 ` [Qemu-devel] [PATCH 1/2] util/pmem: add function to make writes to pmem persistent Haozhong Zhang
2017-12-31 15:55   ` Michael S. Tsirkin
2018-01-03  2:04     ` Haozhong Zhang
2017-12-25  1:06 ` [Qemu-devel] [PATCH 2/2] mem/nvdimm: ensure persistence of QEMU writes to real NVDIMM device Haozhong Zhang

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.