diff options
author | Jacob Bramley <jacob.bramley@arm.com> | 2019-01-18 16:01:08 +0000 |
---|---|---|
committer | Jacob Bramley <jacob.bramley@arm.com> | 2019-02-21 13:18:51 +0000 |
commit | 18c97bde7e79589210a1b156f56e35964174b331 (patch) | |
tree | a752e7b4555f9f0ee043ad5d966266760fc2eb86 /src | |
parent | af0ca0a8e5a90c116e09c359323ef428839df372 (diff) |
Add support for UDF.
This is a backwards-incompatible change because we have to add a visitor to keep
the semantics correct.
Change-Id: I7a5aa95928c9183f85ba833d34d6b024e4ca0e3c
Diffstat (limited to 'src')
-rw-r--r-- | src/aarch64/assembler-aarch64.cc | 2 | ||||
-rw-r--r-- | src/aarch64/assembler-aarch64.h | 8 | ||||
-rw-r--r-- | src/aarch64/constants-aarch64.h | 9 | ||||
-rw-r--r-- | src/aarch64/cpu-features-auditor-aarch64.cc | 5 | ||||
-rw-r--r-- | src/aarch64/decoder-aarch64.cc | 1 | ||||
-rw-r--r-- | src/aarch64/decoder-aarch64.h | 14 | ||||
-rw-r--r-- | src/aarch64/decoder-constants-aarch64.h | 10 | ||||
-rw-r--r-- | src/aarch64/disasm-aarch64.cc | 11 | ||||
-rw-r--r-- | src/aarch64/instrument-aarch64.cc | 8 | ||||
-rw-r--r-- | src/aarch64/macro-assembler-aarch64.h | 6 | ||||
-rw-r--r-- | src/aarch64/simulator-aarch64.cc | 12 | ||||
-rw-r--r-- | src/aarch64/simulator-aarch64.h | 13 |
12 files changed, 88 insertions, 11 deletions
diff --git a/src/aarch64/assembler-aarch64.cc b/src/aarch64/assembler-aarch64.cc index 094bf86d..74a89fef 100644 --- a/src/aarch64/assembler-aarch64.cc +++ b/src/aarch64/assembler-aarch64.cc @@ -5335,6 +5335,8 @@ void Assembler::brk(int code) { void Assembler::svc(int code) { Emit(SVC | ImmException(code)); } +void Assembler::udf(int code) { Emit(UDF | ImmUdf(code)); } + // TODO(all): The third parameter should be passed by reference but gcc 4.8.2 // reports a bogus uninitialised warning then. diff --git a/src/aarch64/assembler-aarch64.h b/src/aarch64/assembler-aarch64.h index ad5773d5..250a0bc3 100644 --- a/src/aarch64/assembler-aarch64.h +++ b/src/aarch64/assembler-aarch64.h @@ -2148,6 +2148,9 @@ class Assembler : public vixl::internal::AssemblerBase { // Generate exception targeting EL1. void svc(int code); + // Generate undefined instruction exception. + void udf(int code); + // Move register to register. void mov(const Register& rd, const Register& rn); @@ -3872,6 +3875,11 @@ class Assembler : public vixl::internal::AssemblerBase { return imm16 << ImmException_offset; } + static Instr ImmUdf(int imm16) { + VIXL_ASSERT(IsUint16(imm16)); + return imm16 << ImmUdf_offset; + } + static Instr ImmSystemRegister(int imm16) { VIXL_ASSERT(IsUint16(imm16)); return imm16 << ImmSystemRegister_offset; diff --git a/src/aarch64/constants-aarch64.h b/src/aarch64/constants-aarch64.h index 696bc9ce..30d2a56d 100644 --- a/src/aarch64/constants-aarch64.h +++ b/src/aarch64/constants-aarch64.h @@ -131,6 +131,7 @@ V_(ImmException, 20, 5, ExtractBits) \ V_(ImmHint, 11, 5, ExtractBits) \ V_(ImmBarrierDomain, 11, 10, ExtractBits) \ V_(ImmBarrierType, 9, 8, ExtractBits) \ +V_(ImmUdf, 15, 0, ExtractBits) \ \ /* System (MRS, MSR, SYS) */ \ V_(ImmSystemRegister, 20, 5, ExtractBits) \ @@ -2643,6 +2644,14 @@ enum NEONScalarShiftImmediateOp { NEON_FCVTZU_imm_scalar = NEON_Q | NEONScalar | NEON_FCVTZU_imm }; +enum ReservedOp { + ReservedFixed = 0x00000000, + ReservedFMask = 0x1E000000, + ReservedMask = 0xFFFF0000, + + UDF = ReservedFixed | 0x00000000 +}; + // Unimplemented and unallocated instructions. These are defined to make fixed // bit assertion easier. enum UnimplementedOp { diff --git a/src/aarch64/cpu-features-auditor-aarch64.cc b/src/aarch64/cpu-features-auditor-aarch64.cc index 0a55a780..3207e73b 100644 --- a/src/aarch64/cpu-features-auditor-aarch64.cc +++ b/src/aarch64/cpu-features-auditor-aarch64.cc @@ -1167,6 +1167,11 @@ void CPUFeaturesAuditor::VisitUnconditionalBranchToRegister( } } +void CPUFeaturesAuditor::VisitReserved(const Instruction* instr) { + RecordInstructionFeaturesScope scope(this); + USE(instr); +} + void CPUFeaturesAuditor::VisitUnimplemented(const Instruction* instr) { RecordInstructionFeaturesScope scope(this); USE(instr); diff --git a/src/aarch64/decoder-aarch64.cc b/src/aarch64/decoder-aarch64.cc index fe72512d..b089e158 100644 --- a/src/aarch64/decoder-aarch64.cc +++ b/src/aarch64/decoder-aarch64.cc @@ -292,6 +292,7 @@ BitExtractFn DecodeNode::GetBitExtractFunction(uint32_t mask, uint32_t value) { INSTANTIATE_TEMPLATE(0xc4000000, 0xc4000000); INSTANTIATE_TEMPLATE(0xe0000010, 0xa0000000); INSTANTIATE_TEMPLATE(0xe01c0000, 0x20000000); + INSTANTIATE_TEMPLATE(0xe1ff0000, 0x00000000); #undef INSTANTIATE_TEMPLATE if (!instantiated) { diff --git a/src/aarch64/decoder-aarch64.h b/src/aarch64/decoder-aarch64.h index 5f467152..2deb5789 100644 --- a/src/aarch64/decoder-aarch64.h +++ b/src/aarch64/decoder-aarch64.h @@ -119,12 +119,18 @@ V(UnconditionalBranch) \ V(UnconditionalBranchToRegister) -#define VISITOR_LIST_THAT_DONT_RETURN(V) \ - V(Unallocated) \ +// TODO: We shouldn't expose debug-only behaviour like this. Instead, we should +// use release-mode aborts where appropriate, and merge thse into a single +// no-return list. +#define VISITOR_LIST_THAT_DONT_RETURN_IN_DEBUG_MODE(V) \ + V(Unallocated) \ V(Unimplemented) -#define VISITOR_LIST(V) \ - VISITOR_LIST_THAT_RETURN(V) \ +#define VISITOR_LIST_THAT_DONT_RETURN(V) V(Reserved) + +#define VISITOR_LIST(V) \ + VISITOR_LIST_THAT_RETURN(V) \ + VISITOR_LIST_THAT_DONT_RETURN_IN_DEBUG_MODE(V) \ VISITOR_LIST_THAT_DONT_RETURN(V) namespace vixl { diff --git a/src/aarch64/decoder-constants-aarch64.h b/src/aarch64/decoder-constants-aarch64.h index c0235555..ef048fe8 100644 --- a/src/aarch64/decoder-constants-aarch64.h +++ b/src/aarch64/decoder-constants-aarch64.h @@ -38,7 +38,8 @@ namespace aarch64 { static const DecodeMapping kDecodeMapping[] = { { "Root", {28, 27, 26, 25}, - { {"100x", "DecodeDataProcessingImmediate"}, + { {"0000", "DecodeReserved"}, + {"100x", "DecodeDataProcessingImmediate"}, {"101x", "DecodeBranchesExceptionAndSystem"}, {"x1x0", "DecodeLoadsAndStores"}, {"x101", "DecodeDataProcessingRegister"}, @@ -46,6 +47,13 @@ static const DecodeMapping kDecodeMapping[] = { }, }, + { "DecodeReserved", + {31, 30, 29, 24, 23, 22, 21, 20, 19, 18, 17, 16}, + { {"000000000000", "VisitReserved"}, + {"otherwise", "VisitUnallocated"}, + }, + }, + { "DecodeDataProcessingImmediate", {25, 24, 23}, { {"00x", "VisitPCRelAddressing"}, diff --git a/src/aarch64/disasm-aarch64.cc b/src/aarch64/disasm-aarch64.cc index c3527eec..ab986e1e 100644 --- a/src/aarch64/disasm-aarch64.cc +++ b/src/aarch64/disasm-aarch64.cc @@ -4905,6 +4905,13 @@ void Disassembler::VisitNEONPerm(const Instruction *instr) { } +void Disassembler::VisitReserved(const Instruction *instr) { + // UDF is the only instruction in this group, and the Decoder is precise. + VIXL_ASSERT(instr->Mask(ReservedMask) == UDF); + Format(instr, "udf", "'IUdf"); +} + + void Disassembler::VisitUnimplemented(const Instruction *instr) { Format(instr, "unimplemented", "(Unimplemented)"); } @@ -5443,6 +5450,10 @@ int Disassembler::SubstituteImmediateField(const Instruction *instr, AppendToOutput("#0x%" PRIx32, instr->GetImmException()); return 6; } + case 'U': { // IUdf - UDF immediate. + AppendToOutput("#0x%" PRIx32, instr->GetImmUdf()); + return 4; + } case 'V': { // Immediate Vector. switch (format[2]) { case 'F': { diff --git a/src/aarch64/instrument-aarch64.cc b/src/aarch64/instrument-aarch64.cc index 02a1083e..72132877 100644 --- a/src/aarch64/instrument-aarch64.cc +++ b/src/aarch64/instrument-aarch64.cc @@ -947,6 +947,14 @@ void Instrument::VisitNEONPerm(const Instruction* instr) { } +void Instrument::VisitReserved(const Instruction* instr) { + USE(instr); + Update(); + static Counter* counter = GetCounter("Other"); + counter->Increment(); +} + + void Instrument::VisitUnallocated(const Instruction* instr) { USE(instr); Update(); diff --git a/src/aarch64/macro-assembler-aarch64.h b/src/aarch64/macro-assembler-aarch64.h index fe95b831..d2f41132 100644 --- a/src/aarch64/macro-assembler-aarch64.h +++ b/src/aarch64/macro-assembler-aarch64.h @@ -2585,9 +2585,9 @@ class MacroAssembler : public Assembler, public MacroAssemblerInterface { if (generate_simulator_code_) { hlt(kUnreachableOpcode); } else { - // Branch to 0 to generate a segfault. - // lr - kInstructionSize is the address of the offending instruction. - blr(xzr); + // Use the architecturally-defined UDF instruction to abort on hardware, + // because using HLT and BRK tends to make the process difficult to debug. + udf(kUnreachableOpcode); } } void Uxtb(const Register& rd, const Register& rn) { diff --git a/src/aarch64/simulator-aarch64.cc b/src/aarch64/simulator-aarch64.cc index 80a99c74..b2b06d92 100644 --- a/src/aarch64/simulator-aarch64.cc +++ b/src/aarch64/simulator-aarch64.cc @@ -1050,6 +1050,18 @@ void Simulator::PrintTakenBranch(const Instruction* target) { // Visitors--------------------------------------------------------------------- + +void Simulator::VisitReserved(const Instruction* instr) { + // UDF is the only instruction in this group, and the Decoder is precise here. + VIXL_ASSERT(instr->Mask(ReservedMask) == UDF); + + printf("UDF (permanently undefined) instruction at %p: 0x%08" PRIx32 "\n", + reinterpret_cast<const void*>(instr), + instr->GetInstructionBits()); + VIXL_ABORT_WITH_MSG("UNDEFINED (UDF)\n"); +} + + void Simulator::VisitUnimplemented(const Instruction* instr) { printf("Unimplemented instruction at %p: 0x%08" PRIx32 "\n", reinterpret_cast<const void*>(instr), diff --git a/src/aarch64/simulator-aarch64.h b/src/aarch64/simulator-aarch64.h index 13803e4f..3c9d146f 100644 --- a/src/aarch64/simulator-aarch64.h +++ b/src/aarch64/simulator-aarch64.h @@ -767,13 +767,20 @@ class Simulator : public DecoderVisitor { VISITOR_LIST_THAT_RETURN(DECLARE) #undef DECLARE -#define DECLARE(A) \ - VIXL_DEBUG_NO_RETURN virtual void Visit##A(const Instruction* instr) \ - VIXL_OVERRIDE; + +#define DECLARE(A) \ + VIXL_NO_RETURN virtual void Visit##A(const Instruction* instr) VIXL_OVERRIDE; VISITOR_LIST_THAT_DONT_RETURN(DECLARE) #undef DECLARE +#define DECLARE(A) \ + VIXL_NO_RETURN_IN_DEBUG_MODE virtual void Visit##A(const Instruction* instr) \ + VIXL_OVERRIDE; + VISITOR_LIST_THAT_DONT_RETURN_IN_DEBUG_MODE(DECLARE) +#undef DECLARE + + // Integer register accessors. // Basic accessor: Read the register as the specified type. |