8277204: Implement PAC-RET branch protection on Linux/AArch64
Reviewed-by: erikj, ihse, adinn, ngasson
This commit is contained in:
parent
abc0ce11df
commit
6fab8a2d6a
@ -135,6 +135,14 @@ space is required.
|
||||
If you do not have access to sufficiently powerful hardware, it is also
|
||||
possible to use [cross-compiling](#cross-compiling).
|
||||
|
||||
#### Branch Protection
|
||||
|
||||
In order to use Branch Protection features in the VM, `--enable-branch-protection`
|
||||
must be used. This option requires C++ compiler support (GCC 9.1.0+ or Clang
|
||||
10+). The resulting build can be run on both machines with and without support
|
||||
for branch protection in hardware. Branch Protection is only supported for
|
||||
Linux targets.
|
||||
|
||||
### Building on 32-bit arm
|
||||
|
||||
This is not recommended. Instead, see the section on [Cross-compiling](
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2011, 2022, Oracle and/or its affiliates. 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
|
||||
@ -803,17 +803,19 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP],
|
||||
fi
|
||||
AC_SUBST(FILE_MACRO_CFLAGS)
|
||||
|
||||
FLAGS_SETUP_BRANCH_PROTECTION
|
||||
|
||||
# EXPORT to API
|
||||
CFLAGS_JVM_COMMON="$ALWAYS_CFLAGS_JVM $ALWAYS_DEFINES_JVM \
|
||||
$TOOLCHAIN_CFLAGS_JVM ${$1_TOOLCHAIN_CFLAGS_JVM} \
|
||||
$OS_CFLAGS $OS_CFLAGS_JVM $CFLAGS_OS_DEF_JVM $DEBUG_CFLAGS_JVM \
|
||||
$WARNING_CFLAGS $WARNING_CFLAGS_JVM $JVM_PICFLAG $FILE_MACRO_CFLAGS \
|
||||
$REPRODUCIBLE_CFLAGS"
|
||||
$REPRODUCIBLE_CFLAGS $BRANCH_PROTECTION_CFLAGS"
|
||||
|
||||
CFLAGS_JDK_COMMON="$ALWAYS_CFLAGS_JDK $ALWAYS_DEFINES_JDK $TOOLCHAIN_CFLAGS_JDK \
|
||||
$OS_CFLAGS $CFLAGS_OS_DEF_JDK $DEBUG_CFLAGS_JDK $DEBUG_OPTIONS_FLAGS_JDK \
|
||||
$WARNING_CFLAGS $WARNING_CFLAGS_JDK $DEBUG_SYMBOLS_CFLAGS_JDK \
|
||||
$FILE_MACRO_CFLAGS $REPRODUCIBLE_CFLAGS"
|
||||
$FILE_MACRO_CFLAGS $REPRODUCIBLE_CFLAGS $BRANCH_PROTECTION_CFLAGS"
|
||||
|
||||
# Use ${$2EXTRA_CFLAGS} to block EXTRA_CFLAGS to be added to build flags.
|
||||
# (Currently we don't have any OPENJDK_BUILD_EXTRA_CFLAGS, but that might
|
||||
@ -879,3 +881,24 @@ AC_DEFUN([FLAGS_SETUP_GCC6_COMPILER_FLAGS],
|
||||
PREFIX: $2, IF_FALSE: [NO_LIFETIME_DSE_CFLAG=""])
|
||||
$1_GCC6_CFLAGS="${NO_DELETE_NULL_POINTER_CHECKS_CFLAG} ${NO_LIFETIME_DSE_CFLAG}"
|
||||
])
|
||||
|
||||
AC_DEFUN_ONCE([FLAGS_SETUP_BRANCH_PROTECTION],
|
||||
[
|
||||
# Is branch protection available?
|
||||
BRANCH_PROTECTION_AVAILABLE=false
|
||||
BRANCH_PROTECTION_FLAG="-mbranch-protection=standard"
|
||||
|
||||
if test "x$OPENJDK_TARGET_CPU" = xaarch64; then
|
||||
if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
|
||||
FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [${BRANCH_PROTECTION_FLAG}],
|
||||
IF_TRUE: [BRANCH_PROTECTION_AVAILABLE=true])
|
||||
fi
|
||||
fi
|
||||
|
||||
BRANCH_PROTECTION_CFLAGS=""
|
||||
UTIL_ARG_ENABLE(NAME: branch-protection, DEFAULT: false,
|
||||
RESULT: USE_BRANCH_PROTECTION, AVAILABLE: $BRANCH_PROTECTION_AVAILABLE,
|
||||
DESC: [enable branch protection when compiling C/C++],
|
||||
IF_ENABLED: [ BRANCH_PROTECTION_CFLAGS=${BRANCH_PROTECTION_FLAG}])
|
||||
AC_SUBST(BRANCH_PROTECTION_CFLAGS)
|
||||
])
|
||||
|
@ -407,6 +407,7 @@ LIBFFI_CFLAGS:=@LIBFFI_CFLAGS@
|
||||
ENABLE_LIBFFI_BUNDLING:=@ENABLE_LIBFFI_BUNDLING@
|
||||
LIBFFI_LIB_FILE:=@LIBFFI_LIB_FILE@
|
||||
FILE_MACRO_CFLAGS := @FILE_MACRO_CFLAGS@
|
||||
BRANCH_PROTECTION_CFLAGS := @BRANCH_PROTECTION_CFLAGS@
|
||||
|
||||
STATIC_LIBS_CFLAGS := @STATIC_LIBS_CFLAGS@
|
||||
|
||||
|
@ -1853,6 +1853,10 @@ void MachPrologNode::format(PhaseRegAlloc *ra_, outputStream *st) const {
|
||||
if (C->output()->need_stack_bang(framesize))
|
||||
st->print("# stack bang size=%d\n\t", framesize);
|
||||
|
||||
if (VM_Version::use_rop_protection()) {
|
||||
st->print("ldr zr, [lr]\n\t");
|
||||
st->print("pacia lr, rfp\n\t");
|
||||
}
|
||||
if (framesize < ((1 << 9) + 2 * wordSize)) {
|
||||
st->print("sub sp, sp, #%d\n\t", framesize);
|
||||
st->print("stp rfp, lr, [sp, #%d]", framesize - 2 * wordSize);
|
||||
@ -1961,6 +1965,10 @@ void MachEpilogNode::format(PhaseRegAlloc *ra_, outputStream *st) const {
|
||||
st->print("add sp, sp, rscratch1\n\t");
|
||||
st->print("ldp lr, rfp, [sp],#%d\n\t", (2 * wordSize));
|
||||
}
|
||||
if (VM_Version::use_rop_protection()) {
|
||||
st->print("autia lr, rfp\n\t");
|
||||
st->print("ldr zr, [lr]\n\t");
|
||||
}
|
||||
|
||||
if (do_polling() && C->is_method_compilation()) {
|
||||
st->print("# test polling word\n\t");
|
||||
|
@ -987,33 +987,35 @@ public:
|
||||
rf(rt, 0);
|
||||
}
|
||||
|
||||
void hint(int imm) {
|
||||
system(0b00, 0b011, 0b0010, 0b0000, imm);
|
||||
// Hint instructions
|
||||
|
||||
#define INSN(NAME, crm, op2) \
|
||||
void NAME() { \
|
||||
system(0b00, 0b011, 0b0010, crm, op2); \
|
||||
}
|
||||
|
||||
void nop() {
|
||||
hint(0);
|
||||
}
|
||||
INSN(nop, 0b000, 0b0000);
|
||||
INSN(yield, 0b000, 0b0001);
|
||||
INSN(wfe, 0b000, 0b0010);
|
||||
INSN(wfi, 0b000, 0b0011);
|
||||
INSN(sev, 0b000, 0b0100);
|
||||
INSN(sevl, 0b000, 0b0101);
|
||||
|
||||
void yield() {
|
||||
hint(1);
|
||||
}
|
||||
INSN(autia1716, 0b0001, 0b100);
|
||||
INSN(autiasp, 0b0011, 0b101);
|
||||
INSN(autiaz, 0b0011, 0b100);
|
||||
INSN(autib1716, 0b0001, 0b110);
|
||||
INSN(autibsp, 0b0011, 0b111);
|
||||
INSN(autibz, 0b0011, 0b110);
|
||||
INSN(pacia1716, 0b0001, 0b000);
|
||||
INSN(paciasp, 0b0011, 0b001);
|
||||
INSN(paciaz, 0b0011, 0b000);
|
||||
INSN(pacib1716, 0b0001, 0b010);
|
||||
INSN(pacibsp, 0b0011, 0b011);
|
||||
INSN(pacibz, 0b0011, 0b010);
|
||||
INSN(xpaclri, 0b0000, 0b111);
|
||||
|
||||
void wfe() {
|
||||
hint(2);
|
||||
}
|
||||
|
||||
void wfi() {
|
||||
hint(3);
|
||||
}
|
||||
|
||||
void sev() {
|
||||
hint(4);
|
||||
}
|
||||
|
||||
void sevl() {
|
||||
hint(5);
|
||||
}
|
||||
#undef INSN
|
||||
|
||||
// we only provide mrs and msr for the special purpose system
|
||||
// registers where op1 (instr[20:19]) == 11 and, (currently) only
|
||||
@ -1099,18 +1101,21 @@ public:
|
||||
}
|
||||
|
||||
// Unconditional branch (register)
|
||||
void branch_reg(Register R, int opc) {
|
||||
|
||||
void branch_reg(int OP, int A, int M, Register RN, Register RM) {
|
||||
starti;
|
||||
f(0b1101011, 31, 25);
|
||||
f(opc, 24, 21);
|
||||
f(0b11111000000, 20, 10);
|
||||
rf(R, 5);
|
||||
f(0b00000, 4, 0);
|
||||
f(OP, 24, 21);
|
||||
f(0b111110000, 20, 12);
|
||||
f(A, 11, 11);
|
||||
f(M, 10, 10);
|
||||
rf(RN, 5);
|
||||
rf(RM, 0);
|
||||
}
|
||||
|
||||
#define INSN(NAME, opc) \
|
||||
void NAME(Register R) { \
|
||||
branch_reg(R, opc); \
|
||||
#define INSN(NAME, opc) \
|
||||
void NAME(Register RN) { \
|
||||
branch_reg(opc, 0, 0, RN, r0); \
|
||||
}
|
||||
|
||||
INSN(br, 0b0000);
|
||||
@ -1121,14 +1126,48 @@ public:
|
||||
|
||||
#undef INSN
|
||||
|
||||
#define INSN(NAME, opc) \
|
||||
void NAME() { \
|
||||
branch_reg(dummy_reg, opc); \
|
||||
#define INSN(NAME, opc) \
|
||||
void NAME() { \
|
||||
branch_reg(opc, 0, 0, dummy_reg, r0); \
|
||||
}
|
||||
|
||||
INSN(eret, 0b0100);
|
||||
INSN(drps, 0b0101);
|
||||
|
||||
#undef INSN
|
||||
|
||||
#define INSN(NAME, M) \
|
||||
void NAME() { \
|
||||
branch_reg(0b0010, 1, M, dummy_reg, dummy_reg); \
|
||||
}
|
||||
|
||||
INSN(retaa, 0);
|
||||
INSN(retab, 1);
|
||||
|
||||
#undef INSN
|
||||
|
||||
#define INSN(NAME, OP, M) \
|
||||
void NAME(Register rn) { \
|
||||
branch_reg(OP, 1, M, rn, dummy_reg); \
|
||||
}
|
||||
|
||||
INSN(braaz, 0b0000, 0);
|
||||
INSN(brabz, 0b0000, 1);
|
||||
INSN(blraaz, 0b0001, 0);
|
||||
INSN(blrabz, 0b0001, 1);
|
||||
|
||||
#undef INSN
|
||||
|
||||
#define INSN(NAME, OP, M) \
|
||||
void NAME(Register rn, Register rm) { \
|
||||
branch_reg(OP, 1, M, rn, rm); \
|
||||
}
|
||||
|
||||
INSN(braa, 0b1000, 0);
|
||||
INSN(brab, 0b1000, 1);
|
||||
INSN(blraa, 0b1001, 0);
|
||||
INSN(blrab, 0b1001, 1);
|
||||
|
||||
#undef INSN
|
||||
|
||||
// Load/store exclusive
|
||||
@ -1792,6 +1831,37 @@ void mvnw(Register Rd, Register Rm,
|
||||
INSN(clz, 0b110, 0b00000, 0b00100);
|
||||
INSN(cls, 0b110, 0b00000, 0b00101);
|
||||
|
||||
// PAC instructions
|
||||
INSN(pacia, 0b110, 0b00001, 0b00000);
|
||||
INSN(pacib, 0b110, 0b00001, 0b00001);
|
||||
INSN(pacda, 0b110, 0b00001, 0b00010);
|
||||
INSN(pacdb, 0b110, 0b00001, 0b00011);
|
||||
INSN(autia, 0b110, 0b00001, 0b00100);
|
||||
INSN(autib, 0b110, 0b00001, 0b00101);
|
||||
INSN(autda, 0b110, 0b00001, 0b00110);
|
||||
INSN(autdb, 0b110, 0b00001, 0b00111);
|
||||
|
||||
#undef INSN
|
||||
|
||||
#define INSN(NAME, op29, opcode2, opcode) \
|
||||
void NAME(Register Rd) { \
|
||||
starti; \
|
||||
f(opcode2, 20, 16); \
|
||||
data_processing(current_insn, op29, opcode, Rd, dummy_reg); \
|
||||
}
|
||||
|
||||
// PAC instructions (with zero modifier)
|
||||
INSN(paciza, 0b110, 0b00001, 0b01000);
|
||||
INSN(pacizb, 0b110, 0b00001, 0b01001);
|
||||
INSN(pacdza, 0b110, 0b00001, 0b01010);
|
||||
INSN(pacdzb, 0b110, 0b00001, 0b01011);
|
||||
INSN(autiza, 0b110, 0b00001, 0b01100);
|
||||
INSN(autizb, 0b110, 0b00001, 0b01101);
|
||||
INSN(autdza, 0b110, 0b00001, 0b01110);
|
||||
INSN(autdzb, 0b110, 0b00001, 0b01111);
|
||||
INSN(xpaci, 0b110, 0b00001, 0b10000);
|
||||
INSN(xpacd, 0b110, 0b00001, 0b10001);
|
||||
|
||||
#undef INSN
|
||||
|
||||
// (2 sources)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -385,6 +385,7 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
|
||||
|
||||
// load issuing PC (the return address for this stub) into r3
|
||||
__ ldr(exception_pc, Address(rfp, 1*BytesPerWord));
|
||||
__ authenticate_return_address(exception_pc, rscratch1);
|
||||
|
||||
// make sure that the vm_results are cleared (may be unnecessary)
|
||||
__ str(zr, Address(rthread, JavaThread::vm_result_offset()));
|
||||
@ -433,6 +434,7 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
|
||||
__ str(exception_pc, Address(rthread, JavaThread::exception_pc_offset()));
|
||||
|
||||
// patch throwing pc into return address (has bci & oop map)
|
||||
__ protect_return_address(exception_pc, rscratch1);
|
||||
__ str(exception_pc, Address(rfp, 1*BytesPerWord));
|
||||
|
||||
// compute the exception handler.
|
||||
@ -448,6 +450,7 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
|
||||
__ invalidate_registers(false, true, true, true, true, true);
|
||||
|
||||
// patch the return address, this stub will directly return to the exception handler
|
||||
__ protect_return_address(r0, rscratch1);
|
||||
__ str(r0, Address(rfp, 1*BytesPerWord));
|
||||
|
||||
switch (id) {
|
||||
@ -496,10 +499,12 @@ void Runtime1::generate_unwind_exception(StubAssembler *sasm) {
|
||||
// Save our return address because
|
||||
// exception_handler_for_return_address will destroy it. We also
|
||||
// save exception_oop
|
||||
__ mov(r3, lr);
|
||||
__ protect_return_address();
|
||||
__ stp(lr, exception_oop, Address(__ pre(sp, -2 * wordSize)));
|
||||
|
||||
// search the exception handler address of the caller (using the return address)
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), rthread, lr);
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), rthread, r3);
|
||||
// r0: exception handler address of the caller
|
||||
|
||||
// Only R0 is valid at this time; all other registers have been
|
||||
@ -512,6 +517,7 @@ void Runtime1::generate_unwind_exception(StubAssembler *sasm) {
|
||||
// get throwing pc (= return address).
|
||||
// lr has been destroyed by the call
|
||||
__ ldp(lr, exception_oop, Address(__ post(sp, 2 * wordSize)));
|
||||
__ authenticate_return_address();
|
||||
__ mov(r3, lr);
|
||||
|
||||
__ verify_not_null_oop(exception_oop);
|
||||
|
@ -128,13 +128,13 @@ bool frame::safe_for_sender(JavaThread *thread) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sender_pc = (address) this->fp()[return_addr_offset];
|
||||
// for interpreted frames, the value below is the sender "raw" sp,
|
||||
// which can be different from the sender unextended sp (the sp seen
|
||||
// by the sender) because of current frame local variables
|
||||
sender_sp = (intptr_t*) addr_at(sender_sp_offset);
|
||||
sender_unextended_sp = (intptr_t*) this->fp()[interpreter_frame_sender_sp_offset];
|
||||
saved_fp = (intptr_t*) this->fp()[link_offset];
|
||||
sender_pc = pauth_strip_verifiable((address) this->fp()[return_addr_offset], (address)saved_fp);
|
||||
|
||||
} else {
|
||||
// must be some sort of compiled/runtime frame
|
||||
@ -151,9 +151,9 @@ bool frame::safe_for_sender(JavaThread *thread) {
|
||||
return false;
|
||||
}
|
||||
sender_unextended_sp = sender_sp;
|
||||
sender_pc = (address) *(sender_sp-1);
|
||||
// Note: frame::sender_sp_offset is only valid for compiled frame
|
||||
saved_fp = (intptr_t*) *(sender_sp - frame::sender_sp_offset);
|
||||
sender_pc = pauth_strip_verifiable((address) *(sender_sp-1), (address)saved_fp);
|
||||
}
|
||||
|
||||
|
||||
@ -268,17 +268,22 @@ bool frame::safe_for_sender(JavaThread *thread) {
|
||||
void frame::patch_pc(Thread* thread, address pc) {
|
||||
assert(_cb == CodeCache::find_blob(pc), "unexpected pc");
|
||||
address* pc_addr = &(((address*) sp())[-1]);
|
||||
address signing_sp = (((address*) sp())[-2]);
|
||||
address signed_pc = pauth_sign_return_address(pc, (address)signing_sp);
|
||||
address pc_old = pauth_strip_verifiable(*pc_addr, (address)signing_sp);
|
||||
if (TracePcPatching) {
|
||||
tty->print_cr("patch_pc at address " INTPTR_FORMAT " [" INTPTR_FORMAT " -> " INTPTR_FORMAT "]",
|
||||
p2i(pc_addr), p2i(*pc_addr), p2i(pc));
|
||||
tty->print("patch_pc at address " INTPTR_FORMAT " [" INTPTR_FORMAT " -> " INTPTR_FORMAT "]",
|
||||
p2i(pc_addr), p2i(pc_old), p2i(pc));
|
||||
if (VM_Version::use_rop_protection()) {
|
||||
tty->print(" [signed " INTPTR_FORMAT " -> " INTPTR_FORMAT "]", p2i(*pc_addr), p2i(signed_pc));
|
||||
}
|
||||
tty->print_cr("");
|
||||
}
|
||||
|
||||
// Only generated code frames should be patched, therefore the return address will not be signed.
|
||||
assert(pauth_ptr_is_raw(*pc_addr), "cannot be signed");
|
||||
// Either the return address is the original one or we are going to
|
||||
// patch in the same address that's already there.
|
||||
assert(_pc == *pc_addr || pc == *pc_addr, "must be");
|
||||
*pc_addr = pc;
|
||||
assert(_pc == pc_old || pc == pc_old, "must be");
|
||||
*pc_addr = signed_pc;
|
||||
address original_pc = CompiledMethod::get_deopt_original_pc(this);
|
||||
if (original_pc != NULL) {
|
||||
assert(original_pc == _pc, "expected original PC to be stored before patching");
|
||||
@ -455,12 +460,12 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
|
||||
}
|
||||
#endif // COMPILER2_OR_JVMCI
|
||||
|
||||
// Use the raw version of pc - the interpreter should not have signed it.
|
||||
// For ROP protection, Interpreter will have signed the sender_pc, but there is no requirement to authenticate it here.
|
||||
address sender_pc = pauth_strip_verifiable(sender_pc_maybe_signed(), (address)link());
|
||||
|
||||
return frame(sender_sp, unextended_sp, link(), sender_pc_maybe_signed());
|
||||
return frame(sender_sp, unextended_sp, link(), sender_pc);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// frame::sender_for_compiled_frame
|
||||
frame frame::sender_for_compiled_frame(RegisterMap* map) const {
|
||||
@ -482,7 +487,9 @@ frame frame::sender_for_compiled_frame(RegisterMap* map) const {
|
||||
intptr_t* unextended_sp = l_sender_sp;
|
||||
|
||||
// the return_address is always the word on the stack
|
||||
address sender_pc = (address) *(l_sender_sp-1);
|
||||
|
||||
// For ROP protection, C1/C2 will have signed the sender_pc, but there is no requirement to authenticate it here.
|
||||
address sender_pc = pauth_strip_verifiable((address) *(l_sender_sp-1), (address) *(l_sender_sp-2));
|
||||
|
||||
intptr_t** saved_fp_addr = (intptr_t**) (l_sender_sp - frame::sender_sp_offset);
|
||||
|
||||
@ -530,6 +537,9 @@ frame frame::sender_raw(RegisterMap* map) const {
|
||||
// Must be native-compiled frame, i.e. the marshaling code for native
|
||||
// methods that exists in the core system.
|
||||
|
||||
// Native code may or may not have signed the return address, we have no way to be sure or what
|
||||
// signing methods they used. Instead, just ensure the stripped value is used.
|
||||
|
||||
return frame(sender_sp(), link(), sender_pc());
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. 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
|
||||
@ -271,7 +271,7 @@ void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorator
|
||||
ModRefBarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread);
|
||||
if (on_oop && on_reference) {
|
||||
// LR is live. It must be saved around calls.
|
||||
__ enter(); // barrier may call runtime
|
||||
__ enter(/*strip_ret_addr*/true); // barrier may call runtime
|
||||
// Generate the G1 pre-barrier code to log the value of
|
||||
// the referent field in an SATB buffer.
|
||||
g1_write_barrier_pre(masm /* masm */,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2021, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (c) 2018, 2022, Red Hat, 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
|
||||
@ -237,7 +237,7 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm,
|
||||
bool is_narrow = UseCompressedOops && !is_native;
|
||||
|
||||
Label heap_stable, not_cset;
|
||||
__ enter();
|
||||
__ enter(/*strip_ret_addr*/true);
|
||||
Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
|
||||
__ ldrb(rscratch2, gc_state);
|
||||
|
||||
@ -359,7 +359,7 @@ void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet d
|
||||
|
||||
// 3: apply keep-alive barrier if needed
|
||||
if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) {
|
||||
__ enter();
|
||||
__ enter(/*strip_ret_addr*/true);
|
||||
__ push_call_clobbered_registers();
|
||||
satb_write_barrier_pre(masm /* masm */,
|
||||
noreg /* obj */,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. 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
|
||||
@ -78,7 +78,7 @@ void ZBarrierSetAssembler::load_at(MacroAssembler* masm,
|
||||
__ tst(dst, rscratch1);
|
||||
__ br(Assembler::EQ, done);
|
||||
|
||||
__ enter();
|
||||
__ enter(/*strip_ret_addr*/true);
|
||||
|
||||
__ push_call_clobbered_registers_except(RegSet::of(dst));
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2019, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -118,7 +118,9 @@ define_pd_global(intx, InlineSmallCode, 1000);
|
||||
product(uint, OnSpinWaitInstCount, 1, DIAGNOSTIC, \
|
||||
"The number of OnSpinWaitInst instructions to generate." \
|
||||
"It cannot be used with OnSpinWaitInst=none.") \
|
||||
range(1, 99)
|
||||
range(1, 99) \
|
||||
product(ccstr, UseBranchProtection, "none", \
|
||||
"Branch Protection to use: none, standard, pac-ret") \
|
||||
|
||||
// end of ARCH_FLAGS
|
||||
|
||||
|
@ -1137,6 +1137,8 @@ void MacroAssembler::verify_oop(Register reg, const char* s) {
|
||||
}
|
||||
BLOCK_COMMENT("verify_oop {");
|
||||
|
||||
strip_return_address(); // This might happen within a stack frame.
|
||||
protect_return_address();
|
||||
stp(r0, rscratch1, Address(pre(sp, -2 * wordSize)));
|
||||
stp(rscratch2, lr, Address(pre(sp, -2 * wordSize)));
|
||||
|
||||
@ -1150,6 +1152,7 @@ void MacroAssembler::verify_oop(Register reg, const char* s) {
|
||||
|
||||
ldp(rscratch2, lr, Address(post(sp, 2 * wordSize)));
|
||||
ldp(r0, rscratch1, Address(post(sp, 2 * wordSize)));
|
||||
authenticate_return_address();
|
||||
|
||||
BLOCK_COMMENT("} verify_oop");
|
||||
}
|
||||
@ -1166,6 +1169,8 @@ void MacroAssembler::verify_oop_addr(Address addr, const char* s) {
|
||||
}
|
||||
BLOCK_COMMENT("verify_oop_addr {");
|
||||
|
||||
strip_return_address(); // This might happen within a stack frame.
|
||||
protect_return_address();
|
||||
stp(r0, rscratch1, Address(pre(sp, -2 * wordSize)));
|
||||
stp(rscratch2, lr, Address(pre(sp, -2 * wordSize)));
|
||||
|
||||
@ -1186,6 +1191,7 @@ void MacroAssembler::verify_oop_addr(Address addr, const char* s) {
|
||||
|
||||
ldp(rscratch2, lr, Address(post(sp, 2 * wordSize)));
|
||||
ldp(r0, rscratch1, Address(post(sp, 2 * wordSize)));
|
||||
authenticate_return_address();
|
||||
|
||||
BLOCK_COMMENT("} verify_oop_addr");
|
||||
}
|
||||
@ -4296,6 +4302,7 @@ void MacroAssembler::load_byte_map_base(Register reg) {
|
||||
void MacroAssembler::build_frame(int framesize) {
|
||||
assert(framesize >= 2 * wordSize, "framesize must include space for FP/LR");
|
||||
assert(framesize % (2*wordSize) == 0, "must preserve 2*wordSize alignment");
|
||||
protect_return_address();
|
||||
if (framesize < ((1 << 9) + 2 * wordSize)) {
|
||||
sub(sp, sp, framesize);
|
||||
stp(rfp, lr, Address(sp, framesize - 2 * wordSize));
|
||||
@ -4328,6 +4335,7 @@ void MacroAssembler::remove_frame(int framesize) {
|
||||
}
|
||||
ldp(rfp, lr, Address(post(sp, 2 * wordSize)));
|
||||
}
|
||||
authenticate_return_address();
|
||||
}
|
||||
|
||||
|
||||
@ -5169,6 +5177,7 @@ void MacroAssembler::get_thread(Register dst) {
|
||||
LINUX_ONLY(RegSet::range(r0, r1) + lr - dst)
|
||||
NOT_LINUX (RegSet::range(r0, r17) + lr - dst);
|
||||
|
||||
protect_return_address();
|
||||
push(saved_regs, sp);
|
||||
|
||||
mov(lr, CAST_FROM_FN_PTR(address, JavaThread::aarch64_get_thread_helper));
|
||||
@ -5178,6 +5187,7 @@ void MacroAssembler::get_thread(Register dst) {
|
||||
}
|
||||
|
||||
pop(saved_regs, sp);
|
||||
authenticate_return_address();
|
||||
}
|
||||
|
||||
void MacroAssembler::cache_wb(Address line) {
|
||||
@ -5269,3 +5279,102 @@ void MacroAssembler::spin_wait() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stack frame creation/removal
|
||||
|
||||
void MacroAssembler::enter(bool strip_ret_addr) {
|
||||
if (strip_ret_addr) {
|
||||
// Addresses can only be signed once. If there are multiple nested frames being created
|
||||
// in the same function, then the return address needs stripping first.
|
||||
strip_return_address();
|
||||
}
|
||||
protect_return_address();
|
||||
stp(rfp, lr, Address(pre(sp, -2 * wordSize)));
|
||||
mov(rfp, sp);
|
||||
}
|
||||
|
||||
void MacroAssembler::leave() {
|
||||
mov(sp, rfp);
|
||||
ldp(rfp, lr, Address(post(sp, 2 * wordSize)));
|
||||
authenticate_return_address();
|
||||
}
|
||||
|
||||
// ROP Protection
|
||||
// Use the AArch64 PAC feature to add ROP protection for generated code. Use whenever creating/
|
||||
// destroying stack frames or whenever directly loading/storing the LR to memory.
|
||||
// If ROP protection is not set then these functions are no-ops.
|
||||
// For more details on PAC see pauth_aarch64.hpp.
|
||||
|
||||
// Sign the LR. Use during construction of a stack frame, before storing the LR to memory.
|
||||
// Uses the FP as the modifier.
|
||||
//
|
||||
void MacroAssembler::protect_return_address() {
|
||||
if (VM_Version::use_rop_protection()) {
|
||||
check_return_address();
|
||||
// The standard convention for C code is to use paciasp, which uses SP as the modifier. This
|
||||
// works because in C code, FP and SP match on function entry. In the JDK, SP and FP may not
|
||||
// match, so instead explicitly use the FP.
|
||||
pacia(lr, rfp);
|
||||
}
|
||||
}
|
||||
|
||||
// Sign the return value in the given register. Use before updating the LR in the exisiting stack
|
||||
// frame for the current function.
|
||||
// Uses the FP from the start of the function as the modifier - which is stored at the address of
|
||||
// the current FP.
|
||||
//
|
||||
void MacroAssembler::protect_return_address(Register return_reg, Register temp_reg) {
|
||||
if (VM_Version::use_rop_protection()) {
|
||||
assert(PreserveFramePointer, "PreserveFramePointer must be set for ROP protection");
|
||||
check_return_address(return_reg);
|
||||
ldr(temp_reg, Address(rfp));
|
||||
pacia(return_reg, temp_reg);
|
||||
}
|
||||
}
|
||||
|
||||
// Authenticate the LR. Use before function return, after restoring FP and loading LR from memory.
|
||||
//
|
||||
void MacroAssembler::authenticate_return_address(Register return_reg) {
|
||||
if (VM_Version::use_rop_protection()) {
|
||||
autia(return_reg, rfp);
|
||||
check_return_address(return_reg);
|
||||
}
|
||||
}
|
||||
|
||||
// Authenticate the return value in the given register. Use before updating the LR in the exisiting
|
||||
// stack frame for the current function.
|
||||
// Uses the FP from the start of the function as the modifier - which is stored at the address of
|
||||
// the current FP.
|
||||
//
|
||||
void MacroAssembler::authenticate_return_address(Register return_reg, Register temp_reg) {
|
||||
if (VM_Version::use_rop_protection()) {
|
||||
assert(PreserveFramePointer, "PreserveFramePointer must be set for ROP protection");
|
||||
ldr(temp_reg, Address(rfp));
|
||||
autia(return_reg, temp_reg);
|
||||
check_return_address(return_reg);
|
||||
}
|
||||
}
|
||||
|
||||
// Strip any PAC data from LR without performing any authentication. Use with caution - only if
|
||||
// there is no guaranteed way of authenticating the LR.
|
||||
//
|
||||
void MacroAssembler::strip_return_address() {
|
||||
if (VM_Version::use_rop_protection()) {
|
||||
xpaclri();
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
// PAC failures can be difficult to debug. After an authentication failure, a segfault will only
|
||||
// occur when the pointer is used - ie when the program returns to the invalid LR. At this point
|
||||
// it is difficult to debug back to the callee function.
|
||||
// This function simply loads from the address in the given register.
|
||||
// Use directly after authentication to catch authentication failures.
|
||||
// Also use before signing to check that the pointer is valid and hasn't already been signed.
|
||||
//
|
||||
void MacroAssembler::check_return_address(Register return_reg) {
|
||||
if (VM_Version::use_rop_protection()) {
|
||||
ldr(zr, Address(return_reg));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -688,16 +688,16 @@ public:
|
||||
void align(int modulus);
|
||||
|
||||
// Stack frame creation/removal
|
||||
void enter()
|
||||
{
|
||||
stp(rfp, lr, Address(pre(sp, -2 * wordSize)));
|
||||
mov(rfp, sp);
|
||||
}
|
||||
void leave()
|
||||
{
|
||||
mov(sp, rfp);
|
||||
ldp(rfp, lr, Address(post(sp, 2 * wordSize)));
|
||||
}
|
||||
void enter(bool strip_ret_addr = false);
|
||||
void leave();
|
||||
|
||||
// ROP Protection
|
||||
void protect_return_address();
|
||||
void protect_return_address(Register return_reg, Register temp_reg);
|
||||
void authenticate_return_address(Register return_reg = lr);
|
||||
void authenticate_return_address(Register return_reg, Register temp_reg);
|
||||
void strip_return_address();
|
||||
void check_return_address(Register return_reg=lr) PRODUCT_RETURN;
|
||||
|
||||
// Support for getting the JavaThread pointer (i.e.; a reference to thread-local information)
|
||||
// The pointer will be loaded into the thread register.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Arm Limited. All rights reserved.
|
||||
* Copyright (c) 2021, 2022, Arm Limited. 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
|
||||
@ -27,9 +27,58 @@
|
||||
|
||||
#include OS_CPU_HEADER_INLINE(pauth)
|
||||
|
||||
// Support for ROP Protection in VM code.
|
||||
// This is provided via the AArch64 PAC feature.
|
||||
// For more details on PAC see The Arm ARM, section "Pointer authentication in AArch64 state".
|
||||
//
|
||||
// PAC provides a method to sign and authenticate pointer values. Signing combines the register
|
||||
// being signed, an additional modifier and a per-process secret key, writing the result to unused
|
||||
// high bits of the signed register. Once signed a register must be authenticated or stripped
|
||||
// before it can be used.
|
||||
// Authentication reverses the signing operation, clearing the high bits. If the signed register
|
||||
// or modifier has changed then authentication will fail and invalid data will be written to the
|
||||
// high bits and the next time the pointer is used a segfault will be raised.
|
||||
//
|
||||
// Assume a malicious attacker is able to edit the stack via an exploit. Control flow can be
|
||||
// changed by re-writing the return values stored on the stack. ROP protection prevents this by
|
||||
// signing return addresses before saving them on the stack, then authenticating when they are
|
||||
// loaded back. The scope of this protection is per function (a value is signed and authenticated
|
||||
// by the same function), therefore it is possible for different functions within the same
|
||||
// program to use different signing methods.
|
||||
//
|
||||
// The VM and native code is protected by compiling with the GCC AArch64 branch protection flag.
|
||||
//
|
||||
// All generated code is protected via the ROP functions provided in macroAssembler.
|
||||
//
|
||||
// In addition, the VM needs to be aware of PAC whenever viewing or editing the stack. Functions
|
||||
// are provided here and in the OS specific files. We should assume all stack frames for generated
|
||||
// code have signed return values. Rewriting the stack should ensure new values are correctly
|
||||
// signed. However, we cannot make any assumptions about how (or if) native code uses PAC - here
|
||||
// we should limit access to viewing via stripping.
|
||||
//
|
||||
|
||||
|
||||
// Confirm the given pointer has not been signed - ie none of the high bits are set.
|
||||
//
|
||||
// Note this can give false positives. The PAC signing can generate a signature with all signing
|
||||
// bits as zeros, causing this function to return true. Therefore this should only be used for
|
||||
// assert style checking. In addition, this function should never be used with a "not" to confirm
|
||||
// a pointer is signed, as it will fail the above case. The only safe way to do this is to instead
|
||||
// authenticate the pointer.
|
||||
//
|
||||
inline bool pauth_ptr_is_raw(address ptr) {
|
||||
// Confirm none of the high bits are set in the pointer.
|
||||
return ptr == pauth_strip_pointer(ptr);
|
||||
}
|
||||
|
||||
// Strip a return value (same as pauth_strip_pointer). When debug is enabled then authenticate
|
||||
// instead.
|
||||
//
|
||||
inline address pauth_strip_verifiable(address ret_addr, address modifier) {
|
||||
if (VM_Version::use_rop_protection()) {
|
||||
DEBUG_ONLY(ret_addr = pauth_authenticate_return_address(ret_addr, modifier);)
|
||||
NOT_DEBUG(ret_addr = pauth_strip_pointer(ret_addr));
|
||||
}
|
||||
return ret_addr;
|
||||
}
|
||||
|
||||
#endif // CPU_AARCH64_PAUTH_AARCH64_HPP
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved.
|
||||
* Copyright (c) 2021, Azul Systems, Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
@ -410,6 +410,7 @@ static void patch_callers_callsite(MacroAssembler *masm) {
|
||||
|
||||
__ mov(c_rarg0, rmethod);
|
||||
__ mov(c_rarg1, lr);
|
||||
__ authenticate_return_address(c_rarg1, rscratch1);
|
||||
__ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::fixup_callers_callsite)));
|
||||
__ blr(rscratch1);
|
||||
|
||||
@ -2178,8 +2179,8 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
|
||||
// load throwing pc from JavaThread and patch it as the return address
|
||||
// of the current frame. Then clear the field in JavaThread
|
||||
|
||||
__ ldr(r3, Address(rthread, JavaThread::exception_pc_offset()));
|
||||
__ protect_return_address(r3, rscratch1);
|
||||
__ str(r3, Address(rfp, wordSize));
|
||||
__ str(zr, Address(rthread, JavaThread::exception_pc_offset()));
|
||||
|
||||
@ -2287,6 +2288,7 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
__ sub(r2, r2, 2 * wordSize);
|
||||
__ add(sp, sp, r2);
|
||||
__ ldp(rfp, lr, __ post(sp, 2 * wordSize));
|
||||
__ authenticate_return_address();
|
||||
// LR should now be the return address to the caller (3)
|
||||
|
||||
#ifdef ASSERT
|
||||
@ -2428,6 +2430,7 @@ void SharedRuntime::generate_uncommon_trap_blob() {
|
||||
// Push self-frame. We get here with a return address in LR
|
||||
// and sp should be 16 byte aligned
|
||||
// push rfp and retaddr by hand
|
||||
__ protect_return_address();
|
||||
__ stp(rfp, lr, Address(__ pre(sp, -2 * wordSize)));
|
||||
// we don't expect an arg reg save area
|
||||
#ifndef PRODUCT
|
||||
@ -2502,6 +2505,7 @@ void SharedRuntime::generate_uncommon_trap_blob() {
|
||||
__ sub(r2, r2, 2 * wordSize);
|
||||
__ add(sp, sp, r2);
|
||||
__ ldp(rfp, lr, __ post(sp, 2 * wordSize));
|
||||
__ authenticate_return_address();
|
||||
// LR should now be the return address to the caller (3) frame
|
||||
|
||||
#ifdef ASSERT
|
||||
@ -2624,6 +2628,11 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t
|
||||
bool cause_return = (poll_type == POLL_AT_RETURN);
|
||||
RegisterSaver reg_save(poll_type == POLL_AT_VECTOR_LOOP /* save_vectors */);
|
||||
|
||||
// When the signal occured, the LR was either signed and stored on the stack (in which
|
||||
// case it will be restored from the stack before being used) or unsigned and not stored
|
||||
// on the stack. Stipping ensures we get the right value.
|
||||
__ strip_return_address();
|
||||
|
||||
// Save Integer and Float registers.
|
||||
map = reg_save.save_live_registers(masm, 0, &frame_size_in_words);
|
||||
|
||||
@ -2643,6 +2652,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t
|
||||
// it later to determine if someone changed the return address for
|
||||
// us!
|
||||
__ ldr(r20, Address(rthread, JavaThread::saved_exception_pc_offset()));
|
||||
__ protect_return_address(r20, rscratch1);
|
||||
__ str(r20, Address(rfp, wordSize));
|
||||
}
|
||||
|
||||
@ -2683,6 +2693,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t
|
||||
__ ldr(rscratch1, Address(rfp, wordSize));
|
||||
__ cmp(r20, rscratch1);
|
||||
__ br(Assembler::NE, no_adjust);
|
||||
__ authenticate_return_address(r20, rscratch1);
|
||||
|
||||
#ifdef ASSERT
|
||||
// Verify the correct encoding of the poll we're about to skip.
|
||||
@ -2697,6 +2708,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t
|
||||
#endif
|
||||
// Adjust return pc forward to step over the safepoint poll instruction
|
||||
__ add(r20, r20, NativeInstruction::instruction_size);
|
||||
__ protect_return_address(r20, rscratch1);
|
||||
__ str(r20, Address(rfp, wordSize));
|
||||
}
|
||||
|
||||
@ -2857,6 +2869,7 @@ void OptoRuntime::generate_exception_blob() {
|
||||
|
||||
// push rfp and retaddr by hand
|
||||
// Exception pc is 'return address' for stack walker
|
||||
__ protect_return_address();
|
||||
__ stp(rfp, lr, Address(__ pre(sp, -2 * wordSize)));
|
||||
// there are no callee save registers and we don't expect an
|
||||
// arg reg save area
|
||||
@ -2910,6 +2923,7 @@ void OptoRuntime::generate_exception_blob() {
|
||||
// there are no callee save registers now that adapter frames are gone.
|
||||
// and we dont' expect an arg reg save area
|
||||
__ ldp(rfp, r3, Address(__ post(sp, 2 * wordSize)));
|
||||
__ authenticate_return_address(r3);
|
||||
|
||||
// r0: exception handler
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -832,6 +832,7 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
|
||||
__ ldr(rcpool, Address(rcpool, ConstantPool::cache_offset_in_bytes()));
|
||||
__ stp(rlocals, rcpool, Address(sp, 2 * wordSize));
|
||||
|
||||
__ protect_return_address();
|
||||
__ stp(rfp, lr, Address(sp, 10 * wordSize));
|
||||
__ lea(rfp, Address(sp, 10 * wordSize));
|
||||
|
||||
@ -1748,6 +1749,8 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
|
||||
// adapter frames in C2.
|
||||
Label caller_not_deoptimized;
|
||||
__ ldr(c_rarg1, Address(rfp, frame::return_addr_offset * wordSize));
|
||||
// This is a return address, so requires authenticating for PAC.
|
||||
__ authenticate_return_address(c_rarg1, rscratch1);
|
||||
__ super_call_VM_leaf(CAST_FROM_FN_PTR(address,
|
||||
InterpreterRuntime::interpreter_contains), c_rarg1);
|
||||
__ cbnz(r0, caller_not_deoptimized);
|
||||
@ -1937,6 +1940,7 @@ void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t,
|
||||
address TemplateInterpreterGenerator::generate_trace_code(TosState state) {
|
||||
address entry = __ pc();
|
||||
|
||||
__ protect_return_address();
|
||||
__ push(lr);
|
||||
__ push(state);
|
||||
__ push(RegSet::range(r0, r15), sp);
|
||||
@ -1947,6 +1951,7 @@ address TemplateInterpreterGenerator::generate_trace_code(TosState state) {
|
||||
__ pop(RegSet::range(r0, r15), sp);
|
||||
__ pop(state);
|
||||
__ pop(lr);
|
||||
__ authenticate_return_address();
|
||||
__ ret(lr); // return from result handler
|
||||
|
||||
return entry;
|
||||
|
@ -45,6 +45,7 @@ int VM_Version::_zva_length;
|
||||
int VM_Version::_dcache_line_size;
|
||||
int VM_Version::_icache_line_size;
|
||||
int VM_Version::_initial_sve_vector_length;
|
||||
bool VM_Version::_rop_protection;
|
||||
|
||||
SpinWait VM_Version::_spin_wait;
|
||||
|
||||
@ -409,6 +410,39 @@ void VM_Version::initialize() {
|
||||
UsePopCountInstruction = true;
|
||||
}
|
||||
|
||||
if (UseBranchProtection == nullptr || strcmp(UseBranchProtection, "none") == 0) {
|
||||
_rop_protection = false;
|
||||
} else if (strcmp(UseBranchProtection, "standard") == 0) {
|
||||
_rop_protection = false;
|
||||
// Enable PAC if this code has been built with branch-protection and the CPU/OS supports it.
|
||||
#ifdef __ARM_FEATURE_PAC_DEFAULT
|
||||
if ((_features & CPU_PACA) != 0) {
|
||||
_rop_protection = true;
|
||||
}
|
||||
#endif
|
||||
} else if (strcmp(UseBranchProtection, "pac-ret") == 0) {
|
||||
_rop_protection = true;
|
||||
#ifdef __ARM_FEATURE_PAC_DEFAULT
|
||||
if ((_features & CPU_PACA) == 0) {
|
||||
warning("ROP-protection specified, but not supported on this CPU.");
|
||||
// Disable PAC to prevent illegal instruction crashes.
|
||||
_rop_protection = false;
|
||||
}
|
||||
#else
|
||||
warning("ROP-protection specified, but this VM was built without ROP-protection support.");
|
||||
#endif
|
||||
} else {
|
||||
vm_exit_during_initialization(err_msg("Unsupported UseBranchProtection: %s", UseBranchProtection));
|
||||
}
|
||||
|
||||
// The frame pointer must be preserved for ROP protection.
|
||||
if (_rop_protection == true) {
|
||||
if (FLAG_IS_DEFAULT(PreserveFramePointer) == false && PreserveFramePointer == false ) {
|
||||
vm_exit_during_initialization(err_msg("PreserveFramePointer cannot be disabled for ROP-protection"));
|
||||
}
|
||||
PreserveFramePointer = true;
|
||||
}
|
||||
|
||||
#ifdef COMPILER2
|
||||
if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
|
||||
UseMultiplyToLenIntrinsic = true;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -45,6 +45,7 @@ protected:
|
||||
static int _dcache_line_size;
|
||||
static int _icache_line_size;
|
||||
static int _initial_sve_vector_length;
|
||||
static bool _rop_protection;
|
||||
|
||||
static SpinWait _spin_wait;
|
||||
|
||||
@ -114,10 +115,11 @@ public:
|
||||
decl(SHA3, "sha3", 17) \
|
||||
decl(SHA512, "sha512", 21) \
|
||||
decl(SVE, "sve", 22) \
|
||||
decl(PACA, "paca", 30) \
|
||||
/* flags above must follow Linux HWCAP */ \
|
||||
decl(SVE2, "sve2", 28) \
|
||||
decl(STXR_PREFETCH, "stxr_prefetch", 29) \
|
||||
decl(A53MAC, "a53mac", 30)
|
||||
decl(A53MAC, "a53mac", 31)
|
||||
|
||||
#define DECLARE_CPU_FEATURE_FLAG(id, name, bit) CPU_##id = (1 << bit),
|
||||
CPU_FEATURE_FLAGS(DECLARE_CPU_FEATURE_FLAG)
|
||||
@ -156,6 +158,7 @@ public:
|
||||
|
||||
static void initialize_cpu_information(void);
|
||||
|
||||
static bool use_rop_protection() { return _rop_protection; }
|
||||
};
|
||||
|
||||
#endif // CPU_AARCH64_VM_VERSION_AARCH64_HPP
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Arm Limited. All rights reserved.
|
||||
* Copyright (c) 2021, 2022, Arm Limited. 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,29 +25,23 @@
|
||||
#ifndef OS_CPU_BSD_AARCH64_PAUTH_BSD_AARCH64_INLINE_HPP
|
||||
#define OS_CPU_BSD_AARCH64_PAUTH_BSD_AARCH64_INLINE_HPP
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <ptrauth.h>
|
||||
#endif
|
||||
|
||||
// Only the PAC instructions in the NOP space can be used. This ensures the
|
||||
// binaries work on systems without PAC. Write these instructions using their
|
||||
// alternate "hint" instructions to ensure older compilers can still be used.
|
||||
// For Apple, use the provided interface as this may provide additional
|
||||
// optimization.
|
||||
|
||||
#define XPACLRI "hint #0x7;"
|
||||
// OS specific Support for ROP Protection in VM code.
|
||||
// For more details on PAC see pauth_aarch64.hpp.
|
||||
|
||||
inline address pauth_strip_pointer(address ptr) {
|
||||
#ifdef __APPLE__
|
||||
return ptrauth_strip(ptr, ptrauth_key_asib);
|
||||
#else
|
||||
register address result __asm__("x30") = ptr;
|
||||
asm (XPACLRI : "+r"(result));
|
||||
return result;
|
||||
#endif
|
||||
// No PAC support in BSD as of yet.
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#undef XPACLRI
|
||||
inline address pauth_sign_return_address(address ret_addr, address sp) {
|
||||
// No PAC support in BSD as of yet.
|
||||
return ret_addr;
|
||||
}
|
||||
|
||||
inline address pauth_authenticate_return_address(address ret_addr, address sp) {
|
||||
// No PAC support in BSD as of yet.
|
||||
return ret_addr;
|
||||
}
|
||||
|
||||
#endif // OS_CPU_BSD_AARCH64_PAUTH_BSD_AARCH64_INLINE_HPP
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Arm Limited. All rights reserved.
|
||||
* Copyright (c) 2021, 2022, Arm Limited. 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,18 +25,57 @@
|
||||
#ifndef OS_CPU_LINUX_AARCH64_PAUTH_LINUX_AARCH64_INLINE_HPP
|
||||
#define OS_CPU_LINUX_AARCH64_PAUTH_LINUX_AARCH64_INLINE_HPP
|
||||
|
||||
// Only the PAC instructions in the NOP space can be used. This ensures the
|
||||
// binaries work on systems without PAC. Write these instructions using their
|
||||
// alternate "hint" instructions to ensure older compilers can still be used.
|
||||
// OS specific Support for ROP Protection in VM code.
|
||||
// For more details on PAC see pauth_aarch64.hpp.
|
||||
|
||||
#define XPACLRI "hint #0x7;"
|
||||
inline bool pauth_ptr_is_raw(address ptr);
|
||||
|
||||
// Use only the PAC instructions in the NOP space. This ensures the binaries work on systems
|
||||
// without PAC. Write these instructions using their alternate "hint" instructions to ensure older
|
||||
// compilers can still be used.
|
||||
#define XPACLRI "hint #0x7;"
|
||||
#define PACIA1716 "hint #0x8;"
|
||||
#define AUTIA1716 "hint #0xc;"
|
||||
|
||||
// Strip an address. Use with caution - only if there is no guaranteed way of authenticating the
|
||||
// value.
|
||||
//
|
||||
inline address pauth_strip_pointer(address ptr) {
|
||||
register address result __asm__("x30") = ptr;
|
||||
asm (XPACLRI : "+r"(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Sign a return value, using the given modifier.
|
||||
//
|
||||
inline address pauth_sign_return_address(address ret_addr, address sp) {
|
||||
if (VM_Version::use_rop_protection()) {
|
||||
// A pointer cannot be double signed.
|
||||
guarantee(pauth_ptr_is_raw(ret_addr), "Return address is already signed");
|
||||
register address r17 __asm("r17") = ret_addr;
|
||||
register address r16 __asm("r16") = sp;
|
||||
asm (PACIA1716 : "+r"(r17) : "r"(r16));
|
||||
ret_addr = r17;
|
||||
}
|
||||
return ret_addr;
|
||||
}
|
||||
|
||||
// Authenticate a return value, using the given modifier.
|
||||
//
|
||||
inline address pauth_authenticate_return_address(address ret_addr, address sp) {
|
||||
if (VM_Version::use_rop_protection()) {
|
||||
register address r17 __asm("r17") = ret_addr;
|
||||
register address r16 __asm("r16") = sp;
|
||||
asm (AUTIA1716 : "+r"(r17) : "r"(r16));
|
||||
ret_addr = r17;
|
||||
// Ensure that the pointer authenticated.
|
||||
guarantee(pauth_ptr_is_raw(ret_addr), "Return address did not authenticate");
|
||||
}
|
||||
return ret_addr;
|
||||
}
|
||||
|
||||
#undef XPACLRI
|
||||
#undef PACIA1716
|
||||
#undef AUTIA1716
|
||||
|
||||
#endif // OS_CPU_LINUX_AARCH64_PAUTH_LINUX_AARCH64_INLINE_HPP
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2015, Red Hat Inc. All rights reserved.
|
||||
// Copyright (c) 2015, 2022, Red Hat 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
|
||||
@ -29,6 +29,7 @@
|
||||
.type _ZN10JavaThread25aarch64_get_thread_helperEv, %function
|
||||
|
||||
_ZN10JavaThread25aarch64_get_thread_helperEv:
|
||||
hint #0x19 // paciasp
|
||||
stp x29, x30, [sp, -16]!
|
||||
adrp x0, :tlsdesc:_ZN6Thread12_thr_currentE
|
||||
ldr x1, [x0, #:tlsdesc_lo12:_ZN6Thread12_thr_currentE]
|
||||
@ -39,6 +40,7 @@ _ZN10JavaThread25aarch64_get_thread_helperEv:
|
||||
add x0, x1, x0
|
||||
ldr x0, [x0]
|
||||
ldp x29, x30, [sp], 16
|
||||
hint #0x1d // autiasp
|
||||
ret
|
||||
|
||||
.size _ZN10JavaThread25aarch64_get_thread_helperEv, .-_ZN10JavaThread25aarch64_get_thread_helperEv
|
||||
|
@ -72,6 +72,10 @@
|
||||
#define HWCAP_SVE (1 << 22)
|
||||
#endif
|
||||
|
||||
#ifndef HWCAP_PACA
|
||||
#define HWCAP_PACA (1 << 30)
|
||||
#endif
|
||||
|
||||
#ifndef HWCAP2_SVE2
|
||||
#define HWCAP2_SVE2 (1 << 1)
|
||||
#endif
|
||||
@ -111,6 +115,7 @@ void VM_Version::get_os_cpu_info() {
|
||||
static_assert(CPU_SHA3 == HWCAP_SHA3, "Flag CPU_SHA3 must follow Linux HWCAP");
|
||||
static_assert(CPU_SHA512 == HWCAP_SHA512, "Flag CPU_SHA512 must follow Linux HWCAP");
|
||||
static_assert(CPU_SVE == HWCAP_SVE, "Flag CPU_SVE must follow Linux HWCAP");
|
||||
static_assert(CPU_PACA == HWCAP_PACA, "Flag CPU_PACA must follow Linux HWCAP");
|
||||
_features = auxv & (
|
||||
HWCAP_FP |
|
||||
HWCAP_ASIMD |
|
||||
@ -124,7 +129,8 @@ void VM_Version::get_os_cpu_info() {
|
||||
HWCAP_DCPOP |
|
||||
HWCAP_SHA3 |
|
||||
HWCAP_SHA512 |
|
||||
HWCAP_SVE);
|
||||
HWCAP_SVE |
|
||||
HWCAP_PACA);
|
||||
|
||||
if (auxv2 & HWCAP2_SVE2) _features |= CPU_SVE2;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Arm Limited. All rights reserved.
|
||||
* Copyright (c) 2021, 2022, Arm Limited. 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,10 +25,22 @@
|
||||
#ifndef OS_CPU_WINDOWS_AARCH64_PAUTH_WINDOWS_AARCH64_INLINE_HPP
|
||||
#define OS_CPU_WINDOWS_AARCH64_PAUTH_WINDOWS_AARCH64_INLINE_HPP
|
||||
|
||||
// OS specific Support for ROP Protection in VM code.
|
||||
// For more details on PAC see pauth_aarch64.hpp.
|
||||
|
||||
inline address pauth_strip_pointer(address ptr) {
|
||||
// No PAC support in windows as of yet.
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#endif // OS_CPU_WINDOWS_AARCH64_PAUTH_WINDOWS_AARCH64_INLINE_HPP
|
||||
inline address pauth_sign_return_address(address ret_addr, address sp) {
|
||||
// No PAC support in windows as of yet.
|
||||
return ret_addr;
|
||||
}
|
||||
|
||||
inline address pauth_authenticate_return_address(address ret_addr, address sp) {
|
||||
// No PAC support in windows as of yet.
|
||||
return ret_addr;
|
||||
}
|
||||
|
||||
#endif // OS_CPU_WINDOWS_AARCH64_PAUTH_WINDOWS_AARCH64_INLINE_HPP
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. 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
|
||||
@ -28,6 +28,7 @@
|
||||
#include "gc/shared/barrierSet.hpp"
|
||||
#include "gc/shared/barrierSetNMethod.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "runtime/frame.inline.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
#include "runtime/threadWXSetters.inline.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
@ -54,6 +55,7 @@ int BarrierSetNMethod::nmethod_stub_entry_barrier(address* return_address_ptr) {
|
||||
MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, Thread::current()));
|
||||
|
||||
address return_address = *return_address_ptr;
|
||||
AARCH64_ONLY(return_address = pauth_strip_pointer(return_address));
|
||||
CodeBlob* cb = CodeCache::find_blob(return_address);
|
||||
assert(cb != NULL, "invariant");
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2022, Oracle and/or its affiliates. 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
|
||||
@ -744,6 +744,7 @@
|
||||
static_field(VM_Version, _zva_length, int) \
|
||||
static_field(StubRoutines::aarch64, _has_negatives, address) \
|
||||
static_field(StubRoutines::aarch64, _has_negatives_long, address) \
|
||||
static_field(VM_Version, _rop_protection, bool) \
|
||||
volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*)
|
||||
|
||||
#define DECLARE_INT_CPU_FEATURE_CONSTANT(id, name, bit) GENERATE_VM_INT_CONSTANT_ENTRY(VM_Version::CPU_##id)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2022, Oracle and/or its affiliates. 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
|
||||
@ -1465,6 +1465,12 @@ address OptoRuntime::rethrow_C(oopDesc* exception, JavaThread* thread, address r
|
||||
// Enable WXWrite: the function called directly by compiled code.
|
||||
MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, thread));
|
||||
|
||||
// ret_pc will have been loaded from the stack, so for AArch64 will be signed.
|
||||
// This needs authenticating, but to do that here requires the fp of the previous frame.
|
||||
// A better way of doing it would be authenticate in the caller by adding a
|
||||
// AuthPAuthNode and using it in GraphKit::gen_stub. For now, just strip it.
|
||||
AARCH64_ONLY(ret_pc = pauth_strip_pointer(ret_pc));
|
||||
|
||||
#ifndef PRODUCT
|
||||
SharedRuntime::_rethrow_ctr++; // count rethrows
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. 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
|
||||
@ -1110,6 +1110,11 @@ void frame::verify(const RegisterMap* map) const {
|
||||
|
||||
#ifdef ASSERT
|
||||
bool frame::verify_return_pc(address x) {
|
||||
#ifdef AARCH64
|
||||
if (!pauth_ptr_is_raw(x)) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if (StubRoutines::returns_to_call_stub(x)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. 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
|
||||
@ -1947,6 +1947,8 @@ bool SharedRuntime::should_fixup_call_destination(address destination, address e
|
||||
JRT_LEAF(void, SharedRuntime::fixup_callers_callsite(Method* method, address caller_pc))
|
||||
Method* moop(method);
|
||||
|
||||
AARCH64_ONLY(assert(pauth_ptr_is_raw(caller_pc), "should be raw"));
|
||||
|
||||
address entry_point = moop->from_compiled_entry_no_trampoline();
|
||||
|
||||
// It's possible that deoptimization can occur at a call site which hasn't
|
||||
|
@ -1981,6 +1981,32 @@ Allows user to specify VM options in a file, for example,
|
||||
\f[CB]java\ \-XX:VMOptionsFile=/var/my_vm_options\ HelloWorld\f[R].
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
.B \f[CB]\-XX:UseBranchProtection=\f[R]\f[I]mode\f[R]
|
||||
Specifies the branch protection mode. All options other than none require
|
||||
the VM to have been built with branch protection enabled. In addition, for
|
||||
full protection, any native libraries provided by applications should be
|
||||
compiled with the same level of protection. (AArch64 Linux only).
|
||||
.RS
|
||||
.PP
|
||||
Possible \f[I]mode\f[R] arguments for this option include the
|
||||
following:
|
||||
.RS
|
||||
.TP
|
||||
.B \f[CB]none\f[R]
|
||||
Do not use branch protection. This is the default value.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
.B \f[CB]standard\f[R]
|
||||
Enables all branch protection modes available on the current platform.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
.B \f[CB]pac-ret\f[R]
|
||||
Enables protection against ROP based attacks. (AArch64 8.3+ only)
|
||||
.RS
|
||||
.RE
|
||||
.SH ADVANCED JIT COMPILER OPTIONS FOR JAVA
|
||||
.PP
|
||||
These \f[CB]java\f[R] options control the dynamic just\-in\-time (JIT)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2022, Oracle and/or its affiliates. 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
|
||||
@ -177,6 +177,7 @@ public class AArch64 extends Architecture {
|
||||
SHA3,
|
||||
SHA512,
|
||||
SVE,
|
||||
PACA,
|
||||
SVE2,
|
||||
STXR_PREFETCH,
|
||||
A53MAC,
|
||||
|
@ -209,15 +209,17 @@ class Instruction(object):
|
||||
self._name = name
|
||||
self.isWord = name.endswith("w") | name.endswith("wi")
|
||||
self.asmRegPrefix = ["x", "w"][self.isWord]
|
||||
self.isPostfixException = False
|
||||
|
||||
def aname(self):
|
||||
if (self._name.endswith("wi")):
|
||||
if self.isPostfixException:
|
||||
return self._name
|
||||
elif (self._name.endswith("wi")):
|
||||
return self._name[:len(self._name)-2]
|
||||
elif (self._name.endswith("i") | self._name.endswith("w")):
|
||||
return self._name[:len(self._name)-1]
|
||||
else:
|
||||
if (self._name.endswith("i") | self._name.endswith("w")):
|
||||
return self._name[:len(self._name)-1]
|
||||
else:
|
||||
return self._name
|
||||
return self._name
|
||||
|
||||
def emit(self) :
|
||||
pass
|
||||
@ -348,6 +350,12 @@ class OneRegOp(Instruction):
|
||||
return (super(OneRegOp, self).astr()
|
||||
+ '%s' % self.reg.astr(self.asmRegPrefix))
|
||||
|
||||
class PostfixExceptionOneRegOp(OneRegOp):
|
||||
|
||||
def __init__(self, op):
|
||||
OneRegOp.__init__(self, op)
|
||||
self.isPostfixException=True
|
||||
|
||||
class ArithOp(ThreeRegInstruction):
|
||||
|
||||
def generate(self):
|
||||
@ -597,6 +605,13 @@ class Op(Instruction):
|
||||
def astr(self):
|
||||
return self.aname();
|
||||
|
||||
|
||||
class PostfixExceptionOp(Op):
|
||||
|
||||
def __init__(self, op):
|
||||
Op.__init__(self, op)
|
||||
self.isPostfixException=True
|
||||
|
||||
class SystemOp(Instruction):
|
||||
|
||||
def __init__(self, op):
|
||||
@ -1335,14 +1350,26 @@ generate (CondBranchOp, ["EQ", "NE", "HS", "CS", "LO", "CC", "MI", "PL", "VS", "
|
||||
generate (ImmOp, ["svc", "hvc", "smc", "brk", "hlt", # "dcps1", "dcps2", "dcps3"
|
||||
])
|
||||
|
||||
generate (Op, ["nop", "eret", "drps", "isb"])
|
||||
generate (Op, ["nop", "yield", "wfe", "sev", "sevl",
|
||||
"autia1716", "autiasp", "autiaz", "autib1716", "autibsp", "autibz",
|
||||
"pacia1716", "paciasp", "paciaz", "pacib1716", "pacibsp", "pacibz",
|
||||
"eret", "drps", "isb",])
|
||||
|
||||
# Ensure the "i" is not stripped off the end of the instruction
|
||||
generate (PostfixExceptionOp, ["wfi", "xpaclri"])
|
||||
|
||||
barriers = ["OSHLD", "OSHST", "OSH", "NSHLD", "NSHST", "NSH",
|
||||
"ISHLD", "ISHST", "ISH", "LD", "ST", "SY"]
|
||||
|
||||
generate (SystemOp, [["dsb", barriers], ["dmb", barriers]])
|
||||
|
||||
generate (OneRegOp, ["br", "blr"])
|
||||
generate (OneRegOp, ["br", "blr",
|
||||
"paciza", "pacizb", "pacdza", "pacdzb",
|
||||
"autiza", "autizb", "autdza", "autdzb", "xpacd",
|
||||
"braaz", "brabz", "blraaz", "blrabz"])
|
||||
|
||||
# Ensure the "i" is not stripped off the end of the instruction
|
||||
generate (PostfixExceptionOneRegOp, ["xpaci"])
|
||||
|
||||
for mode in 'xwhb':
|
||||
generate (LoadStoreExclusiveOp, [["stxr", mode, 3], ["stlxr", mode, 3],
|
||||
@ -1387,7 +1414,10 @@ generate(ConditionalSelectOp,
|
||||
|
||||
generate(TwoRegOp,
|
||||
["rbitw", "rev16w", "revw", "clzw", "clsw", "rbit",
|
||||
"rev16", "rev32", "rev", "clz", "cls"])
|
||||
"rev16", "rev32", "rev", "clz", "cls",
|
||||
"pacia", "pacib", "pacda", "pacdb", "autia", "autib", "autda", "autdb",
|
||||
"braa", "brab", "blraa", "blrab"])
|
||||
|
||||
generate(ThreeRegOp,
|
||||
["udivw", "sdivw", "lslvw", "lsrvw", "asrvw", "rorvw", "udiv", "sdiv",
|
||||
"lslv", "lsrv", "asrv", "rorv", "umulh", "smulh"])
|
||||
@ -1839,8 +1869,8 @@ outfile.write("forth:\n")
|
||||
|
||||
outfile.close()
|
||||
|
||||
# compile for sve with 8.2 and sha3 because of SHA3 crypto extension.
|
||||
subprocess.check_call([AARCH64_AS, "-march=armv8.2-a+sha3+sve", "aarch64ops.s", "-o", "aarch64ops.o"])
|
||||
# compile for sve with 8.3 and sha3 because of SHA3 crypto extension.
|
||||
subprocess.check_call([AARCH64_AS, "-march=armv8.3-a+sha3+sve", "aarch64ops.s", "-o", "aarch64ops.o"])
|
||||
|
||||
print
|
||||
print "/*"
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2022, Oracle and/or its affiliates. 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
|
||||
@ -54,6 +54,7 @@ public class CodeInstallationTest {
|
||||
protected final TargetDescription target;
|
||||
protected final ConstantReflectionProvider constantReflection;
|
||||
protected final TestHotSpotVMConfig config;
|
||||
protected final Architecture arch;
|
||||
|
||||
public CodeInstallationTest() {
|
||||
JVMCIBackend backend = JVMCI.getRuntime().getHostJVMCIBackend();
|
||||
@ -61,7 +62,8 @@ public class CodeInstallationTest {
|
||||
codeCache = backend.getCodeCache();
|
||||
target = backend.getTarget();
|
||||
constantReflection = backend.getConstantReflection();
|
||||
config = new TestHotSpotVMConfig(HotSpotJVMCIRuntime.runtime().getConfigStore());
|
||||
arch = codeCache.getTarget().arch;
|
||||
config = new TestHotSpotVMConfig(HotSpotJVMCIRuntime.runtime().getConfigStore(), arch);
|
||||
}
|
||||
|
||||
protected interface TestCompiler {
|
||||
@ -70,7 +72,6 @@ public class CodeInstallationTest {
|
||||
}
|
||||
|
||||
private TestAssembler createAssembler() {
|
||||
Architecture arch = codeCache.getTarget().arch;
|
||||
if (arch instanceof AMD64) {
|
||||
return new AMD64TestAssembler(codeCache, config);
|
||||
} else if (arch instanceof AArch64) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2022, Oracle and/or its affiliates. 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
|
||||
@ -22,13 +22,16 @@
|
||||
*/
|
||||
package jdk.vm.ci.code.test;
|
||||
|
||||
import jdk.vm.ci.aarch64.AArch64;
|
||||
import jdk.vm.ci.code.Architecture;
|
||||
import jdk.vm.ci.hotspot.HotSpotVMConfigAccess;
|
||||
import jdk.vm.ci.hotspot.HotSpotVMConfigStore;
|
||||
|
||||
public class TestHotSpotVMConfig extends HotSpotVMConfigAccess {
|
||||
|
||||
public TestHotSpotVMConfig(HotSpotVMConfigStore config) {
|
||||
public TestHotSpotVMConfig(HotSpotVMConfigStore config, Architecture arch) {
|
||||
super(config);
|
||||
ropProtection = (arch instanceof AArch64) ? getFieldValue("VM_Version::_rop_protection", Boolean.class) : false;
|
||||
}
|
||||
|
||||
public final boolean useCompressedOops = getFlag("UseCompressedOops", Boolean.class);
|
||||
@ -48,4 +51,6 @@ public class TestHotSpotVMConfig extends HotSpotVMConfigAccess {
|
||||
|
||||
public final int maxOopMapStackOffset = getFieldValue("CompilerToVM::Data::_max_oop_map_stack_offset", Integer.class, "int");
|
||||
public final int heapWordSize = getConstant("HeapWordSize", Integer.class);
|
||||
|
||||
public final boolean ropProtection;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, Arm Limited. All rights reserved.
|
||||
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2022, Arm Limited. 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
|
||||
@ -254,6 +254,9 @@ public class AArch64TestAssembler extends TestAssembler {
|
||||
public void emitPrologue() {
|
||||
// Must be patchable by NativeJump::patch_verified_entry
|
||||
emitNop();
|
||||
if (config.ropProtection) {
|
||||
code.emitInt(0xdac103be); // pacia x30, x29
|
||||
}
|
||||
code.emitInt(0xa9be7bfd); // stp x29, x30, [sp, #-32]!
|
||||
code.emitInt(0x910003fd); // mov x29, sp
|
||||
|
||||
@ -469,6 +472,9 @@ public class AArch64TestAssembler extends TestAssembler {
|
||||
emitMov(AArch64.r0, a);
|
||||
code.emitInt(0x910003bf); // mov sp, x29
|
||||
code.emitInt(0xa8c27bfd); // ldp x29, x30, [sp], #32
|
||||
if (config.ropProtection) {
|
||||
code.emitInt(0xdac113be); // autia x30, x29
|
||||
}
|
||||
code.emitInt(0xd65f03c0); // ret
|
||||
}
|
||||
|
||||
@ -477,6 +483,9 @@ public class AArch64TestAssembler extends TestAssembler {
|
||||
assert a == AArch64.v0 : "Unimplemented move " + a;
|
||||
code.emitInt(0x910003bf); // mov sp, x29
|
||||
code.emitInt(0xa8c27bfd); // ldp x29, x30, [sp], #32
|
||||
if (config.ropProtection) {
|
||||
code.emitInt(0xdac113be); // autia x30, x29
|
||||
}
|
||||
code.emitInt(0xd65f03c0); // ret
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user