git subrepo clone --branch=develop https://github.com/m4xw/emuMMC emummc
subrepo: subdir: "emummc" merged: "e72e8f1c" upstream: origin: "https://github.com/m4xw/emuMMC" branch: "develop" commit: "e72e8f1c" git-subrepo: version: "0.4.0" origin: "https://github.com/ingydotnet/git-subrepo" commit: "5d6aba9"
This commit is contained in:
41
emummc/source/nx/cache.h
Normal file
41
emummc/source/nx/cache.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @file cache.h
|
||||
* @brief AArch64 cache operations.
|
||||
* @author plutoo
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include "../utils/types.h"
|
||||
|
||||
/**
|
||||
* @brief Performs a data cache flush on the specified buffer.
|
||||
* @param addr Address of the buffer.
|
||||
* @param size Size of the buffer, in bytes.
|
||||
* @remarks Cache flush is defined as Clean + Invalidate.
|
||||
* @note The start and end addresses of the buffer are forcibly rounded to cache line boundaries (read from CTR_EL0 system register).
|
||||
*/
|
||||
void armDCacheFlush(void* addr, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Performs a data cache clean on the specified buffer.
|
||||
* @param addr Address of the buffer.
|
||||
* @param size Size of the buffer, in bytes.
|
||||
* @note The start and end addresses of the buffer are forcibly rounded to cache line boundaries (read from CTR_EL0 system register).
|
||||
*/
|
||||
void armDCacheClean(void* addr, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Performs an instruction cache invalidation clean on the specified buffer.
|
||||
* @param addr Address of the buffer.
|
||||
* @param size Size of the buffer, in bytes.
|
||||
* @note The start and end addresses of the buffer are forcibly rounded to cache line boundaries (read from CTR_EL0 system register).
|
||||
*/
|
||||
void armICacheInvalidate(void* addr, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Performs a data cache zeroing operation on the specified buffer.
|
||||
* @param addr Address of the buffer.
|
||||
* @param size Size of the buffer, in bytes.
|
||||
* @note The start and end addresses of the buffer are forcibly rounded to cache line boundaries (read from CTR_EL0 system register).
|
||||
*/
|
||||
void armDCacheZero(void* addr, size_t size);
|
||||
100
emummc/source/nx/cache.s
Normal file
100
emummc/source/nx/cache.s
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @file cache.s
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
|
||||
.macro CODE_BEGIN name
|
||||
.section .text.\name, "ax", %progbits
|
||||
.global \name
|
||||
.type \name, %function
|
||||
.align 2
|
||||
.cfi_startproc
|
||||
\name:
|
||||
.endm
|
||||
|
||||
.macro CODE_END
|
||||
.cfi_endproc
|
||||
.endm
|
||||
|
||||
CODE_BEGIN armDCacheFlush
|
||||
add x1, x1, x0
|
||||
mrs x8, CTR_EL0
|
||||
lsr x8, x8, #16
|
||||
and x8, x8, #0xf
|
||||
mov x9, #4
|
||||
lsl x9, x9, x8
|
||||
sub x10, x9, #1
|
||||
bic x8, x0, x10
|
||||
mov x10, x1
|
||||
|
||||
armDCacheFlush_L0:
|
||||
dc civac, x8
|
||||
add x8, x8, x9
|
||||
cmp x8, x10
|
||||
bcc armDCacheFlush_L0
|
||||
|
||||
dsb sy
|
||||
ret
|
||||
CODE_END
|
||||
|
||||
CODE_BEGIN armDCacheClean
|
||||
add x1, x1, x0
|
||||
mrs x8, CTR_EL0
|
||||
lsr x8, x8, #16
|
||||
and x8, x8, #0xf
|
||||
mov x9, #4
|
||||
lsl x9, x9, x8
|
||||
sub x10, x9, #1
|
||||
bic x8, x0, x10
|
||||
mov x10, x1
|
||||
|
||||
armDCacheClean_L0:
|
||||
dc cvac, x8
|
||||
add x8, x8, x9
|
||||
cmp x8, x10
|
||||
bcc armDCacheClean_L0
|
||||
|
||||
dsb sy
|
||||
ret
|
||||
CODE_END
|
||||
|
||||
CODE_BEGIN armICacheInvalidate
|
||||
add x1, x1, x0
|
||||
mrs x8, CTR_EL0
|
||||
and x8, x8, #0xf
|
||||
mov x9, #4
|
||||
lsl x9, x9, x8
|
||||
sub x10, x9, #1
|
||||
bic x8, x0, x10
|
||||
mov x10, x1
|
||||
|
||||
armICacheInvalidate_L0:
|
||||
ic ivau, x8
|
||||
add x8, x8, x9
|
||||
cmp x8, x10
|
||||
bcc armICacheInvalidate_L0
|
||||
|
||||
dsb sy
|
||||
ret
|
||||
CODE_END
|
||||
|
||||
CODE_BEGIN armDCacheZero
|
||||
add x1, x1, x0
|
||||
mrs x8, CTR_EL0
|
||||
lsr x8, x8, #16
|
||||
and x8, x8, #0xf
|
||||
mov x9, #4
|
||||
lsl x9, x9, x8
|
||||
sub x10, x9, #1
|
||||
bic x8, x0, x10
|
||||
mov x10, x1
|
||||
|
||||
armDCacheZero_L0:
|
||||
dc zva, x8
|
||||
add x8, x8, x9
|
||||
cmp x8, x10
|
||||
bcc armDCacheZero_L0
|
||||
|
||||
dsb sy
|
||||
ret
|
||||
CODE_END
|
||||
46
emummc/source/nx/counter.h
Normal file
46
emummc/source/nx/counter.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* @file counter.h
|
||||
* @brief AArch64 system counter-timer.
|
||||
* @author fincs
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include "../utils/types.h"
|
||||
|
||||
/**
|
||||
* @brief Gets the current system tick.
|
||||
* @return The current system tick.
|
||||
*/
|
||||
static inline u64 armGetSystemTick(void) {
|
||||
u64 ret;
|
||||
__asm__ __volatile__ ("mrs %x[data], cntpct_el0" : [data] "=r" (ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the system counter-timer frequency
|
||||
* @return The system counter-timer frequency, in Hz.
|
||||
*/
|
||||
static inline u64 armGetSystemTickFreq(void) {
|
||||
u64 ret;
|
||||
__asm__ ("mrs %x[data], cntfrq_el0" : [data] "=r" (ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Converts from nanoseconds to CPU ticks unit.
|
||||
* @param ns Time in nanoseconds.
|
||||
* @return Time in CPU ticks.
|
||||
*/
|
||||
static inline u64 armNsToTicks(u64 ns) {
|
||||
return (ns * 12) / 625;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Converts from CPU ticks unit to nanoseconds.
|
||||
* @param tick Time in ticks.
|
||||
* @return Time in nanoseconds.
|
||||
*/
|
||||
static inline u64 armTicksToNs(u64 tick) {
|
||||
return (tick * 625) / 12;
|
||||
}
|
||||
45
emummc/source/nx/dynamic.c
Normal file
45
emummc/source/nx/dynamic.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @file dynamic.c
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include "../utils/types.h"
|
||||
#include <elf.h>
|
||||
|
||||
void __nx_dynamic(uintptr_t base, const Elf64_Dyn* dyn)
|
||||
{
|
||||
const Elf64_Rela* rela = NULL;
|
||||
u64 relasz = 0;
|
||||
|
||||
for (; dyn->d_tag != DT_NULL; dyn++)
|
||||
{
|
||||
switch (dyn->d_tag)
|
||||
{
|
||||
case DT_RELA:
|
||||
rela = (const Elf64_Rela*)(base + dyn->d_un.d_ptr);
|
||||
break;
|
||||
case DT_RELASZ:
|
||||
relasz = dyn->d_un.d_val / sizeof(Elf64_Rela);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rela == NULL) {
|
||||
while(true)
|
||||
;
|
||||
}
|
||||
|
||||
for (; relasz--; rela++)
|
||||
{
|
||||
switch (ELF64_R_TYPE(rela->r_info))
|
||||
{
|
||||
case R_AARCH64_RELATIVE:
|
||||
{
|
||||
u64* ptr = (u64*)(base + rela->r_offset);
|
||||
*ptr = base + rela->r_addend;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3147
emummc/source/nx/elf.h
Normal file
3147
emummc/source/nx/elf.h
Normal file
File diff suppressed because it is too large
Load Diff
180
emummc/source/nx/smc.c
Normal file
180
emummc/source/nx/smc.c
Normal file
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
* @file smc.c
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "smc.h"
|
||||
|
||||
void smcRebootToRcm(void)
|
||||
{
|
||||
SecmonArgs args;
|
||||
args.X[0] = 0xC3000401; /* smcSetConfig */
|
||||
args.X[1] = SplConfigItem_NeedsReboot; /* Exosphere reboot */
|
||||
args.X[3] = 1; /* Perform reboot to RCM. */
|
||||
svcCallSecureMonitor(&args);
|
||||
}
|
||||
|
||||
void smcRebootToIramPayload(void)
|
||||
{
|
||||
SecmonArgs args;
|
||||
args.X[0] = 0xC3000401; /* smcSetConfig */
|
||||
args.X[1] = SplConfigItem_NeedsReboot; /* Exosphere reboot */
|
||||
args.X[3] = 2; /* Perform reboot to payload at 0x40010000 in IRAM. */
|
||||
svcCallSecureMonitor(&args);
|
||||
}
|
||||
|
||||
void smcPerformShutdown(void)
|
||||
{
|
||||
SecmonArgs args;
|
||||
args.X[0] = 0xC3000401; /* smcSetConfig */
|
||||
args.X[1] = SplConfigItem_NeedsShutdown; /* Exosphere shutdown */
|
||||
args.X[3] = 1; /* Perform shutdown. */
|
||||
svcCallSecureMonitor(&args);
|
||||
}
|
||||
|
||||
Result smcGetConfig(SplConfigItem config_item, u64 *out_config)
|
||||
{
|
||||
SecmonArgs args;
|
||||
args.X[0] = 0xC3000002; /* smcGetConfig */
|
||||
args.X[1] = (u64)config_item; /* config item */
|
||||
Result rc = svcCallSecureMonitor(&args);
|
||||
if (rc == 0)
|
||||
{
|
||||
if (args.X[0] == 0)
|
||||
{
|
||||
if (out_config)
|
||||
{
|
||||
*out_config = args.X[1];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* SPL result n = SMC result n */
|
||||
rc = (26u | ((u32)args.X[0] << 9u));
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result smcCopyToIram(uintptr_t iram_addr, const void *src_addr, u32 size)
|
||||
{
|
||||
SecmonArgs args;
|
||||
args.X[0] = 0xF0000201; /* smcAmsIramCopy */
|
||||
args.X[1] = (u64)src_addr; /* DRAM address */
|
||||
args.X[2] = (u64)iram_addr; /* IRAM address */
|
||||
args.X[3] = size; /* Amount to copy */
|
||||
args.X[4] = 1; /* 1 = 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 smcCopyFromIram(void *dst_addr, uintptr_t iram_addr, u32 size)
|
||||
{
|
||||
SecmonArgs args;
|
||||
args.X[0] = 0xF0000201; /* smcAmsIramCopy */
|
||||
args.X[1] = (u64)dst_addr; /* DRAM address */
|
||||
args.X[2] = (u64)iram_addr; /* IRAM address */
|
||||
args.X[3] = size; /* Amount to copy */
|
||||
args.X[4] = 0; /* 0 = Read */
|
||||
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 smcReadWriteRegister(u32 phys_addr, u32 value, u32 mask)
|
||||
{
|
||||
SecmonArgs args;
|
||||
args.X[0] = 0xF0000002; /* smcAmsReadWriteRegister */
|
||||
args.X[1] = phys_addr; /* MMIO address */
|
||||
args.X[2] = mask; /* mask */
|
||||
args.X[3] = value; /* value */
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
args.X[0] = 0xF0000404; /* smcAmsGetEmunandConfig */
|
||||
args.X[1] = mmc_id;
|
||||
args.X[2] = (u64)out_paths; /* out path */
|
||||
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(out_cfg, &args.X[1], sizeof(*out_cfg));
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
|
||||
}
|
||||
90
emummc/source/nx/smc.h
Normal file
90
emummc/source/nx/smc.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* @file smc.h
|
||||
* @brief Wrappers for secure monitor calls.
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include "../utils/types.h"
|
||||
#include "svc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
SplConfigItem_DisableProgramVerification = 1,
|
||||
SplConfigItem_DramId = 2,
|
||||
SplConfigItem_SecurityEngineIrqNumber = 3,
|
||||
SplConfigItem_Version = 4,
|
||||
SplConfigItem_HardwareType = 5,
|
||||
SplConfigItem_IsRetail = 6,
|
||||
SplConfigItem_IsRecoveryBoot = 7,
|
||||
SplConfigItem_DeviceId = 8,
|
||||
SplConfigItem_BootReason = 9,
|
||||
SplConfigItem_MemoryArrange = 10,
|
||||
SplConfigItem_IsDebugMode = 11,
|
||||
SplConfigItem_KernelMemoryConfiguration = 12,
|
||||
SplConfigItem_IsChargerHiZModeEnabled = 13,
|
||||
SplConfigItem_IsKiosk = 14,
|
||||
SplConfigItem_NewHardwareType = 15,
|
||||
SplConfigItem_NewKeyGeneration = 16,
|
||||
SplConfigItem_Package2Hash = 17,
|
||||
|
||||
SplConfigItem_ExosphereVersion = 65000,
|
||||
SplConfigItem_NeedsReboot = 65001,
|
||||
SplConfigItem_NeedsShutdown = 65002,
|
||||
SplConfigItem_ExosphereVerHash = 65003,
|
||||
SplConfigItem_HasRcmBugPatch = 65004,
|
||||
} SplConfigItem;
|
||||
|
||||
typedef enum {
|
||||
EXO_EMUMMC_TYPE_NONE = 0,
|
||||
EXO_EMUMMC_TYPE_PARTITION = 1,
|
||||
EXO_EMUMMC_TYPE_FILES = 2,
|
||||
} exo_emummc_type_t;
|
||||
|
||||
typedef enum {
|
||||
EXO_EMUMMC_MMC_NAND = 0,
|
||||
EXO_EMUMMC_MMC_SD = 1,
|
||||
EXO_EMUMMC_MMC_GC = 2,
|
||||
} exo_emummc_mmc_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t magic;
|
||||
uint32_t type;
|
||||
uint32_t id;
|
||||
uint32_t fs_version;
|
||||
} exo_emummc_base_config_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t start_sector;
|
||||
} exo_emummc_partition_config_t;
|
||||
|
||||
typedef struct {
|
||||
exo_emummc_base_config_t base_cfg;
|
||||
union {
|
||||
exo_emummc_partition_config_t partition_cfg;
|
||||
};
|
||||
} exo_emummc_config_t;
|
||||
|
||||
Result smcGetConfig(SplConfigItem config_item, u64 *out_config);
|
||||
|
||||
void smcRebootToRcm(void);
|
||||
void smcRebootToIramPayload(void);
|
||||
void smcPerformShutdown(void);
|
||||
|
||||
Result smcCopyToIram(uintptr_t iram_addr, const void *src_addr, u32 size);
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
131
emummc/source/nx/start.s
Normal file
131
emummc/source/nx/start.s
Normal file
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* @file start.s
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
|
||||
.macro push_all
|
||||
SUB SP, SP, #0x100
|
||||
STP X29, X30, [SP, #0x0]
|
||||
STP X27, X28, [SP, #0x10]
|
||||
STP X25, X26, [SP, #0x20]
|
||||
STP X23, X24, [SP, #0x30]
|
||||
STP X21, X22, [SP, #0x40]
|
||||
STP X19, X20, [SP, #0x50]
|
||||
STP X17, X18, [SP, #0x60]
|
||||
STP X15, X16, [SP, #0x70]
|
||||
STP X13, X14, [SP, #0x80]
|
||||
STP X11, X12, [SP, #0x90]
|
||||
STP X9, X10, [SP, #0xA0]
|
||||
STP X7, X8, [SP, #0xB0]
|
||||
STP X5, X6, [SP, #0xC0]
|
||||
STP X3, X4, [SP, #0xD0]
|
||||
STP X1, X2, [SP, #0xE0]
|
||||
STR X0, [SP, #0xF0]
|
||||
.endm
|
||||
|
||||
.macro pop_all
|
||||
LDR X0, [SP, #0xF0]
|
||||
LDP X1, X2, [SP, #0xE0]
|
||||
LDP X3, X4, [SP, #0xD0]
|
||||
LDP X5, X6, [SP, #0xC0]
|
||||
LDP X7, X8, [SP, #0xB0]
|
||||
LDP X9, X10, [SP, #0xA0]
|
||||
LDP X11, X12, [SP, #0x90]
|
||||
LDP X13, X14, [SP, #0x80]
|
||||
LDP X15, X16, [SP, #0x70]
|
||||
LDP X17, X18, [SP, #0x60]
|
||||
LDP X19, X20, [SP, #0x50]
|
||||
LDP X21, X22, [SP, #0x40]
|
||||
LDP X23, X24, [SP, #0x30]
|
||||
LDP X25, X26, [SP, #0x20]
|
||||
LDP X27, X28, [SP, #0x10]
|
||||
LDP X29, X30, [SP, #0x0]
|
||||
ADD SP, SP, #0x100
|
||||
.endm
|
||||
|
||||
.section ".crt0","ax"
|
||||
.global _start
|
||||
_start:
|
||||
B startup
|
||||
.org _start+0xc
|
||||
B sdmmc_wrapper_read
|
||||
.org _start+0x18
|
||||
B sdmmc_wrapper_write
|
||||
.org _start+0x80
|
||||
|
||||
.section ".crt0","ax"
|
||||
startup:
|
||||
# Save LR
|
||||
MOV X7, X30
|
||||
|
||||
# Retrieve ASLR Base
|
||||
BL +4
|
||||
SUB X6, X30, #0x88
|
||||
|
||||
# Context Ptr and MainThread Handle
|
||||
MOV X5, X0
|
||||
MOV X4, X1
|
||||
|
||||
# Inject start
|
||||
push_all
|
||||
|
||||
MOV W0, #0xFFFF8001
|
||||
ADR X1, __rodata_start
|
||||
ADR X2, __data_start
|
||||
SUB X2, X2, X1
|
||||
MOV X3, #1
|
||||
SVC 0x73
|
||||
|
||||
MOV W0, #0xFFFF8001
|
||||
ADR X1, __data_start
|
||||
ADR X2, __end__
|
||||
SUB X2, X2, X1
|
||||
MOV X3, #3
|
||||
SVC 0x73
|
||||
|
||||
pop_all
|
||||
|
||||
MOV X27, X7
|
||||
MOV X25, X5
|
||||
MOV X26, X4
|
||||
|
||||
# Clear .bss
|
||||
ADRP X0, __bss_start__
|
||||
ADRP X1, __bss_end__
|
||||
ADD X0, X0, #:lo12:__bss_start__
|
||||
ADD X1, X1, #:lo12:__bss_end__
|
||||
SUB X1, X1, X0
|
||||
ADD X1, X1, #7
|
||||
BIC X1, X1, #7
|
||||
|
||||
bss_loop:
|
||||
STR XZR, [X0], #8
|
||||
SUBS X1, X1, #8
|
||||
BNE bss_loop
|
||||
|
||||
# Store SP
|
||||
MOV X1, SP
|
||||
ADRP X0, __stack_top
|
||||
STR X1, [X0, #:lo12:__stack_top]
|
||||
|
||||
# Process _DYNAMIC Section
|
||||
MOV X0, X6
|
||||
ADRP X1, _DYNAMIC
|
||||
ADD X1, X1, #:lo12:_DYNAMIC
|
||||
BL __nx_dynamic
|
||||
|
||||
# TODO: handle in code
|
||||
MOV X0, X25
|
||||
MOV X1, X26
|
||||
MOV X2, X27
|
||||
|
||||
BL __initheap
|
||||
BL __init
|
||||
|
||||
MOV X0, X25
|
||||
MOV X1, X26
|
||||
MOV X30, X27
|
||||
|
||||
# FS main
|
||||
ADR X16, __injected_size__
|
||||
BR X16
|
||||
112
emummc/source/nx/svc.h
Normal file
112
emummc/source/nx/svc.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* @file svc.h
|
||||
* @brief Wrappers for kernel syscalls.
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include "../utils/types.h"
|
||||
|
||||
/// Memory information structure.
|
||||
typedef struct {
|
||||
u64 addr; ///< Base address.
|
||||
u64 size; ///< Size.
|
||||
u32 type; ///< Memory type (see lower 8 bits of \ref MemoryState).
|
||||
u32 attr; ///< Memory attributes (see \ref MemoryAttribute).
|
||||
u32 perm; ///< Memory permissions (see \ref Permission).
|
||||
u32 device_refcount; ///< Device reference count.
|
||||
u32 ipc_refcount; ///< IPC reference count.
|
||||
u32 padding; ///< Padding.
|
||||
} MemoryInfo;
|
||||
|
||||
/// Memory permission bitmasks.
|
||||
typedef enum {
|
||||
Perm_None = 0, ///< No permissions.
|
||||
Perm_R = BIT(0), ///< Read permission.
|
||||
Perm_W = BIT(1), ///< Write permission.
|
||||
Perm_X = BIT(2), ///< Execute permission.
|
||||
Perm_Rw = Perm_R | Perm_W, ///< Read/write permissions.
|
||||
Perm_Rx = Perm_R | Perm_X, ///< Read/execute permissions.
|
||||
Perm_DontCare = BIT(28), ///< Don't care
|
||||
} Permission;
|
||||
|
||||
/// Secure monitor arguments.
|
||||
typedef struct {
|
||||
u64 X[8]; ///< Values of X0 through X7.
|
||||
} SecmonArgs;
|
||||
|
||||
_Static_assert(sizeof(SecmonArgs) == 0x40, "SecmonArgs definition");
|
||||
|
||||
#define DeviceName_SDMMC1A 19
|
||||
#define DeviceName_SDMMC2A 20
|
||||
#define DeviceName_SDMMC3A 21
|
||||
#define DeviceName_SDMMC4A 22
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Returns a virtual address mapped to a given IO range.
|
||||
* @return Result code.
|
||||
* @note Syscall number 0x55.
|
||||
* @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available.
|
||||
*/
|
||||
Result svcQueryIoMapping(u64* virtaddr, u64 physaddr, u64 size);
|
||||
|
||||
/**
|
||||
* @brief Attaches a device address space to a device.
|
||||
* @return Result code.
|
||||
* @note Syscall number 0x57.
|
||||
* @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available.
|
||||
*/
|
||||
Result svcAttachDeviceAddressSpace(u64 device, Handle handle);
|
||||
|
||||
/**
|
||||
* @brief Query information about an address. Will always fetch the lowest page-aligned mapping that contains the provided address.
|
||||
* @param[out] meminfo_ptr \ref MemoryInfo structure which will be filled in.
|
||||
* @param[out] pageinfo Page information which will be filled in.
|
||||
* @param[in] addr Address to query.
|
||||
* @return Result code.
|
||||
* @note Syscall number 0x06.
|
||||
*/
|
||||
Result svcQueryMemory(MemoryInfo* meminfo_ptr, u32 *pageinfo, u64 addr);
|
||||
|
||||
/**
|
||||
* @brief Sets the memory permissions for the specified memory with the supplied process handle.
|
||||
* @param[in] proc Process handle.
|
||||
* @param[in] addr Address of the memory.
|
||||
* @param[in] size Size of the memory.
|
||||
* @param[in] perm Permissions (see \ref Permission).
|
||||
* @return Result code.
|
||||
* @remark This returns an error (0xD801) when \p perm is >0x5, hence -WX and RWX are not allowed.
|
||||
* @note Syscall number 0x73.
|
||||
* @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available.
|
||||
*/
|
||||
Result svcSetProcessMemoryPermission(Handle proc, u64 addr, u64 size, u32 perm);
|
||||
|
||||
/**
|
||||
* @brief Set the memory permissions of a (page-aligned) range of memory.
|
||||
* @param[in] addr Start address of the range.
|
||||
* @param[in] size Size of the range, in bytes.
|
||||
* @param[in] perm Permissions (see \ref Permission).
|
||||
* @return Result code.
|
||||
* @remark Perm_X is not allowed. Setting write-only is not allowed either (Perm_W).
|
||||
* This can be used to move back and forth between Perm_None, Perm_R and Perm_Rw.
|
||||
* @note Syscall number 0x01.
|
||||
*/
|
||||
Result svcSetMemoryPermission(void* addr, u64 size, u32 perm);
|
||||
|
||||
/**
|
||||
* @brief Calls a secure monitor function (TrustZone, EL3).
|
||||
* @param regs Arguments to pass to the secure monitor.
|
||||
* @return Return value from the secure monitor.
|
||||
* @note Syscall number 0x7F.
|
||||
* @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available.
|
||||
*/
|
||||
u64 svcCallSecureMonitor(SecmonArgs* regs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
///@}
|
||||
64
emummc/source/nx/svc.s
Normal file
64
emummc/source/nx/svc.s
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* @file svc.s
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
|
||||
.macro SVC_BEGIN name
|
||||
.section .text.\name, "ax", %progbits
|
||||
.global \name
|
||||
.type \name, %function
|
||||
.align 2
|
||||
.cfi_startproc
|
||||
\name:
|
||||
.endm
|
||||
|
||||
.macro SVC_END
|
||||
.cfi_endproc
|
||||
.endm
|
||||
|
||||
SVC_BEGIN svcQueryIoMapping
|
||||
STR X0, [SP, #-16]!
|
||||
SVC 0x55
|
||||
LDR X2, [SP], #16
|
||||
STR X1, [X2]
|
||||
RET
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcAttachDeviceAddressSpace
|
||||
SVC 0x57
|
||||
RET
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcQueryMemory
|
||||
STR X1, [SP, #-16]!
|
||||
SVC 0x6
|
||||
LDR X2, [SP], #16
|
||||
STR W1, [X2]
|
||||
RET
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcSetMemoryPermission
|
||||
SVC 0x2
|
||||
RET
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcSetProcessMemoryPermission
|
||||
SVC 0x73
|
||||
RET
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcCallSecureMonitor
|
||||
STR X0, [SP, #-16]!
|
||||
MOV X8, X0
|
||||
LDP X0, X1, [X8]
|
||||
LDP X2, X3, [X8, #0x10]
|
||||
LDP X4, X5, [X8, #0x20]
|
||||
LDP X6, X7, [X8, #0x30]
|
||||
SVC 0x7F
|
||||
LDR X8, [SP], #16
|
||||
STP X0, X1, [X8]
|
||||
STP X2, X3, [X8, #0x10]
|
||||
STP X4, X5, [X8, #0x20]
|
||||
STP X6, X7, [X8, #0x30]
|
||||
RET
|
||||
SVC_END
|
||||
Reference in New Issue
Block a user