Skip to content

Commit

Permalink
[codegen] Re-derive sentries when we modify them.
Browse files Browse the repository at this point in the history
Similar to cfa1aba, sometimes v8's
codegen modifies sentries. In order to preserve them, we need to
generate an instruction sequence as follows:

  adr c1, 0
  orr x0, x0, #1
  scvalue c1, c1, x0
  seal c0, c1, rb

However, we also need to check if we are actually operating on a sentry,
because we might be working with JITted code that simply has an RX
capability. We don't produce sentries for those yet, so we either derive
from the PCC, or we don't derive anything.

This commit further adds various Morello instructions such as gclen,
scbndse, gcseal, seal and build and re-formats some existing parts of
the code. It also adds a new abort reason for the codegen to use in case
of unexpected sealed capabilities and makes use of it in the Mov
immediate instruction, which should help debugging.
  • Loading branch information
dstolfa committed Aug 23, 2024
1 parent cfa1aba commit 154ced1
Show file tree
Hide file tree
Showing 11 changed files with 232 additions and 35 deletions.
14 changes: 7 additions & 7 deletions src/builtins/arm64/builtins-arm64.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1918,7 +1918,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(
__ Ldr(kJavaScriptCallCodeStartRegister,
MemOperand(kInterpreterDispatchTableRegister, x1));
#if defined(__CHERI_PURE_CAPABILITY__)
__ Orr(kJavaScriptCallCodeStartRegister, kJavaScriptCallCodeStartRegister, 0x1);
__ PrepareC64Jump(kJavaScriptCallCodeStartRegister);
#endif // defined(__CHERI_PURE_CAPABILITY__)
__ Call(kJavaScriptCallCodeStartRegister);

Expand Down Expand Up @@ -2266,7 +2266,7 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) {
Label return_from_bytecode_dispatch;
__ Adr(lr, &return_from_bytecode_dispatch);
#if defined(__CHERI_PURE_CAPABILITY__)
__ Orr(lr, lr, 0x1);
__ PrepareC64Jump(lr);
#endif // defined(__CHERI_PURE_CAPABILITY__)

// Dispatch to the target bytecode.
Expand Down Expand Up @@ -2351,7 +2351,7 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) {
#if defined(__CHERI_PURE_CAPABILITY__)
temps.Exclude(c17);
__ Add(c17, c1, Operand(interpreter_entry_return_pc_offset.value()));
__ Orr(c17, c17, 0x1);
__ PrepareC64Jump(c17);
__ Br(c17);
#else // defined(__CHERI_PURE_CAPABILITY__)
temps.Exclude(x17);
Expand Down Expand Up @@ -2552,7 +2552,7 @@ void Generate_OSREntry(MacroAssembler* masm, Register entry_address,
Label jump;
__ Adr(lr, &jump);
#if defined(__CHERI_PURE_CAPABILITY__)
__ Orr(lr, lr, 0x1);
__ PrepareC64Jump(lr);
#endif // defined(__CHERI_PURE_CAPABILITY__)
__ Ret();

Expand All @@ -2566,7 +2566,7 @@ void Generate_OSREntry(MacroAssembler* masm, Register entry_address,
} else {
__ Add(c17, entry_address, offset);
}
__ Orr(c17, c17, 0x1);
__ PrepareC64Jump(c17);
__ Br(c17);
#else // defined(__CHERI_PURE_CAPABILITY__)
__ Mov(x17, entry_address);
Expand Down Expand Up @@ -6067,7 +6067,7 @@ void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size,
__ Mov(c17, ER::Create(IsolateAddressId::kPendingHandlerEntrypointAddress,
masm->isolate()));
__ Ldr(c17, MemOperand(c17));
__ Orr(c17, c17, 0x1);
__ PrepareC64Jump(c17);
__ Br(c17);
#else // defined(__CHERI_PURE_CAPABILITY__)
temps.Exclude(x17);
Expand Down Expand Up @@ -7098,7 +7098,7 @@ void Generate_DeoptimizationEntry(MacroAssembler* masm,
Register continuation = c17;
__ Ldr(continuation, MemOperand(last_output_frame,
FrameDescription::continuation_offset()));
__ Orr(continuation, continuation, 0x1);
__ PrepareC64Jump(continuation);
__ Ldr(lr, MemOperand(last_output_frame, FrameDescription::pc_offset()));
#else // defined(__CHERI_PURE_CAPABILITY__)
temps.Exclude(x17);
Expand Down
2 changes: 1 addition & 1 deletion src/builtins/setup-builtins-internal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ Handle<Code> BuildPlaceholder(Isolate* isolate, Builtin builtin) {
FrameScope frame_scope(&masm, StackFrame::NO_FRAME_TYPE);
// The contents of placeholder don't matter, as long as they don't create
// embedded constants or external references.
masm.Move(kJavaScriptCallCodeStartRegister, Smi::zero());
masm.Move(kJavaScriptCallCodeStartRegister.X(), Smi::zero());
masm.Call(kJavaScriptCallCodeStartRegister);
}
CodeDesc desc;
Expand Down
12 changes: 9 additions & 3 deletions src/codegen/arm64/assembler-arm64-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1101,19 +1101,25 @@ Instr Assembler::ImmRotate(unsigned immr, unsigned reg_size) {
return immr << ImmRotate_offset;
}

#ifdef __CHERI_PURE_CAPABILITY__
Instr Assembler::ImmSealForm(Cheri::SealImmediateForm form) {
return form << 13;
}
#endif // __CHERI_PURE_CAPABILITY__

Instr Assembler::ImmLLiteral(int imm19) {
CHECK(is_int19(imm19));
return truncate_to_int19(imm19) << ImmLLiteral_offset;
}

Instr Assembler::BitN(unsigned bitn, unsigned reg_size) {
#ifdef __CHERI_PURE_CAPABILITY__
DCHECK((reg_size == kWRegSizeInBits) || (reg_size == kXRegSizeInBits));
#else
DCHECK((reg_size == kCRegSizeInBits) || (reg_size == kWRegSizeInBits) ||
(reg_size == kXRegSizeInBits));
#endif
#else
DCHECK((reg_size == kWRegSizeInBits) || (reg_size == kXRegSizeInBits));
DCHECK((reg_size == kXRegSizeInBits) || (bitn == 0));
#endif
USE(reg_size);
return bitn << BitN_offset;
}
Expand Down
53 changes: 45 additions & 8 deletions src/codegen/arm64/assembler-arm64.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1429,7 +1429,7 @@ void Assembler::LoadStorePairCap(const Register& ct, const Register& ct2,
}
Emit(addrmodeop | memop);
}
#endif // __CHERI_PURE_CAPABILITY__
#endif // __CHERI_PURE_CAPABILITY__

// Memory instructions.
void Assembler::ldrb(const Register& rt, const MemOperand& src) {
Expand Down Expand Up @@ -1470,22 +1470,38 @@ void Assembler::cpy(const Register& cd, const Register& cn) {
}

void Assembler::cselc(const Register& cd, const Register& cn,
const Register& cm, Condition cond) {
const Register& cm, Condition cond) {
DCHECK(cd.SizeInBits() == cn.SizeInBits());
DCHECK(cd.SizeInBits() == cm.SizeInBits());
Emit(CSEL_c | Cm(cm) | Cond(cond) | Cn(cn) | Cd(cd));
}

void Assembler::gcvalue(const Register& cn, const Register& rd)
{
void Assembler::gcvalue(const Register& cn, const Register& rd) {
DCHECK(cn.Is128Bits());
DCHECK(rd.Is64Bits());
Emit(GCVALUE | CnCSP(cn) | Rd(rd));
}

void Assembler::gclen(const Register& cn, const Register& rd) {
DCHECK(cn.Is128Bits());
DCHECK(rd.Is64Bits());
Emit(GCLEN | CnCSP(cn) | Rd(rd));
}

void Assembler::gcbase(const Register& cn, const Register& rd) {
DCHECK(cn.Is128Bits());
DCHECK(rd.Is64Bits());
Emit(GCBASE | CnCSP(cn) | Rd(rd));
}

void Assembler::gcseal(const Register& cn, const Register& rd) {
DCHECK(cn.Is128Bits());
DCHECK(rd.Is64Bits());
Emit(GCSEAL | CnCSP(cn) | Rd(rd));
}

void Assembler::subsc(const Register& rd, const Register& cn,
const Operand& operand)
{
const Operand& operand) {
DCHECK(rd.Is64Bits());
DCHECK(cn.Is128Bits());
DCHECK(operand.reg().IsC());
Expand All @@ -1498,12 +1514,33 @@ bool Assembler::IsImmAddSubCapability(int64_t immediate) {
}

void Assembler::scvalue(const Register& cd, const Register& cn,
const Register& rm)
{
const Register& rm) {
DCHECK(cn.Is128Bits() && cd.Is128Bits());
DCHECK(rm.Is64Bits());
Emit(SCVALUE | Rm(rm) | CdCSP(cd) | CnCSP(cn));
}

void Assembler::scbndse(const Register& cd, const Register& cn,
const Register& rm) {
DCHECK(cn.Is128Bits() && cd.Is128Bits());
DCHECK(rm.Is64Bits());
Emit(SCBNDSE | Rm(rm) | CdCSP(cd) | CnCSP(cn));
}

void Assembler::build(const Register& cd, const Register& cn, const Register& cm) {
DCHECK(cd.Is128Bits());
DCHECK(cn.Is128Bits());
DCHECK(cm.Is128Bits());
Emit(BUILD | Cm(cm) | CnCSP(cn) | CdCSP(cd));
}

void Assembler::seal(const Register& cd, const Register& cn,
Cheri::SealImmediateForm form) {
DCHECK(cd.Is128Bits());
DCHECK(cn.Is128Bits());
DCHECK_NE(form & 0b11, 0);
Emit(SEAL | ImmSealForm(form) | CnCSP(cn) | CdCSP(cd));
}
#endif // __CHERI_PURE_CAPABILITY__

void Assembler::ldrsw(const Register& rt, const MemOperand& src) {
Expand Down
16 changes: 16 additions & 0 deletions src/codegen/arm64/assembler-arm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -832,9 +832,22 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
const MemOperand& src);
// Load a capability value field
void gcvalue(const Register& cd, const Register& rd);
// Load a capability base field
void gcbase(const Register& cd, const Register& rd);
// Load a capability length field
void gclen(const Register& cd, const Register& rd);
// Load a capability sealed flag
void gcseal(const Register& cd, const Register& rd);
// Store a capability value field
void scvalue(const Register& cd, const Register& cn,
const Register& rm);
// Set capability bounds exact
void scbndse(const Register& cd, const Register& cn, const Register& rm);
// Build a capability from a bit pattern.
void build(const Register& cd, const Register& cn, const Register& cm);
// Seal a capability using an immediate form.
void seal(const Register& cd, const Register& cn,
Cheri::SealImmediateForm form);
#endif // __CHERI_PURE_CAPABILITY__

// Load word with sign extension.
Expand Down Expand Up @@ -2868,6 +2881,9 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
inline static Instr ImmR(unsigned immr, unsigned reg_size);
inline static Instr ImmSetBits(unsigned imms, unsigned reg_size);
inline static Instr ImmRotate(unsigned immr, unsigned reg_size);
#ifdef __CHERI_PURE_CAPABILITY__
inline static Instr ImmSealForm(Cheri::SealImmediateForm form);
#endif
inline static Instr ImmLLiteral(int imm19);
inline static Instr BitN(unsigned bitn, unsigned reg_size);
inline static Instr ShiftDP(Shift shift);
Expand Down
43 changes: 43 additions & 0 deletions src/codegen/arm64/constants-arm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -3033,6 +3033,20 @@ using GetField1Op = uint32_t;
constexpr GetField1Op GetField1Fixed = 0xC2C01000;
constexpr GetField1Op GetField1FMask = 0xFFFF1C00;
constexpr GetField1Op GetField1Mask = 0xFFFFFC00;
// 4.4.52 GCBASE
// Get the Base field of a capability calculates the base field of a capability
// and writes it to the destination register.
constexpr GetField1Op GCBASE = GetField1Fixed | 0x00000000;
// 4.4.54 GCLEN
// Get the Length of a capability calculates the length of a capability from the
// limit and the base of that capability and writes the result to the
// destination register.
constexpr GetField1Op GCLEN = GetField1Fixed | 0x00002000;
// 4.4.58 GCSEAL
// Get the sealed status of a capability writes zero to the destination register
// if the ObjectType field of the source Capability register is zero and writes
// one otherwise.
constexpr GetField1Op GCSEAL = GetField1Fixed | 0x0000A000;
// 4.4.61 GCVALUE
// Get the Value field of a capability gets the range of the Value field of
// a capability and writes the result to the destination register.
Expand All @@ -3042,11 +3056,40 @@ using SetField1Op = uint32_t;
constexpr SetField1Op SetField1Fixed = 0xC2C00000;
constexpr SetField1Op SetField1FMask = 0xFFE09C00;
constexpr SetField1Op SetField1Mask = 0xFFE0FC00;
// 4.4.116 SCBNDSE (register)
// Set Bounds derives Capability Bounds using the source Capability register and
// a length from a 64-bit register and writes the result to the destination
// Capability register. If the bounds cannot be set exactly, this instruction
// clears the Capability Tag. If the source capability is sealed, the Capability
// Tag written to the destination Capability register is cleared.
constexpr SetField1Op SCBNDSE = SetField1Fixed | 0x00002000;
// 4.4.120 SCVALUE
// Set value field of a capability, writes the source Capability register
// to the destination Capability register with the Value field set to a
// value based on a 64-bit general-purpose register.
constexpr SetField1Op SCVALUE = SetField1Fixed | 0x00004000;
// 4.4.19 BUILD
// Build capability from untagged and possibly sealed bit pattern interprets and
// treats an untagged and possibly sealed bit pattern as a capability, checks
// this capability against a testing capability and based on the result, writes
// the built capability to the destination Capability register.
constexpr SetField1Op BUILD = SetField1Fixed | 0x00000400;

using SealImmediateOp = uint32_t;
// 4.4.122 SEAL (immediate)
// Seal capability (immediate) seals a capability by setting the ObjectType of
// that capability to nonzero, and writes the result to the destination
// Capability register. An operand of rb seals for use with a register based
// branch, lpb for a load pair and branch and lb for a load and branch.
constexpr SealImmediateOp SEAL = 0xC2C31000;

namespace Cheri {
using SealImmediateForm = uint32_t;
constexpr SealImmediateForm kSealFormRb = 0b01;
constexpr SealImmediateForm kSealFormLpb = 0b10;
constexpr SealImmediateForm kSealFormLb = 0b11;
}

#endif // __CHERI_PURE_CAPABILITY__

} // namespace internal
Expand Down
49 changes: 48 additions & 1 deletion src/codegen/arm64/macro-assembler-arm64-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ void MacroAssembler::Orr(const Register& rd, const Register& rn,
Scvalue(rd, rd, temp);
return;
}
#endif // __CHERI_PURE_CAPABILITY__
#endif // __CHERI_PURE_CAPABILITY__
LogicalMacro(rd, rn, operand, ORR);
}

Expand Down Expand Up @@ -264,12 +264,59 @@ void MacroAssembler::Gcvalue(const Register& cs, const Register& rd) {
gcvalue(cs, rd);
}

void MacroAssembler::Gclen(const Register& cs, const Register& rd) {
DCHECK(allow_macro_instructions());
DCHECK(cs.Is128Bits());
DCHECK(rd.Is64Bits());
gclen(cs, rd);
}

void MacroAssembler::Gcbase(const Register& cs, const Register& rd) {
DCHECK(allow_macro_instructions());
DCHECK(cs.Is128Bits());
DCHECK(rd.Is64Bits());
gcbase(cs, rd);
}

void MacroAssembler::Gcseal(const Register& cs, const Register& rd) {
DCHECK(allow_macro_instructions());
DCHECK(cs.Is128Bits());
DCHECK(rd.Is64Bits());
gcseal(cs, rd);
}

void MacroAssembler::Scvalue(const Register& cd, const Register& cn,
const Register& rm) {
DCHECK(allow_macro_instructions());
scvalue(cd, cn, rm);
}

void MacroAssembler::Scbndse(const Register& cd, const Register& cn,
const Register& rm) {
DCHECK(allow_macro_instructions());
DCHECK(cd.Is128Bits());
DCHECK(cn.Is128Bits());
DCHECK(rm.Is64Bits());
scbndse(cd, cn, rm);
}

void MacroAssembler::Build(const Register& cd, const Register& cn,
const Register& cm) {
DCHECK(allow_macro_instructions());
DCHECK(cd.Is128Bits());
DCHECK(cn.Is128Bits());
DCHECK(cm.Is128Bits());
build(cd, cn, cm);
}

void MacroAssembler::Seal(const Register& cd, const Register& cn, Cheri::SealImmediateForm form) {
DCHECK(allow_macro_instructions());
DCHECK(cd.Is128Bits());
DCHECK(cn.Is128Bits());
DCHECK_NE(form & 0b11, 0);
seal(cd, cn, form);
}

void MacroAssembler::Subsc(const Register& rd, const Register& cn,
const Operand& operand) {
DCHECK(allow_macro_instructions());
Expand Down
Loading

0 comments on commit 154ced1

Please sign in to comment.