diff --git a/include/dynarmic/A64/config.h b/include/dynarmic/A64/config.h index 3edbf0f8..aab79f01 100644 --- a/include/dynarmic/A64/config.h +++ b/include/dynarmic/A64/config.h @@ -120,6 +120,10 @@ struct UserConfig { /// emitted code. const std::uint64_t* tpidrro_el0 = nullptr; + /// Pointer to where TPIDR_EL0 is stored. This pointer will be inserted into + /// emitted code. + const std::uint64_t* tpidr_el0 = nullptr; + /// Pointer to the page table which we can use for direct page table access. /// If an entry in page_table is null, the relevant memory callback will be called. /// If page_table is nullptr, all memory accesses hit the memory callbacks. diff --git a/src/backend_x64/a64_emit_x64.cpp b/src/backend_x64/a64_emit_x64.cpp index 4df1f142..fea42c9f 100644 --- a/src/backend_x64/a64_emit_x64.cpp +++ b/src/backend_x64/a64_emit_x64.cpp @@ -530,6 +530,27 @@ void A64EmitX64::EmitA64GetDCZID(A64EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.DefineValue(inst, result); } +void A64EmitX64::EmitA64GetTPIDR(A64EmitContext& ctx, IR::Inst* inst) { + Xbyak::Reg64 result = ctx.reg_alloc.ScratchGpr(); + if (conf.tpidr_el0) { + code.mov(result, u64(conf.tpidr_el0)); + code.mov(result, qword[result]); + } else { + code.xor_(result.cvt32(), result.cvt32()); + } + ctx.reg_alloc.DefineValue(inst, result); +} + +void A64EmitX64::EmitA64SetTPIDR(A64EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + Xbyak::Reg64 value = ctx.reg_alloc.UseGpr(args[0]); + Xbyak::Reg64 addr = ctx.reg_alloc.ScratchGpr(); + if (conf.tpidr_el0) { + code.mov(addr, u64(conf.tpidr_el0)); + code.mov(qword[addr], value); + } +} + void A64EmitX64::EmitA64GetTPIDRRO(A64EmitContext& ctx, IR::Inst* inst) { Xbyak::Reg64 result = ctx.reg_alloc.ScratchGpr(); if (conf.tpidrro_el0) { diff --git a/src/frontend/A64/ir_emitter.cpp b/src/frontend/A64/ir_emitter.cpp index 64176b25..24703f8c 100644 --- a/src/frontend/A64/ir_emitter.cpp +++ b/src/frontend/A64/ir_emitter.cpp @@ -65,6 +65,14 @@ IR::U32 IREmitter::GetDCZID() { return Inst(Opcode::A64GetDCZID); } +IR::U64 IREmitter::GetTPIDR() { + return Inst(Opcode::A64GetTPIDR); +} + +void IREmitter::SetTPIDR(const IR::U64& value) { + Inst(Opcode::A64SetTPIDR, value); +} + IR::U64 IREmitter::GetTPIDRRO() { return Inst(Opcode::A64GetTPIDRRO); } diff --git a/src/frontend/A64/ir_emitter.h b/src/frontend/A64/ir_emitter.h index 2fb8e525..1a47f644 100644 --- a/src/frontend/A64/ir_emitter.h +++ b/src/frontend/A64/ir_emitter.h @@ -47,6 +47,8 @@ public: IR::U64 GetCNTPCT(); // TODO: Ensure sub-basic-block cycle counts are updated before this. IR::U32 GetCTR(); IR::U32 GetDCZID(); + IR::U64 GetTPIDR(); + void SetTPIDR(const IR::U64& value); IR::U64 GetTPIDRRO(); void ClearExclusive(); diff --git a/src/frontend/A64/translate/impl/system.cpp b/src/frontend/A64/translate/impl/system.cpp index f88829e4..b8a3dc03 100644 --- a/src/frontend/A64/translate/impl/system.cpp +++ b/src/frontend/A64/translate/impl/system.cpp @@ -54,6 +54,9 @@ bool TranslatorVisitor::DMB(Imm<4> /*CRm*/) { bool TranslatorVisitor::MSR_reg(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3> op2, Reg Rt) { const size_t sys_reg = concatenate(Imm<1>{1}, o0, op1, CRn, CRm, op2).ZeroExtend(); switch (sys_reg) { + case 0b11'011'1101'0000'010: // TPIDR_EL0 + ir.SetTPIDR(X(64, Rt)); + return true; case 0b11'011'0100'0100'000: // FPCR ir.SetFPCR(X(32, Rt)); ir.SetTerm(IR::Term::ReturnToDispatch{}); @@ -68,6 +71,9 @@ bool TranslatorVisitor::MSR_reg(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, I bool TranslatorVisitor::MRS(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3> op2, Reg Rt) { const size_t sys_reg = concatenate(Imm<1>{1}, o0, op1, CRn, CRm, op2).ZeroExtend(); switch (sys_reg) { + case 0b11'011'1101'0000'010: // TPIDR_EL0 + X(64, Rt, ir.GetTPIDR()); + return true; case 0b11'011'1101'0000'011: // TPIDRRO_EL0 X(64, Rt, ir.GetTPIDRRO()); return true; diff --git a/src/frontend/ir/opcodes.inc b/src/frontend/ir/opcodes.inc index 630464db..83c10c2a 100644 --- a/src/frontend/ir/opcodes.inc +++ b/src/frontend/ir/opcodes.inc @@ -68,6 +68,8 @@ A64OPC(DataMemoryBarrier, T::Void, A64OPC(GetCNTPCT, T::U64, ) A64OPC(GetCTR, T::U32, ) A64OPC(GetDCZID, T::U32, ) +A64OPC(GetTPIDR, T::U64, ) +A64OPC(SetTPIDR, T::Void, T::U64 ) A64OPC(GetTPIDRRO, T::U64, ) // Hints