mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-29 22:04:17 +01:00
Emulate TPIDR_EL0 accesses using TLS
This commit is contained in:
parent
c423a66020
commit
138e219e0c
@ -209,6 +209,7 @@ namespace skyline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u32> NCE::PatchCode(std::vector<u8> &code, u64 baseAddress, i64 offset) {
|
std::vector<u32> NCE::PatchCode(std::vector<u8> &code, u64 baseAddress, i64 offset) {
|
||||||
|
constexpr u32 TpidrEl0 = 0x5e82; // ID of TPIDR_EL0 in MRS
|
||||||
constexpr u32 TpidrroEl0 = 0x5E83; // ID of TPIDRRO_EL0 in MRS
|
constexpr u32 TpidrroEl0 = 0x5E83; // ID of TPIDRRO_EL0 in MRS
|
||||||
constexpr u32 CntfrqEl0 = 0x5F00; // ID of CNTFRQ_EL0 in MRS
|
constexpr u32 CntfrqEl0 = 0x5F00; // ID of CNTFRQ_EL0 in MRS
|
||||||
constexpr u32 CntpctEl0 = 0x5F01; // ID of CNTPCT_EL0 in MRS
|
constexpr u32 CntpctEl0 = 0x5F01; // ID of CNTPCT_EL0 in MRS
|
||||||
@ -237,6 +238,7 @@ namespace skyline {
|
|||||||
for (u32 *address = start; address < end; address++) {
|
for (u32 *address = start; address < end; address++) {
|
||||||
auto instrSvc = reinterpret_cast<instr::Svc *>(address);
|
auto instrSvc = reinterpret_cast<instr::Svc *>(address);
|
||||||
auto instrMrs = reinterpret_cast<instr::Mrs *>(address);
|
auto instrMrs = reinterpret_cast<instr::Mrs *>(address);
|
||||||
|
auto instrMsr = reinterpret_cast<instr::Msr *>(address);
|
||||||
|
|
||||||
if (instrSvc->Verify()) {
|
if (instrSvc->Verify()) {
|
||||||
// If this is an SVC we need to branch to saveCtx then to the SVC Handler after putting the PC + SVC into X0 and W1 and finally loadCtx before returning to where we were before
|
// If this is an SVC we need to branch to saveCtx then to the SVC Handler after putting the PC + SVC into X0 and W1 and finally loadCtx before returning to where we were before
|
||||||
@ -277,8 +279,8 @@ namespace skyline {
|
|||||||
patch.push_back(ldrLr);
|
patch.push_back(ldrLr);
|
||||||
patch.push_back(bret.raw);
|
patch.push_back(bret.raw);
|
||||||
} else if (instrMrs->Verify()) {
|
} else if (instrMrs->Verify()) {
|
||||||
if (instrMrs->srcReg == TpidrroEl0) {
|
if (instrMrs->srcReg == TpidrroEl0 || instrMrs->srcReg == TpidrEl0) {
|
||||||
// If this moves TPIDRRO_EL0 into a register then we retrieve the value of our virtual TPIDRRO_EL0 from TLS and write it to the register
|
// If this moves TPIDR(RO)_EL0 into a register then we retrieve the value of our virtual TPIDR(RO)_EL0 from TLS and write it to the register
|
||||||
instr::B bJunc(offset);
|
instr::B bJunc(offset);
|
||||||
|
|
||||||
u32 strX0{};
|
u32 strX0{};
|
||||||
@ -290,7 +292,12 @@ namespace skyline {
|
|||||||
constexpr u32 mrsX0 = 0xD53BD040; // MRS X0, TPIDR_EL0
|
constexpr u32 mrsX0 = 0xD53BD040; // MRS X0, TPIDR_EL0
|
||||||
offset += sizeof(mrsX0);
|
offset += sizeof(mrsX0);
|
||||||
|
|
||||||
constexpr u32 ldrTls = 0xF9408000; // LDR X0, [X0, #256] (ThreadContext::tpidrroEl0)
|
u32 ldrTls;
|
||||||
|
if (instrMrs->srcReg == TpidrroEl0)
|
||||||
|
ldrTls = 0xF9408000; // LDR X0, [X0, #256] (ThreadContext::tpidrroEl0)
|
||||||
|
else
|
||||||
|
ldrTls = 0xF9408400; // LDR X0, [X0, #264] (ThreadContext::tpidrEl0)
|
||||||
|
|
||||||
offset += sizeof(ldrTls);
|
offset += sizeof(ldrTls);
|
||||||
|
|
||||||
u32 movXn{};
|
u32 movXn{};
|
||||||
@ -362,6 +369,41 @@ namespace skyline {
|
|||||||
*address = instr::Mrs(CntvctEl0, regs::X(instrMrs->destReg)).raw;
|
*address = instr::Mrs(CntvctEl0, regs::X(instrMrs->destReg)).raw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (instrMsr->Verify()) {
|
||||||
|
if (instrMsr->destReg == TpidrEl0) {
|
||||||
|
// If this moves a register into TPIDR_EL0 then we retrieve the value of the register and write it to our virtual TPIDR_EL0 in TLS
|
||||||
|
instr::B bJunc(offset);
|
||||||
|
|
||||||
|
// Used to avoid conflicts as we cannot read the source register from the stack
|
||||||
|
bool x0x1 = instrMrs->srcReg != regs::X0 && instrMrs->srcReg != regs::X1;
|
||||||
|
|
||||||
|
// Push two registers to stack that can be used to load the TLS and arguments into
|
||||||
|
u32 pushXn = x0x1 ? 0xA9BF07E0 : 0xA9BF0FE2; // STP X(0/2), X(1/3), [SP, #-16]!
|
||||||
|
offset += sizeof(pushXn);
|
||||||
|
|
||||||
|
u32 loadRealTls = x0x1 ? 0xD53BD040 : 0xD53BD042; // MRS X(0/2), TPIDR_EL0
|
||||||
|
offset += sizeof(loadRealTls);
|
||||||
|
|
||||||
|
instr::Mov moveParam(x0x1 ? regs::X1 : regs::X3, regs::X(instrMsr->srcReg));
|
||||||
|
offset += sizeof(moveParam);
|
||||||
|
|
||||||
|
u32 storeEmuTls = x0x1 ? 0xF9008401 : 0xF9008403; // STR X(1/3), [X0, #264] (ThreadContext::tpidrEl0)
|
||||||
|
offset += sizeof(storeEmuTls);
|
||||||
|
|
||||||
|
u32 popXn = x0x1 ? 0xA8C107E0 : 0xA8C10FE2; // LDP X(0/2), X(1/3), [SP], #16
|
||||||
|
offset += sizeof(popXn);
|
||||||
|
|
||||||
|
instr::B bret(-offset + sizeof(u32));
|
||||||
|
offset += sizeof(bret);
|
||||||
|
|
||||||
|
*address = bJunc.raw;
|
||||||
|
patch.push_back(pushXn);
|
||||||
|
patch.push_back(loadRealTls);
|
||||||
|
patch.push_back(moveParam.raw);
|
||||||
|
patch.push_back(storeEmuTls);
|
||||||
|
patch.push_back(popXn);
|
||||||
|
patch.push_back(bret.raw);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
offset -= sizeof(u32);
|
offset -= sizeof(u32);
|
||||||
|
@ -153,6 +153,7 @@ namespace skyline {
|
|||||||
u64 pc; //!< The program counter register on the guest
|
u64 pc; //!< The program counter register on the guest
|
||||||
Registers registers; //!< The general purpose registers on the guest
|
Registers registers; //!< The general purpose registers on the guest
|
||||||
u64 tpidrroEl0; //!< The value for TPIDRRO_EL0 for the current thread
|
u64 tpidrroEl0; //!< The value for TPIDRRO_EL0 for the current thread
|
||||||
|
u64 tpidrEl0; //!< The value for TPIDR_EL0 for the current thread
|
||||||
u64 faultAddress; //!< The address a fault has occurred at during guest crash
|
u64 faultAddress; //!< The address a fault has occurred at during guest crash
|
||||||
u64 sp; //!< The current location of the stack pointer set during guest crash
|
u64 sp; //!< The current location of the stack pointer set during guest crash
|
||||||
};
|
};
|
||||||
|
@ -101,6 +101,29 @@ namespace skyline {
|
|||||||
};
|
};
|
||||||
static_assert(sizeof(Mrs) == sizeof(u32));
|
static_assert(sizeof(Mrs) == sizeof(u32));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A bit-field struct that encapsulates a MSR instruction. See https://developer.arm.com/docs/ddi0596/g/base-instructions-alphabetic-order/msr-register-move-general-purpose-register-to-system-register.
|
||||||
|
*/
|
||||||
|
struct Msr {
|
||||||
|
/**
|
||||||
|
* @brief Returns if the opcode is valid or not
|
||||||
|
* @return If the opcode represents a valid MSR instruction
|
||||||
|
*/
|
||||||
|
inline constexpr bool Verify() {
|
||||||
|
return (sig == 0xD51);
|
||||||
|
}
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
u8 srcReg : 5; //!< 5-bit destination register
|
||||||
|
u32 destReg : 15; //!< 15-bit source register
|
||||||
|
u16 sig : 12; //!< 16-bit signature (0xD51)
|
||||||
|
};
|
||||||
|
u32 raw{}; //!< The raw value of the instruction
|
||||||
|
};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(Msr) == sizeof(u32));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A bit-field struct that encapsulates a B instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/b-branch.
|
* @brief A bit-field struct that encapsulates a B instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/b-branch.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user