1 /*
   2  * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include "precompiled.hpp"
  26 #include "asm/macroAssembler.hpp"
  27 #include "assembler_arm.inline.hpp"
  28 #include "code/codeCacheExtensions.hpp"
  29 #include "runtime/icache.hpp"
  30 
  31 #define __ _masm->
  32 
  33 #ifdef AARCH64
  34 
  35 static int icache_flush(address addr, int lines, int magic) {
  36   // TODO-AARCH64 Figure out actual cache line size (mrs Xt, CTR_EL0)
  37 
  38   address p = addr;
  39   for (int i = 0; i < lines; i++, p += ICache::line_size) {
  40     __asm__ volatile(
  41       " dc cvau, %[p]"
  42       :
  43       : [p] "r" (p)
  44       : "memory");
  45   }
  46 
  47   __asm__ volatile(
  48     " dsb ish"
  49     : : : "memory");
  50 
  51   p = addr;
  52   for (int i = 0; i < lines; i++, p += ICache::line_size) {
  53     __asm__ volatile(
  54       " ic ivau, %[p]"
  55       :
  56       : [p] "r" (p)
  57       : "memory");
  58   }
  59 
  60   __asm__ volatile(
  61     " dsb ish\n\t"
  62     " isb\n\t"
  63     : : : "memory");
  64 
  65   return magic;
  66 }
  67 
  68 #else
  69 
  70 static int icache_flush(address addr, int lines, int magic) {
  71   __builtin___clear_cache(addr, addr + (lines << ICache::log2_line_size));
  72   return magic;
  73 }
  74 
  75 #endif // AARCH64
  76 
  77 void ICacheStubGenerator::generate_icache_flush(ICache::flush_icache_stub_t* flush_icache_stub) {
  78   address start = (address)icache_flush;
  79 
  80   *flush_icache_stub = (ICache::flush_icache_stub_t)start;
  81 
  82   // ICache::invalidate_range() contains explicit condition that the first
  83   // call is invoked on the generated icache flush stub code range.
  84   ICache::invalidate_range(start, 0);
  85 
  86   {
  87     // dummy code mark to make the shared code happy
  88     // (fields that would need to be modified to emulate the correct
  89     // mark are not accessible)
  90     StubCodeMark mark(this, "ICache", "fake_stub_for_inlined_icache_flush");
  91     __ ret();
  92   }
  93 }
  94 
  95 #undef __