mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
emummc: update for exo2
This commit is contained in:
parent
f82954e98b
commit
ff87ff2592
8 changed files with 328 additions and 49 deletions
|
@ -128,6 +128,8 @@
|
|||
"svcUnmapDeviceAddressSpace": "0x5c",
|
||||
"svcGetSystemInfo": "0x6f",
|
||||
"svcSetProcessMemoryPermission": "0x73",
|
||||
"svcMapProcessMemory": "0x74",
|
||||
"svcUnmapProcessMemory": "0x75",
|
||||
"svcCallSecureMonitor": "0x7f"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,8 +39,11 @@ void hook_function(uintptr_t source, uintptr_t target);
|
|||
|
||||
void *__stack_top;
|
||||
uintptr_t text_base;
|
||||
size_t fs_code_size;
|
||||
char inner_heap[INNER_HEAP_SIZE];
|
||||
size_t inner_heap_size = INNER_HEAP_SIZE;
|
||||
Handle self_proc_handle = 0;
|
||||
u8 *fs_rw_mapping = NULL;
|
||||
extern char _start;
|
||||
extern char __argdata__;
|
||||
|
||||
|
@ -148,15 +151,117 @@ void __initheap(void)
|
|||
fake_heap_end = (char *)addr + size;
|
||||
}
|
||||
|
||||
static void _receive_process_handle_thread(void *_session_handle) {
|
||||
Result rc;
|
||||
|
||||
// Convert the argument to a handle we can use.
|
||||
Handle session_handle = (Handle)(uintptr_t)_session_handle;
|
||||
|
||||
// Receive the request from the client thread.
|
||||
memset(armGetTls(), 0, 0x10);
|
||||
s32 idx = 0;
|
||||
rc = svcReplyAndReceive(&idx, &session_handle, 1, INVALID_HANDLE, UINT64_MAX);
|
||||
if (rc != 0)
|
||||
{
|
||||
fatal_abort(Fatal_BadResult);
|
||||
}
|
||||
|
||||
// Set the process handle.
|
||||
self_proc_handle = ((u32 *)armGetTls())[3];
|
||||
|
||||
// Close the session.
|
||||
svcCloseHandle(session_handle);
|
||||
|
||||
// Terminate ourselves.
|
||||
svcExitThread();
|
||||
|
||||
// This code will never execute.
|
||||
while (true);
|
||||
}
|
||||
|
||||
static void _init_process_handle(void) {
|
||||
Result rc;
|
||||
u8 temp_thread_stack[0x1000];
|
||||
|
||||
// Create a new session to transfer our process handle to ourself
|
||||
Handle server_handle, client_handle;
|
||||
rc = svcCreateSession(&server_handle, &client_handle, 0, 0);
|
||||
if (rc != 0)
|
||||
{
|
||||
fatal_abort(Fatal_BadResult);
|
||||
}
|
||||
|
||||
// Create a new thread to receive our handle.
|
||||
Handle thread_handle;
|
||||
rc = svcCreateThread(&thread_handle, _receive_process_handle_thread, (void *)(uintptr_t)server_handle, temp_thread_stack + sizeof(temp_thread_stack), 0x20, 3);
|
||||
if (rc != 0)
|
||||
{
|
||||
fatal_abort(Fatal_BadResult);
|
||||
}
|
||||
|
||||
// Start the new thread.
|
||||
rc = svcStartThread(thread_handle);
|
||||
if (rc != 0)
|
||||
{
|
||||
fatal_abort(Fatal_BadResult);
|
||||
}
|
||||
|
||||
// Send the message.
|
||||
static const u32 SendProcessHandleMessage[4] = { 0x00000000, 0x80000000, 0x00000002, CUR_PROCESS_HANDLE };
|
||||
memcpy(armGetTls(), SendProcessHandleMessage, sizeof(SendProcessHandleMessage));
|
||||
svcSendSyncRequest(client_handle);
|
||||
|
||||
// Close the session handle.
|
||||
svcCloseHandle(client_handle);
|
||||
|
||||
// Wait for the thread to be done.
|
||||
rc = svcWaitSynchronizationSingle(thread_handle, UINT64_MAX);
|
||||
if (rc != 0)
|
||||
{
|
||||
fatal_abort(Fatal_BadResult);
|
||||
}
|
||||
|
||||
// Close the thread handle.
|
||||
svcCloseHandle(thread_handle);
|
||||
}
|
||||
|
||||
static void _map_fs_rw(void) {
|
||||
Result rc;
|
||||
|
||||
do {
|
||||
fs_rw_mapping = (u8 *)(smcGenerateRandomU64() & 0xFFFFFF000ull);
|
||||
rc = svcMapProcessMemory(fs_rw_mapping, self_proc_handle, INJECT_OFFSET(u64, 0), fs_code_size);
|
||||
} while (rc == 0xDC01 || rc == 0xD401);
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
fatal_abort(Fatal_BadResult);
|
||||
}
|
||||
}
|
||||
|
||||
static void _unmap_fs_rw(void) {
|
||||
Result rc = svcUnmapProcessMemory(fs_rw_mapping, self_proc_handle, INJECT_OFFSET(u64, 0), fs_code_size);
|
||||
if (rc != 0)
|
||||
{
|
||||
fatal_abort(Fatal_BadResult);
|
||||
}
|
||||
|
||||
fs_rw_mapping = NULL;
|
||||
}
|
||||
|
||||
static void _write32(uintptr_t source, u32 value) {
|
||||
*((u32 *)(fs_rw_mapping + (source - INJECT_OFFSET(u64, 0)))) = value;
|
||||
}
|
||||
|
||||
void hook_function(uintptr_t source, uintptr_t target)
|
||||
{
|
||||
u32 branch_opcode = GENERATE_BRANCH(source, target);
|
||||
smcWriteAddress32((void *)source, branch_opcode);
|
||||
_write32(source, branch_opcode);
|
||||
}
|
||||
|
||||
void write_nop(uintptr_t source)
|
||||
{
|
||||
smcWriteAddress32((void *)source, GENERATE_NOP());
|
||||
_write32(source, GENERATE_NOP());
|
||||
}
|
||||
|
||||
void write_adrp_add(int reg, uintptr_t pc, uintptr_t add_rel_offset, intptr_t destination)
|
||||
|
@ -167,8 +272,8 @@ void write_adrp_add(int reg, uintptr_t pc, uintptr_t add_rel_offset, intptr_t de
|
|||
uint32_t opcode_adrp = GENERATE_ADRP(reg, offset);
|
||||
uint32_t opcode_add = GENERATE_ADD(reg, reg, (destination & 0x00000FFF));
|
||||
|
||||
smcWriteAddress32((void *)pc, opcode_adrp);
|
||||
smcWriteAddress32((void *)add_opcode_location, opcode_add);
|
||||
_write32(pc, opcode_adrp);
|
||||
_write32(add_opcode_location, opcode_add);
|
||||
}
|
||||
|
||||
void setup_hooks(void)
|
||||
|
@ -306,14 +411,21 @@ void __init()
|
|||
|
||||
text_base = meminfo.addr;
|
||||
|
||||
// Get code size
|
||||
svcQueryMemory(&meminfo, &pageinfo, INJECT_OFFSET(u64, 0));
|
||||
fs_code_size = meminfo.size;
|
||||
|
||||
load_emummc_ctx();
|
||||
|
||||
fs_offsets = get_fs_offsets(emuMMC_ctx.fs_ver);
|
||||
|
||||
_init_process_handle();
|
||||
_map_fs_rw();
|
||||
setup_hooks();
|
||||
populate_function_pointers();
|
||||
write_nops();
|
||||
setup_nintendo_paths();
|
||||
_unmap_fs_rw();
|
||||
|
||||
clock_enable_i2c5();
|
||||
i2c_init();
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "smc.h"
|
||||
#include "../utils/fatal.h"
|
||||
|
||||
void smcRebootToRcm(void)
|
||||
{
|
||||
|
@ -117,45 +118,6 @@ Result smcReadWriteRegister(u32 phys_addr, u32 value, u32 mask)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static Result _smcWriteAddress(void *dst_addr, u64 val, u32 size)
|
||||
{
|
||||
SecmonArgs args;
|
||||
args.X[0] = 0xF0000003; /* smcAmsWriteAddress */
|
||||
args.X[1] = (u64)dst_addr; /* DRAM address */
|
||||
args.X[2] = val; /* value */
|
||||
args.X[3] = size; /* Amount to write */
|
||||
Result rc = svcCallSecureMonitor(&args);
|
||||
if (rc == 0)
|
||||
{
|
||||
if (args.X[0] != 0)
|
||||
{
|
||||
/* SPL result n = SMC result n */
|
||||
rc = (26u | ((u32)args.X[0] << 9u));
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result smcWriteAddress8(void *dst_addr, u8 val)
|
||||
{
|
||||
return _smcWriteAddress(dst_addr, val, 1);
|
||||
}
|
||||
|
||||
Result smcWriteAddress16(void *dst_addr, u16 val)
|
||||
{
|
||||
return _smcWriteAddress(dst_addr, val, 2);
|
||||
}
|
||||
|
||||
Result smcWriteAddress32(void *dst_addr, u32 val)
|
||||
{
|
||||
return _smcWriteAddress(dst_addr, val, 4);
|
||||
}
|
||||
|
||||
Result smcWriteAddress64(void *dst_addr, u64 val)
|
||||
{
|
||||
return _smcWriteAddress(dst_addr, val, 8);
|
||||
}
|
||||
|
||||
Result smcGetEmummcConfig(exo_emummc_mmc_t mmc_id, exo_emummc_config_t *out_cfg, void *out_paths)
|
||||
{
|
||||
SecmonArgs args;
|
||||
|
@ -178,3 +140,37 @@ Result smcGetEmummcConfig(exo_emummc_mmc_t mmc_id, exo_emummc_config_t *out_cfg,
|
|||
return rc;
|
||||
|
||||
}
|
||||
|
||||
Result smcGenerateRandomBytes(void *dst, u32 size)
|
||||
{
|
||||
SecmonArgs args;
|
||||
args.X[0] = 0xC3000006; /* smcGenerateRandomBytes */
|
||||
args.X[1] = size;
|
||||
Result rc = svcCallSecureMonitor(&args);
|
||||
if (rc == 0)
|
||||
{
|
||||
if (args.X[0] != 0)
|
||||
{
|
||||
/* SPL result n = SMC result n */
|
||||
rc = (26u | ((u32)args.X[0] << 9u));
|
||||
}
|
||||
if (rc == 0)
|
||||
{
|
||||
memcpy(dst, &args.X[1], size);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
u64 smcGenerateRandomU64(void)
|
||||
{
|
||||
u64 random;
|
||||
|
||||
Result rc = smcGenerateRandomBytes(&random, sizeof(random));
|
||||
if (rc != 0)
|
||||
{
|
||||
fatal_abort(Fatal_BadResult);
|
||||
}
|
||||
|
||||
return random;
|
||||
}
|
||||
|
|
|
@ -78,13 +78,11 @@ Result smcCopyFromIram(void *dst_addr, uintptr_t iram_addr, u32 size);
|
|||
|
||||
Result smcReadWriteRegister(u32 phys_addr, u32 value, u32 mask);
|
||||
|
||||
Result smcWriteAddress8(void *dst_addr, u8 val);
|
||||
Result smcWriteAddress16(void *dst_addr, u16 val);
|
||||
Result smcWriteAddress32(void *dst_addr, u32 val);
|
||||
Result smcWriteAddress64(void *dst_addr, u64 val);
|
||||
|
||||
Result smcGetEmummcConfig(exo_emummc_mmc_t mmc_id, exo_emummc_config_t *out_cfg, void *out_paths);
|
||||
|
||||
Result smcGenerateRandomBytes(void *dst, u32 size);
|
||||
u64 smcGenerateRandomU64(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -106,6 +106,104 @@ Result svcSetProcessMemoryPermission(Handle proc, u64 addr, u64 size, u32 perm);
|
|||
*/
|
||||
Result svcSetMemoryPermission(void* addr, u64 size, u32 perm);
|
||||
|
||||
/**
|
||||
* @brief Creates a thread.
|
||||
* @return Result code.
|
||||
* @note Syscall number 0x08.
|
||||
*/
|
||||
Result svcCreateThread(Handle* out, void* entry, void* arg, void* stack_top, int prio, int cpuid);
|
||||
|
||||
/**
|
||||
* @brief Starts a freshly created thread.
|
||||
* @return Result code.
|
||||
* @note Syscall number 0x09.
|
||||
*/
|
||||
Result svcStartThread(Handle handle);
|
||||
|
||||
/**
|
||||
* @brief Exits the current thread.
|
||||
* @note Syscall number 0x0A.
|
||||
*/
|
||||
void __attribute__((noreturn)) svcExitThread(void);
|
||||
|
||||
/**
|
||||
* @brief Closes a handle, decrementing the reference count of the corresponding kernel object.
|
||||
* This might result in the kernel freeing the object.
|
||||
* @param handle Handle to close.
|
||||
* @return Result code.
|
||||
* @note Syscall number 0x16.
|
||||
*/
|
||||
Result svcCloseHandle(Handle handle);
|
||||
|
||||
/**
|
||||
* @brief Waits on one or more synchronization objects, optionally with a timeout.
|
||||
* @return Result code.
|
||||
* @note Syscall number 0x18.
|
||||
* @note \p handleCount must not be greater than \ref MAX_WAIT_OBJECTS. This is a Horizon kernel limitation.
|
||||
* @note This is the raw syscall, which can be cancelled by \ref svcCancelSynchronization or other means. \ref waitHandles or \ref waitMultiHandle should normally be used instead.
|
||||
*/
|
||||
Result svcWaitSynchronization(s32* index, const Handle* handles, s32 handleCount, u64 timeout);
|
||||
|
||||
/**
|
||||
* @brief Waits on a single synchronization object, optionally with a timeout.
|
||||
* @return Result code.
|
||||
* @note Wrapper for \ref svcWaitSynchronization.
|
||||
* @note This is the raw syscall, which can be cancelled by \ref svcCancelSynchronization or other means. \ref waitSingleHandle should normally be used instead.
|
||||
*/
|
||||
static inline Result svcWaitSynchronizationSingle(Handle handle, u64 timeout) {
|
||||
s32 tmp;
|
||||
return svcWaitSynchronization(&tmp, &handle, 1, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates an IPC session.
|
||||
* @return Result code.
|
||||
* @note Syscall number 0x40.
|
||||
* @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available.
|
||||
*/
|
||||
Result svcCreateSession(Handle *server_handle, Handle *client_handle, u32 unk0, u64 unk1);//unk* are normally 0?
|
||||
|
||||
/**
|
||||
* @brief Sends an IPC synchronization request to a session.
|
||||
* @return Result code.
|
||||
* @note Syscall number 0x21.
|
||||
*/
|
||||
Result svcSendSyncRequest(Handle session);
|
||||
|
||||
/**
|
||||
* @brief Performs IPC input/output.
|
||||
* @return Result code.
|
||||
* @note Syscall number 0x43.
|
||||
* @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available.
|
||||
*/
|
||||
Result svcReplyAndReceive(s32* index, const Handle* handles, s32 handleCount, Handle replyTarget, u64 timeout);
|
||||
|
||||
/**
|
||||
* @brief Maps the src address from the supplied process handle into the current process.
|
||||
* @param[in] dst Address to which map the memory in the current process.
|
||||
* @param[in] proc Process handle.
|
||||
* @param[in] src Source mapping address.
|
||||
* @param[in] size Size of the memory.
|
||||
* @return Result code.
|
||||
* @remark This allows mapping code and rodata with RW- permission.
|
||||
* @note Syscall number 0x74.
|
||||
* @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available.
|
||||
*/
|
||||
Result svcMapProcessMemory(void* dst, Handle proc, u64 src, u64 size);
|
||||
|
||||
/**
|
||||
* @brief Undoes the effects of \ref svcMapProcessMemory.
|
||||
* @param[in] dst Destination mapping address
|
||||
* @param[in] proc Process handle.
|
||||
* @param[in] src Address of the memory in the process.
|
||||
* @param[in] size Size of the memory.
|
||||
* @return Result code.
|
||||
* @remark This allows mapping code and rodata with RW- permission.
|
||||
* @note Syscall number 0x75.
|
||||
* @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available.
|
||||
*/
|
||||
Result svcUnmapProcessMemory(void* dst, Handle proc, u64 src, u64 size);
|
||||
|
||||
/**
|
||||
* @brief Calls a secure monitor function (TrustZone, EL3).
|
||||
* @param regs Arguments to pass to the secure monitor.
|
||||
|
|
|
@ -56,6 +56,69 @@ SVC_BEGIN svcSetProcessMemoryPermission
|
|||
RET
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcCreateThread
|
||||
STR X0, [SP, #-16]!
|
||||
SVC 0x8
|
||||
LDR X2, [SP], #16
|
||||
STR W1, [X2]
|
||||
RET
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcStartThread
|
||||
SVC 0x9
|
||||
RET
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcExitThread
|
||||
SVC 0xA
|
||||
RET
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcCloseHandle
|
||||
SVC 0x16
|
||||
RET
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcWaitSynchronization
|
||||
STR X0, [SP, #-16]!
|
||||
SVC 0x18
|
||||
LDR X2, [SP], #16
|
||||
STR W1, [X2]
|
||||
RET
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcCreateSession
|
||||
STP X0, X1, [SP, #-16]!
|
||||
SVC 0x40
|
||||
LDP X3, X4, [SP], #16
|
||||
STR W1, [X3]
|
||||
STR W2, [X4]
|
||||
RET
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcSendSyncRequest
|
||||
SVC 0x21
|
||||
RET
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcReplyAndReceive
|
||||
STR X0, [SP, #-16]!
|
||||
SVC 0x43
|
||||
LDR X2, [SP], #16
|
||||
STR W1, [X2]
|
||||
RET
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcMapProcessMemory
|
||||
SVC 0x74
|
||||
RET
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcUnmapProcessMemory
|
||||
SVC 0x75
|
||||
RET
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcCallSecureMonitor
|
||||
STR X0, [SP, #-16]!
|
||||
MOV X8, X0
|
||||
|
|
|
@ -55,6 +55,10 @@ typedef volatile unsigned int vu32;
|
|||
typedef u32 Handle; ///< Kernel object handle.
|
||||
typedef u32 Result; ///< Function error code result type.
|
||||
|
||||
#define INVALID_HANDLE ((Handle) 0)
|
||||
#define CUR_PROCESS_HANDLE ((Handle) 0xFFFF8001)
|
||||
|
||||
|
||||
#ifndef __cplusplus
|
||||
typedef int bool;
|
||||
#define true 1
|
||||
|
|
|
@ -38,6 +38,12 @@ void usleep(u64 ticks);
|
|||
void msleep(u64 milliseconds);
|
||||
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops);
|
||||
|
||||
static inline void *armGetTls(void) {
|
||||
void *ret;
|
||||
__asm__ __volatile__("MRS %x[data], TPIDRRO_EL0" : [data]"=r"(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern volatile emuMMC_ctx_t emuMMC_ctx;
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue