From faf1b822d03b726413d77a2b247dfbbf4db7d57e Mon Sep 17 00:00:00 2001 From: Robbin Ehn Date: Sun, 2 Jul 2023 16:15:28 +0000 Subject: [PATCH] 8310656: RISC-V: __builtin___clear_cache can fail silently. Reviewed-by: luhenry, stuefe, fyang --- src/hotspot/cpu/riscv/icache_riscv.cpp | 19 ++++-- .../os_cpu/linux_riscv/riscv_flush_icache.cpp | 67 +++++++++++++++++++ .../os_cpu/linux_riscv/riscv_flush_icache.hpp | 39 +++++++++++ 3 files changed, 120 insertions(+), 5 deletions(-) create mode 100644 src/hotspot/os_cpu/linux_riscv/riscv_flush_icache.cpp create mode 100644 src/hotspot/os_cpu/linux_riscv/riscv_flush_icache.hpp diff --git a/src/hotspot/cpu/riscv/icache_riscv.cpp b/src/hotspot/cpu/riscv/icache_riscv.cpp index a6a5f42b47a..d615dcfb9e9 100644 --- a/src/hotspot/cpu/riscv/icache_riscv.cpp +++ b/src/hotspot/cpu/riscv/icache_riscv.cpp @@ -1,6 +1,7 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2023, Rivos Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +26,8 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" +#include "riscv_flush_icache.hpp" +#include "runtime/java.hpp" #include "runtime/icache.hpp" #define __ _masm-> @@ -33,16 +36,22 @@ static int icache_flush(address addr, int lines, int magic) { // To make a store to instruction memory visible to all RISC-V harts, // the writing hart has to execute a data FENCE before requesting that // all remote RISC-V harts execute a FENCE.I. - // - // No sush assurance is defined at the interface level of the builtin - // method, and so we should make sure it works. + + // We need to make sure stores happens before the I/D cache synchronization. __asm__ volatile("fence rw, rw" : : : "memory"); - __builtin___clear_cache(addr, addr + (lines << ICache::log2_line_size)); + RiscvFlushIcache::flush((uintptr_t)addr, ((uintptr_t)lines) << ICache::log2_line_size); + return magic; } void ICacheStubGenerator::generate_icache_flush(ICache::flush_icache_stub_t* flush_icache_stub) { + // Only riscv_flush_icache is supported as I-cache synchronization. + // We must make sure the VM can execute such without error. + if (!RiscvFlushIcache::test()) { + vm_exit_during_initialization("Unable to synchronize I-cache"); + } + address start = (address)icache_flush; *flush_icache_stub = (ICache::flush_icache_stub_t)start; diff --git a/src/hotspot/os_cpu/linux_riscv/riscv_flush_icache.cpp b/src/hotspot/os_cpu/linux_riscv/riscv_flush_icache.cpp new file mode 100644 index 00000000000..4ca977bd576 --- /dev/null +++ b/src/hotspot/os_cpu/linux_riscv/riscv_flush_icache.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, Rivos Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "logging/log.hpp" +#include "riscv_flush_icache.hpp" +#include "runtime/os.hpp" +#include "runtime/vm_version.hpp" +#include "utilities/debug.hpp" + +#include +#include + +#ifndef NR_riscv_flush_icache +#ifndef NR_arch_specific_syscall +#define NR_arch_specific_syscall 244 +#endif +#define NR_riscv_flush_icache (NR_arch_specific_syscall + 15) +#endif + +#define SYS_RISCV_FLUSH_ICACHE_LOCAL 1UL +#define SYS_RISCV_FLUSH_ICACHE_ALL 0UL + +static long sys_flush_icache(uintptr_t start, uintptr_t end , uintptr_t flags) { + return syscall(NR_riscv_flush_icache, start, end, flags); +} + +bool RiscvFlushIcache::test() { + alignas(64) char memory[64]; + long ret = sys_flush_icache((uintptr_t)&memory[0], + (uintptr_t)&memory[sizeof(memory) - 1], + SYS_RISCV_FLUSH_ICACHE_ALL); + if (ret == 0) { + return true; + } + int err = errno; \ + log_error(os)("Syscall: RISCV_FLUSH_ICACHE not available; error='%s' (errno=%s)", + os::strerror(err), os::errno_name(err)); + return false; +} + +void RiscvFlushIcache::flush(uintptr_t start, uintptr_t end) { + long ret = sys_flush_icache(start, end, SYS_RISCV_FLUSH_ICACHE_ALL); + guarantee_with_errno(ret == 0, "riscv_flush_icache failed"); +} diff --git a/src/hotspot/os_cpu/linux_riscv/riscv_flush_icache.hpp b/src/hotspot/os_cpu/linux_riscv/riscv_flush_icache.hpp new file mode 100644 index 00000000000..34742c173ab --- /dev/null +++ b/src/hotspot/os_cpu/linux_riscv/riscv_flush_icache.hpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, Rivos Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_LINUX_RISCV_FLUSH_ICACHE_LINUX_HPP +#define OS_LINUX_RISCV_FLUSH_ICACHE_LINUX_HPP + +#include "memory/allStatic.hpp" +#include "runtime/vm_version.hpp" +#include "utilities/growableArray.hpp" + +class RiscvFlushIcache: public AllStatic { + public: + static bool test(); + static void flush(uintptr_t start, uintptr_t end); +}; + +#endif // OS_LINUX_RISCV_FLUSH_ICACHE_LINUX_HPP