2020-04-19 23:04:05 +02:00
// SPDX-License-Identifier: MPL-2.0
2020-03-27 20:36:02 +01:00
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
2019-09-24 22:54:27 +02:00
# include <sched.h>
2020-01-11 05:52:25 +01:00
# include <unistd.h>
2019-12-05 16:35:34 +01:00
# include "os.h"
# include "jvm.h"
2020-01-07 03:36:08 +01:00
# include "nce/guest.h"
2020-03-24 21:20:28 +01:00
# include "nce/instructions.h"
2020-01-07 03:36:08 +01:00
# include "kernel/svc.h"
2020-01-21 08:16:57 +01:00
# include "nce.h"
2019-09-24 22:54:27 +02:00
extern bool Halt ;
2020-02-11 07:34:22 +01:00
extern jobject Surface ;
2020-03-24 21:20:28 +01:00
extern skyline : : GroupMutex JniMtx ;
2019-09-24 22:54:27 +02:00
namespace skyline {
2020-01-07 03:36:08 +01:00
void NCE : : KernelThread ( pid_t thread ) {
2020-01-09 02:37:54 +01:00
try {
2020-01-21 08:16:57 +01:00
state . thread = state . process - > threads . at ( thread ) ;
state . ctx = reinterpret_cast < ThreadContext * > ( state . thread - > ctxMemory - > kernel . address ) ;
2020-03-24 21:20:28 +01:00
2020-01-11 05:52:25 +01:00
while ( true ) {
2020-02-11 07:34:22 +01:00
asm ( " yield " ) ;
2020-03-24 21:20:28 +01:00
2020-03-23 17:10:22 +01:00
if ( __predict_false ( Halt ) )
2020-01-11 05:52:25 +01:00
break ;
2020-03-23 17:10:22 +01:00
if ( __predict_false ( ! Surface ) )
2020-02-11 07:34:22 +01:00
continue ;
2020-03-24 21:20:28 +01:00
2020-01-09 02:37:54 +01:00
if ( state . ctx - > state = = ThreadState : : WaitKernel ) {
2020-03-24 21:20:28 +01:00
std : : lock_guard jniGd ( JniMtx ) ;
2020-03-23 17:10:22 +01:00
if ( __predict_false ( Halt ) )
2020-02-11 07:34:22 +01:00
break ;
2020-03-23 17:10:22 +01:00
if ( __predict_false ( ! Surface ) )
2020-02-11 07:34:22 +01:00
continue ;
2020-03-24 21:20:28 +01:00
2020-04-22 19:02:27 +02:00
auto svc = state . ctx - > svc ;
2020-03-24 21:20:28 +01:00
2020-01-09 02:37:54 +01:00
try {
if ( kernel : : svc : : SvcTable [ svc ] ) {
state . logger - > Debug ( " SVC called 0x{:X} " , svc ) ;
( * kernel : : svc : : SvcTable [ svc ] ) ( state ) ;
2020-02-15 10:38:17 +01:00
} else {
2020-01-09 02:37:54 +01:00
throw exception ( " Unimplemented SVC 0x{:X} " , svc ) ;
2020-02-15 10:38:17 +01:00
}
2020-01-09 02:37:54 +01:00
} catch ( const std : : exception & e ) {
throw exception ( " {} (SVC: 0x{:X}) " , e.what(), svc) ;
}
2020-03-24 21:20:28 +01:00
2020-01-09 02:37:54 +01:00
state . ctx - > state = ThreadState : : WaitRun ;
2020-03-23 17:10:22 +01:00
} else if ( __predict_false ( state . ctx - > state = = ThreadState : : GuestCrash ) ) {
2020-04-22 19:02:27 +02:00
state . logger - > Warn ( " Thread with PID {} has crashed due to signal: {} " , thread , strsignal ( state . ctx - > svc ) ) ;
2020-01-09 02:37:54 +01:00
ThreadTrace ( ) ;
2020-03-24 21:20:28 +01:00
2020-01-11 05:52:25 +01:00
state . ctx - > state = ThreadState : : WaitRun ;
2020-01-09 02:37:54 +01:00
break ;
2020-01-07 03:36:08 +01:00
}
}
2020-02-01 16:51:32 +01:00
} catch ( const std : : exception & e ) {
2020-01-09 02:37:54 +01:00
state . logger - > Error ( e . what ( ) ) ;
} catch ( . . . ) {
state . logger - > Error ( " An unknown exception has occurred " ) ;
2020-01-07 03:36:08 +01:00
}
2020-03-24 21:20:28 +01:00
2020-02-11 07:34:22 +01:00
if ( ! Halt ) {
if ( thread = = state . process - > pid ) {
2020-03-24 21:20:28 +01:00
JniMtx . lock ( GroupMutex : : Group : : Group2 ) ;
2020-02-11 07:34:22 +01:00
state . os - > KillThread ( thread ) ;
Halt = true ;
2020-03-24 21:20:28 +01:00
JniMtx . unlock ( ) ;
2020-02-15 10:38:17 +01:00
} else {
2020-02-11 07:34:22 +01:00
state . os - > KillThread ( thread ) ;
2020-02-15 10:38:17 +01:00
}
2020-01-11 05:52:25 +01:00
}
2019-09-24 22:54:27 +02:00
}
2020-01-07 03:36:08 +01:00
NCE : : NCE ( DeviceState & state ) : state ( state ) { }
2019-09-24 22:54:27 +02:00
2020-01-09 02:37:54 +01:00
NCE : : ~ NCE ( ) {
for ( auto & thread : threadMap )
thread . second - > join ( ) ;
}
2019-09-24 22:54:27 +02:00
void NCE : : Execute ( ) {
2020-03-23 17:10:22 +01:00
try {
while ( true ) {
2020-03-24 21:20:28 +01:00
std : : lock_guard guard ( JniMtx ) ;
2020-03-23 17:10:22 +01:00
if ( Halt )
break ;
2020-03-24 21:20:28 +01:00
2020-03-23 17:10:22 +01:00
state . gpu - > Loop ( ) ;
}
} catch ( const std : : exception & e ) {
state . logger - > Error ( e . what ( ) ) ;
} catch ( . . . ) {
state . logger - > Error ( " An unknown exception has occurred " ) ;
Framebuffer and NativeActivity
What was added:
* Framebuffer
* NativeActivity
* NV Services
* IOCTL Handler
* NV Devices:
* * /dev/nvmap - 0xC0080101, 0xC0080103, 0xC0200104, 0xC0180105, 0xC00C0109, 0xC008010E
* * /dev/nvhost-as-gpu
* * /dev/nvhost-channel - 0x40044801, 0xC0104809, 0xC010480B, 0xC018480C, 0x4004480D, 0xC020481A, 0x40084714
* * /dev/nvhost-ctrl
* * /dev/nvhost-ctrl-gpu - 0x80044701, 0x80284702, 0xC0184706, 0xC0B04705, 0x80084714
* SVCs:
* * SetMemoryAttribute
* * CreateTransferMemory
* * ResetSignal
* * GetSystemTick
* Addition of Compact Logger
What was fixed:
* SVCs:
* * SetHeapSize
* * SetMemoryAttribute
* * QueryMemory
* A release build would not set CMAKE_BUILD_TYPE to "RELEASE"
* The logger code was simplified
2019-11-13 21:09:31 +01:00
}
2020-03-24 21:20:28 +01:00
2020-02-11 07:34:22 +01:00
if ( ! Halt ) {
2020-03-24 21:20:28 +01:00
JniMtx . lock ( GroupMutex : : Group : : Group2 ) ;
2020-02-11 07:34:22 +01:00
Halt = true ;
2020-03-24 21:20:28 +01:00
JniMtx . unlock ( ) ;
2020-02-11 07:34:22 +01:00
}
2019-09-24 22:54:27 +02:00
}
2020-01-11 05:52:25 +01:00
/**
* This function will not work if optimizations are enabled as ThreadContext isn ' t volatile
* and due to that is not read on every iteration of the while loop .
* However , making ThreadContext or parts of it volatile slows down the applications as a whole .
* So , we opted to use the hacky solution and disable optimizations for this single function .
*/
void ExecuteFunctionCtx ( ThreadCall call , Registers & funcRegs , ThreadContext * ctx ) __attribute__ ( ( optnone ) ) {
2020-04-22 19:02:27 +02:00
ctx - > threadCall = call ;
2020-01-07 03:36:08 +01:00
Registers registers = ctx - > registers ;
2020-03-24 21:20:28 +01:00
2020-01-09 02:37:54 +01:00
while ( ctx - > state ! = ThreadState : : WaitInit & & ctx - > state ! = ThreadState : : WaitKernel ) ;
2020-03-24 21:20:28 +01:00
2020-01-07 03:36:08 +01:00
ctx - > registers = funcRegs ;
ctx - > state = ThreadState : : WaitFunc ;
2020-03-24 21:20:28 +01:00
2020-01-09 02:37:54 +01:00
while ( ctx - > state ! = ThreadState : : WaitInit & & ctx - > state ! = ThreadState : : WaitKernel ) ;
2020-03-24 21:20:28 +01:00
2020-01-07 03:36:08 +01:00
funcRegs = ctx - > registers ;
ctx - > registers = registers ;
2019-09-24 22:54:27 +02:00
}
2020-01-09 02:37:54 +01:00
void NCE : : ExecuteFunction ( ThreadCall call , Registers & funcRegs , std : : shared_ptr < kernel : : type : : KThread > & thread ) {
ExecuteFunctionCtx ( call , funcRegs , reinterpret_cast < ThreadContext * > ( thread - > ctxMemory - > kernel . address ) ) ;
}
2020-01-21 08:16:57 +01:00
void NCE : : ExecuteFunction ( ThreadCall call , Registers & funcRegs ) {
2020-02-11 07:34:22 +01:00
if ( state . process - > status = = kernel : : type : : KProcess : : Status : : Exiting )
2020-02-05 19:37:45 +01:00
throw exception ( " Executing function on Exiting process " ) ;
2020-03-24 21:20:28 +01:00
2020-01-21 08:16:57 +01:00
auto thread = state . thread ? state . thread : state . process - > threads . at ( state . process - > pid ) ;
ExecuteFunctionCtx ( call , funcRegs , reinterpret_cast < ThreadContext * > ( thread - > ctxMemory - > kernel . address ) ) ;
2019-09-24 22:54:27 +02:00
}
2020-01-11 05:52:25 +01:00
void NCE : : WaitThreadInit ( std : : shared_ptr < kernel : : type : : KThread > & thread ) __attribute__ ( ( optnone ) ) {
2020-01-07 03:36:08 +01:00
auto ctx = reinterpret_cast < ThreadContext * > ( thread - > ctxMemory - > kernel . address ) ;
2020-01-09 02:37:54 +01:00
while ( ctx - > state = = ThreadState : : NotReady ) ;
2019-09-24 22:54:27 +02:00
}
2020-01-07 03:36:08 +01:00
void NCE : : StartThread ( u64 entryArg , u32 handle , std : : shared_ptr < kernel : : type : : KThread > & thread ) {
auto ctx = reinterpret_cast < ThreadContext * > ( thread - > ctxMemory - > kernel . address ) ;
2020-01-09 02:37:54 +01:00
while ( ctx - > state ! = ThreadState : : WaitInit ) ;
2020-03-24 21:20:28 +01:00
2020-01-07 03:36:08 +01:00
ctx - > tpidrroEl0 = thread - > tls ;
ctx - > registers . x0 = entryArg ;
ctx - > registers . x1 = handle ;
ctx - > state = ThreadState : : WaitRun ;
2020-03-24 21:20:28 +01:00
2020-04-19 21:56:49 +02:00
state . logger - > Debug ( " Starting kernel thread for guest thread: {} " , thread - > tid ) ;
threadMap [ thread - > tid ] = std : : make_shared < std : : thread > ( & NCE : : KernelThread , this , thread - > tid ) ;
2019-09-24 22:54:27 +02:00
}
2020-01-07 03:36:08 +01:00
void NCE : : ThreadTrace ( u16 numHist , ThreadContext * ctx ) {
std : : string raw ;
std : : string trace ;
2019-12-25 20:03:57 +01:00
std : : string regStr ;
2020-03-24 21:20:28 +01:00
2020-01-07 03:36:08 +01:00
ctx = ctx ? ctx : state . ctx ;
2020-03-24 21:20:28 +01:00
2020-01-09 02:37:54 +01:00
if ( numHist ) {
2020-01-07 03:36:08 +01:00
std : : vector < u32 > instrs ( numHist ) ;
2020-01-11 05:52:25 +01:00
u64 size = sizeof ( u32 ) * numHist ;
2020-01-09 02:37:54 +01:00
u64 offset = ctx - > pc - size + ( 2 * sizeof ( u32 ) ) ;
2020-03-24 21:20:28 +01:00
2020-01-07 03:36:08 +01:00
state . process - > ReadMemory ( instrs . data ( ) , offset , size ) ;
2020-03-24 21:20:28 +01:00
2020-01-07 03:36:08 +01:00
for ( auto & instr : instrs ) {
instr = __builtin_bswap32 ( instr ) ;
2020-03-24 21:20:28 +01:00
2020-01-07 03:36:08 +01:00
if ( offset = = ctx - > pc )
trace + = fmt : : format ( " \n -> 0x{:X} : 0x{:08X} " , offset , instr ) ;
else
trace + = fmt : : format ( " \n 0x{:X} : 0x{:08X} " , offset , instr ) ;
2020-03-24 21:20:28 +01:00
2020-01-07 03:36:08 +01:00
raw + = fmt : : format ( " {:08X} " , instr ) ;
offset + = sizeof ( u32 ) ;
}
}
2020-03-24 21:20:28 +01:00
2020-01-11 05:52:25 +01:00
if ( ctx - > faultAddress )
regStr + = fmt : : format ( " \n Fault Address: 0x{:X} " , ctx - > faultAddress ) ;
2020-03-24 21:20:28 +01:00
2020-01-11 05:52:25 +01:00
if ( ctx - > sp )
regStr + = fmt : : format ( " \n Stack Pointer: 0x{:X} " , ctx - > sp ) ;
2020-03-24 21:20:28 +01:00
2020-04-22 19:02:27 +02:00
constexpr u8 numRegisters = 31 ; //!< The amount of general-purpose registers in ARMv8
2020-03-25 18:59:37 +01:00
2020-04-22 19:02:27 +02:00
for ( u8 index = 0 ; index < numRegisters - 2 ; index + = 2 ) {
2020-01-15 19:58:58 +01:00
auto xStr = index < 10 ? " X " : " X " ;
regStr + = fmt : : format ( " \n {}{}: 0x{:<16X} {}{}: 0x{:X} " , xStr , index , ctx - > registers . regs [ index ] , xStr , index + 1 , ctx - > registers . regs [ index + 1 ] ) ;
Framebuffer and NativeActivity
What was added:
* Framebuffer
* NativeActivity
* NV Services
* IOCTL Handler
* NV Devices:
* * /dev/nvmap - 0xC0080101, 0xC0080103, 0xC0200104, 0xC0180105, 0xC00C0109, 0xC008010E
* * /dev/nvhost-as-gpu
* * /dev/nvhost-channel - 0x40044801, 0xC0104809, 0xC010480B, 0xC018480C, 0x4004480D, 0xC020481A, 0x40084714
* * /dev/nvhost-ctrl
* * /dev/nvhost-ctrl-gpu - 0x80044701, 0x80284702, 0xC0184706, 0xC0B04705, 0x80084714
* SVCs:
* * SetMemoryAttribute
* * CreateTransferMemory
* * ResetSignal
* * GetSystemTick
* Addition of Compact Logger
What was fixed:
* SVCs:
* * SetHeapSize
* * SetMemoryAttribute
* * QueryMemory
* A release build would not set CMAKE_BUILD_TYPE to "RELEASE"
* The logger code was simplified
2019-11-13 21:09:31 +01:00
}
2020-03-24 21:20:28 +01:00
2020-01-09 02:37:54 +01:00
if ( numHist ) {
state . logger - > Debug ( " Process Trace:{} " , trace ) ;
2020-01-11 05:52:25 +01:00
state . logger - > Debug ( " Raw Instructions: 0x{} " , raw ) ;
state . logger - > Debug ( " CPU Context:{} " , regStr ) ;
2020-02-15 10:38:17 +01:00
} else {
2020-01-11 05:52:25 +01:00
state . logger - > Debug ( " CPU Context:{} " , regStr ) ;
2020-02-15 10:38:17 +01:00
}
2019-09-24 22:54:27 +02:00
}
2020-01-07 03:36:08 +01:00
std : : vector < u32 > NCE : : PatchCode ( std : : vector < u8 > & code , u64 baseAddress , i64 offset ) {
2020-04-22 19:02:27 +02:00
constexpr u32 TpidrroEl0 = 0x5E83 ; // ID of TPIDRRO_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 CntvctEl0 = 0x5F02 ; // ID of CNTVCT_EL0 in MRS
constexpr u32 TegraX1Freq = 19200000 ; // The clock frequency of the Tegra X1 (19.2 MHz)
2020-03-25 18:59:37 +01:00
2020-01-07 03:36:08 +01:00
u32 * start = reinterpret_cast < u32 * > ( code . data ( ) ) ;
u32 * end = start + ( code . size ( ) / sizeof ( u32 ) ) ;
2019-12-25 20:03:57 +01:00
i64 patchOffset = offset ;
2020-03-25 18:59:37 +01:00
std : : vector < u32 > patch ( ( guest : : SaveCtxSize + guest : : LoadCtxSize + guest : : SvcHandlerSize ) / sizeof ( u32 ) ) ;
2020-01-07 03:36:08 +01:00
2020-03-25 18:59:37 +01:00
std : : memcpy ( patch . data ( ) , reinterpret_cast < void * > ( & guest : : SaveCtx ) , guest : : SaveCtxSize ) ;
offset + = guest : : SaveCtxSize ;
2019-12-25 20:03:57 +01:00
2020-03-25 18:59:37 +01:00
std : : memcpy ( reinterpret_cast < u8 * > ( patch . data ( ) ) + guest : : SaveCtxSize , reinterpret_cast < void * > ( & guest : : LoadCtx ) , guest : : LoadCtxSize ) ;
offset + = guest : : LoadCtxSize ;
2019-12-25 20:03:57 +01:00
2020-03-25 18:59:37 +01:00
std : : memcpy ( reinterpret_cast < u8 * > ( patch . data ( ) ) + guest : : SaveCtxSize + guest : : LoadCtxSize , reinterpret_cast < void * > ( & guest : : SvcHandler ) , guest : : SvcHandlerSize ) ;
offset + = guest : : SvcHandlerSize ;
2020-01-07 03:36:08 +01:00
2020-02-11 07:34:22 +01:00
static u64 frequency { } ;
if ( ! frequency )
asm ( " MRS %0, CNTFRQ_EL0 " : " =r " ( frequency ) ) ;
2020-01-09 02:37:54 +01:00
for ( u32 * address = start ; address < end ; address + + ) {
2019-12-25 20:03:57 +01:00
auto instrSvc = reinterpret_cast < instr : : Svc * > ( address ) ;
auto instrMrs = reinterpret_cast < instr : : Mrs * > ( address ) ;
if ( instrSvc - > Verify ( ) ) {
2020-04-22 19:02:27 +02:00
// 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
2020-03-24 21:20:28 +01:00
instr : : B bJunc ( offset ) ;
2020-04-22 19:02:27 +02:00
2019-12-25 20:03:57 +01:00
constexpr u32 strLr = 0xF81F0FFE ; // STR LR, [SP, #-16]!
offset + = sizeof ( strLr ) ;
2020-04-22 19:02:27 +02:00
2019-12-25 20:03:57 +01:00
instr : : BL bSvCtx ( patchOffset - offset ) ;
offset + = sizeof ( bSvCtx ) ;
2020-01-07 03:36:08 +01:00
2020-04-22 19:02:27 +02:00
auto movPc = instr : : MoveRegister < u64 > ( regs : : X0 , baseAddress + ( address - start ) ) ;
2020-01-07 03:36:08 +01:00
offset + = sizeof ( u32 ) * movPc . size ( ) ;
2020-04-22 19:02:27 +02:00
2020-01-07 03:36:08 +01:00
instr : : Movz movCmd ( regs : : W1 , static_cast < u16 > ( instrSvc - > value ) ) ;
offset + = sizeof ( movCmd ) ;
2020-04-22 19:02:27 +02:00
2020-03-25 18:59:37 +01:00
instr : : BL bSvcHandler ( ( patchOffset + guest : : SaveCtxSize + guest : : LoadCtxSize ) - offset ) ;
2020-01-07 03:36:08 +01:00
offset + = sizeof ( bSvcHandler ) ;
2020-03-25 18:59:37 +01:00
instr : : BL bLdCtx ( ( patchOffset + guest : : SaveCtxSize ) - offset ) ;
2019-12-25 20:03:57 +01:00
offset + = sizeof ( bLdCtx ) ;
2020-04-22 19:02:27 +02:00
2019-12-25 20:03:57 +01:00
constexpr u32 ldrLr = 0xF84107FE ; // LDR LR, [SP], #16
offset + = sizeof ( ldrLr ) ;
2020-04-22 19:02:27 +02:00
2019-12-25 20:03:57 +01:00
instr : : B bret ( - offset + sizeof ( u32 ) ) ;
offset + = sizeof ( bret ) ;
2020-03-24 21:20:28 +01:00
* address = bJunc . raw ;
2019-12-25 20:03:57 +01:00
patch . push_back ( strLr ) ;
patch . push_back ( bSvCtx . raw ) ;
2020-01-09 02:37:54 +01:00
for ( auto & instr : movPc )
2020-01-07 03:36:08 +01:00
patch . push_back ( instr ) ;
patch . push_back ( movCmd . raw ) ;
patch . push_back ( bSvcHandler . raw ) ;
2019-12-25 20:03:57 +01:00
patch . push_back ( bLdCtx . raw ) ;
patch . push_back ( ldrLr ) ;
patch . push_back ( bret . raw ) ;
2020-01-09 02:37:54 +01:00
} else if ( instrMrs - > Verify ( ) ) {
2020-03-25 18:59:37 +01:00
if ( instrMrs - > srcReg = = TpidrroEl0 ) {
2020-04-22 19:02:27 +02:00
// 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
2020-03-24 21:20:28 +01:00
instr : : B bJunc ( offset ) ;
2020-04-22 19:02:27 +02:00
2020-01-07 03:36:08 +01:00
u32 strX0 { } ;
2020-01-09 02:37:54 +01:00
if ( instrMrs - > destReg ! = regs : : X0 ) {
2020-01-07 03:36:08 +01:00
strX0 = 0xF81F0FE0 ; // STR X0, [SP, #-16]!
offset + = sizeof ( strX0 ) ;
}
2020-04-22 19:02:27 +02:00
constexpr u32 mrsX0 = 0xD53BD040 ; // MRS X0, TPIDR_EL0
2020-01-07 03:36:08 +01:00
offset + = sizeof ( mrsX0 ) ;
2020-04-22 19:02:27 +02:00
constexpr u32 ldrTls = 0xF9408000 ; // LDR X0, [X0, #256] (ThreadContext::tpidrroEl0)
2020-01-07 03:36:08 +01:00
offset + = sizeof ( ldrTls ) ;
2020-04-22 19:02:27 +02:00
2020-01-07 03:36:08 +01:00
u32 movXn { } ;
u32 ldrX0 { } ;
2020-01-09 02:37:54 +01:00
if ( instrMrs - > destReg ! = regs : : X0 ) {
2020-01-07 03:36:08 +01:00
movXn = instr : : Mov ( regs : : X ( instrMrs - > destReg ) , regs : : X0 ) . raw ;
offset + = sizeof ( movXn ) ;
2020-04-22 19:02:27 +02:00
2020-01-07 03:36:08 +01:00
ldrX0 = 0xF84107E0 ; // LDR X0, [SP], #16
offset + = sizeof ( ldrX0 ) ;
}
2020-04-22 19:02:27 +02:00
2020-01-07 03:36:08 +01:00
instr : : B bret ( - offset + sizeof ( u32 ) ) ;
offset + = sizeof ( bret ) ;
2020-03-24 21:20:28 +01:00
* address = bJunc . raw ;
2020-01-09 02:37:54 +01:00
if ( strX0 )
patch . push_back ( strX0 ) ;
2020-01-07 03:36:08 +01:00
patch . push_back ( mrsX0 ) ;
patch . push_back ( ldrTls ) ;
2020-01-09 02:37:54 +01:00
if ( movXn )
patch . push_back ( movXn ) ;
if ( ldrX0 )
patch . push_back ( ldrX0 ) ;
2020-01-07 03:36:08 +01:00
patch . push_back ( bret . raw ) ;
2020-03-25 18:59:37 +01:00
} else if ( frequency ! = TegraX1Freq ) {
2020-04-22 19:02:27 +02:00
// These deal with changing the timer registers, we only do this if the clock frequency doesn't match the X1's clock frequency
2020-03-25 18:59:37 +01:00
if ( instrMrs - > srcReg = = CntpctEl0 ) {
2020-04-22 19:02:27 +02:00
// If this moves CNTPCT_EL0 into a register then call RescaleClock to rescale the device's clock to the X1's clock frequency and write result to register
2020-03-24 21:20:28 +01:00
instr : : B bJunc ( offset ) ;
2020-03-25 18:59:37 +01:00
offset + = guest : : RescaleClockSize ;
2020-04-22 19:02:27 +02:00
2020-02-11 07:34:22 +01:00
instr : : Ldr ldr ( 0xF94003E0 ) ; // LDR XOUT, [SP]
ldr . destReg = instrMrs - > destReg ;
offset + = sizeof ( ldr ) ;
2020-04-22 19:02:27 +02:00
constexpr u32 addSp = 0x910083FF ; // ADD SP, SP, #32
2020-02-11 07:34:22 +01:00
offset + = sizeof ( addSp ) ;
2020-04-22 19:02:27 +02:00
2020-02-11 07:34:22 +01:00
instr : : B bret ( - offset + sizeof ( u32 ) ) ;
offset + = sizeof ( bret ) ;
2020-01-07 03:36:08 +01:00
2020-03-24 21:20:28 +01:00
* address = bJunc . raw ;
2020-02-15 10:38:17 +01:00
auto size = patch . size ( ) ;
2020-03-25 18:59:37 +01:00
patch . resize ( size + ( guest : : RescaleClockSize / sizeof ( u32 ) ) ) ;
std : : memcpy ( patch . data ( ) + size , reinterpret_cast < void * > ( & guest : : RescaleClock ) , guest : : RescaleClockSize ) ;
2020-02-11 07:34:22 +01:00
patch . push_back ( ldr . raw ) ;
patch . push_back ( addSp ) ;
patch . push_back ( bret . raw ) ;
2020-03-25 18:59:37 +01:00
} else if ( instrMrs - > srcReg = = CntfrqEl0 ) {
2020-04-22 19:02:27 +02:00
// If this moves CNTFRQ_EL0 into a register then move the Tegra X1's clock frequency into the register (Rather than the host clock frequency)
2020-03-24 21:20:28 +01:00
instr : : B bJunc ( offset ) ;
2020-04-22 19:02:27 +02:00
auto movFreq = instr : : MoveRegister < u32 > ( static_cast < regs : : X > ( instrMrs - > destReg ) , TegraX1Freq ) ;
2020-02-11 07:34:22 +01:00
offset + = sizeof ( u32 ) * movFreq . size ( ) ;
2020-04-22 19:02:27 +02:00
2020-02-11 07:34:22 +01:00
instr : : B bret ( - offset + sizeof ( u32 ) ) ;
offset + = sizeof ( bret ) ;
2020-03-24 21:20:28 +01:00
* address = bJunc . raw ;
2020-02-11 07:34:22 +01:00
for ( auto & instr : movFreq )
2020-01-07 03:36:08 +01:00
patch . push_back ( instr ) ;
2020-02-11 07:34:22 +01:00
patch . push_back ( bret . raw ) ;
}
} else {
2020-04-22 19:02:27 +02:00
// If the host clock frequency is the same as the Tegra X1's clock frequency
2020-03-25 18:59:37 +01:00
if ( instrMrs - > srcReg = = CntpctEl0 ) {
2020-04-22 19:02:27 +02:00
// If this moves CNTPCT_EL0 into a register, change the instruction to move CNTVCT_EL0 instead as Linux or most other OSes don't allow access to CNTPCT_EL0 rather only CNTVCT_EL0 can be accessed from userspace
* address = instr : : Mrs ( CntvctEl0 , regs : : X ( instrMrs - > destReg ) ) . raw ;
2020-01-09 02:37:54 +01:00
}
2019-12-25 20:03:57 +01:00
}
}
2020-03-24 21:20:28 +01:00
2019-12-25 20:03:57 +01:00
offset - = sizeof ( u32 ) ;
patchOffset - = sizeof ( u32 ) ;
}
return patch ;
}
2019-09-24 22:54:27 +02:00
}