blob: eb2d2ef5cbf32df14d5a25dfa5a85ad2d2bdf1b4 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <zircon/syscalls.h>
#include <zircon/compiler.h>
#include "private.h"
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)))
return ZX_ERR_INVALID_ARGS;
#if defined(__x86_64__)
// Nothing needs doing for x86.
#elif defined(__aarch64__)
if (flags & ZX_CACHE_FLUSH_DATA) {
for (uintptr_t p = ((uintptr_t)addr &
-((uintptr_t)DATA_CONSTANTS.dcache_line_size));
p < (uintptr_t)addr + len;
p += DATA_CONSTANTS.dcache_line_size) {
// Clean data cache (dc) to point of coherency (cvac).
__asm__ volatile("dc cvac, %0" :: "r"(p));
}
}
if (flags & ZX_CACHE_FLUSH_INSN) {
// If we didn't already clean the dcache all the way to the point
// of coherency, clean it the point to unification.
if (!(flags & ZX_CACHE_FLUSH_DATA)) {
for (uintptr_t p = ((uintptr_t)addr &
-((uintptr_t)DATA_CONSTANTS.dcache_line_size));
p < (uintptr_t)addr + len;
p += DATA_CONSTANTS.dcache_line_size) {
// Clean data cache (dc) to point of unification (cvau).
__asm__ volatile("dc cvau, %0" :: "r"(p));
}
}
// Synchronize the dcache flush to before the icache flush.
__asm__ volatile("dsb ish");
for (uintptr_t p = ((uintptr_t)addr &
-((uintptr_t)DATA_CONSTANTS.icache_line_size));
p < (uintptr_t)addr + len;
p += DATA_CONSTANTS.icache_line_size) {
// Clean instruction cache (ic) to point of unification (ivau).
__asm__ volatile("ic ivau, %0" :: "r"(p));
}
// Synchronize the icache flush to before future instruction fetches.
__asm__ volatile("isb sy");
}
#else
# error what architecture?
#endif
return ZX_OK;
}
VDSO_INTERFACE_FUNCTION(zx_cache_flush);