diff options
| author | 2023-01-25 17:37:06 +0000 | |
|---|---|---|
| committer | 2023-02-14 15:52:29 +0000 | |
| commit | 7923ae2c8fabcb3914f0e229b394dd0b39a8fe46 (patch) | |
| tree | 782e19a5818109c56f69af8916a7daeff684102a | |
| parent | ed98175c8b944229d3ecc1bbdb8ffdfc2d79c3a5 (diff) | |
riscv64: define CPU context.
Also fix a few misleading comments for other architectures.
Test: lunch aosp_riscv64-userdebug && m dist
Co-authored-by: Ulya Trafimovich <skvadrik@google.com>
Change-Id: Iad9cb5559dea8b9463a2b130454044ae361c804e
| -rw-r--r-- | runtime/Android.bp | 6 | ||||
| -rw-r--r-- | runtime/arch/arm/asm_support_arm.S | 2 | ||||
| -rw-r--r-- | runtime/arch/arm64/asm_support_arm64.S | 2 | ||||
| -rw-r--r-- | runtime/arch/context-inl.h | 3 | ||||
| -rw-r--r-- | runtime/arch/riscv64/asm_support_riscv64.S | 23 | ||||
| -rw-r--r-- | runtime/arch/riscv64/context_riscv64.cc | 150 | ||||
| -rw-r--r-- | runtime/arch/riscv64/context_riscv64.h | 100 | ||||
| -rw-r--r-- | runtime/arch/riscv64/quick_entrypoints_riscv64.S | 19 | ||||
| -rw-r--r-- | runtime/arch/x86/asm_support_x86.S | 1 | ||||
| -rw-r--r-- | runtime/arch/x86_64/asm_support_x86_64.S | 1 |
10 files changed, 305 insertions, 2 deletions
diff --git a/runtime/Android.bp b/runtime/Android.bp index c4fb600397..640a5ca60c 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -364,6 +364,12 @@ libart_cc_defaults { "arch/arm64/fault_handler_arm64.cc", ], }, + riscv64: { + srcs: [ + "arch/riscv64/context_riscv64.cc", + "arch/riscv64/quick_entrypoints_riscv64.S", + ], + }, x86: { srcs: [ "interpreter/mterp/nterp.cc", diff --git a/runtime/arch/arm/asm_support_arm.S b/runtime/arch/arm/asm_support_arm.S index 7f1f4708b2..c5bc76ff88 100644 --- a/runtime/arch/arm/asm_support_arm.S +++ b/runtime/arch/arm/asm_support_arm.S @@ -86,7 +86,7 @@ // Prefix the assembly code with 0xFFs, which means there is no method header. .byte 0xFF, 0xFF, 0xFF, 0xFF // Cache alignment for function entry. - // NB: 0xFF because there is a bug in balign where 0x00 creates nop instructions. + // Use 0xFF as the last 4 bytes of alignment stand for OatQuickMethodHeader. .balign \alignment, 0xFF \name: .cfi_startproc diff --git a/runtime/arch/arm64/asm_support_arm64.S b/runtime/arch/arm64/asm_support_arm64.S index 7210262809..3f9e7af9ff 100644 --- a/runtime/arch/arm64/asm_support_arm64.S +++ b/runtime/arch/arm64/asm_support_arm64.S @@ -84,7 +84,7 @@ // Prefix the assembly code with 0xFFs, which means there is no method header. .byte 0xFF, 0xFF, 0xFF, 0xFF // Cache alignment for function entry. - // NB: 0xFF because there is a bug in balign where 0x00 creates nop instructions. + // Use 0xFF as the last 4 bytes of alignment stand for OatQuickMethodHeader. .balign \alignment, 0xFF \name: .cfi_startproc diff --git a/runtime/arch/context-inl.h b/runtime/arch/context-inl.h index cac7c4357d..453432bf34 100644 --- a/runtime/arch/context-inl.h +++ b/runtime/arch/context-inl.h @@ -28,6 +28,9 @@ #elif defined(__aarch64__) #include "arm64/context_arm64.h" #define RUNTIME_CONTEXT_TYPE arm64::Arm64Context +#elif defined(__riscv) +#include "riscv64/context_riscv64.h" +#define RUNTIME_CONTEXT_TYPE riscv64::Riscv64Context #elif defined(__i386__) #include "x86/context_x86.h" #define RUNTIME_CONTEXT_TYPE x86::X86Context diff --git a/runtime/arch/riscv64/asm_support_riscv64.S b/runtime/arch/riscv64/asm_support_riscv64.S index 6a1f8872c8..139c085601 100644 --- a/runtime/arch/riscv64/asm_support_riscv64.S +++ b/runtime/arch/riscv64/asm_support_riscv64.S @@ -24,4 +24,27 @@ // Register holding Thread::Current(). #define xSELF s1 +.macro ENTRY name + .hidden \name // Hide this as a global symbol, so we do not incur plt calls. + .global \name + // ART-compiled functions have OatQuickMethodHeader but assembly functions do not. + // Prefix the assembly code with 0xFFs, which means there is no method header. + .byte 0xFF, 0xFF, 0xFF, 0xFF + // Cache alignment for function entry. + // Use 0xFF as the last 4 bytes of alignment stand for OatQuickMethodHeader. + .balign 16, 0xFF +\name: + .cfi_startproc +.endm + +.macro END name + .cfi_endproc +.endm + +.macro UNDEFINED name + ENTRY \name + unimp + END \name +.endm + #endif // ART_RUNTIME_ARCH_RISCV64_ASM_SUPPORT_RISCV64_S_ diff --git a/runtime/arch/riscv64/context_riscv64.cc b/runtime/arch/riscv64/context_riscv64.cc new file mode 100644 index 0000000000..ddd079b811 --- /dev/null +++ b/runtime/arch/riscv64/context_riscv64.cc @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "context_riscv64.h" + +#include <stdint.h> + +#include "base/bit_utils.h" +#include "base/bit_utils_iterator.h" +#include "quick/quick_method_frame_info.h" +#include "thread-current-inl.h" + +#if __has_feature(hwaddress_sanitizer) +#include <sanitizer/hwasan_interface.h> +#else +#define __hwasan_handle_longjmp(sp) +#endif + +namespace art { +namespace riscv64 { + +static constexpr uint64_t gZero = 0; + +void Riscv64Context::Reset() { + std::fill_n(gprs_, arraysize(gprs_), nullptr); + std::fill_n(fprs_, arraysize(fprs_), nullptr); + gprs_[SP] = &sp_; + gprs_[kPC] = &pc_; + gprs_[A0] = &arg0_; + // Initialize registers with easy to spot debug values. + sp_ = Riscv64Context::kBadGprBase + SP; + pc_ = Riscv64Context::kBadGprBase + kPC; + arg0_ = 0; +} + +void Riscv64Context::FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& frame_info) { + // RA is at top of the frame + DCHECK_NE(frame_info.CoreSpillMask() & ~(1u << RA), 0u); + gprs_[RA] = CalleeSaveAddress(frame, 0, frame_info.FrameSizeInBytes()); + + // Core registers come first, from the highest down to the lowest, with the exception of RA/X1. + int spill_pos = 1; + for (uint32_t core_reg : HighToLowBits(frame_info.CoreSpillMask() & ~(1u << RA))) { + gprs_[core_reg] = CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes()); + ++spill_pos; + } + DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask())); + + // FP registers come second, from the highest down to the lowest. + for (uint32_t fp_reg : HighToLowBits(frame_info.FpSpillMask())) { + fprs_[fp_reg] = CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes()); + ++spill_pos; + } + DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()) + POPCOUNT(frame_info.FpSpillMask())); +} + +void Riscv64Context::SetGPR(uint32_t reg, uintptr_t value) { + DCHECK_LT(reg, arraysize(gprs_)); + DCHECK_NE(reg, static_cast<uint32_t>(Zero)); // Zero/X0 is immutable (hard-wired zero) + DCHECK(IsAccessibleGPR(reg)); + DCHECK_NE(gprs_[reg], &gZero); // Can't overwrite this static value since they are never reset. + *gprs_[reg] = value; +} + +void Riscv64Context::SetFPR(uint32_t reg, uintptr_t value) { + DCHECK_LT(reg, static_cast<uint32_t>(kNumberOfFRegisters)); + DCHECK(IsAccessibleFPR(reg)); + DCHECK_NE(fprs_[reg], &gZero); // Can't overwrite this static value since they are never reset. + *fprs_[reg] = value; +} + +void Riscv64Context::SmashCallerSaves() { + // Temporary registers T0 - T6 and argument registers A0 - A7 are caller-saved. + gprs_[Zero] = const_cast<uint64_t*>(&gZero); // hard-wired zero + gprs_[T0] = nullptr; + gprs_[T1] = nullptr; + gprs_[T2] = nullptr; + gprs_[T3] = nullptr; + gprs_[T4] = nullptr; + gprs_[T5] = nullptr; + gprs_[T6] = nullptr; + gprs_[A0] = const_cast<uint64_t*>(&gZero); // must be 0 because we want a null/zero return value + gprs_[A1] = nullptr; + gprs_[A2] = nullptr; + gprs_[A3] = nullptr; + gprs_[A4] = nullptr; + gprs_[A5] = nullptr; + gprs_[A6] = nullptr; + gprs_[A7] = nullptr; + + // Temporary registers FT0 - FT11 and argument registers FA0 - FA7 are caller-saved. + fprs_[FT0] = nullptr; + fprs_[FT1] = nullptr; + fprs_[FT2] = nullptr; + fprs_[FT3] = nullptr; + fprs_[FT4] = nullptr; + fprs_[FT5] = nullptr; + fprs_[FT6] = nullptr; + fprs_[FT7] = nullptr; + fprs_[FT8] = nullptr; + fprs_[FT9] = nullptr; + fprs_[FT10] = nullptr; + fprs_[FT11] = nullptr; + fprs_[FA0] = nullptr; + fprs_[FA1] = nullptr; + fprs_[FA2] = nullptr; + fprs_[FA3] = nullptr; + fprs_[FA4] = nullptr; + fprs_[FA5] = nullptr; + fprs_[FA6] = nullptr; + fprs_[FA7] = nullptr; +} + +extern "C" NO_RETURN void art_quick_do_long_jump(uint64_t*, uint64_t*); + +void Riscv64Context::DoLongJump() { + uint64_t gprs[arraysize(gprs_)]; + uint64_t fprs[kNumberOfFRegisters]; + + // The long jump routine called below expects to find the value for SP at index 2. + DCHECK_EQ(SP, 2); + + for (size_t i = 0; i < arraysize(gprs_); ++i) { + gprs[i] = gprs_[i] != nullptr ? *gprs_[i] : Riscv64Context::kBadGprBase + i; + } + for (size_t i = 0; i < kNumberOfFRegisters; ++i) { + fprs[i] = fprs_[i] != nullptr ? *fprs_[i] : Riscv64Context::kBadFprBase + i; + } + // Ensure the Thread Register contains the address of the current thread. + DCHECK_EQ(reinterpret_cast<uintptr_t>(Thread::Current()), gprs[TR]); + // Tell HWASan about the new stack top. + __hwasan_handle_longjmp(reinterpret_cast<void*>(gprs[SP])); + art_quick_do_long_jump(gprs, fprs); +} + +} // namespace riscv64 +} // namespace art diff --git a/runtime/arch/riscv64/context_riscv64.h b/runtime/arch/riscv64/context_riscv64.h new file mode 100644 index 0000000000..437d6d9d8e --- /dev/null +++ b/runtime/arch/riscv64/context_riscv64.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_ARCH_RISCV64_CONTEXT_RISCV64_H_ +#define ART_RUNTIME_ARCH_RISCV64_CONTEXT_RISCV64_H_ + +#include <android-base/logging.h> + +#include <cstdlib> + +#include "arch/context.h" +#include "base/macros.h" +#include "registers_riscv64.h" + +namespace art { +namespace riscv64 { + +class Riscv64Context final : public Context { + public: + Riscv64Context() { Reset(); } + + ~Riscv64Context() {} + + void Reset() override; + + void FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& fr) override; + + void SetSP(uintptr_t new_sp) override { SetGPR(SP, new_sp); } + + void SetPC(uintptr_t new_pc) override { SetGPR(kPC, new_pc); } + + void SetNterpDexPC(uintptr_t /*dex_pc_ptr*/) override { + UNREACHABLE(); // Nterp is not supported on RISC-V yet + } + + void SetArg0(uintptr_t new_arg0_value) override { SetGPR(A0, new_arg0_value); } + + bool IsAccessibleGPR(uint32_t reg) override { + DCHECK_LT(reg, arraysize(gprs_)); + return gprs_[reg] != nullptr; + } + + uintptr_t* GetGPRAddress(uint32_t reg) override { + DCHECK_LT(reg, arraysize(gprs_)); + return gprs_[reg]; + } + + uintptr_t GetGPR(uint32_t reg) override { + // Note: PC isn't an available GPR (outside of internals), so don't allow retrieving the value. + DCHECK_LT(reg, static_cast<uint32_t>(kNumberOfXRegisters)); + DCHECK(IsAccessibleGPR(reg)); + return *gprs_[reg]; + } + + void SetGPR(uint32_t reg, uintptr_t value) override; + + bool IsAccessibleFPR(uint32_t reg) override { + DCHECK_LT(reg, static_cast<uint32_t>(kNumberOfFRegisters)); + return fprs_[reg] != nullptr; + } + + uintptr_t GetFPR(uint32_t reg) override { + DCHECK_LT(reg, static_cast<uint32_t>(kNumberOfFRegisters)); + DCHECK(IsAccessibleFPR(reg)); + return *fprs_[reg]; + } + + void SetFPR(uint32_t reg, uintptr_t value) override; + + void SmashCallerSaves() override; + NO_RETURN void DoLongJump() override; + + static constexpr size_t kPC = kNumberOfXRegisters; + + private: + // Pointers to register locations, initialized to null or the specific registers below. We need + // an additional one for the PC. + uintptr_t* gprs_[kNumberOfXRegisters + 1]; + uint64_t* fprs_[kNumberOfFRegisters]; + // Hold values for sp, pc and arg0 if they are not located within a stack frame. + uintptr_t sp_, pc_, arg0_; +}; + +} // namespace riscv64 +} // namespace art + +#endif // ART_RUNTIME_ARCH_RISCV64_CONTEXT_RISCV64_H_ diff --git a/runtime/arch/riscv64/quick_entrypoints_riscv64.S b/runtime/arch/riscv64/quick_entrypoints_riscv64.S new file mode 100644 index 0000000000..87025a9d00 --- /dev/null +++ b/runtime/arch/riscv64/quick_entrypoints_riscv64.S @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "asm_support_riscv64.S" + +UNDEFINED art_quick_do_long_jump diff --git a/runtime/arch/x86/asm_support_x86.S b/runtime/arch/x86/asm_support_x86.S index c42aa67e45..91336c090f 100644 --- a/runtime/arch/x86/asm_support_x86.S +++ b/runtime/arch/x86/asm_support_x86.S @@ -168,6 +168,7 @@ MACRO0(ALIGN_FUNCTION_ENTRY) // Prefix the assembly code with 0xFFs, which means there is no method header. .byte 0xFF, 0xFF, 0xFF, 0xFF // Cache alignment for function entry. + // Use 0xFF as the last 4 bytes of alignment stand for OatQuickMethodHeader. .balign 16, 0xFF END_MACRO diff --git a/runtime/arch/x86_64/asm_support_x86_64.S b/runtime/arch/x86_64/asm_support_x86_64.S index a2aa686879..f21827fa87 100644 --- a/runtime/arch/x86_64/asm_support_x86_64.S +++ b/runtime/arch/x86_64/asm_support_x86_64.S @@ -174,6 +174,7 @@ MACRO0(ALIGN_FUNCTION_ENTRY) // Prefix the assembly code with 0xFFs, which means there is no method header. .byte 0xFF, 0xFF, 0xFF, 0xFF // Cache alignment for function entry. + // Use 0xFF as the last 4 bytes of alignment stand for OatQuickMethodHeader. .balign 16, 0xFF END_MACRO |