Compare commits
13 Commits
1.5.0-prer
...
allow_stan
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51d692dfba | ||
|
|
545ade835d | ||
|
|
be5cd35ef6 | ||
|
|
d30af4763a | ||
|
|
7e110ee8f7 | ||
|
|
ea61ac9ea6 | ||
|
|
95ef9da873 | ||
|
|
d2b024f19f | ||
|
|
9011384dbe | ||
|
|
56669e34b7 | ||
|
|
6df7a87727 | ||
|
|
90473a2307 | ||
|
|
29ffa4b7fd |
2
Makefile
2
Makefile
@@ -112,6 +112,7 @@ dist-no-debug: all
|
|||||||
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000042
|
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000042
|
||||||
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000420
|
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000420
|
||||||
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000B240
|
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000B240
|
||||||
|
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D609
|
||||||
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D623
|
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D623
|
||||||
cp stratosphere/boot2/boot2.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000008/exefs.nsp
|
cp stratosphere/boot2/boot2.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000008/exefs.nsp
|
||||||
cp stratosphere/dmnt/dmnt.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000000D/exefs.nsp
|
cp stratosphere/dmnt/dmnt.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000000D/exefs.nsp
|
||||||
@@ -125,6 +126,7 @@ dist-no-debug: all
|
|||||||
cp stratosphere/pgl/pgl.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000042/exefs.nsp
|
cp stratosphere/pgl/pgl.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000042/exefs.nsp
|
||||||
cp stratosphere/LogManager/LogManager.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000420/exefs.nsp
|
cp stratosphere/LogManager/LogManager.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000420/exefs.nsp
|
||||||
cp stratosphere/htc/htc.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000B240/exefs.nsp
|
cp stratosphere/htc/htc.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000B240/exefs.nsp
|
||||||
|
cp stratosphere/dmnt.gen2/dmnt.gen2.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D609/exefs.nsp
|
||||||
cp stratosphere/TioServer/TioServer.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D623/exefs.nsp
|
cp stratosphere/TioServer/TioServer.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D623/exefs.nsp
|
||||||
@build_romfs atmosphere-$(AMSVER)/stratosphere_romfs atmosphere-$(AMSVER)/atmosphere/stratosphere.romfs
|
@build_romfs atmosphere-$(AMSVER)/stratosphere_romfs atmosphere-$(AMSVER)/atmosphere/stratosphere.romfs
|
||||||
rm -r atmosphere-$(AMSVER)/stratosphere_romfs
|
rm -r atmosphere-$(AMSVER)/stratosphere_romfs
|
||||||
|
|||||||
@@ -40,6 +40,12 @@
|
|||||||
/* of the right side, and so this does not actually cost any space. */
|
/* of the right side, and so this does not actually cost any space. */
|
||||||
#define MESOSPHERE_ENABLE_DEVIRTUALIZED_DYNAMIC_CAST
|
#define MESOSPHERE_ENABLE_DEVIRTUALIZED_DYNAMIC_CAST
|
||||||
|
|
||||||
|
/* NOTE: This enables usage of KDebug handles as parameter for svc::GetInfo */
|
||||||
|
/* calls which require a process parameter. This enables a debugger to obtain */
|
||||||
|
/* address space/layout information, for example. However, it changes abi, and so */
|
||||||
|
/* this define allows toggling the extension. */
|
||||||
|
#define MESOSPHERE_ENABLE_GET_INFO_OF_DEBUG_PROCESS
|
||||||
|
|
||||||
/* NOTE: This uses currently-reserved bits inside the MapRange capability */
|
/* NOTE: This uses currently-reserved bits inside the MapRange capability */
|
||||||
/* in order to support large physical addresses (40-bit instead of 36). */
|
/* in order to support large physical addresses (40-bit instead of 36). */
|
||||||
/* This is toggleable in order to disable it if N ever uses those bits. */
|
/* This is toggleable in order to disable it if N ever uses those bits. */
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace ams::kern {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr std::tuple<KMemoryState, const char *> MemoryStateNames[] = {
|
constexpr const std::pair<KMemoryState, const char *> MemoryStateNames[] = {
|
||||||
{KMemoryState_Free , "----- Free -----"},
|
{KMemoryState_Free , "----- Free -----"},
|
||||||
{KMemoryState_Io , "Io "},
|
{KMemoryState_Io , "Io "},
|
||||||
{KMemoryState_Static , "Static "},
|
{KMemoryState_Static , "Static "},
|
||||||
@@ -41,6 +41,7 @@ namespace ams::kern {
|
|||||||
{KMemoryState_Kernel , "Kernel "},
|
{KMemoryState_Kernel , "Kernel "},
|
||||||
{KMemoryState_GeneratedCode , "GeneratedCode "},
|
{KMemoryState_GeneratedCode , "GeneratedCode "},
|
||||||
{KMemoryState_CodeOut , "CodeOut "},
|
{KMemoryState_CodeOut , "CodeOut "},
|
||||||
|
{KMemoryState_Coverage , "Coverage "},
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr const char *GetMemoryStateName(KMemoryState state) {
|
constexpr const char *GetMemoryStateName(KMemoryState state) {
|
||||||
|
|||||||
@@ -38,6 +38,80 @@ namespace ams::kern::svc {
|
|||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result GetInfoImpl(u64 *out, ams::svc::InfoType info_type, KProcess *process) {
|
||||||
|
switch (info_type) {
|
||||||
|
case ams::svc::InfoType_CoreMask:
|
||||||
|
*out = process->GetCoreMask();
|
||||||
|
break;
|
||||||
|
case ams::svc::InfoType_PriorityMask:
|
||||||
|
*out = process->GetPriorityMask();
|
||||||
|
break;
|
||||||
|
case ams::svc::InfoType_AliasRegionAddress:
|
||||||
|
*out = GetInteger(process->GetPageTable().GetAliasRegionStart());
|
||||||
|
break;
|
||||||
|
case ams::svc::InfoType_AliasRegionSize:
|
||||||
|
*out = process->GetPageTable().GetAliasRegionSize();
|
||||||
|
break;
|
||||||
|
case ams::svc::InfoType_HeapRegionAddress:
|
||||||
|
*out = GetInteger(process->GetPageTable().GetHeapRegionStart());
|
||||||
|
break;
|
||||||
|
case ams::svc::InfoType_HeapRegionSize:
|
||||||
|
*out = process->GetPageTable().GetHeapRegionSize();
|
||||||
|
break;
|
||||||
|
case ams::svc::InfoType_TotalMemorySize:
|
||||||
|
*out = process->GetTotalUserPhysicalMemorySize();
|
||||||
|
break;
|
||||||
|
case ams::svc::InfoType_UsedMemorySize:
|
||||||
|
*out = process->GetUsedUserPhysicalMemorySize();
|
||||||
|
break;
|
||||||
|
case ams::svc::InfoType_AslrRegionAddress:
|
||||||
|
*out = GetInteger(process->GetPageTable().GetAliasCodeRegionStart());
|
||||||
|
break;
|
||||||
|
case ams::svc::InfoType_AslrRegionSize:
|
||||||
|
*out = process->GetPageTable().GetAliasCodeRegionSize();
|
||||||
|
break;
|
||||||
|
case ams::svc::InfoType_StackRegionAddress:
|
||||||
|
*out = GetInteger(process->GetPageTable().GetStackRegionStart());
|
||||||
|
break;
|
||||||
|
case ams::svc::InfoType_StackRegionSize:
|
||||||
|
*out = process->GetPageTable().GetStackRegionSize();
|
||||||
|
break;
|
||||||
|
case ams::svc::InfoType_SystemResourceSizeTotal:
|
||||||
|
*out = process->GetTotalSystemResourceSize();
|
||||||
|
break;
|
||||||
|
case ams::svc::InfoType_SystemResourceSizeUsed:
|
||||||
|
*out = process->GetUsedSystemResourceSize();
|
||||||
|
break;
|
||||||
|
case ams::svc::InfoType_ProgramId:
|
||||||
|
*out = process->GetProgramId();
|
||||||
|
break;
|
||||||
|
case ams::svc::InfoType_UserExceptionContextAddress:
|
||||||
|
*out = GetInteger(process->GetProcessLocalRegionAddress());
|
||||||
|
break;
|
||||||
|
case ams::svc::InfoType_TotalNonSystemMemorySize:
|
||||||
|
*out = process->GetTotalNonSystemUserPhysicalMemorySize();
|
||||||
|
break;
|
||||||
|
case ams::svc::InfoType_UsedNonSystemMemorySize:
|
||||||
|
*out = process->GetUsedNonSystemUserPhysicalMemorySize();
|
||||||
|
break;
|
||||||
|
case ams::svc::InfoType_IsApplication:
|
||||||
|
*out = process->IsApplication();
|
||||||
|
break;
|
||||||
|
case ams::svc::InfoType_FreeThreadCount:
|
||||||
|
if (KResourceLimit *resource_limit = process->GetResourceLimit(); resource_limit != nullptr) {
|
||||||
|
const auto current_value = resource_limit->GetCurrentValue(ams::svc::LimitableResource_ThreadCountMax);
|
||||||
|
const auto limit_value = resource_limit->GetLimitValue(ams::svc::LimitableResource_ThreadCountMax);
|
||||||
|
*out = limit_value - current_value;
|
||||||
|
} else {
|
||||||
|
*out = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
Result GetInfo(u64 *out, ams::svc::InfoType info_type, ams::svc::Handle handle, u64 info_subtype) {
|
Result GetInfo(u64 *out, ams::svc::InfoType info_type, ams::svc::Handle handle, u64 info_subtype) {
|
||||||
switch (info_type) {
|
switch (info_type) {
|
||||||
case ams::svc::InfoType_CoreMask:
|
case ams::svc::InfoType_CoreMask:
|
||||||
@@ -66,77 +140,34 @@ namespace ams::kern::svc {
|
|||||||
|
|
||||||
/* Get the process from its handle. */
|
/* Get the process from its handle. */
|
||||||
KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(handle);
|
KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(handle);
|
||||||
|
|
||||||
|
#if defined(MESOSPHERE_ENABLE_GET_INFO_OF_DEBUG_PROCESS)
|
||||||
|
/* If we the process is valid, use it. */
|
||||||
|
if (process.IsNotNull()) {
|
||||||
|
return GetInfoImpl(out, info_type, process.GetPointerUnsafe());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, as a mesosphere extension check if we were passed a usable KDebug. */
|
||||||
|
KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(handle);
|
||||||
|
R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle());
|
||||||
|
|
||||||
|
/* Get the process from the debug object. */
|
||||||
|
/* TODO: ResultInvalidHandle()? */
|
||||||
|
R_UNLESS(debug->IsAttached(), svc::ResultProcessTerminated());
|
||||||
|
R_UNLESS(debug->OpenProcess(), svc::ResultProcessTerminated());
|
||||||
|
|
||||||
|
/* Close the process when we're done. */
|
||||||
|
ON_SCOPE_EXIT { debug->CloseProcess(); };
|
||||||
|
|
||||||
|
/* Return the info. */
|
||||||
|
return GetInfoImpl(out, info_type, debug->GetProcessUnsafe());
|
||||||
|
#else
|
||||||
|
/* Verify that the process is valid. */
|
||||||
R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle());
|
R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle());
|
||||||
|
|
||||||
switch (info_type) {
|
/* Return the relevant info. */
|
||||||
case ams::svc::InfoType_CoreMask:
|
return GetInfoImpl(out, info_type, process.GetPointerUnsafe());
|
||||||
*out = process->GetCoreMask();
|
#endif
|
||||||
break;
|
|
||||||
case ams::svc::InfoType_PriorityMask:
|
|
||||||
*out = process->GetPriorityMask();
|
|
||||||
break;
|
|
||||||
case ams::svc::InfoType_AliasRegionAddress:
|
|
||||||
*out = GetInteger(process->GetPageTable().GetAliasRegionStart());
|
|
||||||
break;
|
|
||||||
case ams::svc::InfoType_AliasRegionSize:
|
|
||||||
*out = process->GetPageTable().GetAliasRegionSize();
|
|
||||||
break;
|
|
||||||
case ams::svc::InfoType_HeapRegionAddress:
|
|
||||||
*out = GetInteger(process->GetPageTable().GetHeapRegionStart());
|
|
||||||
break;
|
|
||||||
case ams::svc::InfoType_HeapRegionSize:
|
|
||||||
*out = process->GetPageTable().GetHeapRegionSize();
|
|
||||||
break;
|
|
||||||
case ams::svc::InfoType_TotalMemorySize:
|
|
||||||
*out = process->GetTotalUserPhysicalMemorySize();
|
|
||||||
break;
|
|
||||||
case ams::svc::InfoType_UsedMemorySize:
|
|
||||||
*out = process->GetUsedUserPhysicalMemorySize();
|
|
||||||
break;
|
|
||||||
case ams::svc::InfoType_AslrRegionAddress:
|
|
||||||
*out = GetInteger(process->GetPageTable().GetAliasCodeRegionStart());
|
|
||||||
break;
|
|
||||||
case ams::svc::InfoType_AslrRegionSize:
|
|
||||||
*out = process->GetPageTable().GetAliasCodeRegionSize();
|
|
||||||
break;
|
|
||||||
case ams::svc::InfoType_StackRegionAddress:
|
|
||||||
*out = GetInteger(process->GetPageTable().GetStackRegionStart());
|
|
||||||
break;
|
|
||||||
case ams::svc::InfoType_StackRegionSize:
|
|
||||||
*out = process->GetPageTable().GetStackRegionSize();
|
|
||||||
break;
|
|
||||||
case ams::svc::InfoType_SystemResourceSizeTotal:
|
|
||||||
*out = process->GetTotalSystemResourceSize();
|
|
||||||
break;
|
|
||||||
case ams::svc::InfoType_SystemResourceSizeUsed:
|
|
||||||
*out = process->GetUsedSystemResourceSize();
|
|
||||||
break;
|
|
||||||
case ams::svc::InfoType_ProgramId:
|
|
||||||
*out = process->GetProgramId();
|
|
||||||
break;
|
|
||||||
case ams::svc::InfoType_UserExceptionContextAddress:
|
|
||||||
*out = GetInteger(process->GetProcessLocalRegionAddress());
|
|
||||||
break;
|
|
||||||
case ams::svc::InfoType_TotalNonSystemMemorySize:
|
|
||||||
*out = process->GetTotalNonSystemUserPhysicalMemorySize();
|
|
||||||
break;
|
|
||||||
case ams::svc::InfoType_UsedNonSystemMemorySize:
|
|
||||||
*out = process->GetUsedNonSystemUserPhysicalMemorySize();
|
|
||||||
break;
|
|
||||||
case ams::svc::InfoType_IsApplication:
|
|
||||||
*out = process->IsApplication();
|
|
||||||
break;
|
|
||||||
case ams::svc::InfoType_FreeThreadCount:
|
|
||||||
if (KResourceLimit *resource_limit = process->GetResourceLimit(); resource_limit != nullptr) {
|
|
||||||
const auto current_value = resource_limit->GetCurrentValue(ams::svc::LimitableResource_ThreadCountMax);
|
|
||||||
const auto limit_value = resource_limit->GetLimitValue(ams::svc::LimitableResource_ThreadCountMax);
|
|
||||||
*out = limit_value - current_value;
|
|
||||||
} else {
|
|
||||||
*out = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ams::svc::InfoType_DebuggerAttached:
|
case ams::svc::InfoType_DebuggerAttached:
|
||||||
|
|||||||
@@ -118,12 +118,12 @@ namespace ams::fssystem {
|
|||||||
|
|
||||||
/* Copy API. */
|
/* Copy API. */
|
||||||
Result CopyFile(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size);
|
Result CopyFile(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size);
|
||||||
NX_INLINE Result CopyFile(fs::fsa::IFileSystem *fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size) {
|
ALWAYS_INLINE Result CopyFile(fs::fsa::IFileSystem *fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size) {
|
||||||
return CopyFile(fs, fs, dst_parent_path, src_path, dir_ent, work_buf, work_buf_size);
|
return CopyFile(fs, fs, dst_parent_path, src_path, dir_ent, work_buf, work_buf_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result CopyDirectoryRecursively(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const char *dst_path, const char *src_path, void *work_buf, size_t work_buf_size);
|
Result CopyDirectoryRecursively(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const char *dst_path, const char *src_path, void *work_buf, size_t work_buf_size);
|
||||||
NX_INLINE Result CopyDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *dst_path, const char *src_path, void *work_buf, size_t work_buf_size) {
|
ALWAYS_INLINE Result CopyDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *dst_path, const char *src_path, void *work_buf, size_t work_buf_size) {
|
||||||
return CopyDirectoryRecursively(fs, fs, dst_path, src_path, work_buf, work_buf_size);
|
return CopyDirectoryRecursively(fs, fs, dst_path, src_path, work_buf, work_buf_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,11 +148,11 @@ namespace ams::fssystem {
|
|||||||
Result EnsureDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path);
|
Result EnsureDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path);
|
||||||
Result EnsureParentDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path);
|
Result EnsureParentDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path);
|
||||||
|
|
||||||
template<typename F>
|
template<s64 RetryMilliSeconds = 100>
|
||||||
NX_INLINE Result RetryFinitelyForTargetLocked(F f) {
|
ALWAYS_INLINE Result RetryFinitelyForTargetLocked(auto f) {
|
||||||
/* Retry up to 10 times, 100ms between retries. */
|
/* Retry up to 10 times, 100ms between retries. */
|
||||||
constexpr s32 MaxRetryCount = 10;
|
constexpr s32 MaxRetryCount = 10;
|
||||||
constexpr TimeSpan RetryWaitTime = TimeSpan::FromMilliSeconds(100);
|
constexpr TimeSpan RetryWaitTime = TimeSpan::FromMilliSeconds(RetryMilliSeconds);
|
||||||
|
|
||||||
s32 remaining_retries = MaxRetryCount;
|
s32 remaining_retries = MaxRetryCount;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ namespace ams::socket {
|
|||||||
|
|
||||||
s32 Shutdown(s32 desc, ShutdownMethod how);
|
s32 Shutdown(s32 desc, ShutdownMethod how);
|
||||||
|
|
||||||
|
s32 Socket(Family domain, Type type, Protocol protocol);
|
||||||
s32 SocketExempt(Family domain, Type type, Protocol protocol);
|
s32 SocketExempt(Family domain, Type type, Protocol protocol);
|
||||||
|
|
||||||
s32 Accept(s32 desc, SockAddr *out_address, SockLenT *out_addr_len);
|
s32 Accept(s32 desc, SockAddr *out_address, SockLenT *out_addr_len);
|
||||||
|
|||||||
@@ -57,4 +57,42 @@ namespace ams::socket {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SystemConfigLightDefault : public Config {
|
||||||
|
public:
|
||||||
|
static constexpr size_t DefaultTcpInitialSendBufferSize = 16_KB;
|
||||||
|
static constexpr size_t DefaultTcpInitialReceiveBufferSize = 16_KB;
|
||||||
|
static constexpr size_t DefaultTcpAutoSendBufferSizeMax = 0_KB;
|
||||||
|
static constexpr size_t DefaultTcpAutoReceiveBufferSizeMax = 0_KB;
|
||||||
|
static constexpr size_t DefaultUdpSendBufferSize = 9_KB;
|
||||||
|
static constexpr size_t DefaultUdpReceiveBufferSize = 42240;
|
||||||
|
static constexpr auto DefaultSocketBufferEfficiency = 2;
|
||||||
|
static constexpr auto DefaultConcurrency = 2;
|
||||||
|
static constexpr size_t DefaultAllocatorPoolSize = 64_KB;
|
||||||
|
|
||||||
|
static constexpr size_t PerTcpSocketWorstCaseMemoryPoolSize = [] {
|
||||||
|
constexpr size_t WorstCaseTcpSendBufferSize = AlignMss(std::max(DefaultTcpInitialSendBufferSize, DefaultTcpAutoSendBufferSizeMax));
|
||||||
|
constexpr size_t WorstCaseTcpReceiveBufferSize = AlignMss(std::max(DefaultTcpInitialReceiveBufferSize, DefaultTcpAutoReceiveBufferSizeMax));
|
||||||
|
|
||||||
|
return util::AlignUp(WorstCaseTcpSendBufferSize * DefaultSocketBufferEfficiency + WorstCaseTcpReceiveBufferSize * DefaultSocketBufferEfficiency, os::MemoryPageSize);
|
||||||
|
}();
|
||||||
|
|
||||||
|
static constexpr size_t PerUdpSocketWorstCaseMemoryPoolSize = [] {
|
||||||
|
constexpr size_t WorstCaseUdpSendBufferSize = AlignMss(DefaultUdpSendBufferSize);
|
||||||
|
constexpr size_t WorstCaseUdpReceiveBufferSize = AlignMss(DefaultUdpReceiveBufferSize);
|
||||||
|
|
||||||
|
return util::AlignUp(WorstCaseUdpSendBufferSize * DefaultSocketBufferEfficiency + WorstCaseUdpReceiveBufferSize * DefaultSocketBufferEfficiency, os::MemoryPageSize);
|
||||||
|
}();
|
||||||
|
public:
|
||||||
|
constexpr SystemConfigLightDefault(void *mp, size_t mp_sz, size_t ap, int c=DefaultConcurrency)
|
||||||
|
: Config(mp, mp_sz, ap,
|
||||||
|
DefaultTcpInitialSendBufferSize, DefaultTcpInitialReceiveBufferSize,
|
||||||
|
DefaultTcpAutoSendBufferSizeMax, DefaultTcpAutoReceiveBufferSizeMax,
|
||||||
|
DefaultUdpSendBufferSize, DefaultUdpReceiveBufferSize,
|
||||||
|
DefaultSocketBufferEfficiency, c)
|
||||||
|
{
|
||||||
|
/* Mark as system. */
|
||||||
|
m_system = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -188,6 +188,12 @@ namespace ams::boot2 {
|
|||||||
return enable_htc != 0;
|
return enable_htc != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsStandaloneGdbstubEnabled() {
|
||||||
|
u8 enable_gdbstub = 0;
|
||||||
|
settings::fwdbg::GetSettingsItemValue(std::addressof(enable_gdbstub), sizeof(enable_gdbstub), "atmosphere", "enable_standalone_gdbstub");
|
||||||
|
return enable_gdbstub != 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsAtmosphereLogManagerEnabled() {
|
bool IsAtmosphereLogManagerEnabled() {
|
||||||
/* If htc is enabled, ams log manager is enabled. */
|
/* If htc is enabled, ams log manager is enabled. */
|
||||||
if (IsHtcEnabled()) {
|
if (IsHtcEnabled()) {
|
||||||
@@ -403,6 +409,9 @@ namespace ams::boot2 {
|
|||||||
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Htc, ncm::StorageId::None), 0);
|
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Htc, ncm::StorageId::None), 0);
|
||||||
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Cs, ncm::StorageId::None), 0);
|
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Cs, ncm::StorageId::None), 0);
|
||||||
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::DmntGen2, ncm::StorageId::None), 0);
|
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::DmntGen2, ncm::StorageId::None), 0);
|
||||||
|
} else if (IsStandaloneGdbstubEnabled()) {
|
||||||
|
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::DmntGen2, ncm::StorageId::None), 0);
|
||||||
|
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Tma, ncm::StorageId::BuiltInSystem), 0);
|
||||||
} else {
|
} else {
|
||||||
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Dmnt, ncm::StorageId::None), 0);
|
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Dmnt, ncm::StorageId::None), 0);
|
||||||
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Tma, ncm::StorageId::BuiltInSystem), 0);
|
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Tma, ncm::StorageId::BuiltInSystem), 0);
|
||||||
|
|||||||
@@ -52,6 +52,26 @@ namespace ams::os::impl {
|
|||||||
/* Get the thread impl object from libnx. */
|
/* Get the thread impl object from libnx. */
|
||||||
ThreadImpl *thread_impl = ::threadGetSelf();
|
ThreadImpl *thread_impl = ::threadGetSelf();
|
||||||
|
|
||||||
|
/* Hack around libnx's main thread, to ensure stratosphere thread type consistency. */
|
||||||
|
{
|
||||||
|
auto *tlr = reinterpret_cast<uintptr_t *>(svc::GetThreadLocalRegion());
|
||||||
|
for (size_t i = sizeof(svc::ThreadLocalRegion) / sizeof(uintptr_t); i > 0; --i) {
|
||||||
|
if (auto *candidate = reinterpret_cast<ThreadImpl *>(tlr[i - 1]); candidate == thread_impl) {
|
||||||
|
ThreadImpl *embedded_thread = std::addressof(main_thread->thread_impl_storage);
|
||||||
|
|
||||||
|
*embedded_thread = *thread_impl;
|
||||||
|
|
||||||
|
if (embedded_thread->next) {
|
||||||
|
embedded_thread->next->prev_next = std::addressof(embedded_thread->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_impl = embedded_thread;
|
||||||
|
tlr[i-1] = reinterpret_cast<uintptr_t>(thread_impl);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Get the thread priority. */
|
/* Get the thread priority. */
|
||||||
s32 horizon_priority;
|
s32 horizon_priority;
|
||||||
R_ABORT_UNLESS(svc::GetThreadPriority(std::addressof(horizon_priority), thread_impl->handle));
|
R_ABORT_UNLESS(svc::GetThreadPriority(std::addressof(horizon_priority), thread_impl->handle));
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ namespace ams::osdbg::impl {
|
|||||||
static_assert(AMS_OFFSETOF(ThreadLocalRegionIlp32, tls) == 0x1C0);
|
static_assert(AMS_OFFSETOF(ThreadLocalRegionIlp32, tls) == 0x1C0);
|
||||||
|
|
||||||
struct LibnxThreadVars {
|
struct LibnxThreadVars {
|
||||||
static constexpr u32 Magic = util::FourCC<'!','T','V','$'>::Code;
|
static constexpr u32 Magic = util::ReverseFourCC<'!','T','V','$'>::Code;
|
||||||
|
|
||||||
u32 magic;
|
u32 magic;
|
||||||
::Handle handle;
|
::Handle handle;
|
||||||
@@ -69,11 +69,11 @@ namespace ams::osdbg::impl {
|
|||||||
volatile u16 disable_counter;
|
volatile u16 disable_counter;
|
||||||
volatile u16 interrupt_flag;
|
volatile u16 interrupt_flag;
|
||||||
u32 reserved0;
|
u32 reserved0;
|
||||||
u64 tls[(0x1E0 - 0x108) / sizeof(u64)];
|
u64 tls[(0x200 - sizeof(LibnxThreadVars) - 0x108) / sizeof(u64)];
|
||||||
LibnxThreadVars thread_vars;
|
LibnxThreadVars thread_vars;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(ThreadLocalRegionLibnx) == sizeof(svc::ThreadLocalRegion));
|
static_assert(sizeof(ThreadLocalRegionLibnx) == sizeof(svc::ThreadLocalRegion));
|
||||||
static_assert(AMS_OFFSETOF(ThreadLocalRegionLibnx, thread_vars) == 0x1E0);
|
static_assert(AMS_OFFSETOF(ThreadLocalRegionLibnx, thread_vars) == 0x200 - sizeof(LibnxThreadVars));
|
||||||
|
|
||||||
struct LibnxThreadEntryArgs {
|
struct LibnxThreadEntryArgs {
|
||||||
u64 t;
|
u64 t;
|
||||||
|
|||||||
@@ -50,9 +50,9 @@ namespace ams::osdbg {
|
|||||||
} else {
|
} else {
|
||||||
/* Special-case libnx threads. */
|
/* Special-case libnx threads. */
|
||||||
if (thread_info->_thread_type_type == ThreadTypeType_Libnx) {
|
if (thread_info->_thread_type_type == ThreadTypeType_Libnx) {
|
||||||
util::TSNPrintf(dst, os::ThreadNameLengthMax, "libnx Thread_0x%p", reinterpret_cast<void *>(thread_info->_thread_type));
|
util::TSNPrintf(dst, os::ThreadNameLengthMax, "libnx Thread_0x%010lx", reinterpret_cast<uintptr_t>(thread_info->_thread_type));
|
||||||
} else {
|
} else {
|
||||||
util::TSNPrintf(dst, os::ThreadNameLengthMax, "Thread_0x%p", reinterpret_cast<void *>(thread_info->_thread_type));
|
util::TSNPrintf(dst, os::ThreadNameLengthMax, "Thread_0x%010lx", reinterpret_cast<uintptr_t>(thread_info->_thread_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ namespace ams::socket::impl {
|
|||||||
|
|
||||||
s32 Shutdown(s32 desc, ShutdownMethod how);
|
s32 Shutdown(s32 desc, ShutdownMethod how);
|
||||||
|
|
||||||
|
s32 Socket(Family domain, Type type, Protocol protocol);
|
||||||
s32 SocketExempt(Family domain, Type type, Protocol protocol);
|
s32 SocketExempt(Family domain, Type type, Protocol protocol);
|
||||||
|
|
||||||
s32 Accept(s32 desc, SockAddr *out_address, SockLenT *out_addr_len);
|
s32 Accept(s32 desc, SockAddr *out_address, SockLenT *out_addr_len);
|
||||||
|
|||||||
@@ -206,6 +206,8 @@ namespace ams::socket::impl {
|
|||||||
|
|
||||||
/* TODO: socket::resolver::EnableResolverCalls()? Not necessary in our case (htc), but consider calling it. */
|
/* TODO: socket::resolver::EnableResolverCalls()? Not necessary in our case (htc), but consider calling it. */
|
||||||
|
|
||||||
|
g_initialized = true;
|
||||||
|
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -422,6 +424,22 @@ namespace ams::socket::impl {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s32 Socket(Family domain, Type type, Protocol protocol) {
|
||||||
|
/* Check pre-conditions. */
|
||||||
|
AMS_ABORT_UNLESS(IsInitialized());
|
||||||
|
|
||||||
|
/* Perform the call. */
|
||||||
|
Errno error = Errno::ESuccess;
|
||||||
|
int result = ::bsdSocket(static_cast<int>(domain), static_cast<int>(type), static_cast<int>(protocol));
|
||||||
|
TranslateResultToBsdError(error, result);
|
||||||
|
|
||||||
|
if (result < 0) {
|
||||||
|
socket::impl::SetLastError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
s32 SocketExempt(Family domain, Type type, Protocol protocol) {
|
s32 SocketExempt(Family domain, Type type, Protocol protocol) {
|
||||||
/* Check pre-conditions. */
|
/* Check pre-conditions. */
|
||||||
AMS_ABORT_UNLESS(IsInitialized());
|
AMS_ABORT_UNLESS(IsInitialized());
|
||||||
|
|||||||
@@ -74,6 +74,10 @@ namespace ams::socket {
|
|||||||
return impl::Shutdown(desc, how);
|
return impl::Shutdown(desc, how);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s32 Socket(Family domain, Type type, Protocol protocol) {
|
||||||
|
return impl::Socket(domain, type, protocol);
|
||||||
|
}
|
||||||
|
|
||||||
s32 SocketExempt(Family domain, Type type, Protocol protocol) {
|
s32 SocketExempt(Family domain, Type type, Protocol protocol) {
|
||||||
return impl::SocketExempt(domain, type, protocol);
|
return impl::SocketExempt(domain, type, protocol);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -378,6 +378,12 @@ namespace ams::settings::fwdbg {
|
|||||||
/* 0 = Disabled, 1 = Enabled */
|
/* 0 = Disabled, 1 = Enabled */
|
||||||
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "enable_htc", "u8!0x0"));
|
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "enable_htc", "u8!0x0"));
|
||||||
|
|
||||||
|
/* Controls whether atmosphere's dmnt.gen2 gdbstub should run as a standalone via sockets. */
|
||||||
|
/* Note that this setting is ignored (and treated as 0) when htc is enabled. */
|
||||||
|
/* Note that this setting may disappear in the future. */
|
||||||
|
/* 0 = Disabled, 1 = Enabled */
|
||||||
|
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "enable_standalone_gdbstub", "u8!0x0"));
|
||||||
|
|
||||||
/* Controls whether atmosphere's log manager is enabled. */
|
/* Controls whether atmosphere's log manager is enabled. */
|
||||||
/* Note that this setting is ignored (and treated as 1) when htc is enabled. */
|
/* Note that this setting is ignored (and treated as 1) when htc is enabled. */
|
||||||
/* 0 = Disabled, 1 = Enabled */
|
/* 0 = Disabled, 1 = Enabled */
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace ams::creport {
|
|||||||
|
|
||||||
struct ModulePath {
|
struct ModulePath {
|
||||||
u32 zero;
|
u32 zero;
|
||||||
u32 path_length;
|
s32 path_length;
|
||||||
char path[ModulePathLengthMax];
|
char path[ModulePathLengthMax];
|
||||||
};
|
};
|
||||||
static_assert(sizeof(ModulePath) == 0x208, "ModulePath definition!");
|
static_assert(sizeof(ModulePath) == 0x208, "ModulePath definition!");
|
||||||
@@ -210,7 +210,7 @@ namespace ams::creport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Also validate that we're looking at a valid name. */
|
/* Also validate that we're looking at a valid name. */
|
||||||
if (rodata_start.module_path.zero != 0 || rodata_start.module_path.path_length != strnlen(rodata_start.module_path.path, sizeof(rodata_start.module_path.path))) {
|
if (rodata_start.module_path.zero != 0 || rodata_start.module_path.path_length <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -219,7 +219,7 @@ namespace ams::creport {
|
|||||||
/* Start after last slash in path. */
|
/* Start after last slash in path. */
|
||||||
const char *path = rodata_start.module_path.path;
|
const char *path = rodata_start.module_path.path;
|
||||||
int ofs;
|
int ofs;
|
||||||
for (ofs = rodata_start.module_path.path_length; ofs >= 0; ofs--) {
|
for (ofs = std::min<size_t>(rodata_start.module_path.path_length, sizeof(rodata_start.module_path.path)); ofs >= 0; ofs--) {
|
||||||
if (path[ofs] == '/' || path[ofs] == '\\') {
|
if (path[ofs] == '/' || path[ofs] == '\\') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -227,8 +227,8 @@ namespace ams::creport {
|
|||||||
ofs++;
|
ofs++;
|
||||||
|
|
||||||
/* Copy name to output. */
|
/* Copy name to output. */
|
||||||
const size_t name_size = std::min(ModuleNameLengthMax, sizeof(rodata_start.module_path.path) - ofs);
|
const size_t name_size = std::min(ModuleNameLengthMax, std::min<size_t>(rodata_start.module_path.path_length, sizeof(rodata_start.module_path.path)) - ofs);
|
||||||
std::strncpy(out_name, path + ofs, name_size);
|
std::memcpy(out_name, path + ofs, name_size);
|
||||||
out_name[ModuleNameLengthMax - 1] = '\x00';
|
out_name[ModuleNameLengthMax - 1] = '\x00';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
"filesystem_access": {
|
"filesystem_access": {
|
||||||
"permissions": "0xFFFFFFFFFFFFFFFF"
|
"permissions": "0xFFFFFFFFFFFFFFFF"
|
||||||
},
|
},
|
||||||
"service_access": ["pm:dmnt", "ldr:dmnt", "ro:dmnt", "ns:dev", "lr", "fsp-srv", "fatal:u", "pgl", "htcs"],
|
"service_access": ["pm:dmnt", "ldr:dmnt", "ro:dmnt", "ns:dev", "lr", "fsp-srv", "fatal:u", "pgl", "htcs", "bsd:s", "set:sys"],
|
||||||
"service_host": [],
|
"service_host": [],
|
||||||
"kernel_capabilities": [{
|
"kernel_capabilities": [{
|
||||||
"type": "kernel_flags",
|
"type": "kernel_flags",
|
||||||
|
|||||||
@@ -16,7 +16,8 @@
|
|||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "dmnt2_debug_log.hpp"
|
#include "dmnt2_debug_log.hpp"
|
||||||
|
|
||||||
#define AMS_DMNT2_ENABLE_HTCS_DEBUG_LOG
|
// TODO: This should be converted to use log manager. */
|
||||||
|
//#define AMS_DMNT2_ENABLE_HTCS_DEBUG_LOG
|
||||||
|
|
||||||
#if defined(AMS_DMNT2_ENABLE_HTCS_DEBUG_LOG)
|
#if defined(AMS_DMNT2_ENABLE_HTCS_DEBUG_LOG)
|
||||||
|
|
||||||
@@ -164,15 +165,78 @@ namespace ams::dmnt {
|
|||||||
|
|
||||||
namespace ams::dmnt {
|
namespace ams::dmnt {
|
||||||
|
|
||||||
|
//#define AMS_DMNT2_ENABLE_SD_CARD_DEBUG_LOG
|
||||||
|
|
||||||
|
#if defined(AMS_DMNT2_ENABLE_SD_CARD_DEBUG_LOG)
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
alignas(0x40) constinit u8 g_buffer[os::MemoryPageSize * 4];
|
||||||
|
constinit lmem::HeapHandle g_debug_log_heap;
|
||||||
|
constinit fs::FileHandle g_debug_log_file;
|
||||||
|
|
||||||
|
constinit os::SdkMutex g_fs_mutex;
|
||||||
|
constinit s64 g_fs_offset = 0;
|
||||||
|
|
||||||
|
void *Allocate(size_t size) {
|
||||||
|
return lmem::AllocateFromExpHeap(g_debug_log_heap, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Deallocate(void *p, size_t size) {
|
||||||
|
AMS_UNUSED(size);
|
||||||
|
return lmem::FreeToExpHeap(g_debug_log_heap, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void InitializeDebugLog() {
|
void InitializeDebugLog() {
|
||||||
/* Do nothing. */
|
g_debug_log_heap = lmem::CreateExpHeap(g_buffer, sizeof(g_buffer), lmem::CreateOption_ThreadSafe);
|
||||||
|
|
||||||
|
fs::SetAllocator(Allocate, Deallocate);
|
||||||
|
fs::InitializeForSystem();
|
||||||
|
fs::SetEnabledAutoAbort(false);
|
||||||
|
|
||||||
|
R_ABORT_UNLESS(fs::MountSdCard("sdmc"));
|
||||||
|
|
||||||
|
fs::DeleteFile("sdmc:/dmnt2.log");
|
||||||
|
R_ABORT_UNLESS(fs::CreateFile("sdmc:/dmnt2.log", 0));
|
||||||
|
R_ABORT_UNLESS(fs::OpenFile(std::addressof(g_debug_log_file), "sdmc:/dmnt2.log", fs::OpenMode_Write | fs::OpenMode_AllowAppend));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugLog(const char *prefix, const char *fmt, ...) {
|
void DebugLog(const char *prefix, const char *fmt, ...) {
|
||||||
/* Do nothing. */
|
/* Do nothing. */
|
||||||
|
char buffer[0x200];
|
||||||
|
{
|
||||||
|
const auto prefix_len = std::strlen(prefix);
|
||||||
|
std::memcpy(buffer, prefix, prefix_len);
|
||||||
|
|
||||||
|
std::va_list vl;
|
||||||
|
va_start(vl, fmt);
|
||||||
|
util::VSNPrintf(buffer + prefix_len, sizeof(buffer) - prefix_len, fmt, vl);
|
||||||
|
va_end(vl);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto len = std::strlen(buffer);
|
||||||
|
|
||||||
|
std::scoped_lock lk(g_fs_mutex);
|
||||||
|
R_ABORT_UNLESS(fs::WriteFile(g_debug_log_file, g_fs_offset, buffer, len, fs::WriteOption::Flush));
|
||||||
|
g_fs_offset += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
void InitializeDebugLog() {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugLog(const char *prefix, const char *fmt, ...) {
|
||||||
|
AMS_UNUSED(prefix, fmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -27,10 +27,15 @@ namespace ams::dmnt {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DebugProcess::Attach(os::ProcessId process_id) {
|
Result DebugProcess::Attach(os::ProcessId process_id, bool start_process) {
|
||||||
/* Attach to the process. */
|
/* Attach to the process. */
|
||||||
R_TRY(svc::DebugActiveProcess(std::addressof(m_debug_handle), process_id.value));
|
R_TRY(svc::DebugActiveProcess(std::addressof(m_debug_handle), process_id.value));
|
||||||
|
|
||||||
|
/* If necessary, start the process. */
|
||||||
|
if (start_process) {
|
||||||
|
R_ABORT_UNLESS(pm::dmnt::StartProcess(process_id));
|
||||||
|
}
|
||||||
|
|
||||||
/* Collect initial information. */
|
/* Collect initial information. */
|
||||||
R_TRY(this->Start());
|
R_TRY(this->Start());
|
||||||
|
|
||||||
@@ -42,6 +47,10 @@ namespace ams::dmnt {
|
|||||||
svc::GetProcessId(std::addressof(pid_value), m_debug_handle);
|
svc::GetProcessId(std::addressof(pid_value), m_debug_handle);
|
||||||
|
|
||||||
m_process_id = { pid_value };
|
m_process_id = { pid_value };
|
||||||
|
|
||||||
|
/* Get process info. */
|
||||||
|
this->CollectProcessInfo();
|
||||||
|
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,13 +196,25 @@ namespace ams::dmnt {
|
|||||||
char path[ModuleDefinition::PathLengthMax];
|
char path[ModuleDefinition::PathLengthMax];
|
||||||
} module_path;
|
} module_path;
|
||||||
if (R_SUCCEEDED(this->ReadMemory(std::addressof(module_path), memory_info.base_address + memory_info.size, sizeof(module_path)))) {
|
if (R_SUCCEEDED(this->ReadMemory(std::addressof(module_path), memory_info.base_address + memory_info.size, sizeof(module_path)))) {
|
||||||
if (module_path.zero == 0 && module_path.path_length == util::Strnlen(module_path.path, sizeof(module_path.path))) {
|
if (module_path.zero == 0 && module_path.path_length > 0) {
|
||||||
std::memcpy(module_name, module_path.path, ModuleDefinition::PathLengthMax);
|
std::memcpy(module_name, module_path.path, std::min<size_t>(ModuleDefinition::PathLengthMax, module_path.path_length));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
module_path.path_length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Truncate module name. */
|
/* Truncate module name. */
|
||||||
module_name[ModuleDefinition::PathLengthMax - 1] = 0;
|
module_name[ModuleDefinition::PathLengthMax - 1] = 0;
|
||||||
|
|
||||||
|
/* Set default module name start. */
|
||||||
|
module.SetNameStart(0);
|
||||||
|
|
||||||
|
/* Ignore leading directories. */
|
||||||
|
for (size_t i = 0; i < std::min<size_t>(ModuleDefinition::PathLengthMax, module_path.path_length) && module_name[i] != 0; ++i) {
|
||||||
|
if (module_name[i] == '/' || module_name[i] == '\\') {
|
||||||
|
module.SetNameStart(i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,6 +233,53 @@ namespace ams::dmnt {
|
|||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DebugProcess::CollectProcessInfo() {
|
||||||
|
/* Define helper for getting process info. */
|
||||||
|
auto CollectProcessInfoImpl = [&](os::NativeHandle handle) -> Result {
|
||||||
|
/* Collect all values. */
|
||||||
|
R_TRY(svc::GetInfo(std::addressof(m_process_alias_address), svc::InfoType_AliasRegionAddress, handle, 0));
|
||||||
|
R_TRY(svc::GetInfo(std::addressof(m_process_alias_size), svc::InfoType_AliasRegionSize, handle, 0));
|
||||||
|
R_TRY(svc::GetInfo(std::addressof(m_process_heap_address), svc::InfoType_HeapRegionAddress, handle, 0));
|
||||||
|
R_TRY(svc::GetInfo(std::addressof(m_process_heap_size), svc::InfoType_HeapRegionSize, handle, 0));
|
||||||
|
R_TRY(svc::GetInfo(std::addressof(m_process_aslr_address), svc::InfoType_AslrRegionAddress, handle, 0));
|
||||||
|
R_TRY(svc::GetInfo(std::addressof(m_process_aslr_size), svc::InfoType_AslrRegionSize, handle, 0));
|
||||||
|
R_TRY(svc::GetInfo(std::addressof(m_process_stack_address), svc::InfoType_StackRegionAddress, handle, 0));
|
||||||
|
R_TRY(svc::GetInfo(std::addressof(m_process_stack_size), svc::InfoType_StackRegionSize, handle, 0));
|
||||||
|
|
||||||
|
if (m_program_location.program_id == ncm::InvalidProgramId) {
|
||||||
|
R_TRY(svc::GetInfo(std::addressof(m_program_location.program_id.value), svc::InfoType_ProgramId, handle, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 value;
|
||||||
|
R_TRY(svc::GetInfo(std::addressof(value), svc::InfoType_IsApplication, handle, 0));
|
||||||
|
m_is_application = value != 0;
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Get process info/status. */
|
||||||
|
os::NativeHandle process_handle;
|
||||||
|
if (R_FAILED(pm::dmnt::AtmosphereGetProcessInfo(std::addressof(process_handle), std::addressof(m_program_location), std::addressof(m_process_override_status), m_process_id))) {
|
||||||
|
process_handle = os::InvalidNativeHandle;
|
||||||
|
m_program_location = { ncm::InvalidProgramId, };
|
||||||
|
m_process_override_status = {};
|
||||||
|
}
|
||||||
|
ON_SCOPE_EXIT { os::CloseNativeHandle(process_handle); };
|
||||||
|
|
||||||
|
/* Try collecting from our debug handle, then the process handle. */
|
||||||
|
if (R_FAILED(CollectProcessInfoImpl(m_debug_handle)) && R_FAILED(CollectProcessInfoImpl(process_handle))) {
|
||||||
|
m_process_alias_address = 0;
|
||||||
|
m_process_alias_size = 0;
|
||||||
|
m_process_heap_address = 0;
|
||||||
|
m_process_heap_size = 0;
|
||||||
|
m_process_aslr_address = 0;
|
||||||
|
m_process_aslr_size = 0;
|
||||||
|
m_process_stack_address = 0;
|
||||||
|
m_process_stack_size = 0;
|
||||||
|
m_is_application = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Result DebugProcess::GetThreadContext(svc::ThreadContext *out, u64 thread_id, u32 flags) {
|
Result DebugProcess::GetThreadContext(svc::ThreadContext *out, u64 thread_id, u32 flags) {
|
||||||
return svc::GetDebugThreadContext(out, m_debug_handle, thread_id, flags);
|
return svc::GetDebugThreadContext(out, m_debug_handle, thread_id, flags);
|
||||||
}
|
}
|
||||||
@@ -228,6 +296,11 @@ namespace ams::dmnt {
|
|||||||
return svc::WriteDebugProcessMemory(m_debug_handle, reinterpret_cast<uintptr_t>(src), address, size);
|
return svc::WriteDebugProcessMemory(m_debug_handle, reinterpret_cast<uintptr_t>(src), address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result DebugProcess::QueryMemory(svc::MemoryInfo *out, uintptr_t address) {
|
||||||
|
svc::PageInfo dummy;
|
||||||
|
return svc::QueryDebugProcessMemory(out, std::addressof(dummy), m_debug_handle, address);
|
||||||
|
}
|
||||||
|
|
||||||
Result DebugProcess::Continue() {
|
Result DebugProcess::Continue() {
|
||||||
AMS_DMNT2_GDB_LOG_DEBUG("DebugProcess::Continue() all\n");
|
AMS_DMNT2_GDB_LOG_DEBUG("DebugProcess::Continue() all\n");
|
||||||
|
|
||||||
@@ -522,5 +595,25 @@ namespace ams::dmnt {
|
|||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DebugProcess::GetThreadName(char *dst, u64 thread_id) const {
|
||||||
|
for (size_t i = 0; i < ThreadCountMax; ++i) {
|
||||||
|
if (m_thread_valid[i] && m_thread_ids[i] == thread_id) {
|
||||||
|
if (R_FAILED(osdbg::GetThreadName(dst, std::addressof(m_thread_infos[i])))) {
|
||||||
|
if (m_thread_infos[i]._thread_type != 0) {
|
||||||
|
if (m_thread_infos[i]._thread_type_type == osdbg::ThreadTypeType_Libnx) {
|
||||||
|
util::TSNPrintf(dst, os::ThreadNameLengthMax, "libnx Thread_0x%010lx", reinterpret_cast<uintptr_t>(m_thread_infos[i]._thread_type));
|
||||||
|
} else {
|
||||||
|
util::TSNPrintf(dst, os::ThreadNameLengthMax, "Thread_0x%010lx", reinterpret_cast<uintptr_t>(m_thread_infos[i]._thread_type));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
util::TSNPrintf(dst, os::ThreadNameLengthMax, "Thread_ID=%lu", thread_id);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -50,6 +50,7 @@ namespace ams::dmnt {
|
|||||||
u64 m_last_thread_id{};
|
u64 m_last_thread_id{};
|
||||||
u64 m_thread_id_override{};
|
u64 m_thread_id_override{};
|
||||||
u64 m_continue_thread_id{};
|
u64 m_continue_thread_id{};
|
||||||
|
u64 m_preferred_debug_break_thread_id{};
|
||||||
GdbSignal m_last_signal{};
|
GdbSignal m_last_signal{};
|
||||||
bool m_stepping{false};
|
bool m_stepping{false};
|
||||||
bool m_use_hardware_single_step{false};
|
bool m_use_hardware_single_step{false};
|
||||||
@@ -64,6 +65,17 @@ namespace ams::dmnt {
|
|||||||
ModuleDefinition m_module_definitions[ModuleCountMax]{};
|
ModuleDefinition m_module_definitions[ModuleCountMax]{};
|
||||||
size_t m_module_count{};
|
size_t m_module_count{};
|
||||||
size_t m_main_module{};
|
size_t m_main_module{};
|
||||||
|
u64 m_process_alias_address{};
|
||||||
|
u64 m_process_alias_size{};
|
||||||
|
u64 m_process_heap_address{};
|
||||||
|
u64 m_process_heap_size{};
|
||||||
|
u64 m_process_aslr_address{};
|
||||||
|
u64 m_process_aslr_size{};
|
||||||
|
u64 m_process_stack_address{};
|
||||||
|
u64 m_process_stack_size{};
|
||||||
|
ncm::ProgramLocation m_program_location{};
|
||||||
|
cfg::OverrideStatus m_process_override_status{};
|
||||||
|
bool m_is_application{false};
|
||||||
public:
|
public:
|
||||||
DebugProcess() : m_software_breakpoints(this), m_hardware_breakpoints(this), m_hardware_watchpoints(this), m_step_breakpoints(m_software_breakpoints) {
|
DebugProcess() : m_software_breakpoints(this), m_hardware_breakpoints(this), m_hardware_watchpoints(this), m_step_breakpoints(m_software_breakpoints) {
|
||||||
if (svc::IsKernelMesosphere()) {
|
if (svc::IsKernelMesosphere()) {
|
||||||
@@ -80,7 +92,8 @@ namespace ams::dmnt {
|
|||||||
size_t GetModuleCount() const { return m_module_count; }
|
size_t GetModuleCount() const { return m_module_count; }
|
||||||
size_t GetMainModuleIndex() const { return m_main_module; }
|
size_t GetMainModuleIndex() const { return m_main_module; }
|
||||||
const char *GetModuleName(size_t ix) const { return m_module_definitions[ix].GetName(); }
|
const char *GetModuleName(size_t ix) const { return m_module_definitions[ix].GetName(); }
|
||||||
uintptr_t GetBaseAddress(size_t ix) const { return m_module_definitions[ix].GetAddress(); }
|
uintptr_t GetModuleBaseAddress(size_t ix) const { return m_module_definitions[ix].GetAddress(); }
|
||||||
|
uintptr_t GetModuleSize(size_t ix) const { return m_module_definitions[ix].GetSize(); }
|
||||||
ProcessStatus GetStatus() const { return m_status; }
|
ProcessStatus GetStatus() const { return m_status; }
|
||||||
os::ProcessId GetProcessId() const { return m_process_id; }
|
os::ProcessId GetProcessId() const { return m_process_id; }
|
||||||
|
|
||||||
@@ -95,20 +108,37 @@ namespace ams::dmnt {
|
|||||||
u64 GetLastThreadId();
|
u64 GetLastThreadId();
|
||||||
u64 GetThreadIdOverride() { this->GetLastThreadId(); return m_thread_id_override; }
|
u64 GetThreadIdOverride() { this->GetLastThreadId(); return m_thread_id_override; }
|
||||||
|
|
||||||
|
u64 GetPreferredDebuggerBreakThreadId() { return m_preferred_debug_break_thread_id; }
|
||||||
|
|
||||||
void SetLastThreadId(u64 tid) {
|
void SetLastThreadId(u64 tid) {
|
||||||
m_last_thread_id = tid;
|
m_last_thread_id = tid;
|
||||||
m_thread_id_override = tid;
|
m_thread_id_override = tid;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetThreadIdOverride(u64 tid) {
|
void SetThreadIdOverride(u64 tid) {
|
||||||
m_thread_id_override = tid;
|
m_thread_id_override = tid;
|
||||||
|
m_preferred_debug_break_thread_id = tid;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetDebugBreaked() {
|
void SetDebugBreaked() {
|
||||||
m_status = ProcessStatus_DebugBreak;
|
m_status = ProcessStatus_DebugBreak;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u64 GetAliasRegionAddress() const { return m_process_alias_address; }
|
||||||
|
u64 GetAliasRegionSize() const { return m_process_alias_size; }
|
||||||
|
u64 GetHeapRegionAddress() const { return m_process_heap_address; }
|
||||||
|
u64 GetHeapRegionSize() const { return m_process_heap_size; }
|
||||||
|
u64 GetAslrRegionAddress() const { return m_process_aslr_address; }
|
||||||
|
u64 GetAslrRegionSize() const { return m_process_aslr_size; }
|
||||||
|
u64 GetStackRegionAddress() const { return m_process_stack_address; }
|
||||||
|
u64 GetStackRegionSize() const { return m_process_stack_size; }
|
||||||
|
|
||||||
|
const ncm::ProgramLocation &GetProgramLocation() const { return m_program_location; }
|
||||||
|
const cfg::OverrideStatus &GetOverrideStatus() const { return m_process_override_status; }
|
||||||
|
|
||||||
|
bool IsApplication() const { return m_is_application; }
|
||||||
public:
|
public:
|
||||||
Result Attach(os::ProcessId process_id);
|
Result Attach(os::ProcessId process_id, bool start_process = false);
|
||||||
void Detach();
|
void Detach();
|
||||||
|
|
||||||
Result GetThreadContext(svc::ThreadContext *out, u64 thread_id, u32 flags);
|
Result GetThreadContext(svc::ThreadContext *out, u64 thread_id, u32 flags);
|
||||||
@@ -117,6 +147,8 @@ namespace ams::dmnt {
|
|||||||
Result ReadMemory(void *dst, uintptr_t address, size_t size);
|
Result ReadMemory(void *dst, uintptr_t address, size_t size);
|
||||||
Result WriteMemory(const void *src, uintptr_t address, size_t size);
|
Result WriteMemory(const void *src, uintptr_t address, size_t size);
|
||||||
|
|
||||||
|
Result QueryMemory(svc::MemoryInfo *out, uintptr_t address);
|
||||||
|
|
||||||
Result Continue();
|
Result Continue();
|
||||||
Result Continue(u64 thread_id);
|
Result Continue(u64 thread_id);
|
||||||
Result Step();
|
Result Step();
|
||||||
@@ -146,9 +178,13 @@ namespace ams::dmnt {
|
|||||||
void GetBranchTarget(svc::ThreadContext &ctx, u64 thread_id, u64 ¤t_pc, u64 &target);
|
void GetBranchTarget(svc::ThreadContext &ctx, u64 thread_id, u64 ¤t_pc, u64 &target);
|
||||||
|
|
||||||
Result CollectModules();
|
Result CollectModules();
|
||||||
|
|
||||||
|
void GetThreadName(char *dst, u64 thread_id) const;
|
||||||
private:
|
private:
|
||||||
Result Start();
|
Result Start();
|
||||||
|
|
||||||
|
void CollectProcessInfo();
|
||||||
|
|
||||||
s32 ThreadCreate(u64 thread_id);
|
s32 ThreadCreate(u64 thread_id);
|
||||||
void ThreadExit(u64 thread_id);
|
void ThreadExit(u64 thread_id);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ namespace ams::dmnt {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GdbPacketIo::SendPacket(bool *out_break, const char *src, HtcsSession *session) {
|
void GdbPacketIo::SendPacket(bool *out_break, const char *src, TransportSession *session) {
|
||||||
/* Default to not breaked. */
|
/* Default to not breaked. */
|
||||||
*out_break = false;
|
*out_break = false;
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ namespace ams::dmnt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *GdbPacketIo::ReceivePacket(bool *out_break, char *dst, size_t size, HtcsSession *session) {
|
char *GdbPacketIo::ReceivePacket(bool *out_break, char *dst, size_t size, TransportSession *session) {
|
||||||
/* Default to not breaked. */
|
/* Default to not breaked. */
|
||||||
*out_break = false;
|
*out_break = false;
|
||||||
|
|
||||||
|
|||||||
@@ -15,11 +15,11 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "dmnt2_htcs_session.hpp"
|
#include "dmnt2_transport_session.hpp"
|
||||||
|
|
||||||
namespace ams::dmnt {
|
namespace ams::dmnt {
|
||||||
|
|
||||||
static constexpr size_t GdbPacketBufferSize = 16_KB;
|
static constexpr size_t GdbPacketBufferSize = 32_KB;
|
||||||
|
|
||||||
class GdbPacketIo {
|
class GdbPacketIo {
|
||||||
private:
|
private:
|
||||||
@@ -30,8 +30,8 @@ namespace ams::dmnt {
|
|||||||
|
|
||||||
void SetNoAck() { m_no_ack = true; }
|
void SetNoAck() { m_no_ack = true; }
|
||||||
|
|
||||||
void SendPacket(bool *out_break, const char *src, HtcsSession *session);
|
void SendPacket(bool *out_break, const char *src, TransportSession *session);
|
||||||
char *ReceivePacket(bool *out_break, char *dst, size_t size, HtcsSession *session);
|
char *ReceivePacket(bool *out_break, char *dst, size_t size, TransportSession *session);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "dmnt2_debug_log.hpp"
|
#include "dmnt2_debug_log.hpp"
|
||||||
|
#include "dmnt2_transport_layer.hpp"
|
||||||
#include "dmnt2_gdb_server.hpp"
|
#include "dmnt2_gdb_server.hpp"
|
||||||
#include "dmnt2_gdb_server_impl.hpp"
|
#include "dmnt2_gdb_server_impl.hpp"
|
||||||
|
|
||||||
@@ -36,34 +37,28 @@ namespace ams::dmnt {
|
|||||||
while (true) {
|
while (true) {
|
||||||
/* Get a socket. */
|
/* Get a socket. */
|
||||||
int fd;
|
int fd;
|
||||||
while ((fd = htcs::Socket()) == -1) {
|
while ((fd = transport::Socket()) == -1) {
|
||||||
os::SleepThread(TimeSpan::FromSeconds(1));
|
os::SleepThread(TimeSpan::FromSeconds(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure we cleanup the socket when we're done with it. */
|
/* Ensure we cleanup the socket when we're done with it. */
|
||||||
ON_SCOPE_EXIT {
|
ON_SCOPE_EXIT {
|
||||||
htcs::Close(fd);
|
transport::Close(fd);
|
||||||
os::SleepThread(TimeSpan::FromSeconds(1));
|
os::SleepThread(TimeSpan::FromSeconds(1));
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Create a sock addr for our server. */
|
|
||||||
htcs::SockAddrHtcs addr;
|
|
||||||
addr.family = htcs::HTCS_AF_HTCS;
|
|
||||||
addr.peer_name = htcs::GetPeerNameAny();
|
|
||||||
std::strcpy(addr.port_name.name, "iywys@$gdb");
|
|
||||||
|
|
||||||
/* Bind. */
|
/* Bind. */
|
||||||
if (htcs::Bind(fd, std::addressof(addr)) == -1) {
|
if (transport::Bind(fd, transport::PortName_GdbServer) == -1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Listen on our port. */
|
/* Listen on our port. */
|
||||||
while (htcs::Listen(fd, 0) == 0) {
|
while (transport::Listen(fd, 0) == 0) {
|
||||||
/* Continue accepting clients, so long as we can. */
|
/* Continue accepting clients, so long as we can. */
|
||||||
int client_fd;
|
int client_fd;
|
||||||
while (true) {
|
while (true) {
|
||||||
/* Try to accept a client. */
|
/* Try to accept a client. */
|
||||||
if (client_fd = htcs::Accept(fd, std::addressof(addr)); client_fd < 0) {
|
if (client_fd = transport::Accept(fd); client_fd < 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +72,7 @@ namespace ams::dmnt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Close the client socket. */
|
/* Close the client socket. */
|
||||||
htcs::Close(client_fd);
|
transport::Close(client_fd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -31,10 +31,11 @@ namespace ams::dmnt {
|
|||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
int m_socket;
|
int m_socket;
|
||||||
HtcsSession m_session;
|
TransportSession m_session;
|
||||||
GdbPacketIo m_packet_io;
|
GdbPacketIo m_packet_io;
|
||||||
char *m_receive_packet{nullptr};
|
char *m_receive_packet{nullptr};
|
||||||
char *m_reply_packet{nullptr};
|
char *m_reply_cur{nullptr};
|
||||||
|
char *m_reply_end{nullptr};
|
||||||
char m_buffer[GdbPacketBufferSize / 2];
|
char m_buffer[GdbPacketBufferSize / 2];
|
||||||
bool m_killed{false};
|
bool m_killed{false};
|
||||||
os::ThreadType m_events_thread;
|
os::ThreadType m_events_thread;
|
||||||
@@ -42,6 +43,7 @@ namespace ams::dmnt {
|
|||||||
DebugProcess m_debug_process;
|
DebugProcess m_debug_process;
|
||||||
os::ProcessId m_process_id{os::InvalidProcessId};
|
os::ProcessId m_process_id{os::InvalidProcessId};
|
||||||
os::Event m_event;
|
os::Event m_event;
|
||||||
|
os::ProcessId m_wait_process_id{os::InvalidProcessId};
|
||||||
public:
|
public:
|
||||||
GdbServerImpl(int socket, void *thread_stack, size_t stack_size);
|
GdbServerImpl(int socket, void *thread_stack, size_t stack_size);
|
||||||
~GdbServerImpl();
|
~GdbServerImpl();
|
||||||
@@ -60,7 +62,7 @@ namespace ams::dmnt {
|
|||||||
static void DebugEventsThreadEntry(void *arg) { static_cast<GdbServerImpl *>(arg)->DebugEventsThread(); }
|
static void DebugEventsThreadEntry(void *arg) { static_cast<GdbServerImpl *>(arg)->DebugEventsThread(); }
|
||||||
void DebugEventsThread();
|
void DebugEventsThread();
|
||||||
void ProcessDebugEvents();
|
void ProcessDebugEvents();
|
||||||
void SetStopReplyPacket(GdbSignal signal);
|
void AppendStopReplyPacket(GdbSignal signal);
|
||||||
private:
|
private:
|
||||||
void D();
|
void D();
|
||||||
|
|
||||||
@@ -98,6 +100,7 @@ namespace ams::dmnt {
|
|||||||
|
|
||||||
void qAttached();
|
void qAttached();
|
||||||
void qC();
|
void qC();
|
||||||
|
void qRcmd();
|
||||||
void qSupported();
|
void qSupported();
|
||||||
void qXfer();
|
void qXfer();
|
||||||
void qXferFeaturesRead();
|
void qXferFeaturesRead();
|
||||||
|
|||||||
@@ -16,15 +16,22 @@
|
|||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "dmnt2_debug_log.hpp"
|
#include "dmnt2_debug_log.hpp"
|
||||||
#include "dmnt2_gdb_server.hpp"
|
#include "dmnt2_gdb_server.hpp"
|
||||||
|
#include "dmnt2_transport_layer.hpp"
|
||||||
|
|
||||||
namespace ams {
|
namespace ams {
|
||||||
|
|
||||||
namespace dmnt {
|
namespace {
|
||||||
|
|
||||||
namespace {
|
bool IsHtcEnabled() {
|
||||||
|
u8 enable_htc = 0;
|
||||||
alignas(0x40) constinit u8 g_htcs_buffer[4_KB];
|
settings::fwdbg::GetSettingsItemValue(std::addressof(enable_htc), sizeof(enable_htc), "atmosphere", "enable_htc");
|
||||||
|
return enable_htc != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsStandaloneGdbstubEnabled() {
|
||||||
|
u8 enable_gdbstub = 0;
|
||||||
|
settings::fwdbg::GetSettingsItemValue(std::addressof(enable_gdbstub), sizeof(enable_gdbstub), "atmosphere", "enable_standalone_gdbstub");
|
||||||
|
return enable_gdbstub != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -35,6 +42,9 @@ namespace ams {
|
|||||||
/* Initialize our connection to sm. */
|
/* Initialize our connection to sm. */
|
||||||
R_ABORT_UNLESS(sm::Initialize());
|
R_ABORT_UNLESS(sm::Initialize());
|
||||||
|
|
||||||
|
/* Initialize other services we need. */
|
||||||
|
R_ABORT_UNLESS(pmdmntInitialize());
|
||||||
|
|
||||||
/* Verify that we can sanely execute. */
|
/* Verify that we can sanely execute. */
|
||||||
ams::CheckApiVersion();
|
ams::CheckApiVersion();
|
||||||
}
|
}
|
||||||
@@ -50,11 +60,23 @@ namespace ams {
|
|||||||
os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(dmnt, Main));
|
os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(dmnt, Main));
|
||||||
AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(dmnt, Main));
|
AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(dmnt, Main));
|
||||||
|
|
||||||
/* Initialize htcs. */
|
bool use_htcs = false, use_tcp = false;
|
||||||
constexpr auto HtcsSocketCountMax = 8;
|
{
|
||||||
const size_t buffer_size = htcs::GetWorkingMemorySize(HtcsSocketCountMax);
|
R_ABORT_UNLESS(::setsysInitialize());
|
||||||
AMS_ABORT_UNLESS(sizeof(dmnt::g_htcs_buffer) >= buffer_size);
|
ON_SCOPE_EXIT { ::setsysExit(); };
|
||||||
htcs::InitializeForSystem(dmnt::g_htcs_buffer, buffer_size, HtcsSocketCountMax);
|
|
||||||
|
use_htcs = IsHtcEnabled();
|
||||||
|
use_tcp = IsStandaloneGdbstubEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize transport layer. */
|
||||||
|
if (use_htcs) {
|
||||||
|
dmnt::transport::InitializeByHtcs();
|
||||||
|
} else if (use_tcp) {
|
||||||
|
dmnt::transport::InitializeByTcp();
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize debug log thread. */
|
/* Initialize debug log thread. */
|
||||||
dmnt::InitializeDebugLog();
|
dmnt::InitializeDebugLog();
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ namespace ams::dmnt {
|
|||||||
char m_name[PathLengthMax];
|
char m_name[PathLengthMax];
|
||||||
u64 m_address;
|
u64 m_address;
|
||||||
u64 m_size;
|
u64 m_size;
|
||||||
|
size_t m_name_start;
|
||||||
public:
|
public:
|
||||||
constexpr ModuleDefinition() : m_name(), m_address(), m_size() { /* ... */ }
|
constexpr ModuleDefinition() : m_name(), m_address(), m_size() { /* ... */ }
|
||||||
constexpr ~ModuleDefinition() { /* ... */ }
|
constexpr ~ModuleDefinition() { /* ... */ }
|
||||||
@@ -34,9 +35,10 @@ namespace ams::dmnt {
|
|||||||
constexpr ModuleDefinition &operator=(const ModuleDefinition &rhs) = default;
|
constexpr ModuleDefinition &operator=(const ModuleDefinition &rhs) = default;
|
||||||
|
|
||||||
constexpr void Reset() {
|
constexpr void Reset() {
|
||||||
m_name[0] = 0;
|
m_name[0] = 0;
|
||||||
m_address = 0;
|
m_address = 0;
|
||||||
m_size = 0;
|
m_size = 0;
|
||||||
|
m_name_start = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool operator==(const ModuleDefinition &rhs) const {
|
constexpr bool operator==(const ModuleDefinition &rhs) const {
|
||||||
@@ -48,7 +50,7 @@ namespace ams::dmnt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr char *GetNameBuffer() { return m_name; }
|
constexpr char *GetNameBuffer() { return m_name; }
|
||||||
constexpr const char *GetName() const { return m_name; }
|
constexpr const char *GetName() const { return m_name + m_name_start; }
|
||||||
|
|
||||||
constexpr u64 GetAddress() const { return m_address; }
|
constexpr u64 GetAddress() const { return m_address; }
|
||||||
constexpr u64 GetSize() const { return m_size; }
|
constexpr u64 GetSize() const { return m_size; }
|
||||||
@@ -57,6 +59,10 @@ namespace ams::dmnt {
|
|||||||
m_address = address;
|
m_address = address;
|
||||||
m_size = size;
|
m_size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr void SetNameStart(size_t offset) {
|
||||||
|
m_name_start = offset;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
196
stratosphere/dmnt.gen2/source/dmnt2_transport_layer.cpp
Normal file
196
stratosphere/dmnt.gen2/source/dmnt2_transport_layer.cpp
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 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 "dmnt2_transport_layer.hpp"
|
||||||
|
|
||||||
|
namespace ams::dmnt::transport {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
enum SocketMode {
|
||||||
|
SocketMode_Invalid,
|
||||||
|
SocketMode_Htcs,
|
||||||
|
SocketMode_Tcp,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline const u16 ListenPort_GdbServer = 22225;
|
||||||
|
constexpr inline const u16 ListenPort_GdbDebugLog = 22227;
|
||||||
|
|
||||||
|
constinit os::SdkMutex g_socket_init_mutex;
|
||||||
|
constinit SocketMode g_socket_mode = SocketMode_Invalid;
|
||||||
|
|
||||||
|
constexpr inline size_t RequiredAlignment = std::max(os::ThreadStackAlignment, os::MemoryPageSize);
|
||||||
|
|
||||||
|
using SocketConfigType = socket::SystemConfigLightDefault;
|
||||||
|
|
||||||
|
/* TODO: If we ever use resolvers, increase this. */
|
||||||
|
constexpr inline size_t SocketAllocatorSize = 4_KB;
|
||||||
|
constexpr inline size_t SocketMemoryPoolSize = util::AlignUp(SocketConfigType::PerTcpSocketWorstCaseMemoryPoolSize + SocketConfigType::PerUdpSocketWorstCaseMemoryPoolSize, os::MemoryPageSize);
|
||||||
|
|
||||||
|
constexpr inline size_t SocketRequiredSize = util::AlignUp(SocketMemoryPoolSize + SocketAllocatorSize, os::MemoryPageSize);
|
||||||
|
|
||||||
|
/* Declare the memory pool. */
|
||||||
|
alignas(RequiredAlignment) constinit u8 g_socket_memory[SocketRequiredSize];
|
||||||
|
|
||||||
|
constexpr inline const SocketConfigType SocketConfig(g_socket_memory, SocketRequiredSize, SocketAllocatorSize, 2);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeByHtcs() {
|
||||||
|
std::scoped_lock lk(g_socket_init_mutex);
|
||||||
|
AMS_ABORT_UNLESS(g_socket_mode == SocketMode_Invalid);
|
||||||
|
|
||||||
|
constexpr auto HtcsSocketCountMax = 8;
|
||||||
|
const size_t buffer_size = htcs::GetWorkingMemorySize(HtcsSocketCountMax);
|
||||||
|
AMS_ABORT_UNLESS(sizeof(g_socket_memory) >= buffer_size);
|
||||||
|
htcs::InitializeForSystem(g_socket_memory, sizeof(g_socket_memory), HtcsSocketCountMax);
|
||||||
|
|
||||||
|
g_socket_mode = SocketMode_Htcs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeByTcp() {
|
||||||
|
std::scoped_lock lk(g_socket_init_mutex);
|
||||||
|
AMS_ABORT_UNLESS(g_socket_mode == SocketMode_Invalid);
|
||||||
|
|
||||||
|
R_ABORT_UNLESS(socket::Initialize(SocketConfig));
|
||||||
|
|
||||||
|
g_socket_mode = SocketMode_Tcp;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 Socket() {
|
||||||
|
switch (g_socket_mode) {
|
||||||
|
case SocketMode_Htcs: return htcs::Socket();
|
||||||
|
case SocketMode_Tcp: return socket::Socket(socket::Family::Af_Inet, socket::Type::Sock_Stream, socket::Protocol::IpProto_Tcp);
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 Close(s32 desc) {
|
||||||
|
switch (g_socket_mode) {
|
||||||
|
case SocketMode_Htcs: return htcs::Close(desc);
|
||||||
|
case SocketMode_Tcp: return socket::Close(desc);
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 Bind(s32 desc, PortName port_name) {
|
||||||
|
switch (g_socket_mode) {
|
||||||
|
case SocketMode_Htcs:
|
||||||
|
{
|
||||||
|
htcs::SockAddrHtcs addr;
|
||||||
|
addr.family = htcs::HTCS_AF_HTCS;
|
||||||
|
addr.peer_name = htcs::GetPeerNameAny();
|
||||||
|
switch (port_name) {
|
||||||
|
case PortName_GdbServer: std::strcpy(addr.port_name.name, "iywys@$gdb"); break;
|
||||||
|
case PortName_GdbDebugLog: std::strcpy(addr.port_name.name, "iywys@$dmnt2_log"); break;
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
|
||||||
|
return htcs::Bind(desc, std::addressof(addr));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SocketMode_Tcp:
|
||||||
|
{
|
||||||
|
socket::SockAddrIn addr = {};
|
||||||
|
addr.sin_family = socket::Family::Af_Inet;
|
||||||
|
addr.sin_addr.s_addr = socket::InAddr_Any;
|
||||||
|
|
||||||
|
switch (port_name){
|
||||||
|
case PortName_GdbServer: addr.sin_port = socket::InetHtons(static_cast<u16>(ListenPort_GdbServer)); break;
|
||||||
|
case PortName_GdbDebugLog: addr.sin_port = socket::InetHtons(static_cast<u16>(ListenPort_GdbDebugLog)); break;
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
|
||||||
|
return socket::Bind(desc, reinterpret_cast<socket::SockAddr *>(std::addressof(addr)), sizeof(addr));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 Listen(s32 desc, s32 backlog_count) {
|
||||||
|
switch (g_socket_mode) {
|
||||||
|
case SocketMode_Htcs: return htcs::Listen(desc, backlog_count);
|
||||||
|
case SocketMode_Tcp: return socket::Listen(desc, backlog_count);
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 Accept(s32 desc) {
|
||||||
|
switch (g_socket_mode) {
|
||||||
|
case SocketMode_Htcs:
|
||||||
|
{
|
||||||
|
htcs::SockAddrHtcs addr;
|
||||||
|
addr.family = htcs::HTCS_AF_HTCS;
|
||||||
|
addr.peer_name = htcs::GetPeerNameAny();
|
||||||
|
addr.port_name.name[0] = '\x00';
|
||||||
|
|
||||||
|
return htcs::Accept(desc, std::addressof(addr));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SocketMode_Tcp:
|
||||||
|
{
|
||||||
|
socket::SockAddrIn addr = {};
|
||||||
|
socket::SockLenT addr_len = sizeof(addr);
|
||||||
|
|
||||||
|
return socket::Accept(desc, reinterpret_cast<socket::SockAddr *>(std::addressof(addr)), std::addressof(addr_len));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 Shutdown(s32 desc) {
|
||||||
|
switch (g_socket_mode) {
|
||||||
|
case SocketMode_Htcs: return htcs::Shutdown(desc, htcs::HTCS_SHUT_RDWR);
|
||||||
|
case SocketMode_Tcp: return socket::Shutdown(desc, socket::ShutdownMethod::Shut_RdWr);
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t Recv(s32 desc, void *buffer, size_t buffer_size, s32 flags) {
|
||||||
|
switch (g_socket_mode) {
|
||||||
|
case SocketMode_Htcs: return htcs::Recv(desc, buffer, buffer_size, flags);
|
||||||
|
case SocketMode_Tcp: return socket::Recv(desc, buffer, buffer_size, static_cast<socket::MsgFlag>(flags));
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t Send(s32 desc, const void *buffer, size_t buffer_size, s32 flags) {
|
||||||
|
switch (g_socket_mode) {
|
||||||
|
case SocketMode_Htcs: return htcs::Send(desc, buffer, buffer_size, flags);
|
||||||
|
case SocketMode_Tcp: return socket::Send(desc, buffer, buffer_size, static_cast<socket::MsgFlag>(flags));
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 GetLastError() {
|
||||||
|
switch (g_socket_mode) {
|
||||||
|
case SocketMode_Htcs: return htcs::GetLastError();
|
||||||
|
case SocketMode_Tcp: return static_cast<s32>(socket::GetLastError());
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsLastErrorEAgain() {
|
||||||
|
switch (g_socket_mode) {
|
||||||
|
case SocketMode_Htcs: return htcs::GetLastError() == htcs::HTCS_EAGAIN;
|
||||||
|
case SocketMode_Tcp: return socket::GetLastError() == socket::Errno::EAgain;
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
42
stratosphere/dmnt.gen2/source/dmnt2_transport_layer.hpp
Normal file
42
stratosphere/dmnt.gen2/source/dmnt2_transport_layer.hpp
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 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 <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::dmnt::transport {
|
||||||
|
|
||||||
|
void InitializeByHtcs();
|
||||||
|
void InitializeByTcp();
|
||||||
|
|
||||||
|
enum PortName {
|
||||||
|
PortName_GdbServer,
|
||||||
|
PortName_GdbDebugLog,
|
||||||
|
};
|
||||||
|
|
||||||
|
s32 Socket();
|
||||||
|
s32 Close(s32 desc);
|
||||||
|
s32 Bind(s32 desc, PortName port_name);
|
||||||
|
s32 Listen(s32 desc, s32 backlog_count);
|
||||||
|
s32 Accept(s32 desc);
|
||||||
|
s32 Shutdown(s32 desc);
|
||||||
|
|
||||||
|
ssize_t Recv(s32 desc, void *buffer, size_t buffer_size, s32 flags);
|
||||||
|
ssize_t Send(s32 desc, const void *buffer, size_t buffer_size, s32 flags);
|
||||||
|
|
||||||
|
s32 GetLastError();
|
||||||
|
bool IsLastErrorEAgain();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -14,11 +14,11 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "dmnt2_htcs_receive_buffer.hpp"
|
#include "dmnt2_transport_receive_buffer.hpp"
|
||||||
|
|
||||||
namespace ams::dmnt {
|
namespace ams::dmnt {
|
||||||
|
|
||||||
ssize_t HtcsReceiveBuffer::Read(void *dst, size_t size) {
|
ssize_t TransportReceiveBuffer::Read(void *dst, size_t size) {
|
||||||
/* Acquire exclusive access to ourselves. */
|
/* Acquire exclusive access to ourselves. */
|
||||||
std::scoped_lock lk(m_mutex);
|
std::scoped_lock lk(m_mutex);
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ namespace ams::dmnt {
|
|||||||
return readable;
|
return readable;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t HtcsReceiveBuffer::Write(const void *src, size_t size) {
|
ssize_t TransportReceiveBuffer::Write(const void *src, size_t size) {
|
||||||
/* Acquire exclusive access to ourselves. */
|
/* Acquire exclusive access to ourselves. */
|
||||||
std::scoped_lock lk(m_mutex);
|
std::scoped_lock lk(m_mutex);
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ namespace ams::dmnt {
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HtcsReceiveBuffer::WaitToBeReadable() {
|
bool TransportReceiveBuffer::WaitToBeReadable() {
|
||||||
/* Check if we're already readable. */
|
/* Check if we're already readable. */
|
||||||
{
|
{
|
||||||
std::scoped_lock lk(m_mutex);
|
std::scoped_lock lk(m_mutex);
|
||||||
@@ -91,7 +91,7 @@ namespace ams::dmnt {
|
|||||||
return this->IsValid();
|
return this->IsValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HtcsReceiveBuffer::WaitToBeReadable(TimeSpan timeout) {
|
bool TransportReceiveBuffer::WaitToBeReadable(TimeSpan timeout) {
|
||||||
/* Check if we're already readable. */
|
/* Check if we're already readable. */
|
||||||
{
|
{
|
||||||
std::scoped_lock lk(m_mutex);
|
std::scoped_lock lk(m_mutex);
|
||||||
@@ -111,7 +111,7 @@ namespace ams::dmnt {
|
|||||||
return res && this->IsValid();
|
return res && this->IsValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HtcsReceiveBuffer::WaitToBeWritable() {
|
bool TransportReceiveBuffer::WaitToBeWritable() {
|
||||||
/* Check if we're already writable. */
|
/* Check if we're already writable. */
|
||||||
{
|
{
|
||||||
std::scoped_lock lk(m_mutex);
|
std::scoped_lock lk(m_mutex);
|
||||||
@@ -131,7 +131,7 @@ namespace ams::dmnt {
|
|||||||
return this->IsValid();
|
return this->IsValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HtcsReceiveBuffer::Invalidate() {
|
void TransportReceiveBuffer::Invalidate() {
|
||||||
/* Acquire exclusive access to ourselves. */
|
/* Acquire exclusive access to ourselves. */
|
||||||
std::scoped_lock lk(m_mutex);
|
std::scoped_lock lk(m_mutex);
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
namespace ams::dmnt {
|
namespace ams::dmnt {
|
||||||
|
|
||||||
class HtcsReceiveBuffer {
|
class TransportReceiveBuffer {
|
||||||
public:
|
public:
|
||||||
static constexpr size_t ReceiveBufferSize = 4_KB;
|
static constexpr size_t ReceiveBufferSize = 4_KB;
|
||||||
private:
|
private:
|
||||||
@@ -30,7 +30,7 @@ namespace ams::dmnt {
|
|||||||
size_t m_offset;
|
size_t m_offset;
|
||||||
bool m_valid;
|
bool m_valid;
|
||||||
public:
|
public:
|
||||||
HtcsReceiveBuffer() : m_readable_event(os::EventClearMode_ManualClear), m_writable_event(os::EventClearMode_ManualClear), m_mutex(), m_readable_size(), m_offset(), m_valid(true) { /* ... */ }
|
TransportReceiveBuffer() : m_readable_event(os::EventClearMode_ManualClear), m_writable_event(os::EventClearMode_ManualClear), m_mutex(), m_readable_size(), m_offset(), m_valid(true) { /* ... */ }
|
||||||
|
|
||||||
ALWAYS_INLINE bool IsReadable() const { return m_readable_size != 0; }
|
ALWAYS_INLINE bool IsReadable() const { return m_readable_size != 0; }
|
||||||
ALWAYS_INLINE bool IsWritable() const { return m_readable_size == 0; }
|
ALWAYS_INLINE bool IsWritable() const { return m_readable_size == 0; }
|
||||||
@@ -14,12 +14,13 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "dmnt2_htcs_session.hpp"
|
#include "dmnt2_transport_layer.hpp"
|
||||||
|
#include "dmnt2_transport_session.hpp"
|
||||||
#include "dmnt2_debug_log.hpp"
|
#include "dmnt2_debug_log.hpp"
|
||||||
|
|
||||||
namespace ams::dmnt {
|
namespace ams::dmnt {
|
||||||
|
|
||||||
HtcsSession::HtcsSession(int fd) : m_socket(fd), m_valid(true) {
|
TransportSession::TransportSession(int fd) : m_socket(fd), m_valid(true) {
|
||||||
/* Create our thread. */
|
/* Create our thread. */
|
||||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(m_receive_thread), ReceiveThreadEntry, this, m_receive_thread_stack, sizeof(m_receive_thread_stack), os::HighestThreadPriority - 1));
|
R_ABORT_UNLESS(os::CreateThread(std::addressof(m_receive_thread), ReceiveThreadEntry, this, m_receive_thread_stack, sizeof(m_receive_thread_stack), os::HighestThreadPriority - 1));
|
||||||
|
|
||||||
@@ -30,7 +31,7 @@ namespace ams::dmnt {
|
|||||||
AMS_DMNT2_GDB_LOG_INFO("Created Session %d\n", m_socket);
|
AMS_DMNT2_GDB_LOG_INFO("Created Session %d\n", m_socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
HtcsSession::~HtcsSession() {
|
TransportSession::~TransportSession() {
|
||||||
/* Note that we connected. */
|
/* Note that we connected. */
|
||||||
AMS_DMNT2_GDB_LOG_INFO("Closing Session %d\n", m_socket);
|
AMS_DMNT2_GDB_LOG_INFO("Closing Session %d\n", m_socket);
|
||||||
|
|
||||||
@@ -38,25 +39,25 @@ namespace ams::dmnt {
|
|||||||
m_receive_buffer.Invalidate();
|
m_receive_buffer.Invalidate();
|
||||||
|
|
||||||
/* Shutdown our socket. */
|
/* Shutdown our socket. */
|
||||||
htcs::Shutdown(m_socket, htcs::HTCS_SHUT_RDWR);
|
transport::Shutdown(m_socket);
|
||||||
|
|
||||||
/* Wait for our thread. */
|
/* Wait for our thread. */
|
||||||
os::WaitThread(std::addressof(m_receive_thread));
|
os::WaitThread(std::addressof(m_receive_thread));
|
||||||
os::DestroyThread(std::addressof(m_receive_thread));
|
os::DestroyThread(std::addressof(m_receive_thread));
|
||||||
|
|
||||||
/* Close our socket. */
|
/* Close our socket. */
|
||||||
htcs::Close(m_socket);
|
transport::Close(m_socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HtcsSession::WaitToBeReadable() {
|
bool TransportSession::WaitToBeReadable() {
|
||||||
return m_receive_buffer.WaitToBeReadable();
|
return m_receive_buffer.WaitToBeReadable();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HtcsSession::WaitToBeReadable(TimeSpan timeout) {
|
bool TransportSession::WaitToBeReadable(TimeSpan timeout) {
|
||||||
return m_receive_buffer.WaitToBeReadable(timeout);
|
return m_receive_buffer.WaitToBeReadable(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::optional<char> HtcsSession::GetChar() {
|
util::optional<char> TransportSession::GetChar() {
|
||||||
/* Wait for us to have data. */
|
/* Wait for us to have data. */
|
||||||
m_receive_buffer.WaitToBeReadable();
|
m_receive_buffer.WaitToBeReadable();
|
||||||
|
|
||||||
@@ -69,9 +70,9 @@ namespace ams::dmnt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t HtcsSession::PutChar(char c) {
|
ssize_t TransportSession::PutChar(char c) {
|
||||||
/* Send the character. */
|
/* Send the character. */
|
||||||
const auto sent = htcs::Send(m_socket, std::addressof(c), sizeof(c), 0);
|
const auto sent = transport::Send(m_socket, std::addressof(c), sizeof(c), 0);
|
||||||
if (sent < 0) {
|
if (sent < 0) {
|
||||||
m_valid = false;
|
m_valid = false;
|
||||||
}
|
}
|
||||||
@@ -79,13 +80,13 @@ namespace ams::dmnt {
|
|||||||
return sent;
|
return sent;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t HtcsSession::PutString(const char *str) {
|
ssize_t TransportSession::PutString(const char *str) {
|
||||||
/* Repeatedly send until all is sent. */
|
/* Repeatedly send until all is sent. */
|
||||||
const size_t len = std::strlen(str);
|
const size_t len = std::strlen(str);
|
||||||
|
|
||||||
size_t remaining = len;
|
size_t remaining = len;
|
||||||
while (remaining > 0) {
|
while (remaining > 0) {
|
||||||
const auto sent = htcs::Send(m_socket, str, remaining, 0);
|
const auto sent = transport::Send(m_socket, str, remaining, 0);
|
||||||
if (sent >= 0) {
|
if (sent >= 0) {
|
||||||
remaining -= sent;
|
remaining -= sent;
|
||||||
str += sent;
|
str += sent;
|
||||||
@@ -98,22 +99,22 @@ namespace ams::dmnt {
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HtcsSession::ReceiveThreadFunction() {
|
void TransportSession::ReceiveThreadFunction() {
|
||||||
/* Create temporary buffer. */
|
/* Create temporary buffer. */
|
||||||
u8 buffer[HtcsReceiveBuffer::ReceiveBufferSize];
|
u8 buffer[TransportReceiveBuffer::ReceiveBufferSize];
|
||||||
|
|
||||||
/* Loop receiving data. */
|
/* Loop receiving data. */
|
||||||
while (true) {
|
while (true) {
|
||||||
/* Receive data. */
|
/* Receive data. */
|
||||||
const auto res = htcs::Recv(m_socket, buffer, sizeof(buffer), 0);
|
const auto res = transport::Recv(m_socket, buffer, sizeof(buffer), 0);
|
||||||
if (res > 0) {
|
if (res > 0) {
|
||||||
/* Write the data to our buffer. */
|
/* Write the data to our buffer. */
|
||||||
m_receive_buffer.WaitToBeWritable();
|
m_receive_buffer.WaitToBeWritable();
|
||||||
m_receive_buffer.Write(buffer, res);
|
m_receive_buffer.Write(buffer, res);
|
||||||
} else {
|
} else {
|
||||||
/* Otherwise, if we got an error other than "try again", we're done. */
|
/* Otherwise, if we got an error other than "try again", we're done. */
|
||||||
if (htcs::GetLastError() != htcs::HTCS_EAGAIN) {
|
if (!transport::IsLastErrorEAgain()) {
|
||||||
AMS_DMNT2_GDB_LOG_INFO("Session %d invalid, res=%ld, err=%d\n", m_socket, res, static_cast<int>(htcs::GetLastError()));
|
AMS_DMNT2_GDB_LOG_INFO("Session %d invalid, res=%ld, err=%d\n", m_socket, res, static_cast<int>(transport::GetLastError()));
|
||||||
m_valid = false;
|
m_valid = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -15,20 +15,20 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "dmnt2_htcs_receive_buffer.hpp"
|
#include "dmnt2_transport_receive_buffer.hpp"
|
||||||
|
|
||||||
namespace ams::dmnt {
|
namespace ams::dmnt {
|
||||||
|
|
||||||
class HtcsSession {
|
class TransportSession {
|
||||||
private:
|
private:
|
||||||
alignas(os::ThreadStackAlignment) u8 m_receive_thread_stack[util::AlignUp(os::MemoryPageSize + HtcsReceiveBuffer::ReceiveBufferSize, os::ThreadStackAlignment)];
|
alignas(os::ThreadStackAlignment) u8 m_receive_thread_stack[util::AlignUp(os::MemoryPageSize + TransportReceiveBuffer::ReceiveBufferSize, os::ThreadStackAlignment)];
|
||||||
HtcsReceiveBuffer m_receive_buffer;
|
TransportReceiveBuffer m_receive_buffer;
|
||||||
os::ThreadType m_receive_thread;
|
os::ThreadType m_receive_thread;
|
||||||
int m_socket;
|
int m_socket;
|
||||||
bool m_valid;
|
bool m_valid;
|
||||||
public:
|
public:
|
||||||
HtcsSession(int fd);
|
TransportSession(int fd);
|
||||||
~HtcsSession();
|
~TransportSession();
|
||||||
|
|
||||||
ALWAYS_INLINE bool IsValid() const { return m_valid; }
|
ALWAYS_INLINE bool IsValid() const { return m_valid; }
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ namespace ams::dmnt {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static void ReceiveThreadEntry(void *arg) {
|
static void ReceiveThreadEntry(void *arg) {
|
||||||
static_cast<HtcsSession *>(arg)->ReceiveThreadFunction();
|
static_cast<TransportSession *>(arg)->ReceiveThreadFunction();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReceiveThreadFunction();
|
void ReceiveThreadFunction();
|
||||||
@@ -248,7 +248,6 @@ namespace ams::dmnt::cheat::impl {
|
|||||||
void StartProcess(os::ProcessId process_id) const {
|
void StartProcess(os::ProcessId process_id) const {
|
||||||
R_ABORT_UNLESS(pm::dmnt::StartProcess(process_id));
|
R_ABORT_UNLESS(pm::dmnt::StartProcess(process_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CheatProcessManager() : m_cheat_lock(), m_unsafe_break_event(os::EventClearMode_ManualClear), m_debug_events_event(os::EventClearMode_AutoClear), m_cheat_process_event(os::EventClearMode_AutoClear, true) {
|
CheatProcessManager() : m_cheat_lock(), m_unsafe_break_event(os::EventClearMode_ManualClear), m_debug_events_event(os::EventClearMode_AutoClear), m_cheat_process_event(os::EventClearMode_AutoClear, true) {
|
||||||
/* Learn whether we should enable cheats by default. */
|
/* Learn whether we should enable cheats by default. */
|
||||||
|
|||||||
Reference in New Issue
Block a user