libstrat: namespace remaining non-namespaced code. more new-ipc updates
This commit is contained in:
46
stratosphere/libstratosphere/source/ams/ams_bpc.c
Normal file
46
stratosphere/libstratosphere/source/ams/ams_bpc.c
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#define NX_SERVICE_ASSUME_NON_DOMAIN
|
||||
#include "../service_guard.h"
|
||||
#include "ams_bpc.h"
|
||||
|
||||
static Service g_amsBpcSrv;
|
||||
|
||||
NX_GENERATE_SERVICE_GUARD(amsBpc);
|
||||
|
||||
Result _amsBpcInitialize(void) {
|
||||
Handle h;
|
||||
Result rc = svcConnectToNamedPort(&h, "bpc:ams"); /* TODO: ams:bpc */
|
||||
if (R_SUCCEEDED(rc)) serviceCreate(&g_amsBpcSrv, h);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void _amsBpcCleanup(void) {
|
||||
serviceClose(&g_amsBpcSrv);
|
||||
}
|
||||
|
||||
Service *amsBpcGetServiceSession(void) {
|
||||
return &g_amsBpcSrv;
|
||||
}
|
||||
|
||||
Result amsBpcRebootToFatalError(void *ctx) {
|
||||
/* Note: this takes in an sts::ams::FatalErrorContext. */
|
||||
/* static_assert(sizeof() == 0x350) is done at type definition. */
|
||||
return serviceDispatch(&g_amsBpcSrv, 65000,
|
||||
.buffer_attrs = { SfBufferAttr_Out | SfBufferAttr_HipcMapAlias | SfBufferAttr_FixedSize },
|
||||
.buffers = { { ctx, 0x350 } },
|
||||
);
|
||||
}
|
||||
@@ -14,11 +14,21 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
#pragma once
|
||||
#include <switch/types.h>
|
||||
#include <switch/kernel/event.h>
|
||||
#include <switch/services/sm.h>
|
||||
|
||||
static sts::os::RecursiveMutex g_sm_session_lock;
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
sts::os::RecursiveMutex &GetSmSessionMutex() {
|
||||
return g_sm_session_lock;
|
||||
Result amsBpcInitialize(void);
|
||||
void amsBpcExit(void);
|
||||
Service *amsBpcGetServiceSession(void);
|
||||
|
||||
Result amsBpcRebootToFatalError(void *ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
153
stratosphere/libstratosphere/source/ams/ams_environment.cpp
Normal file
153
stratosphere/libstratosphere/source/ams/ams_environment.cpp
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stratosphere.hpp>
|
||||
#include "ams_bpc.h"
|
||||
|
||||
namespace sts::ams {
|
||||
|
||||
namespace {
|
||||
|
||||
inline u64 GetPc() {
|
||||
u64 pc;
|
||||
__asm__ __volatile__ ("adr %[pc], ." : [pc]"=&r"(pc) :: );
|
||||
return pc;
|
||||
}
|
||||
|
||||
struct StackFrame {
|
||||
u64 fp;
|
||||
u64 lr;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
extern ncm::TitleId StratosphereTitleId;
|
||||
|
||||
void WEAK ExceptionHandler(FatalErrorContext *ctx) {
|
||||
R_ASSERT(amsBpcInitialize());
|
||||
R_ASSERT(amsBpcRebootToFatalError(ctx));
|
||||
while (1) { /* ... */ }
|
||||
}
|
||||
|
||||
void CrashHandler(ThreadExceptionDump *ctx) {
|
||||
FatalErrorContext ams_ctx;
|
||||
|
||||
/* Convert thread dump to atmosphere dump. */
|
||||
{
|
||||
ams_ctx.magic = FatalErrorContext::Magic;
|
||||
ams_ctx.error_desc = ctx->error_desc;
|
||||
ams_ctx.title_id = static_cast<u64>(StratosphereTitleId);
|
||||
for (size_t i = 0; i < FatalErrorContext::NumGprs; i++) {
|
||||
ams_ctx.gprs[i] = ctx->cpu_gprs[i].x;
|
||||
}
|
||||
if (ams_ctx.error_desc == FatalErrorContext::DataAbortErrorDesc &&
|
||||
ams_ctx.gprs[27] == FatalErrorContext::StdAbortMagicAddress &&
|
||||
ams_ctx.gprs[28] == FatalErrorContext::StdAbortMagicValue)
|
||||
{
|
||||
/* Detect std::abort(). */
|
||||
ams_ctx.error_desc = FatalErrorContext::StdAbortErrorDesc;
|
||||
}
|
||||
|
||||
ams_ctx.fp = ctx->fp.x;
|
||||
ams_ctx.lr = ctx->lr.x;
|
||||
ams_ctx.sp = ctx->sp.x;
|
||||
ams_ctx.pc = ctx->pc.x;
|
||||
ams_ctx.pstate = ctx->pstate;
|
||||
ams_ctx.afsr0 = ctx->afsr0;
|
||||
ams_ctx.afsr1 = ctx->afsr1;
|
||||
ams_ctx.far = ctx->far.x;
|
||||
ams_ctx.report_identifier = armGetSystemTick();
|
||||
/* Grab module base. */
|
||||
{
|
||||
MemoryInfo mem_info;
|
||||
u32 page_info;
|
||||
if (R_SUCCEEDED(svcQueryMemory(&mem_info, &page_info, GetPc()))) {
|
||||
ams_ctx.module_base = mem_info.addr;
|
||||
} else {
|
||||
ams_ctx.module_base = 0;
|
||||
}
|
||||
}
|
||||
ams_ctx.stack_trace_size = 0;
|
||||
u64 cur_fp = ams_ctx.fp;
|
||||
for (size_t i = 0; i < FatalErrorContext::MaxStackTrace; i++) {
|
||||
/* Validate current frame. */
|
||||
if (cur_fp == 0 || (cur_fp & 0xF)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read a new frame. */
|
||||
StackFrame cur_frame;
|
||||
MemoryInfo mem_info;
|
||||
u32 page_info;
|
||||
if (R_SUCCEEDED(svcQueryMemory(&mem_info, &page_info, cur_fp)) && (mem_info.perm & Perm_R) == Perm_R) {
|
||||
std::memcpy(&cur_frame, reinterpret_cast<void *>(cur_fp), sizeof(cur_frame));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Advance to the next frame. */
|
||||
ams_ctx.stack_trace[ams_ctx.stack_trace_size++] = cur_frame.lr;
|
||||
cur_fp = cur_frame.fp;
|
||||
}
|
||||
/* Clear unused parts of stack trace. */
|
||||
for (size_t i = ams_ctx.stack_trace_size; i < FatalErrorContext::MaxStackTrace; i++) {
|
||||
ams_ctx.stack_trace[i] = 0;
|
||||
}
|
||||
|
||||
/* Grab up to 0x100 of stack. */
|
||||
{
|
||||
MemoryInfo mem_info;
|
||||
u32 page_info;
|
||||
if (R_SUCCEEDED(svcQueryMemory(&mem_info, &page_info, ams_ctx.sp)) && (mem_info.perm & Perm_R) == Perm_R) {
|
||||
size_t copy_size = std::min(FatalErrorContext::MaxStackDumpSize, static_cast<size_t>(mem_info.addr + mem_info.size - ams_ctx.sp));
|
||||
ams_ctx.stack_dump_size = copy_size;
|
||||
std::memcpy(ams_ctx.stack_dump, reinterpret_cast<void *>(ams_ctx.sp), copy_size);
|
||||
} else {
|
||||
ams_ctx.stack_dump_size = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Just call the user exception handler. */
|
||||
::sts::ams::ExceptionHandler(&ams_ctx);
|
||||
}
|
||||
|
||||
inline __attribute((noreturn)) void AbortImpl() {
|
||||
/* Just perform a data abort. */
|
||||
register u64 addr __asm__("x27") = FatalErrorContext::StdAbortMagicAddress;
|
||||
register u64 val __asm__("x28") = FatalErrorContext::StdAbortMagicValue;
|
||||
while (true) {
|
||||
__asm__ __volatile__ (
|
||||
"str %[val], [%[addr]]"
|
||||
:
|
||||
: [val]"r"(val), [addr]"r"(addr)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
/* Redefine abort to trigger these handlers. */
|
||||
void abort();
|
||||
|
||||
}
|
||||
|
||||
/* Custom abort handler, so that std::abort will trigger these. */
|
||||
void abort() {
|
||||
sts::ams::AbortImpl();
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stratosphere.hpp>
|
||||
#include <stratosphere/spl.hpp>
|
||||
#include <stratosphere/spl/smc/spl_smc.hpp>
|
||||
|
||||
namespace sts::ams {
|
||||
|
||||
ApiInfo GetApiInfo() {
|
||||
u64 exosphere_cfg;
|
||||
if (spl::smc::GetConfig(&exosphere_cfg, 1, SplConfigItem_ExosphereApiVersion) != spl::smc::Result::Success) {
|
||||
R_ASSERT(ResultAtmosphereExosphereNotPresent);
|
||||
}
|
||||
|
||||
return ApiInfo{
|
||||
.major_version = static_cast<u32>((exosphere_cfg >> 0x20) & 0xFF),
|
||||
.minor_version = static_cast<u32>((exosphere_cfg >> 0x18) & 0xFF),
|
||||
.micro_version = static_cast<u32>((exosphere_cfg >> 0x10) & 0xFF),
|
||||
.target_firmware = static_cast<TargetFirmware>((exosphere_cfg >> 0x08) & 0xFF),
|
||||
.master_key_revision = static_cast<u32>((exosphere_cfg >> 0x00) & 0xFF),
|
||||
};
|
||||
}
|
||||
|
||||
void ForceRebootToRcm() {
|
||||
R_ASSERT(spl::smc::ConvertResult(spl::smc::SetConfig(SplConfigItem_ExosphereNeedsReboot, 1)));
|
||||
}
|
||||
|
||||
void ForceRebootToIramPayload() {
|
||||
R_ASSERT(spl::smc::ConvertResult(spl::smc::SetConfig(SplConfigItem_ExosphereNeedsReboot, 2)));
|
||||
}
|
||||
|
||||
void ForceShutdown() {
|
||||
R_ASSERT(spl::smc::ConvertResult(spl::smc::SetConfig(SplConfigItem_ExosphereNeedsShutdown, 1)));
|
||||
}
|
||||
|
||||
void CopyToIram(uintptr_t iram_dst, const void *dram_src, size_t size) {
|
||||
spl::smc::AtmosphereCopyToIram(iram_dst, dram_src, size);
|
||||
}
|
||||
|
||||
void CopyFromIram(void *dram_dst, uintptr_t iram_src, size_t size) {
|
||||
spl::smc::AtmosphereCopyFromIram(dram_dst, iram_src, size);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
inline Result GetRcmBugPatched(bool *out) {
|
||||
u64 tmp;
|
||||
R_TRY(spl::smc::ConvertResult(spl::smc::GetConfig(&tmp, 1, SplConfigItem_ExosphereHasRcmBugPatch)));
|
||||
*out = (tmp != 0);
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool IsRcmBugPatched() {
|
||||
bool rcm_bug_patched;
|
||||
R_ASSERT(GetRcmBugPatched(&rcm_bug_patched));
|
||||
return rcm_bug_patched;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -35,19 +35,7 @@ namespace sts::hos {
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: spl::smc:: */
|
||||
u32 target_fw = 0;
|
||||
{
|
||||
SecmonArgs args = {0};
|
||||
args.X[0] = 0xC3000002; /* smcGetConfig */
|
||||
args.X[1] = 65000; /* ConfigItem_ExosphereVersion */
|
||||
R_ASSERT(svcCallSecureMonitor(&args));
|
||||
STS_ASSERT(args.X[0] == 0);
|
||||
|
||||
target_fw = (args.X[1] >> 0x08) & 0xFF;
|
||||
}
|
||||
|
||||
switch (static_cast<ams::TargetFirmware>(target_fw)) {
|
||||
switch (ams::GetApiInfo().GetTargetFirmware()) {
|
||||
case ams::TargetFirmware_100:
|
||||
g_hos_version = hos::Version_100;
|
||||
break;
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
#include <switch/arm/atomics.h>
|
||||
#include <stratosphere/services/bpc_ams.h>
|
||||
|
||||
static Service g_bpcAmsSrv;
|
||||
static u64 g_bpcAmsAmsRefcnt;
|
||||
|
||||
Result bpcAmsInitialize(void) {
|
||||
atomicIncrement64(&g_bpcAmsAmsRefcnt);
|
||||
|
||||
if (serviceIsActive(&g_bpcAmsSrv)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Handle h;
|
||||
Result rc = svcConnectToNamedPort(&h, "bpc:ams");
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
serviceCreate(&g_bpcAmsSrv, h);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void bpcAmsExit(void) {
|
||||
if (atomicDecrement64(&g_bpcAmsAmsRefcnt) == 0)
|
||||
serviceClose(&g_bpcAmsSrv);
|
||||
}
|
||||
|
||||
Result bpcAmsRebootToFatalError(AtmosphereFatalErrorContext *ctx) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddSendBuffer(&c, ctx, sizeof(*ctx), BufferType_Normal);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_bpcAmsSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65000;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_bpcAmsSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_bpcAmsSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
55
stratosphere/libstratosphere/source/dd/dd_io_mappings.cpp
Normal file
55
stratosphere/libstratosphere/source/dd/dd_io_mappings.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace sts::dd {
|
||||
|
||||
uintptr_t QueryIoMapping(uintptr_t phys_addr, size_t size) {
|
||||
u64 virtual_addr;
|
||||
const u64 aligned_addr = util::AlignDown(phys_addr, 0x1000);
|
||||
const size_t offset = phys_addr - aligned_addr;
|
||||
const u64 aligned_size = size + offset;
|
||||
R_TRY_CATCH(svcQueryIoMapping(&virtual_addr, aligned_addr, aligned_size)) {
|
||||
/* Official software handles this by returning 0. */
|
||||
R_CATCH(ResultKernelNotFound) { return 0; }
|
||||
} R_END_TRY_CATCH_WITH_ASSERT;
|
||||
|
||||
return static_cast<uintptr_t>(virtual_addr + offset);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
inline u32 ReadWriteRegisterImpl(uintptr_t phys_addr, u32 value, u32 mask) {
|
||||
u32 out_value;
|
||||
R_ASSERT(svcReadWriteRegister(&out_value, phys_addr, mask, value));
|
||||
return out_value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
u32 ReadRegister(uintptr_t phys_addr) {
|
||||
return ReadWriteRegisterImpl(phys_addr, 0, 0);
|
||||
}
|
||||
|
||||
void WriteRegister(uintptr_t phys_addr, u32 value) {
|
||||
ReadWriteRegisterImpl(phys_addr, value, ~u32());
|
||||
}
|
||||
|
||||
u32 ReadWriteRegister(uintptr_t phys_addr, u32 value, u32 mask) {
|
||||
return ReadWriteRegisterImpl(phys_addr, value, mask);
|
||||
}
|
||||
|
||||
}
|
||||
166
stratosphere/libstratosphere/source/dmnt/dmntcht.c
Normal file
166
stratosphere/libstratosphere/source/dmnt/dmntcht.c
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#define NX_SERVICE_ASSUME_NON_DOMAIN
|
||||
#include "../service_guard.h"
|
||||
#include "dmntcht.h"
|
||||
|
||||
static Service g_dmntchtSrv;
|
||||
|
||||
NX_GENERATE_SERVICE_GUARD(dmntcht);
|
||||
|
||||
Result _dmntchtInitialize(void) {
|
||||
return smGetService(&g_dmntchtSrv, "dmnt:cht");
|
||||
}
|
||||
|
||||
void _dmntchtCleanup(void) {
|
||||
serviceClose(&g_dmntchtSrv);
|
||||
}
|
||||
|
||||
Service* dmntchtGetServiceSession(void) {
|
||||
return &g_dmntchtSrv;
|
||||
}
|
||||
|
||||
Result dmntchtHasCheatProcess(bool *out) {
|
||||
u8 tmp;
|
||||
Result rc = serviceDispatchOut(&g_dmntchtSrv, 65000, tmp);
|
||||
if (R_SUCCEEDED(rc) && out) *out = tmp & 1;
|
||||
}
|
||||
|
||||
Result dmntchtGetCheatProcessEvent(Event *event) {
|
||||
Handle evt_handle;
|
||||
Result rc = serviceDispatch(&g_dmntchtSrv, 65001,
|
||||
.out_handle_attrs = { SfOutHandleAttr_HipcCopy },
|
||||
.out_handles = &evt_handle,
|
||||
);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
eventLoadRemote(&g_dmntchtSrv, evt_handle, true);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result dmntchtGetCheatProcessMetadata(DmntCheatProcessMetadata *out_metadata) {
|
||||
return serviceDispatchOut(&g_dmntchtSrv, 65002, *out_metadata);
|
||||
}
|
||||
|
||||
Result dmntchtForceOpenCheatProcess(void) {
|
||||
return serviceDispatch(&g_dmntchtSrv, 65003);
|
||||
}
|
||||
|
||||
static Result _dmntchtGetCount(u64 *out_count, u32 cmd_id) {
|
||||
return serviceDispatchOut(&g_dmntchtSrv, cmd_id, *out_count);
|
||||
}
|
||||
|
||||
static Result _dmntchtGetEntries(void *buffer, u64 buffer_size, u64 offset, u64 *out_count, u32 cmd_id) {
|
||||
return serviceDispatchInOut(&g_dmntchtSrv, cmd_id, offset, *out_count,
|
||||
.buffer_attrs = { SfBufferAttr_Out | SfBufferAttr_HipcMapAlias },
|
||||
.buffers = { { buffer, buffer_size } },
|
||||
);
|
||||
}
|
||||
|
||||
static Result _dmntchtCmdInU32NoOut(u32 in, u32 cmd_id) {
|
||||
return serviceDispatchIn(&g_dmntchtSrv, cmd_id, in);
|
||||
}
|
||||
|
||||
Result dmntchtGetCheatProcessMappingCount(u64 *out_count) {
|
||||
return _dmntchtGetCount(65100, out_count);
|
||||
}
|
||||
|
||||
Result dmntchtGetCheatProcessMappings(MemoryInfo *buffer, u64 max_count, u64 offset, u64 *out_count) {
|
||||
return _dmntchtGetEntries(65101, buffer, sizeof(*buffer) * max_count, offset, out_count);
|
||||
}
|
||||
|
||||
Result dmntchtReadCheatProcessMemory(u64 address, void *buffer, size_t size) {
|
||||
const struct {
|
||||
u64 address;
|
||||
u64 size;
|
||||
} in = { address, size };
|
||||
return serviceDispatchIn(&g_dmntchtSrv, 65102, in,
|
||||
.buffer_attrs = { SfBufferAttr_Out | SfBufferAttr_HipcMapAlias },
|
||||
.buffers = { { buffer, size } },
|
||||
);
|
||||
}
|
||||
|
||||
Result dmntchtWriteCheatProcessMemory(u64 address, const void *buffer, size_t size) {
|
||||
const struct {
|
||||
u64 address;
|
||||
u64 size;
|
||||
} in = { address, size };
|
||||
return serviceDispatchIn(&g_dmntchtSrv, 65103, in,
|
||||
.buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias },
|
||||
.buffers = { { buffer, size } },
|
||||
);
|
||||
}
|
||||
|
||||
Result dmntchtQueryCheatProcessMemory(MemoryInfo *mem_info, u64 address){
|
||||
return serviceDispatchInOut(&g_dmntchtSrv, 65104, address, *mem_info);
|
||||
}
|
||||
|
||||
Result dmntchtGetCheatCount(u64 *out_count) {
|
||||
return _dmntchtGetCount(65200, out_count);
|
||||
}
|
||||
|
||||
Result dmntchtGetCheats(DmntCheatEntry *buffer, u64 max_count, u64 offset, u64 *out_count) {
|
||||
return _dmntchtGetEntries(65201, buffer, sizeof(*buffer) * max_count, offset, out_count);
|
||||
}
|
||||
|
||||
Result dmntchtGetCheatById(DmntCheatEntry *out, u32 cheat_id) {
|
||||
return serviceDispatchIn(&g_dmntchtSrv, 65202, cheat_id,
|
||||
.buffer_attrs = { SfBufferAttr_Out | SfBufferAttr_HipcMapAlias | SfBufferAttr_FixedSize },
|
||||
.buffers = { { out, sizeof(*out) } },
|
||||
);
|
||||
}
|
||||
|
||||
Result dmntchtToggleCheat(u32 cheat_id) {
|
||||
return _dmntchtCmdInU32NoOut(cheat_id, 65203);
|
||||
}
|
||||
|
||||
Result dmntchtAddCheat(DmntCheatDefinition *cheat_def, bool enabled, u32 *out_cheat_id) {
|
||||
const u8 in = enabled != 0;
|
||||
return serviceDispatchInOut(&g_dmntchtSrv, 65204, in, *out_cheat_id,
|
||||
.buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias | SfBufferAttr_FixedSize },
|
||||
.buffers = { { cheat_def, sizeof(*cheat_def) } },
|
||||
);
|
||||
}
|
||||
|
||||
Result dmntchtRemoveCheat(u32 cheat_id) {
|
||||
return _dmntchtCmdInU32NoOut(cheat_id, 65205);
|
||||
}
|
||||
|
||||
Result dmntchtGetFrozenAddressCount(u64 *out_count) {
|
||||
return _dmntchtGetCount(65300, out_count);
|
||||
}
|
||||
|
||||
Result dmntchtGetFrozenAddresses(DmntFrozenAddressEntry *buffer, u64 max_count, u64 offset, u64 *out_count) {
|
||||
return _dmntchtGetEntries(65301, buffer, sizeof(*buffer) * max_count, offset, out_count);
|
||||
}
|
||||
|
||||
Result dmntchtGetFrozenAddress(DmntFrozenAddressEntry *out, u64 address) {
|
||||
return serviceDispatchInOut(&g_dmntchtSrv, 65302, address, *out);
|
||||
}
|
||||
|
||||
Result dmntchtEnableFrozenAddress(u64 address, u64 width, u64 *out_value) {
|
||||
const struct {
|
||||
u64 address;
|
||||
u64 width;
|
||||
} in = { address, width };
|
||||
return serviceDispatchInOut(&g_dmntchtSrv, 65303, in, *out_value);
|
||||
}
|
||||
|
||||
Result dmntchtDisableFrozenAddress(u64 address) {
|
||||
return serviceDispatchIn(&g_dmntchtSrv, 65304, address);
|
||||
}
|
||||
93
stratosphere/libstratosphere/source/dmnt/dmntcht.h
Normal file
93
stratosphere/libstratosphere/source/dmnt/dmntcht.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch/types.h>
|
||||
#include <switch/kernel/event.h>
|
||||
#include <switch/services/sm.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
u64 base;
|
||||
u64 size;
|
||||
} DmntMemoryRegionExtents;
|
||||
|
||||
typedef struct {
|
||||
u64 process_id;
|
||||
u64 title_id;
|
||||
DmntMemoryRegionExtents main_nso_extents;
|
||||
DmntMemoryRegionExtents heap_extents;
|
||||
DmntMemoryRegionExtents alias_extents;
|
||||
DmntMemoryRegionExtents address_space_extents;
|
||||
u8 main_nso_build_id[0x20];
|
||||
} DmntCheatProcessMetadata;
|
||||
|
||||
typedef struct {
|
||||
char readable_name[0x40];
|
||||
uint32_t num_opcodes;
|
||||
uint32_t opcodes[0x100];
|
||||
} DmntCheatDefinition;
|
||||
|
||||
typedef struct {
|
||||
bool enabled;
|
||||
uint32_t cheat_id;
|
||||
DmntCheatDefinition definition;
|
||||
} DmntCheatEntry;
|
||||
|
||||
typedef struct {
|
||||
u64 value;
|
||||
u8 width;
|
||||
} DmntFrozenAddressValue;
|
||||
|
||||
typedef struct {
|
||||
u64 address;
|
||||
DmntFrozenAddressValue value;
|
||||
} DmntFrozenAddressEntry;
|
||||
|
||||
Result dmntchtInitialize(void);
|
||||
void dmntchtExit(void);
|
||||
Service* dmntchtGetServiceSession(void);
|
||||
|
||||
Result dmntchtHasCheatProcess(bool *out);
|
||||
Result dmntchtGetCheatProcessEvent(Event *event);
|
||||
Result dmntchtGetCheatProcessMetadata(DmntCheatProcessMetadata *out_metadata);
|
||||
Result dmntchtForceOpenCheatProcess(void);
|
||||
|
||||
Result dmntchtGetCheatProcessMappingCount(u64 *out_count);
|
||||
Result dmntchtGetCheatProcessMappings(MemoryInfo *buffer, u64 max_count, u64 offset, u64 *out_count);
|
||||
Result dmntchtReadCheatProcessMemory(u64 address, void *buffer, size_t size);
|
||||
Result dmntchtWriteCheatProcessMemory(u64 address, const void *buffer, size_t size);
|
||||
Result dmntchtQueryCheatProcessMemory(MemoryInfo *mem_info, u64 address);
|
||||
|
||||
Result dmntchtGetCheatCount(u64 *out_count);
|
||||
Result dmntchtGetCheats(DmntCheatEntry *buffer, u64 max_count, u64 offset, u64 *out_count);
|
||||
Result dmntchtGetCheatById(DmntCheatEntry *out_cheat, u32 cheat_id);
|
||||
Result dmntchtToggleCheat(u32 cheat_id);
|
||||
Result dmntchtAddCheat(DmntCheatDefinition *cheat, bool enabled, u32 *out_cheat_id);
|
||||
Result dmntchtRemoveCheat(u32 cheat_id);
|
||||
|
||||
Result dmntchtGetFrozenAddressCount(u64 *out_count);
|
||||
Result dmntchtGetFrozenAddresses(DmntFrozenAddressEntry *buffer, u64 max_count, u64 offset, u64 *out_count);
|
||||
Result dmntchtGetFrozenAddress(DmntFrozenAddressEntry *out, u64 address);
|
||||
Result dmntchtEnableFrozenAddress(u64 address, u64 width, u64 *out_value);
|
||||
Result dmntchtDisableFrozenAddress(u64 address);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,650 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
#include <switch/arm/atomics.h>
|
||||
#include <stratosphere/services/dmntcht.h>
|
||||
|
||||
static Service g_dmntchtService;
|
||||
static u64 g_refCnt;
|
||||
|
||||
static Result _dmntchtGetCount(u64 cmd_id, u64 *out_count);
|
||||
static Result _dmntchtGetEntries(u64 cmd_id, void *buffer, u64 buffer_size, u64 offset, u64 *out_count);
|
||||
|
||||
Result dmntchtInitialize(void) {
|
||||
atomicIncrement64(&g_refCnt);
|
||||
|
||||
if (serviceIsActive(&g_dmntchtService)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return smGetService(&g_dmntchtService, "dmnt:cht");
|
||||
}
|
||||
|
||||
void dmntchtExit(void) {
|
||||
if (atomicIncrement64(&g_refCnt) == 0) {
|
||||
serviceClose(&g_dmntchtService);
|
||||
}
|
||||
}
|
||||
|
||||
Service* dmntchtGetServiceSession(void) {
|
||||
return &g_dmntchtService;
|
||||
}
|
||||
|
||||
Result dmntchtHasCheatProcess(bool *out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65000;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_dmntchtService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
bool out;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
if (out) *out = resp->out;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result dmntchtGetCheatProcessEvent(Event *event) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65001;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_dmntchtService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
eventLoadRemote(event, r.Handles[0], true);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result dmntchtGetCheatProcessMetadata(DmntCheatProcessMetadata *out_metadata) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65002;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_dmntchtService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
DmntCheatProcessMetadata metadata;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
if (out_metadata) *out_metadata = resp->metadata;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result dmntchtForceOpenCheatProcess(void) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65003;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_dmntchtService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _dmntchtGetCount(u64 cmd_id, u64 *out_count) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = cmd_id;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_dmntchtService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 count;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
*out_count = resp->count;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _dmntchtGetEntries(u64 cmd_id, void *buffer, u64 buffer_size, u64 offset, u64 *out_count) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddRecvBuffer(&c, buffer, buffer_size, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 offset;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = cmd_id;
|
||||
raw->offset = offset;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_dmntchtService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 count;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
if (out_count) *out_count = resp->count;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result dmntchtGetCheatProcessMappingCount(u64 *out_count) {
|
||||
return _dmntchtGetCount(65100, out_count);
|
||||
}
|
||||
|
||||
Result dmntchtGetCheatProcessMappings(MemoryInfo *buffer, u64 max_count, u64 offset, u64 *out_count) {
|
||||
return _dmntchtGetEntries(65101, buffer, sizeof(*buffer) * max_count, offset, out_count);
|
||||
}
|
||||
|
||||
Result dmntchtReadCheatProcessMemory(u64 address, void *buffer, size_t size) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddRecvBuffer(&c, buffer, size, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 address;
|
||||
u64 size;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65102;
|
||||
raw->address = address;
|
||||
raw->size = size;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_dmntchtService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result dmntchtWriteCheatProcessMemory(u64 address, const void *buffer, size_t size) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddSendBuffer(&c, buffer, size, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 address;
|
||||
u64 size;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65103;
|
||||
raw->address = address;
|
||||
raw->size = size;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_dmntchtService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result dmntchtQueryCheatProcessMemory(MemoryInfo *mem_info, u64 address){
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 address;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65104;
|
||||
raw->address = address;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_dmntchtService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
MemoryInfo mem_info;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
if (mem_info) *mem_info = resp->mem_info;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result dmntchtGetCheatCount(u64 *out_count) {
|
||||
return _dmntchtGetCount(65200, out_count);
|
||||
}
|
||||
|
||||
Result dmntchtGetCheats(DmntCheatEntry *buffer, u64 max_count, u64 offset, u64 *out_count) {
|
||||
return _dmntchtGetEntries(65201, buffer, sizeof(*buffer) * max_count, offset, out_count);
|
||||
}
|
||||
|
||||
Result dmntchtGetCheatById(DmntCheatEntry *buffer, u32 cheat_id) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddRecvBuffer(&c, buffer, sizeof(*buffer), 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u32 cheat_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65202;
|
||||
raw->cheat_id = cheat_id;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_dmntchtService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result dmntchtToggleCheat(u32 cheat_id) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u32 cheat_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65203;
|
||||
raw->cheat_id = cheat_id;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_dmntchtService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result dmntchtAddCheat(DmntCheatDefinition *buffer, bool enabled, u32 *out_cheat_id) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddSendBuffer(&c, buffer, sizeof(*buffer), 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u8 enabled;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65204;
|
||||
raw->enabled = enabled;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_dmntchtService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 cheat_id;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
if (out_cheat_id) *out_cheat_id = resp->cheat_id;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result dmntchtRemoveCheat(u32 cheat_id) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u32 cheat_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65205;
|
||||
raw->cheat_id = cheat_id;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_dmntchtService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
Result dmntchtGetFrozenAddressCount(u64 *out_count) {
|
||||
return _dmntchtGetCount(65300, out_count);
|
||||
}
|
||||
|
||||
Result dmntchtGetFrozenAddresses(DmntFrozenAddressEntry *buffer, u64 max_count, u64 offset, u64 *out_count) {
|
||||
return _dmntchtGetEntries(65301, buffer, sizeof(*buffer) * max_count, offset, out_count);
|
||||
}
|
||||
|
||||
Result dmntchtGetFrozenAddress(DmntFrozenAddressEntry *out, u64 address) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 address;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65302;
|
||||
raw->address = address;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_dmntchtService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
DmntFrozenAddressEntry entry;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
if (out) *out = resp->entry;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result dmntchtEnableFrozenAddress(u64 address, u64 width, u64 *out_value) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 address;
|
||||
u64 width;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65303;
|
||||
raw->address = address;
|
||||
raw->width = width;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_dmntchtService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 value;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
if (out_value) *out_value = resp->value;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result dmntchtDisableFrozenAddress(u64 address) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 address;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65304;
|
||||
raw->address = address;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_dmntchtService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 value;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
/* EFS0 */
|
||||
static constexpr u32 EmummcStorageMagic = 0x30534645;
|
||||
static constexpr size_t EmummcMaxDirLength = 0x7F;
|
||||
|
||||
struct EmummcBaseConfig {
|
||||
u32 magic;
|
||||
u32 type;
|
||||
u32 id;
|
||||
u32 fs_version;
|
||||
};
|
||||
|
||||
struct EmummcPartitionConfig {
|
||||
u64 start_sector;
|
||||
};
|
||||
|
||||
struct EmummcFileConfig {
|
||||
char path[EmummcMaxDirLength+1];
|
||||
};
|
||||
|
||||
struct ExoEmummcConfig {
|
||||
EmummcBaseConfig base_cfg;
|
||||
union {
|
||||
EmummcPartitionConfig partition_cfg;
|
||||
EmummcFileConfig file_cfg;
|
||||
};
|
||||
char emu_dir_path[EmummcMaxDirLength+1];
|
||||
};
|
||||
|
||||
enum EmummcType {
|
||||
EmummcType_Emmc = 0,
|
||||
EmummcType_Sd,
|
||||
EmummcType_SdFile,
|
||||
|
||||
EmummcType_Max,
|
||||
};
|
||||
|
||||
static bool g_IsEmummc = false;
|
||||
static bool g_HasCached = false;
|
||||
static Mutex g_Mutex;
|
||||
static ExoEmummcConfig g_exo_emummc_config;
|
||||
|
||||
static void _CacheValues(void)
|
||||
{
|
||||
if (__atomic_load_n(&g_HasCached, __ATOMIC_SEQ_CST))
|
||||
return;
|
||||
|
||||
mutexLock(&g_Mutex);
|
||||
|
||||
if (g_HasCached) {
|
||||
mutexUnlock(&g_Mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
static struct {
|
||||
char file_path[EmummcMaxDirLength+1];
|
||||
char nintendo_path[EmummcMaxDirLength+1];
|
||||
} __attribute__((aligned(0x1000))) paths;
|
||||
|
||||
{
|
||||
SecmonArgs args = {0};
|
||||
args.X[0] = 0xF0000404; /* smcAmsGetEmunandConfig */
|
||||
args.X[1] = 0; /* NAND */
|
||||
args.X[2] = reinterpret_cast<u64>(&paths); /* path output */
|
||||
R_ASSERT(svcCallSecureMonitor(&args));
|
||||
STS_ASSERT(args.X[0] == 0);
|
||||
std::memcpy(&g_exo_emummc_config, &args.X[1], sizeof(args) - sizeof(args.X[0]));
|
||||
}
|
||||
|
||||
const EmummcType emummc_type = static_cast<EmummcType>(g_exo_emummc_config.base_cfg.type);
|
||||
|
||||
/* Ignore format warnings. */
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wformat-truncation"
|
||||
switch (emummc_type) {
|
||||
case EmummcType_SdFile:
|
||||
std::snprintf(g_exo_emummc_config.file_cfg.path, sizeof(g_exo_emummc_config.file_cfg.path), "/%s", paths.file_path);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
std::snprintf(g_exo_emummc_config.emu_dir_path, sizeof(g_exo_emummc_config.emu_dir_path), "/%s", paths.nintendo_path);
|
||||
|
||||
g_IsEmummc = g_exo_emummc_config.base_cfg.magic == EmummcStorageMagic && emummc_type != EmummcType_Emmc;
|
||||
|
||||
/* Default Nintendo redirection path. */
|
||||
if (g_IsEmummc) {
|
||||
if (std::strcmp(g_exo_emummc_config.emu_dir_path, "/") == 0) {
|
||||
std::snprintf(g_exo_emummc_config.emu_dir_path, sizeof(g_exo_emummc_config.emu_dir_path), "/emummc/Nintendo_%04x", g_exo_emummc_config.base_cfg.id);
|
||||
}
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
__atomic_store_n(&g_HasCached, true, __ATOMIC_SEQ_CST);
|
||||
|
||||
mutexUnlock(&g_Mutex);
|
||||
}
|
||||
|
||||
|
||||
/* Get whether emummc is active. */
|
||||
bool IsEmummc() {
|
||||
_CacheValues();
|
||||
return g_IsEmummc;
|
||||
}
|
||||
|
||||
/* Get Nintendo redirection path. */
|
||||
const char *GetEmummcNintendoDirPath() {
|
||||
_CacheValues();
|
||||
if (!g_IsEmummc) {
|
||||
return nullptr;
|
||||
}
|
||||
return g_exo_emummc_config.emu_dir_path;
|
||||
}
|
||||
|
||||
/* Get Emummc folderpath, NULL if not file-based. */
|
||||
const char *GetEmummcFilePath() {
|
||||
_CacheValues();
|
||||
if (!g_IsEmummc || g_exo_emummc_config.base_cfg.type != EmummcType_SdFile) {
|
||||
return nullptr;
|
||||
}
|
||||
return g_exo_emummc_config.file_cfg.path;
|
||||
}
|
||||
@@ -18,44 +18,9 @@
|
||||
#include "ldr_ams.h"
|
||||
|
||||
static Result _ldrAtmosphereHasLaunchedTitle(Service *srv, bool *out, u64 tid) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 title_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65000;
|
||||
raw->title_id = tid;
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u8 has_launched_title;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*out = resp->has_launched_title != 0;
|
||||
} else {
|
||||
rc = 0x666;
|
||||
}
|
||||
} else {
|
||||
rc = 0x555;
|
||||
}
|
||||
|
||||
u8 tmp;
|
||||
Result rc = serviceDispatchInOut(srv, 65000, tid, tmp);
|
||||
if (R_SUCCEEDED(rc) && out) *out = tmp & 1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <mutex>
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
WEAK sts::ncm::TitleId __stratosphere_title_id = sts::ncm::TitleId::Invalid;
|
||||
|
||||
extern "C" {
|
||||
void WEAK __libstratosphere_exception_handler(AtmosphereFatalErrorContext *ctx);
|
||||
|
||||
/* Redefine abort, so that it triggers these handlers. */
|
||||
void abort();
|
||||
};
|
||||
|
||||
static inline u64 GetPc() {
|
||||
u64 pc;
|
||||
__asm__ __volatile__ ("adr %[pc], ." : [pc]"=&r"(pc) :: );
|
||||
return pc;
|
||||
}
|
||||
|
||||
struct StackFrame {
|
||||
u64 fp;
|
||||
u64 lr;
|
||||
};
|
||||
|
||||
void StratosphereCrashHandler(ThreadExceptionDump *ctx) {
|
||||
AtmosphereFatalErrorContext ams_ctx;
|
||||
/* Convert thread dump to atmosphere dump. */
|
||||
{
|
||||
ams_ctx.magic = AtmosphereFatalErrorMagic;
|
||||
ams_ctx.error_desc = ctx->error_desc;
|
||||
ams_ctx.title_id = static_cast<u64>(__stratosphere_title_id);
|
||||
for (size_t i = 0; i < AtmosphereFatalErrorNumGprs; i++) {
|
||||
ams_ctx.gprs[i] = ctx->cpu_gprs[i].x;
|
||||
}
|
||||
if (ams_ctx.error_desc == DATA_ABORT_ERROR_DESC &&
|
||||
ams_ctx.gprs[2] == STD_ABORT_ADDR_MAGIC &&
|
||||
ams_ctx.gprs[3] == STD_ABORT_VALUE_MAGIC) {
|
||||
/* Detect std::abort(). */
|
||||
ams_ctx.error_desc = STD_ABORT_ERROR_DESC;
|
||||
}
|
||||
|
||||
ams_ctx.fp = ctx->fp.x;
|
||||
ams_ctx.lr = ctx->lr.x;
|
||||
ams_ctx.sp = ctx->sp.x;
|
||||
ams_ctx.pc = ctx->pc.x;
|
||||
ams_ctx.pstate = ctx->pstate;
|
||||
ams_ctx.afsr0 = ctx->afsr0;
|
||||
ams_ctx.afsr1 = ctx->afsr1;
|
||||
ams_ctx.far = ctx->far.x;
|
||||
ams_ctx.report_identifier = armGetSystemTick();
|
||||
/* Grab module base. */
|
||||
{
|
||||
MemoryInfo mem_info;
|
||||
u32 page_info;
|
||||
if (R_SUCCEEDED(svcQueryMemory(&mem_info, &page_info, GetPc()))) {
|
||||
ams_ctx.module_base = mem_info.addr;
|
||||
} else {
|
||||
ams_ctx.module_base = 0;
|
||||
}
|
||||
}
|
||||
ams_ctx.stack_trace_size = 0;
|
||||
u64 cur_fp = ams_ctx.fp;
|
||||
for (size_t i = 0; i < AMS_FATAL_ERROR_MAX_STACKTRACE; i++) {
|
||||
/* Validate current frame. */
|
||||
if (cur_fp == 0 || (cur_fp & 0xF)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read a new frame. */
|
||||
StackFrame cur_frame;
|
||||
MemoryInfo mem_info;
|
||||
u32 page_info;
|
||||
if (R_SUCCEEDED(svcQueryMemory(&mem_info, &page_info, cur_fp)) && (mem_info.perm & Perm_R) == Perm_R) {
|
||||
std::memcpy(&cur_frame, reinterpret_cast<void *>(cur_fp), sizeof(cur_frame));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Advance to the next frame. */
|
||||
ams_ctx.stack_trace[ams_ctx.stack_trace_size++] = cur_frame.lr;
|
||||
cur_fp = cur_frame.fp;
|
||||
}
|
||||
/* Clear unused parts of stack trace. */
|
||||
for (size_t i = ams_ctx.stack_trace_size; i < AMS_FATAL_ERROR_MAX_STACKTRACE; i++) {
|
||||
ams_ctx.stack_trace[i] = 0;
|
||||
}
|
||||
|
||||
/* Grab up to 0x100 of stack. */
|
||||
{
|
||||
MemoryInfo mem_info;
|
||||
u32 page_info;
|
||||
if (R_SUCCEEDED(svcQueryMemory(&mem_info, &page_info, ams_ctx.sp)) && (mem_info.perm & Perm_R) == Perm_R) {
|
||||
size_t copy_size = std::min(static_cast<size_t>(AMS_FATAL_ERROR_MAX_STACKDUMP), static_cast<size_t>(mem_info.addr + mem_info.size - ams_ctx.sp));
|
||||
ams_ctx.stack_dump_size = copy_size;
|
||||
std::memcpy(ams_ctx.stack_dump, reinterpret_cast<void *>(ams_ctx.sp), copy_size);
|
||||
} else {
|
||||
ams_ctx.stack_dump_size = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Just call the user exception handler. */
|
||||
__libstratosphere_exception_handler(&ams_ctx);
|
||||
}
|
||||
|
||||
/* Default exception handler behavior. */
|
||||
void WEAK __libstratosphere_exception_handler(AtmosphereFatalErrorContext *ctx) {
|
||||
R_ASSERT(bpcAmsInitialize());
|
||||
R_ASSERT(bpcAmsRebootToFatalError(ctx));
|
||||
bpcAmsExit();
|
||||
while (1) { }
|
||||
}
|
||||
|
||||
/* Custom abort handler, so that std::abort will trigger these. */
|
||||
void abort() {
|
||||
/* Just perform a data abort. */
|
||||
register u64 addr __asm__("x2") = STD_ABORT_ADDR_MAGIC;
|
||||
register u64 val __asm__("x3") = STD_ABORT_VALUE_MAGIC;
|
||||
while (true) {
|
||||
__asm__ __volatile__ (
|
||||
"str %[val], [%[addr]]"
|
||||
:
|
||||
: [val]"r"(val), [addr]"r"(addr)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -18,124 +18,35 @@
|
||||
#include "pm_ams.h"
|
||||
|
||||
Result pminfoAtmosphereGetProcessId(u64 *out_pid, u64 tid) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
Service *srv = pminfoGetServiceSession();
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 title_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65000;
|
||||
raw->title_id = tid;
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 pid;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*out_pid = resp->pid;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatchInOut(pminfoGetServiceSession(), 65000, tid, *out_pid);
|
||||
}
|
||||
|
||||
Result pminfoAtmosphereHasLaunchedTitle(bool *out, u64 tid) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
Service *srv = pminfoGetServiceSession();
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 title_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65001;
|
||||
raw->title_id = tid;
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u8 has_launched_title;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*out = resp->has_launched_title != 0;
|
||||
}
|
||||
}
|
||||
|
||||
u8 tmp;
|
||||
Result rc = serviceDispatchInOut(pminfoGetServiceSession(), 65001, tid, tmp);
|
||||
if (R_SUCCEEDED(rc) && out) *out = tmp & 1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result pmdmntAtmosphereGetProcessInfo(Handle* out, u64 *tid_out, u8 *sid_out, u64 pid) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
Service *s = pmdmntGetServiceSession();
|
||||
|
||||
Result pmdmntAtmosphereGetProcessInfo(Handle* handle_out, u64 *tid_out, u8 *sid_out, u64 pid) {
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 pid;
|
||||
} *raw;
|
||||
u64 title_id;
|
||||
u8 storage_id;
|
||||
} out;
|
||||
Handle tmp_handle;
|
||||
|
||||
raw = serviceIpcPrepareHeader(s, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65000;
|
||||
raw->pid = pid;
|
||||
|
||||
Result rc = serviceIpcDispatch(s);
|
||||
Result rc = serviceDispatchInOut(pmdmntGetServiceSession(), 65000, pid, out,
|
||||
.out_handle_attrs = { SfOutHandleAttr_HipcCopy },
|
||||
.out_handles = &tmp_handle,
|
||||
);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 title_id;
|
||||
FsStorageId storage_id;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(s, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
if (out) {
|
||||
*out = r.Handles[0];
|
||||
} else {
|
||||
svcCloseHandle(r.Handles[0]);
|
||||
}
|
||||
if (tid_out) *tid_out = resp->title_id;
|
||||
if (sid_out) *sid_out = resp->storage_id;
|
||||
if (tid_out) *tid_out = out.title_id;
|
||||
if (sid_out) *sid_out = out.storage_id;
|
||||
if (handle_out) {
|
||||
*handle_out = tmp_handle;
|
||||
} else {
|
||||
svcCloseHandle(tmp_handle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,44 +54,20 @@ Result pmdmntAtmosphereGetProcessInfo(Handle* out, u64 *tid_out, u8 *sid_out, u6
|
||||
}
|
||||
|
||||
Result pmdmntAtmosphereGetCurrentLimitInfo(u64 *out_cur, u64 *out_lim, u32 group, u32 resource) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
Service *s = pmdmntGetServiceSession();
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
const struct {
|
||||
u32 group;
|
||||
u32 resource;
|
||||
} *raw;
|
||||
} in = { group, resource };
|
||||
struct {
|
||||
u64 cur;
|
||||
u64 lim;
|
||||
} out;
|
||||
|
||||
raw = serviceIpcPrepareHeader(s, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65001;
|
||||
raw->group = group;
|
||||
raw->resource = resource;
|
||||
|
||||
Result rc = serviceIpcDispatch(s);
|
||||
Result rc = serviceDispatchInOut(pmdmntGetServiceSession(), 65001, in, out);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 cur_value;
|
||||
u64 lim_value;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(s, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
if (out_cur) *out_cur = resp->cur_value;
|
||||
if (out_lim) *out_lim = resp->lim_value;
|
||||
}
|
||||
if (out_cur) *out_cur = out.cur;
|
||||
if (out_lim) *out_lim = out.lim;
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
64
stratosphere/libstratosphere/source/service_guard.h
Normal file
64
stratosphere/libstratosphere/source/service_guard.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
#include <switch/types.h>
|
||||
#include <switch/result.h>
|
||||
#include <switch/kernel/mutex.h>
|
||||
#include <switch/sf/service.h>
|
||||
#include <switch/services/sm.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct ServiceGuard {
|
||||
Mutex mutex;
|
||||
u32 refCount;
|
||||
} ServiceGuard;
|
||||
|
||||
NX_INLINE bool serviceGuardBeginInit(ServiceGuard* g)
|
||||
{
|
||||
mutexLock(&g->mutex);
|
||||
return (g->refCount++) == 0;
|
||||
}
|
||||
|
||||
NX_INLINE Result serviceGuardEndInit(ServiceGuard* g, Result rc, void (*cleanupFunc)(void))
|
||||
{
|
||||
if (R_FAILED(rc)) {
|
||||
cleanupFunc();
|
||||
--g->refCount;
|
||||
}
|
||||
mutexUnlock(&g->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
NX_INLINE void serviceGuardExit(ServiceGuard* g, void (*cleanupFunc)(void))
|
||||
{
|
||||
mutexLock(&g->mutex);
|
||||
if (g->refCount && (--g->refCount) == 0)
|
||||
cleanupFunc();
|
||||
mutexUnlock(&g->mutex);
|
||||
}
|
||||
|
||||
#define NX_GENERATE_SERVICE_GUARD_PARAMS(name, _paramdecl, _parampass) \
|
||||
\
|
||||
static ServiceGuard g_##name##Guard; \
|
||||
NX_INLINE Result _##name##Initialize _paramdecl; \
|
||||
static void _##name##Cleanup(void); \
|
||||
\
|
||||
Result name##Initialize _paramdecl \
|
||||
{ \
|
||||
Result rc = 0; \
|
||||
if (serviceGuardBeginInit(&g_##name##Guard)) \
|
||||
rc = _##name##Initialize _parampass; \
|
||||
return serviceGuardEndInit(&g_##name##Guard, rc, _##name##Cleanup); \
|
||||
} \
|
||||
\
|
||||
void name##Exit(void) \
|
||||
{ \
|
||||
serviceGuardExit(&g_##name##Guard, _##name##Cleanup); \
|
||||
}
|
||||
|
||||
#define NX_GENERATE_SERVICE_GUARD(name) NX_GENERATE_SERVICE_GUARD_PARAMS(name, (void), ())
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -13,166 +13,42 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
#include <switch/arm/atomics.h>
|
||||
#define NX_SERVICE_ASSUME_NON_DOMAIN
|
||||
#include "../service_guard.h"
|
||||
#include "sm_ams.h"
|
||||
|
||||
static Service g_smMitmSrv;
|
||||
static u64 g_mitmRefCnt;
|
||||
static Result _smAtmosphereCmdHas(bool *out, u64 service_name, u32 cmd_id) {
|
||||
u8 tmp;
|
||||
Result rc = serviceDispatchInOut(smGetServiceSession(), cmd_id, service_name, tmp);
|
||||
if (R_SUCCEEDED(rc) && out) *out = tmp & 1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _smAtmosphereCmdInServiceNameNoOut(u64 service_name, Service *srv, u32 cmd_id) {
|
||||
return serviceDispatchIn(srv, cmd_id, service_name);
|
||||
}
|
||||
|
||||
Result smAtmosphereHasService(bool *out, const char *name) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
Service *srv = smGetServiceSession();
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 service_name;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65100;
|
||||
raw->service_name = smEncodeName(name);
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u8 has_service;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*out = resp->has_service != 0;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
return _smAtmosphereCmdHas(out, smEncodeName(name), 65100);
|
||||
}
|
||||
|
||||
Result smAtmosphereWaitService(const char *name) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
Service *srv = smGetServiceSession();
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 service_name;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65101;
|
||||
raw->service_name = smEncodeName(name);
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return _smAtmosphereCmdInServiceNameNoOut(smEncodeName(name), smGetServiceSession(), 65101);
|
||||
}
|
||||
|
||||
Result smAtmosphereHasMitm(bool *out, const char *name) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
Service *srv = smGetServiceSession();
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 service_name;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65004;
|
||||
raw->service_name = smEncodeName(name);
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u8 has_mitm;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*out = resp->has_mitm != 0;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
return _smAtmosphereCmdHas(out, smEncodeName(name), 65004);
|
||||
}
|
||||
|
||||
Result smAtmosphereWaitMitm(const char *name) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
Service *srv = smGetServiceSession();
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 service_name;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65005;
|
||||
raw->service_name = smEncodeName(name);
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return _smAtmosphereCmdInServiceNameNoOut(smEncodeName(name), smGetServiceSession(), 65005);
|
||||
}
|
||||
|
||||
Result smAtmosphereMitmInitialize(void) {
|
||||
atomicIncrement64(&g_mitmRefCnt);
|
||||
static Service g_smAtmosphereMitmSrv;
|
||||
|
||||
if (serviceIsActive(&g_smMitmSrv))
|
||||
return 0;
|
||||
NX_GENERATE_SERVICE_GUARD(smAtmosphereMitm);
|
||||
|
||||
Result _smAtmosphereMitmInitialize(void) {
|
||||
Handle sm_handle;
|
||||
Result rc = svcConnectToNamedPort(&sm_handle, "sm:");
|
||||
while (R_VALUE(rc) == KERNELRESULT(NotFound)) {
|
||||
@@ -181,195 +57,64 @@ Result smAtmosphereMitmInitialize(void) {
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
serviceCreate(&g_smMitmSrv, sm_handle);
|
||||
serviceCreate(&g_smAtmosphereMitmSrv, sm_handle);
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcSendPid(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 zero;
|
||||
u64 reserved[2];
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_smMitmSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
raw->zero = 0;
|
||||
|
||||
rc = serviceIpcDispatch(&g_smMitmSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
serviceIpcParse(&g_smMitmSrv, &r, sizeof(*resp));
|
||||
|
||||
resp = r.Raw;
|
||||
rc = resp->result;
|
||||
}
|
||||
const u64 pid_placeholder = 0;
|
||||
rc = serviceDispatchIn(&g_smAtmosphereMitmSrv, 0, pid_placeholder, .in_send_pid = true);
|
||||
}
|
||||
|
||||
if (R_FAILED(rc))
|
||||
smAtmosphereMitmExit();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void smAtmosphereMitmExit(void) {
|
||||
if (atomicDecrement64(&g_mitmRefCnt) == 0) {
|
||||
serviceClose(&g_smMitmSrv);
|
||||
}
|
||||
void _smAtmosphereMitmCleanup(void) {
|
||||
serviceClose(&g_smAtmosphereMitmSrv);
|
||||
}
|
||||
|
||||
Service* smAtmosphereMitmGetServiceSession(void) {
|
||||
return &g_smAtmosphereMitmSrv;
|
||||
}
|
||||
|
||||
Result smAtmosphereMitmInstall(Handle *handle_out, Handle *query_out, const char *name) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
Service *srv = &g_smMitmSrv;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 service_name;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65000;
|
||||
raw->service_name = smEncodeName(name);
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
const u64 in = smEncodeName(name);
|
||||
Handle tmp_handles[2];
|
||||
Result rc = serviceDispatchIn(&g_smAtmosphereMitmSrv, 65000, in,
|
||||
.out_handle_attrs = { SfOutHandleAttr_HipcMove, SfOutHandleAttr_HipcMove },
|
||||
.out_handles = tmp_handles,
|
||||
);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*handle_out = r.Handles[0];
|
||||
*query_out = r.Handles[1];
|
||||
}
|
||||
*handle_out = tmp_handles[0];
|
||||
*query_out = tmp_handles[1];
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result smAtmosphereMitmUninstall(const char *name) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
Service *srv = &g_smMitmSrv;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 service_name;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65001;
|
||||
raw->service_name = smEncodeName(name);
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return _smAtmosphereCmdInServiceNameNoOut(smEncodeName(name), &g_smAtmosphereMitmSrv, 65001);
|
||||
}
|
||||
|
||||
Result smAtmosphereMitmDeclareFuture(const char *name) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
Service *srv = &g_smMitmSrv;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 service_name;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65006;
|
||||
raw->service_name = smEncodeName(name);
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return _smAtmosphereCmdInServiceNameNoOut(smEncodeName(name), &g_smAtmosphereMitmSrv, 65006);
|
||||
}
|
||||
|
||||
Result smAtmosphereMitmAcknowledgeSession(Service *srv_out, u64 *pid_out, u64 *tid_out, const char *name) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
Service *srv = &g_smMitmSrv;
|
||||
|
||||
const u64 in = smEncodeName(name);
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 service_name;
|
||||
} *raw;
|
||||
u64 pid;
|
||||
u64 tid;
|
||||
} out;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65003;
|
||||
raw->service_name = smEncodeName(name);
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
Result rc = serviceDispatchInOut(&g_smAtmosphereMitmSrv, 65003, in, out,
|
||||
.out_num_objects = 1,
|
||||
.out_objects = srv_out,
|
||||
);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 pid;
|
||||
u64 tid;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*pid_out = resp->pid;
|
||||
*tid_out = resp->tid;
|
||||
serviceCreate(srv_out, r.Handles[0]);
|
||||
}
|
||||
if (pid_out) *pid_out = out.pid;
|
||||
if (tid_out) *tid_out = out.tid;
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
#include <switch/types.h>
|
||||
#include <switch/kernel/event.h>
|
||||
#include <switch/services/sm.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -18,6 +20,7 @@ Result smAtmosphereWaitMitm(const char *name);
|
||||
|
||||
Result smAtmosphereMitmInitialize(void);
|
||||
void smAtmosphereMitmExit(void);
|
||||
Service *smAtmosphereMitmGetServiceSession();
|
||||
|
||||
Result smAtmosphereMitmInstall(Handle *handle_out, Handle *query_out, const char *name);
|
||||
Result smAtmosphereMitmUninstall(const char *name);
|
||||
|
||||
@@ -55,4 +55,15 @@ namespace sts::sm {
|
||||
});
|
||||
}
|
||||
|
||||
namespace impl {
|
||||
|
||||
void DoWithSessionImpl(void (*Invoker)(void *), void *Function) {
|
||||
impl::DoWithUserSession([&]() {
|
||||
Invoker(Function);
|
||||
return ResultSuccess;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,117 +13,36 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
#include "smm_ams.h"
|
||||
|
||||
Result smManagerAtmosphereEndInitialDefers(void) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
Service *srv = smManagerGetServiceSession();
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65000;
|
||||
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
return serviceDispatch(smManagerGetServiceSession(), 65000);
|
||||
}
|
||||
|
||||
Result smManagerAtmosphereRegisterProcess(u64 pid, u64 tid, const void *acid_sac, size_t acid_sac_size, const void *aci_sac, size_t aci_sac_size) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddSendBuffer(&c, acid_sac, acid_sac_size, BufferType_Normal);
|
||||
ipcAddSendBuffer(&c, aci_sac, aci_sac_size, BufferType_Normal);
|
||||
Service *srv = smManagerGetServiceSession();
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
const struct {
|
||||
u64 pid;
|
||||
u64 tid;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65002;
|
||||
raw->pid = pid;
|
||||
raw->tid = tid;
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
} in = { pid, tid };
|
||||
return serviceDispatchIn(smManagerGetServiceSession(), 65002, in,
|
||||
.buffer_attrs = {
|
||||
SfBufferAttr_In | SfBufferAttr_HipcMapAlias,
|
||||
SfBufferAttr_In | SfBufferAttr_HipcMapAlias,
|
||||
},
|
||||
.buffers = {
|
||||
{ acid_sac, acid_sac_size },
|
||||
{ aci_sac, aci_sac_size },
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
static Result _smManagerAtmosphereCmdHas(bool *out, u64 service_name, u32 cmd_id) {
|
||||
u8 tmp;
|
||||
Result rc = serviceDispatchInOut(smManagerGetServiceSession(), cmd_id, service_name, tmp);
|
||||
if (R_SUCCEEDED(rc) && out) *out = tmp & 1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result smManagerAtmosphereHasMitm(bool *out, const char* name) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
Service *srv = smManagerGetServiceSession();
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 service_name;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65001;
|
||||
raw->service_name = smEncodeName(name);
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u8 has_mitm;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*out = resp->has_mitm != 0;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
return _smManagerAtmosphereCmdHas(out, smEncodeName(name), 65001);
|
||||
}
|
||||
|
||||
@@ -309,4 +309,59 @@ namespace sts::spl::smc {
|
||||
return static_cast<Result>(args.X[0]);
|
||||
}
|
||||
|
||||
/* Atmosphere functions. */
|
||||
namespace {
|
||||
|
||||
enum class IramCopyDirection {
|
||||
FromIram = 0,
|
||||
ToIram = 1,
|
||||
};
|
||||
|
||||
inline Result AtmosphereIramCopy(uintptr_t dram_address, uintptr_t iram_address, size_t size, IramCopyDirection direction) {
|
||||
SecmonArgs args;
|
||||
args.X[0] = static_cast<u64>(FunctionId::AtmosphereIramCopy);
|
||||
args.X[1] = dram_address;
|
||||
args.X[2] = iram_address;
|
||||
args.X[3] = size;
|
||||
args.X[4] = static_cast<u64>(direction);
|
||||
svcCallSecureMonitor(&args);
|
||||
|
||||
return static_cast<Result>(args.X[0]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Result AtmosphereCopyToIram(uintptr_t iram_dst, const void *dram_src, size_t size) {
|
||||
return AtmosphereIramCopy(reinterpret_cast<uintptr_t>(dram_src), iram_dst, size, IramCopyDirection::ToIram);
|
||||
}
|
||||
|
||||
Result AtmosphereCopyFromIram(void *dram_dst, uintptr_t iram_src, size_t size) {
|
||||
return AtmosphereIramCopy(reinterpret_cast<uintptr_t>(dram_dst), iram_src, size, IramCopyDirection::FromIram);
|
||||
}
|
||||
|
||||
Result AtmosphereReadWriteRegister(uint64_t address, uint32_t mask, uint32_t value, uint32_t *out_value) {
|
||||
SecmonArgs args;
|
||||
args.X[0] = static_cast<u64>(FunctionId::AtmosphereReadWriteRegister);
|
||||
args.X[1] = address;
|
||||
args.X[2] = mask;
|
||||
args.X[3] = value;
|
||||
svcCallSecureMonitor(&args);
|
||||
|
||||
*out_value = static_cast<uint32_t>(args.X[1]);
|
||||
return static_cast<Result>(args.X[0]);
|
||||
}
|
||||
|
||||
Result AtmosphereWriteAddress(void *dst, const void *src, size_t size) {
|
||||
STS_ASSERT(size <= sizeof(u64));
|
||||
|
||||
SecmonArgs args;
|
||||
args.X[0] = static_cast<u64>(FunctionId::AtmosphereWriteAddress);
|
||||
args.X[1] = reinterpret_cast<uintptr_t>(dst);
|
||||
__builtin_memcpy(&args.X[1], src, size);
|
||||
args.X[3] = size;
|
||||
svcCallSecureMonitor(&args);
|
||||
|
||||
return static_cast<Result>(args.X[0]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -346,7 +346,7 @@ namespace sts::updater {
|
||||
}
|
||||
|
||||
/* Only preserve autorcm if on a unit with unpatched rcm bug. */
|
||||
if (HasAutoRcmPreserve(boot_image_update_type) && !IsRcmBugPatched()) {
|
||||
if (HasAutoRcmPreserve(boot_image_update_type) && !ams::IsRcmBugPatched()) {
|
||||
R_TRY(boot0_accessor.PreserveAutoRcm(bct, work, Boot0Partition::BctNormalSub));
|
||||
R_TRY(boot0_accessor.Write(bct, BctSize, Boot0Partition::BctNormalSub));
|
||||
R_TRY(boot0_accessor.PreserveAutoRcm(bct, work, Boot0Partition::BctNormalMain));
|
||||
@@ -407,7 +407,7 @@ namespace sts::updater {
|
||||
R_TRY(boot0_accessor.UpdateEks(bct, work));
|
||||
}
|
||||
/* Only preserve autorcm if on a unit with unpatched rcm bug. */
|
||||
if (HasAutoRcmPreserve(boot_image_update_type) && !IsRcmBugPatched()) {
|
||||
if (HasAutoRcmPreserve(boot_image_update_type) && !ams::IsRcmBugPatched()) {
|
||||
R_TRY(boot0_accessor.PreserveAutoRcm(bct, work, Boot0Partition::BctSafeSub));
|
||||
R_TRY(boot0_accessor.Write(bct, BctSize, Boot0Partition::BctSafeSub));
|
||||
R_TRY(boot0_accessor.PreserveAutoRcm(bct, work, Boot0Partition::BctSafeMain));
|
||||
@@ -522,10 +522,8 @@ namespace sts::updater {
|
||||
}
|
||||
|
||||
/* Get a session to ncm. */
|
||||
DoWithSmSession([&]() {
|
||||
R_ASSERT(ncmInitialize());
|
||||
});
|
||||
ON_SCOPE_EXIT { ncmExit(); };
|
||||
sm::ScopedServiceHolder<ncmInitialize, ncmExit> ncm_holder;
|
||||
R_ASSERT(ncm_holder.GetResult());
|
||||
|
||||
/* Verify normal, verify safe as needed. */
|
||||
if (verification_state.needs_verify_normal) {
|
||||
|
||||
Reference in New Issue
Block a user