1// Copyright 2016 The Fuchsia Authors
2// Copyright (c) 2009 Corey Tabaka
3//
4// Use of this source code is governed by a MIT-style
5// license that can be found in the LICENSE file or at
6// https://opensource.org/licenses/MIT
7
8#include <arch/ops.h>
9#include <arch/x86.h>
10#include <arch/x86/feature.h>
11
12uint32_t arch_dcache_line_size(void) {
13    return x86_get_clflush_line_size();
14}
15
16uint32_t arch_icache_line_size(void) {
17    return x86_get_clflush_line_size();
18}
19
20void arch_sync_cache_range(addr_t start, size_t len) {
21    // Invoke cpuid to act as a serializing instruction.  This will ensure we
22    // see modifications to future parts of the instruction stream.  See
23    // Intel Volume 3, 8.1.3 "Handling Self- and Cross-Modifying Code".  cpuid
24    // is the more conservative approach suggested in this section.
25    uint32_t v;
26    cpuid(0, &v, &v, &v, &v);
27}
28
29void arch_invalidate_cache_range(addr_t start, size_t len) {
30}
31
32void arch_clean_cache_range(addr_t start, size_t len) {
33    // TODO: consider wiring up clwb if present
34    arch_clean_invalidate_cache_range(start, len);
35}
36
37void arch_clean_invalidate_cache_range(addr_t start, size_t len) {
38    if (unlikely(!x86_feature_test(X86_FEATURE_CLFLUSH))) {
39        __asm__ volatile("wbinvd");
40        return;
41    }
42
43    // clflush/clflushopt is present
44    const vaddr_t clsize = x86_get_clflush_line_size();
45    addr_t end = start + len;
46    addr_t ptr = ROUNDDOWN(start, clsize);
47
48    // TODO: use run time patching to merge these two paths
49    if (likely(x86_feature_test(X86_FEATURE_CLFLUSHOPT))) {
50        while (ptr < end) {
51            __asm__ volatile("clflushopt %0" ::"m"(*(char*)ptr));
52            ptr += clsize;
53        }
54    } else {
55        while (ptr < end) {
56            __asm__ volatile("clflush %0" ::"m"(*(char*)ptr));
57            ptr += clsize;
58        }
59    }
60
61    __asm__ volatile("mfence");
62}
63