aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: * aoqi@0: */ aoqi@0: aoqi@0: #include "precompiled.hpp" aoqi@0: #include "memory/resourceArea.hpp" aoqi@0: #include "runtime/icache.hpp" aoqi@0: aoqi@0: // The flush stub function address aoqi@0: AbstractICache::flush_icache_stub_t AbstractICache::_flush_icache_stub = NULL; aoqi@0: aoqi@0: void AbstractICache::initialize() { aoqi@0: // Making this stub must be FIRST use of assembler aoqi@0: ResourceMark rm; aoqi@0: aoqi@0: BufferBlob* b = BufferBlob::create("flush_icache_stub", ICache::stub_size); aoqi@0: CodeBuffer c(b); aoqi@0: aoqi@0: ICacheStubGenerator g(&c); aoqi@0: g.generate_icache_flush(&_flush_icache_stub); aoqi@0: aoqi@0: // The first use of flush_icache_stub must apply it to itself. aoqi@0: // The StubCodeMark destructor in generate_icache_flush will aoqi@0: // call Assembler::flush, which in turn will call invalidate_range, aoqi@0: // which will in turn call the flush stub. Thus we don't need an aoqi@0: // explicit call to invalidate_range here. This assumption is aoqi@0: // checked in invalidate_range. aoqi@0: } aoqi@0: aoqi@0: void AbstractICache::call_flush_stub(address start, int lines) { aoqi@0: // The business with the magic number is just a little security. aoqi@0: // We cannot call the flush stub when generating the flush stub aoqi@0: // because it isn't there yet. So, the stub also returns its third aoqi@0: // parameter. This is a cheap check that the stub was really executed. aoqi@0: static int magic = 0xbaadbabe; aoqi@0: aoqi@0: int auto_magic = magic; // Make a local copy to avoid race condition aoqi@0: int r = (*_flush_icache_stub)(start, lines, auto_magic); aoqi@0: guarantee(r == auto_magic, "flush stub routine did not execute"); aoqi@0: ++magic; aoqi@0: } aoqi@0: aoqi@0: void AbstractICache::invalidate_word(address addr) { aoqi@0: // Because this is called for instruction patching on the fly, long after aoqi@0: // bootstrapping, we execute the stub directly. Account for a 4-byte word aoqi@0: // spanning two cache lines by computing a start line address by rounding aoqi@0: // addr down to a line_size boundary, and an end line address by adding aoqi@0: // the word size - 1 and rounding the result down to a line_size boundary. aoqi@0: // If we just added word size, we'd mistakenly flush the next cache line aoqi@0: // if the word to be flushed started in the last 4 bytes of the line. aoqi@0: // Doing that would segv if the next line weren't mapped. aoqi@0: aoqi@0: const int word_size_in_bytes = 4; // Always, regardless of platform aoqi@0: aoqi@0: intptr_t start_line = ((intptr_t)addr + 0) & ~(ICache::line_size - 1); aoqi@0: intptr_t end_line = ((intptr_t)addr + word_size_in_bytes - 1) aoqi@0: & ~(ICache::line_size - 1); aoqi@0: (*_flush_icache_stub)((address)start_line, start_line == end_line ? 1 : 2, 0); aoqi@0: } aoqi@0: aoqi@0: void AbstractICache::invalidate_range(address start, int nbytes) { aoqi@0: static bool firstTime = true; aoqi@0: if (firstTime) { aoqi@0: guarantee(start == CAST_FROM_FN_PTR(address, _flush_icache_stub), aoqi@0: "first flush should be for flush stub"); aoqi@0: firstTime = false; aoqi@0: return; aoqi@0: } aoqi@0: if (nbytes == 0) { aoqi@0: return; aoqi@0: } aoqi@0: // Align start address to an icache line boundary and transform aoqi@0: // nbytes to an icache line count. aoqi@0: const uint line_offset = mask_address_bits(start, ICache::line_size-1); aoqi@0: if (line_offset != 0) { aoqi@0: start -= line_offset; aoqi@0: nbytes += line_offset; aoqi@0: } aoqi@0: call_flush_stub(start, round_to(nbytes, ICache::line_size) >> aoqi@0: ICache::log2_line_size); aoqi@0: } aoqi@0: aoqi@0: // For init.cpp aoqi@0: void icache_init() { aoqi@0: ICache::initialize(); aoqi@0: }