[ulib][zircon] Add ZX_CACHE_FLUSH_INVALIDATE flag
This can be OR'd in with ZX_CACHE_FLUSH_DATA to force
an invalidation after the writeback.
Also add the missing documentation for zx_cache_flush.
Change-Id: I3ad031541e7851118f73f4c030368b2df82ded8d
diff --git a/docs/syscalls/cache_flush.md b/docs/syscalls/cache_flush.md
new file mode 100644
index 0000000..5247ec7
--- /dev/null
+++ b/docs/syscalls/cache_flush.md
@@ -0,0 +1,51 @@
+# zx_cache_flush
+
+## NAME
+
+zx_cache_flush - Flush CPU data and/or instruction caches
+
+## SYNOPSIS
+
+```
+#include <zircon/syscalls.h>
+
+zx_status_t zx_cache_flush(const void* addr, size_t len, uint32_t flags);
+```
+
+## DESCRIPTION
+
+**zx_cache_flush**() flushes CPU caches covering memory in the given
+virtual address range. If that range of memory is not readable, then
+the thread may fault as it would for a data read.
+
+*flags* is a bitwise OR of:
+
+ * **ZX_CACHE_FLUSH_DATA**
+
+ Clean (write back) data caches, so previous writes on this CPU are
+ visible in main memory.
+
+ * **ZX_CACHE_FLUSH_INVALIDATE**
+ (valid only when combined with **ZX_CACHE_FLUSH_DATA**)
+
+ Clean (write back) data caches and then invalidate data caches, so
+ previous writes on this CPU are visible in main memory and future
+ reads on this CPU see external changes to main memory.
+
+ * **ZX_CACHE_FLUSH_INSN**
+
+ Synchronize instruction caches with data caches, so previous writes
+ on this CPU are visible to instruction fetches. If this is combined
+ with **ZX_CACHE_FLUSH_DATA**, then previous writes will be visible to
+ main memory as well as to instruction fetches.
+
+At least one of **ZX_CACHE_FLUSH_DATA** and **ZX_CACHE_FLUSH_INSN**
+must be included in *flags*.
+
+## RETURN VALUE
+
+**zx_cache_flush**() returns **ZX_OK** on success, or an error code on failure.
+
+## ERRORS
+
+**ZX_ERR_INVALID_ARGS** *flags* is invalid.
diff --git a/system/public/zircon/types.h b/system/public/zircon/types.h
index 24d8b69..cdf2f3f 100644
--- a/system/public/zircon/types.h
+++ b/system/public/zircon/types.h
@@ -307,6 +307,7 @@
// Flag bits for zx_cache_flush.
#define ZX_CACHE_FLUSH_INSN (1u << 0)
#define ZX_CACHE_FLUSH_DATA (1u << 1)
+#define ZX_CACHE_FLUSH_INVALIDATE (1u << 2)
// Timer options.
#define ZX_TIMER_SLACK_CENTER 0u
diff --git a/system/ulib/zircon/zx_cache_flush.cpp b/system/ulib/zircon/zx_cache_flush.cpp
index 5bc6748..d180802 100644
--- a/system/ulib/zircon/zx_cache_flush.cpp
+++ b/system/ulib/zircon/zx_cache_flush.cpp
@@ -32,8 +32,20 @@
} // anonymous namespace
zx_status_t _zx_cache_flush(const void* addr, size_t len, uint32_t flags) {
- if (flags == 0 || (flags & ~(ZX_CACHE_FLUSH_INSN | ZX_CACHE_FLUSH_DATA)))
+ switch (flags) {
+ case ZX_CACHE_FLUSH_INSN:
+ break;
+ case ZX_CACHE_FLUSH_DATA:
+ break;
+ case ZX_CACHE_FLUSH_DATA | ZX_CACHE_FLUSH_INSN:
+ break;
+ case ZX_CACHE_FLUSH_DATA | ZX_CACHE_FLUSH_INVALIDATE:
+ break;
+ case ZX_CACHE_FLUSH_DATA | ZX_CACHE_FLUSH_INVALIDATE | ZX_CACHE_FLUSH_INSN:
+ break;
+ default:
return ZX_ERR_INVALID_ARGS;
+ }
#if defined(__x86_64__)
@@ -42,10 +54,17 @@
#elif defined(__aarch64__)
if (flags & ZX_CACHE_FLUSH_DATA) {
- for_each_dcache_line(addr, len, [](uintptr_t p) {
- // Clean data cache (dc) to point of coherency (cvac).
- __asm__ volatile("dc cvac, %0" :: "r"(p));
- });
+ if (flags & ZX_CACHE_FLUSH_INVALIDATE) {
+ for_each_dcache_line(addr, len, [](uintptr_t p) {
+ // Clean and invalidate data cache to point of coherency.
+ __asm__ volatile("dc civac, %0" :: "r"(p));
+ });
+ } else {
+ for_each_dcache_line(addr, len, [](uintptr_t p) {
+ // Clean data cache (dc) to point of coherency (cvac).
+ __asm__ volatile("dc cvac, %0" :: "r"(p));
+ });
+ }
}
if (flags & ZX_CACHE_FLUSH_INSN) {