diff --git a/Makefile b/Makefile index c8f2e846..26e4c3b3 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ include $(DEVKITPRO)/libnx/switch_rules # INCLUDES is a list of directories containing header files #--------------------------------------------------------------------------------- TARGET := $(notdir $(CURDIR)) -SOURCES := source source/spl source/spl/smc source/updater source/patcher source/map source/rnd source/util source/sm +SOURCES := source source/spl source/spl/smc source/updater source/patcher source/map source/rnd source/util source/sm source/cfg source/pm source/hid source/ldr DATA := data INCLUDES := include diff --git a/include/stratosphere.hpp b/include/stratosphere.hpp index 5e2da836..4227326d 100644 --- a/include/stratosphere.hpp +++ b/include/stratosphere.hpp @@ -45,5 +45,8 @@ #include "stratosphere/on_crash.hpp" +#include "stratosphere/cfg.hpp" +#include "stratosphere/hid.hpp" +#include "stratosphere/pm.hpp" #include "stratosphere/rnd.hpp" #include "stratosphere/util.hpp" \ No newline at end of file diff --git a/include/stratosphere/cfg.hpp b/include/stratosphere/cfg.hpp new file mode 100644 index 00000000..e78dd8a1 --- /dev/null +++ b/include/stratosphere/cfg.hpp @@ -0,0 +1,20 @@ +/* + * 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 . + */ + +#pragma once +#include + +#include "cfg/cfg_api.hpp" diff --git a/include/stratosphere/cfg/cfg_api.hpp b/include/stratosphere/cfg/cfg_api.hpp new file mode 100644 index 00000000..62431da2 --- /dev/null +++ b/include/stratosphere/cfg/cfg_api.hpp @@ -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 . + */ + +#pragma once +#include +#include "../ncm/ncm_types.hpp" + +namespace sts::cfg { + + /* Is the current proces privileged? */ + bool IsInitialProcess(); + + /* SD card configuration. */ + bool IsSdCardInitialized(); + void WaitSdCardInitialized(); + + /* Override key utilities. */ + bool IsTitleOverrideKeyHeld(ncm::TitleId title_id); + bool IsHblOverrideKeyHeld(ncm::TitleId title_id); + void GetOverrideKeyHeldStatus(bool *out_hbl, bool *out_title, ncm::TitleId title_id); + bool IsCheatEnableKeyHeld(ncm::TitleId title_id); + + /* Flag utilities. */ + bool HasFlag(ncm::TitleId title_id, const char *flag); + bool HasTitleSpecificFlag(ncm::TitleId title_id, const char *flag); + bool HasGlobalFlag(const char *flag); + + /* HBL Configuration utilities. */ + bool IsHblTitleId(ncm::TitleId title_id); + bool HasHblFlag(const char *flag); + const char *GetHblPath(); + +} diff --git a/include/stratosphere/hid.hpp b/include/stratosphere/hid.hpp new file mode 100644 index 00000000..bea31e2c --- /dev/null +++ b/include/stratosphere/hid.hpp @@ -0,0 +1,20 @@ +/* + * 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 . + */ + +#pragma once +#include + +#include "hid/hid_api.hpp" \ No newline at end of file diff --git a/include/stratosphere/hid/hid_api.hpp b/include/stratosphere/hid/hid_api.hpp new file mode 100644 index 00000000..b1b97c63 --- /dev/null +++ b/include/stratosphere/hid/hid_api.hpp @@ -0,0 +1,24 @@ +/* + * 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 . + */ + +#pragma once + +namespace sts::hid { + + /* Key API. */ + Result GetKeysHeld(u64 *out); + +} diff --git a/include/stratosphere/ipc/ipc_special.hpp b/include/stratosphere/ipc/ipc_special.hpp index 0588631b..044a7f49 100644 --- a/include/stratosphere/ipc/ipc_special.hpp +++ b/include/stratosphere/ipc/ipc_special.hpp @@ -52,6 +52,10 @@ struct MovedHandle : public IpcHandle { MovedHandle(Handle h) { this->handle = h; } + + Handle GetValue() const { + return this->handle; + } }; /* Represents a copied handle. */ @@ -67,6 +71,10 @@ struct CopiedHandle : public IpcHandle { CopiedHandle(Handle h) { this->handle = h; } + + Handle GetValue() const { + return this->handle; + } }; template <> diff --git a/include/stratosphere/ldr.hpp b/include/stratosphere/ldr.hpp new file mode 100644 index 00000000..fc56cb76 --- /dev/null +++ b/include/stratosphere/ldr.hpp @@ -0,0 +1,20 @@ +/* + * 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 . + */ + +#pragma once +#include + +#include "ldr/ldr_types.hpp" diff --git a/include/stratosphere/ldr/ldr_pm_api.hpp b/include/stratosphere/ldr/ldr_pm_api.hpp new file mode 100644 index 00000000..823c34b1 --- /dev/null +++ b/include/stratosphere/ldr/ldr_pm_api.hpp @@ -0,0 +1,30 @@ +/* + * 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 . + */ + +#pragma once + +#include "ldr_types.hpp" + +namespace sts::ldr::pm { + + /* Process Manager API. */ + Result CreateProcess(Handle *out, PinId pin_id, u32 flags, Handle reslimit); + Result GetProgramInfo(ProgramInfo *out, const ncm::TitleLocation &loc); + Result PinTitle(PinId *out, const ncm::TitleLocation &loc); + Result UnpinTitle(PinId pin_id); + Result HasLaunchedTitle(bool *out, ncm::TitleId title_id); + +} diff --git a/include/stratosphere/ldr/ldr_types.hpp b/include/stratosphere/ldr/ldr_types.hpp new file mode 100644 index 00000000..3efc5726 --- /dev/null +++ b/include/stratosphere/ldr/ldr_types.hpp @@ -0,0 +1,243 @@ +/* + * 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 . + */ + +#pragma once + +#include +#include +#include "../ncm/ncm_types.hpp" + +namespace sts::ldr { + + /* General types. */ + struct ProgramInfo { + u8 main_thread_priority; + u8 default_cpu_id; + u16 flags; + u32 main_thread_stack_size; + ncm::TitleId title_id; + u32 acid_sac_size; + u32 aci_sac_size; + u32 acid_fac_size; + u32 aci_fah_size; + u8 ac_buffer[0x3E0]; + }; + static_assert(sizeof(ProgramInfo) == 0x400, "ProgramInfo definition!"); + + enum ProgramInfoFlag { + ProgramInfoFlag_SystemModule = (0 << 0), + ProgramInfoFlag_Application = (1 << 0), + ProgramInfoFlag_Applet = (2 << 0), + ProgramInfoFlag_InvalidType = (3 << 0), + ProgramInfoFlag_ApplicationTypeMask = (3 << 0), + + ProgramInfoFlag_AllowDebug = (1 << 2), + }; + + enum CreateProcessFlag { + CreateProcessFlag_EnableDebug = (1 << 0), + CreateProcessFlag_DisableAslr = (1 << 1), + }; + + struct ProgramArguments { + u32 allocated_size; + u32 arguments_size; + u8 reserved[0x18]; + u8 arguments[]; + }; + static_assert(sizeof(ProgramArguments) == 0x20, "ProgramArguments definition!"); + + struct PinId { + u64 value; + }; + + inline bool operator==(const PinId &lhs, const PinId &rhs) { + return lhs.value == rhs.value; + } + + inline bool operator!=(const PinId &lhs, const PinId &rhs) { + return lhs.value != rhs.value; + } + static_assert(sizeof(PinId) == sizeof(u64) && std::is_pod::value, "PinId definition!"); + + /* Import ModuleInfo from libnx. */ + using ModuleInfo = ::LoaderModuleInfo; + + /* NSO types. */ + struct NsoHeader { + static constexpr u32 Magic = 0x304F534E; + enum Segment : size_t { + Segment_Text = 0, + Segment_Ro = 1, + Segment_Rw = 2, + Segment_Count, + }; + + enum Flag : u32 { + Flag_CompressedText = (1 << 0), + Flag_CompressedRo = (1 << 1), + Flag_CompressedRw = (1 << 2), + Flag_CheckHashText = (1 << 3), + Flag_CheckHashRo = (1 << 4), + Flag_CheckHashRw = (1 << 5), + }; + + struct SegmentInfo { + u32 file_offset; + u32 dst_offset; + u32 size; + u32 reserved; + }; + + u32 magic; + u32 version; + u32 reserved_08; + u32 flags; + union { + struct { + u32 text_file_offset; + u32 text_dst_offset; + u32 text_size; + u32 unk_file_offset; + u32 ro_file_offset; + u32 ro_dst_offset; + u32 ro_size; + u32 unk_size; + u32 rw_file_offset; + u32 rw_dst_offset; + u32 rw_size; + u32 bss_size; + }; + SegmentInfo segments[Segment_Count]; + }; + u8 build_id[sizeof(ModuleInfo::build_id)]; + union { + u32 compressed_sizes[Segment_Count]; + struct { + u32 text_compressed_size; + u32 ro_compressed_size; + u32 rw_compressed_size; + }; + }; + u8 reserved_6C[0x34]; + union { + u8 segment_hashes[Segment_Count][SHA256_HASH_SIZE]; + struct { + u8 text_hash[SHA256_HASH_SIZE]; + u8 ro_hash[SHA256_HASH_SIZE]; + u8 rw_hash[SHA256_HASH_SIZE]; + }; + }; + }; + static_assert(sizeof(NsoHeader) == 0x100 && std::is_pod::value, "NsoHeader definition!"); + + /* NPDM types. */ + struct Aci { + static constexpr u32 Magic = 0x30494341; + + u32 magic; + u8 reserved_04[0xC]; + ncm::TitleId title_id; + u8 reserved_18[0x8]; + u32 fah_offset; + u32 fah_size; + u32 sac_offset; + u32 sac_size; + u32 kac_offset; + u32 kac_size; + u8 reserved_38[0x8]; + }; + static_assert(sizeof(Aci) == 0x40 && std::is_pod::value, "Aci definition!"); + + struct Acid { + static constexpr u32 Magic = 0x44494341; + + enum AcidFlag { + AcidFlag_Production = (1 << 0), + AcidFlag_UnqualifiedApproval = (1 << 1), + + AcidFlag_DeprecatedUseSecureMemory = (1 << 2), + + AcidFlag_PoolPartitionShift = 2, + AcidFlag_PoolPartitionMask = (3 << AcidFlag_PoolPartitionShift), + }; + + enum PoolPartition { + PoolPartition_Application = 0, + PoolPartition_Applet = 1, + PoolPartition_System = 2, + PoolPartition_SystemNonSecure = 3, + }; + + u8 signature[0x100]; + u8 modulus[0x100]; + u32 magic; + u32 size; + u8 version; + u8 reserved_209[3]; + u32 flags; + ncm::TitleId title_id_min; + ncm::TitleId title_id_max; + u32 fac_offset; + u32 fac_size; + u32 sac_offset; + u32 sac_size; + u32 kac_offset; + u32 kac_size; + u8 reserved_238[0x8]; + }; + static_assert(sizeof(Acid) == 0x240 && std::is_pod::value, "Acid definition!"); + + struct Npdm { + static constexpr u32 Magic = 0x4154454D; + + enum MetaFlag { + MetaFlag_Is64Bit = (1 << 0), + + MetaFlag_AddressSpaceTypeShift = 1, + MetaFlag_AddressSpaceTypeMask = (7 << MetaFlag_AddressSpaceTypeShift), + + MetaFlag_OptimizeMemoryAllocation = (1 << 4), + }; + + enum AddressSpaceType { + AddressSpaceType_32Bit = 0, + AddressSpaceType_64BitDeprecated = 1, + AddressSpaceType_32BitWithoutAlias = 2, + AddressSpaceType_64Bit = 3, + }; + + u32 magic; + u8 reserved_04[8]; + u8 flags; + u8 reserved_0D; + u8 main_thread_priority; + u8 default_cpu_id; + u8 reserved_10[4]; + u32 system_resource_size; + u32 version; + u32 main_thread_stack_size; + char title_name[0x10]; + char product_code[0x10]; + u8 reserved_40[0x30]; + u32 aci_offset; + u32 aci_size; + u32 acid_offset; + u32 acid_size; + }; + static_assert(sizeof(Npdm) == 0x80 && std::is_pod::value, "Npdm definition!"); + +} diff --git a/include/stratosphere/map/map_types.hpp b/include/stratosphere/map/map_types.hpp index f874696b..28a0b8d1 100644 --- a/include/stratosphere/map/map_types.hpp +++ b/include/stratosphere/map/map_types.hpp @@ -33,6 +33,13 @@ namespace sts::map { uintptr_t aslr_end; }; + static constexpr uintptr_t AslrBase32Bit = 0x0000200000ul; + static constexpr size_t AslrSize32Bit = 0x003FE00000ul; + static constexpr uintptr_t AslrBase64BitDeprecated = 0x0008000000ul; + static constexpr size_t AslrSize64BitDeprecated = 0x0078000000ul; + static constexpr uintptr_t AslrBase64Bit = 0x0008000000ul; + static constexpr size_t AslrSize64Bit = 0x7FF8000000ul; + class AutoCloseMap { private: Handle process_handle; diff --git a/include/stratosphere/ncm.hpp b/include/stratosphere/ncm.hpp new file mode 100644 index 00000000..ec0830de --- /dev/null +++ b/include/stratosphere/ncm.hpp @@ -0,0 +1,20 @@ +/* + * 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 . + */ + +#pragma once +#include + +#include "ncm/ncm_types.hpp" diff --git a/include/stratosphere/ncm/ncm_types.hpp b/include/stratosphere/ncm/ncm_types.hpp new file mode 100644 index 00000000..e86295a2 --- /dev/null +++ b/include/stratosphere/ncm/ncm_types.hpp @@ -0,0 +1,82 @@ +/* + * 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 . + */ + +#pragma once + +#include + +namespace sts::ncm { + + /* Storage IDs. */ + enum class StorageId : u8 { + None = 0, + Host = 1, + GameCard = 2, + NandSystem = 3, + NandUser = 4, + SdCard = 5, + }; + + /* Title IDs. */ + struct TitleId { + u64 value; + + inline explicit operator u64() const { + return this->value; + } + }; + static constexpr TitleId InvalidTitleId = {}; + + inline bool operator==(const TitleId &lhs, const TitleId &rhs) { + return lhs.value == rhs.value; + } + + inline bool operator!=(const TitleId &lhs, const TitleId &rhs) { + return lhs.value != rhs.value; + } + + inline bool operator<(const TitleId &lhs, const TitleId &rhs) { + return lhs.value < rhs.value; + } + + inline bool operator<=(const TitleId &lhs, const TitleId &rhs) { + return lhs.value <= rhs.value; + } + + inline bool operator>(const TitleId &lhs, const TitleId &rhs) { + return lhs.value > rhs.value; + } + + inline bool operator>=(const TitleId &lhs, const TitleId &rhs) { + return lhs.value >= rhs.value; + } + + static_assert(sizeof(TitleId) == sizeof(u64) && std::is_pod::value, "TitleId definition!"); + + /* Title Location. */ + struct TitleLocation { + TitleId title_id; + u8 storage_id; + }; + + constexpr TitleLocation MakeTitleLocation(TitleId title_id, StorageId storage_id) { + TitleLocation loc = { .title_id = title_id, .storage_id = static_cast(storage_id) }; + return loc; + } + + static_assert(sizeof(TitleLocation) == 0x10 && std::is_pod::value, "TitleLocation definition!"); + +} diff --git a/include/stratosphere/pm.hpp b/include/stratosphere/pm.hpp new file mode 100644 index 00000000..877cdc1b --- /dev/null +++ b/include/stratosphere/pm.hpp @@ -0,0 +1,20 @@ +/* + * 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 . + */ + +#pragma once +#include + +#include "pm/pm_info_api.hpp" \ No newline at end of file diff --git a/include/stratosphere/pm/pm_info_api.hpp b/include/stratosphere/pm/pm_info_api.hpp new file mode 100644 index 00000000..29f8dc89 --- /dev/null +++ b/include/stratosphere/pm/pm_info_api.hpp @@ -0,0 +1,29 @@ +/* + * 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 . + */ + +#pragma once + +namespace sts::pm::info { + + /* Information API. */ + Result GetTitleId(u64 *out_title_id, u64 process_id); + Result GetProcessId(u64 *out_process_id, u64 title_id); + Result HasLaunchedTitle(bool *out, u64 title_id); + + /* Information convenience API. */ + bool HasLaunchedTitle(u64 title_id); + +} diff --git a/include/stratosphere/results/loader_results.hpp b/include/stratosphere/results/loader_results.hpp index 3bc5e435..7803a68c 100644 --- a/include/stratosphere/results/loader_results.hpp +++ b/include/stratosphere/results/loader_results.hpp @@ -26,7 +26,7 @@ static constexpr Result ResultLoaderInvalidMeta = MAKERESULT(Module_Lo static constexpr Result ResultLoaderInvalidNso = MAKERESULT(Module_Loader, 5); static constexpr Result ResultLoaderInvalidPath = MAKERESULT(Module_Loader, 6); static constexpr Result ResultLoaderTooManyProcesses = MAKERESULT(Module_Loader, 7); -static constexpr Result ResultLoaderProcessNotRegistered = MAKERESULT(Module_Loader, 8); +static constexpr Result ResultLoaderNotPinned = MAKERESULT(Module_Loader, 8); static constexpr Result ResultLoaderInvalidProgramId = MAKERESULT(Module_Loader, 9); static constexpr Result ResultLoaderInvalidVersion = MAKERESULT(Module_Loader, 10); diff --git a/include/stratosphere/results/utilities.h b/include/stratosphere/results/utilities.h index 2638dc09..9a3d6c9a 100644 --- a/include/stratosphere/results/utilities.h +++ b/include/stratosphere/results/utilities.h @@ -8,6 +8,7 @@ #include #ifdef __cplusplus +#include extern "C" { #endif diff --git a/include/stratosphere/title_ids.hpp b/include/stratosphere/title_ids.hpp index 86dcfc9e..52531d5d 100644 --- a/include/stratosphere/title_ids.hpp +++ b/include/stratosphere/title_ids.hpp @@ -187,13 +187,13 @@ static inline bool TitleIdIsSystem(const u64 title_id) { } static inline bool TitleIdIsArchive(const u64 title_id) { - return TitleId_ArchiveStart <= title_id && title_id <= TitleId_ArchiveEnd; + return TitleId_ArchiveStart <= title_id && title_id <= TitleId_ArchiveEnd; } static inline bool TitleIdIsApplet(const u64 title_id) { - return TitleId_AppletStart <= title_id && title_id <= TitleId_AppletEnd; + return TitleId_AppletStart <= title_id && title_id <= TitleId_AppletEnd; } static inline bool TitleIdIsApplication(const u64 title_id) { - return TitleId_ApplicationStart <= title_id && title_id <= TitleId_ApplicationEnd; + return TitleId_ApplicationStart <= title_id && title_id <= TitleId_ApplicationEnd; } \ No newline at end of file diff --git a/source/cfg/cfg_flags.cpp b/source/cfg/cfg_flags.cpp new file mode 100644 index 00000000..48b8ef6b --- /dev/null +++ b/source/cfg/cfg_flags.cpp @@ -0,0 +1,74 @@ +/* + * 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 . + */ + +#include +#include +#include + +namespace sts::cfg { + + namespace { + + /* Helper. */ + bool HasFlagFile(const char *flag_path) { + /* All flags are not present until the SD card is. */ + if (!IsSdCardInitialized()) { + return false; + } + + /* Mount the SD card. */ + FsFileSystem sd_fs = {}; + if (R_FAILED(fsMountSdcard(&sd_fs))) { + return false; + } + ON_SCOPE_EXIT { serviceClose(&sd_fs.s); }; + + /* Open the file. */ + FsFile flag_file; + if (R_FAILED(fsFsOpenFile(&sd_fs, flag_path, FS_OPEN_READ, &flag_file))) { + return false; + } + fsFileClose(&flag_file); + + return true; + } + + } + + /* Flag utilities. */ + bool HasFlag(ncm::TitleId title_id, const char *flag) { + return HasTitleSpecificFlag(title_id, flag) || (IsHblTitleId(title_id) && HasHblFlag(flag)); + } + + bool HasTitleSpecificFlag(ncm::TitleId title_id, const char *flag) { + char title_flag[FS_MAX_PATH]; + std::snprintf(title_flag, sizeof(title_flag) - 1, "/atmosphere/titles/%016lx/flags/%s.flag", static_cast(title_id), flag); + return HasFlagFile(title_flag); + } + + bool HasGlobalFlag(const char *flag) { + char title_flag[FS_MAX_PATH]; + std::snprintf(title_flag, sizeof(title_flag) - 1, "/atmosphere/flags/%s.flag", flag); + return HasFlagFile(title_flag); + } + + bool HasHblFlag(const char *flag) { + char hbl_flag[0x100]; + std::snprintf(hbl_flag, sizeof(hbl_flag) - 1, "hbl_%s", flag); + return HasGlobalFlag(hbl_flag); + } + +} diff --git a/source/cfg/cfg_override.cpp b/source/cfg/cfg_override.cpp new file mode 100644 index 00000000..e6f1814a --- /dev/null +++ b/source/cfg/cfg_override.cpp @@ -0,0 +1,303 @@ +/* + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include + +namespace sts::cfg { + + namespace { + + /* Types. */ + struct OverrideKey { + u64 key_combination; + bool override_by_default; + }; + + struct HblOverrideConfig { + OverrideKey override_key; + ncm::TitleId title_id; + bool override_any_app; + }; + + struct TitleSpecificOverrideConfig { + OverrideKey override_key; + OverrideKey cheat_enable_key; + }; + + /* Override globals. */ + OverrideKey g_default_override_key = { + .key_combination = KEY_L, + .override_by_default = true, + }; + + OverrideKey g_default_cheat_enable_key = { + .key_combination = KEY_L, + .override_by_default = true, + }; + + HblOverrideConfig g_hbl_override_config = { + .override_key = { + .key_combination = KEY_R, + .override_by_default = false, + }, + .title_id = {TitleId_AppletPhotoViewer}, + .override_any_app = true, + }; + + char g_hbl_sd_path[0x100] = "/atmosphere/hbl.nsp"; + + /* Helpers. */ + OverrideKey ParseOverrideKey(const char *value) { + OverrideKey cfg = {}; + + /* Parse on by default. */ + if (value[0] == '!') { + cfg.override_by_default = true; + value++; + } + + /* Parse key combination. */ + if (strcasecmp(value, "A") == 0) { + cfg.key_combination = KEY_A; + } else if (strcasecmp(value, "B") == 0) { + cfg.key_combination = KEY_B; + } else if (strcasecmp(value, "X") == 0) { + cfg.key_combination = KEY_X; + } else if (strcasecmp(value, "Y") == 0) { + cfg.key_combination = KEY_Y; + } else if (strcasecmp(value, "LS") == 0) { + cfg.key_combination = KEY_LSTICK; + } else if (strcasecmp(value, "RS") == 0) { + cfg.key_combination = KEY_RSTICK; + } else if (strcasecmp(value, "L") == 0) { + cfg.key_combination = KEY_L; + } else if (strcasecmp(value, "R") == 0) { + cfg.key_combination = KEY_R; + } else if (strcasecmp(value, "ZL") == 0) { + cfg.key_combination = KEY_ZL; + } else if (strcasecmp(value, "ZR") == 0) { + cfg.key_combination = KEY_ZR; + } else if (strcasecmp(value, "PLUS") == 0) { + cfg.key_combination = KEY_PLUS; + } else if (strcasecmp(value, "MINUS") == 0) { + cfg.key_combination = KEY_MINUS; + } else if (strcasecmp(value, "DLEFT") == 0) { + cfg.key_combination = KEY_DLEFT; + } else if (strcasecmp(value, "DUP") == 0) { + cfg.key_combination = KEY_DUP; + } else if (strcasecmp(value, "DRIGHT") == 0) { + cfg.key_combination = KEY_DRIGHT; + } else if (strcasecmp(value, "DDOWN") == 0) { + cfg.key_combination = KEY_DDOWN; + } else if (strcasecmp(value, "SL") == 0) { + cfg.key_combination = KEY_SL; + } else if (strcasecmp(value, "SR") == 0) { + cfg.key_combination = KEY_SR; + } + + return cfg; + } + + int LoaderIniHandler(void *user, const char *section, const char *name, const char *value) { + /* Taken and modified, with love, from Rajkosto's implementation. */ + if (strcasecmp(section, "hbl_config") == 0) { + if (strcasecmp(name, "title_id") == 0) { + u64 override_tid = strtoul(value, NULL, 16); + if (override_tid != 0) { + g_hbl_override_config.title_id = {override_tid}; + } + } else if (strcasecmp(name, "path") == 0) { + while (*value == '/' || *value == '\\') { + value++; + } + std::snprintf(g_hbl_sd_path, sizeof(g_hbl_sd_path) - 1, "/%s", value); + g_hbl_sd_path[sizeof(g_hbl_sd_path) - 1] = '\0'; + } else if (strcasecmp(name, "override_key") == 0) { + g_hbl_override_config.override_key = ParseOverrideKey(value); + } else if (strcasecmp(name, "override_any_app") == 0) { + if (strcasecmp(value, "true") == 0 || strcasecmp(value, "1") == 0) { + g_hbl_override_config.override_any_app = true; + } else if (strcasecmp(value, "false") == 0 || strcasecmp(value, "0") == 0) { + g_hbl_override_config.override_any_app = false; + } else { + /* I guess we default to not changing the value? */ + } + } + } else if (strcasecmp(section, "default_config") == 0) { + if (strcasecmp(name, "override_key") == 0) { + g_default_override_key = ParseOverrideKey(value); + } else if (strcasecmp(name, "cheat_enable_key") == 0) { + g_default_cheat_enable_key = ParseOverrideKey(value); + } + } else { + return 0; + } + return 1; + } + + int TitleSpecificIniHandler(void *user, const char *section, const char *name, const char *value) { + TitleSpecificOverrideConfig *config = reinterpret_cast(user); + + if (strcasecmp(section, "override_config") == 0) { + if (strcasecmp(name, "override_key") == 0) { + config->override_key = ParseOverrideKey(value); + } else if (strcasecmp(name, "cheat_enable_key") == 0) { + config->cheat_enable_key = ParseOverrideKey(value); + } + } else { + return 0; + } + return 1; + } + + bool IsOverrideKeyHeld(OverrideKey *cfg) { + u64 kHeld = 0; + bool keys_triggered = (R_SUCCEEDED(hid::GetKeysHeld(&kHeld)) && ((kHeld & cfg->key_combination) != 0)); + return IsSdCardInitialized() && (cfg->override_by_default ^ keys_triggered); + } + + void ParseIniFile(util::ini::Handler handler, const char *path, void *user_ctx) { + /* Mount the SD card. */ + FsFileSystem sd_fs = {}; + if (R_FAILED(fsMountSdcard(&sd_fs))) { + return; + } + ON_SCOPE_EXIT { serviceClose(&sd_fs.s); }; + + /* Open the file. */ + FsFile config_file; + if (R_FAILED(fsFsOpenFile(&sd_fs, path, FS_OPEN_READ, &config_file))) { + return; + } + ON_SCOPE_EXIT { fsFileClose(&config_file); }; + + /* Parse the config. */ + util::ini::ParseFile(&config_file, user_ctx, handler); + } + + void RefreshLoaderConfiguration() { + ParseIniFile(LoaderIniHandler, "/atmosphere/loader.ini", nullptr); + } + + TitleSpecificOverrideConfig GetTitleOverrideConfig(ncm::TitleId title_id) { + char path[FS_MAX_PATH]; + std::snprintf(path, sizeof(path) - 1, "/atmosphere/titles/%016lx/config.ini", static_cast(title_id)); + + TitleSpecificOverrideConfig config = { + .override_key = g_default_override_key, + .cheat_enable_key = g_default_cheat_enable_key, + }; + ParseIniFile(TitleSpecificIniHandler, path, &config); + return config; + } + + } + + bool IsHblOverrideKeyHeld(ncm::TitleId title_id) { + /* If the SD card isn't initialized, we can't override. */ + if (!IsSdCardInitialized()) { + return false; + } + + /* For system modules and anything launched before the home menu, always override. */ + if (static_cast(title_id) < TitleId_AppletStart || !pm::info::HasLaunchedTitle(TitleId_AppletQlaunch)) { + return true; + } + + /* Unconditionally refresh loader.ini contents. */ + RefreshLoaderConfiguration(); + + /* Check HBL config. */ + return IsHblTitleId(title_id) && IsOverrideKeyHeld(&g_hbl_override_config.override_key); + } + + bool IsTitleOverrideKeyHeld(ncm::TitleId title_id) { + /* If the SD card isn't initialized, we can't override. */ + if (!IsSdCardInitialized()) { + return false; + } + + /* For system modules and anything launched before the home menu, always override. */ + if (static_cast(title_id) < TitleId_AppletStart || !pm::info::HasLaunchedTitle(TitleId_AppletQlaunch)) { + return true; + } + + /* Unconditionally refresh loader.ini contents. */ + RefreshLoaderConfiguration(); + + TitleSpecificOverrideConfig title_cfg = GetTitleOverrideConfig(title_id); + return IsOverrideKeyHeld(&title_cfg.override_key); + } + + void GetOverrideKeyHeldStatus(bool *out_hbl, bool *out_title, ncm::TitleId title_id) { + + /* If the SD card isn't initialized, we can't override. */ + if (!IsSdCardInitialized()) { + *out_hbl = false; + *out_title = false; + return; + } + + /* For system modules and anything launched before the home menu, always override. */ + if (static_cast(title_id) < TitleId_AppletStart || !pm::info::HasLaunchedTitle(TitleId_AppletQlaunch)) { + *out_hbl = false; + *out_title = true; + return; + } + + /* Unconditionally refresh loader.ini contents. */ + RefreshLoaderConfiguration(); + + /* Set HBL output. */ + *out_hbl = IsHblTitleId(title_id) && IsOverrideKeyHeld(&g_hbl_override_config.override_key); + + /* Set title specific output. */ + TitleSpecificOverrideConfig title_cfg = GetTitleOverrideConfig(title_id); + *out_title = IsOverrideKeyHeld(&title_cfg.override_key); + } + + bool IsCheatEnableKeyHeld(ncm::TitleId title_id) { + /* If the SD card isn't initialized, don't apply cheats. */ + if (!IsSdCardInitialized()) { + return false; + } + + /* Don't apply cheats to HBL. */ + if (IsHblOverrideKeyHeld(title_id)) { + return false; + } + + TitleSpecificOverrideConfig title_cfg = GetTitleOverrideConfig(title_id); + return IsOverrideKeyHeld(&title_cfg.cheat_enable_key); + } + + /* HBL Configuration utilities. */ + bool IsHblTitleId(ncm::TitleId title_id) { + return (g_hbl_override_config.override_any_app && TitleIdIsApplication(static_cast(title_id))) || (title_id == g_hbl_override_config.title_id); + } + + const char *GetHblPath() { + return g_hbl_sd_path; + } + + +} diff --git a/source/cfg/cfg_privileged_process.cpp b/source/cfg/cfg_privileged_process.cpp new file mode 100644 index 00000000..e33af937 --- /dev/null +++ b/source/cfg/cfg_privileged_process.cpp @@ -0,0 +1,85 @@ +/* + * 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 . + */ + +#include +#include +#include + +namespace sts::cfg { + + namespace { + + /* Convenience definitions. */ + constexpr u64 InitialProcessIdMinDeprecated = 0x00; + constexpr u64 InitialProcessIdMaxDeprecated = 0x50; + + /* Privileged process globals. */ + HosMutex g_lock; + bool g_detected_privileged_process = false; + bool g_is_privileged_process = false; + + /* SD card helpers. */ + void GetPrivilegedProcessIdRange(u64 *out_min, u64 *out_max) { + u64 min = 0, max = 0; + if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) { + /* On 5.0.0+, we can get precise limits from svcGetSystemInfo. */ + R_ASSERT(svcGetSystemInfo(&min, SystemInfoType_InitialProcessIdRange, INVALID_HANDLE, InitialProcessIdRangeInfo_Minimum)); + R_ASSERT(svcGetSystemInfo(&max, SystemInfoType_InitialProcessIdRange, INVALID_HANDLE, InitialProcessIdRangeInfo_Maximum)); + } else if (GetRuntimeFirmwareVersion() >= FirmwareVersion_400) { + /* On 4.0.0-4.1.0, we can get the precise limits from normal svcGetInfo. */ + R_ASSERT(svcGetInfo(&min, InfoType_InitialProcessIdRange, INVALID_HANDLE, InitialProcessIdRangeInfo_Minimum)); + R_ASSERT(svcGetInfo(&max, InfoType_InitialProcessIdRange, INVALID_HANDLE, InitialProcessIdRangeInfo_Maximum)); + } else { + /* On < 4.0.0, we just use hardcoded extents. */ + min = InitialProcessIdMinDeprecated; + max = InitialProcessIdMaxDeprecated; + } + + *out_min = min; + *out_max = max; + } + + u64 GetCurrentProcessId() { + u64 process_id = 0; + R_ASSERT(svcGetProcessId(&process_id, CUR_PROCESS_HANDLE)); + return process_id; + } + + void DetectIsPrivilegedProcess() { + u64 min = 0, max = 0, cur = 0; + GetPrivilegedProcessIdRange(&min, &max); + cur = GetCurrentProcessId(); + g_is_privileged_process = min <= cur && cur <= max; + g_detected_privileged_process = true; + } + + + } + + /* SD card utilities. */ + bool IsPrivilegedProcess() { + std::scoped_lock lk(g_lock); + + /* If we've already detected, return cached result. */ + if (!g_detected_privileged_process) { + DetectIsPrivilegedProcess(); + } + + /* Determine if we're privileged, and return. */ + return g_is_privileged_process; + } + +} diff --git a/source/cfg/cfg_sd_card.cpp b/source/cfg/cfg_sd_card.cpp new file mode 100644 index 00000000..a1c1ed7c --- /dev/null +++ b/source/cfg/cfg_sd_card.cpp @@ -0,0 +1,84 @@ +/* + * 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 . + */ + +#include +#include +#include +#include + +namespace sts::cfg { + + namespace { + + /* Convenience definitions. */ + constexpr sm::ServiceName RequiredServicesForSdCardAccess[] = { + sm::ServiceName::Encode("pcv"), + sm::ServiceName::Encode("gpio"), + sm::ServiceName::Encode("pinmux"), + sm::ServiceName::Encode("psc:c") + }; + constexpr size_t NumRequiredServicesForSdCardAccess = sizeof(RequiredServicesForSdCardAccess) / sizeof(RequiredServicesForSdCardAccess[0]); + + /* SD card globals. */ + HosMutex g_sd_card_lock; + bool g_sd_card_initialized = false; + FsFileSystem g_sd_card_filesystem = {}; + + /* SD card helpers. */ + Result TryInitializeSdCard() { + for (size_t i = 0; i < NumRequiredServicesForSdCardAccess; i++) { + bool service_present = false; + R_TRY(sm::HasService(&service_present, RequiredServicesForSdCardAccess[i])); + if (!service_present) { + return ResultFsSdCardNotPresent; + } + } + R_ASSERT(fsMountSdcard(&g_sd_card_filesystem)); + g_sd_card_initialized = true; + return ResultSuccess; + } + + void InitializeSdCard() { + for (size_t i = 0; i < NumRequiredServicesForSdCardAccess; i++) { + Service tmp; + R_ASSERT(sm::GetService(&tmp, RequiredServicesForSdCardAccess[i])); + serviceClose(&tmp); + } + R_ASSERT(fsMountSdcard(&g_sd_card_filesystem)); + g_sd_card_initialized = true; + } + + } + + /* SD card utilities. */ + bool IsSdCardInitialized() { + std::scoped_lock lk(g_sd_card_lock); + + if (!g_sd_card_initialized) { + if (R_SUCCEEDED(TryInitializeSdCard())) { + g_sd_card_initialized = true; + } + } + return g_sd_card_initialized; + } + + void WaitSdCardInitialized() { + std::scoped_lock lk(g_sd_card_lock); + + InitializeSdCard(); + } + +} diff --git a/source/hid/hid_api.cpp b/source/hid/hid_api.cpp new file mode 100644 index 00000000..cee7b577 --- /dev/null +++ b/source/hid/hid_api.cpp @@ -0,0 +1,70 @@ +/* + * 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 . + */ +#include +#include +#include +#include +#include + +namespace sts::hid { + + namespace { + + /* Global lock. */ + HosMutex g_hid_lock; + bool g_initialized_hid = false; + + /* Helper. */ + void InitializeHid() { + R_ASSERT(smInitialize()); + ON_SCOPE_EXIT { smExit(); }; + { + R_ASSERT(hidInitialize()); + } + } + + Result EnsureHidInitialized() { + if (!g_initialized_hid) { + if (!serviceIsActive(hidGetSessionService())) { + if (!pm::info::HasLaunchedTitle(TitleId_Hid)) { + return MAKERESULT(Module_Libnx, LibnxError_InitFail_HID); + } + InitializeHid(); + } + g_initialized_hid = true; + } + + return ResultSuccess; + } + + } + + Result GetKeysHeld(u64 *out) { + std::scoped_lock lk(g_hid_lock); + + R_TRY(EnsureHidInitialized()); + + hidScanInput(); + *out = 0; + + for (size_t controller = 0; controller < 10; controller++) { + *out |= hidKeysHeld(static_cast(controller)); + } + + return ResultSuccess; + } + +} diff --git a/source/ldr/ldr_ams.c b/source/ldr/ldr_ams.c new file mode 100644 index 00000000..94c042e1 --- /dev/null +++ b/source/ldr/ldr_ams.c @@ -0,0 +1,68 @@ +/* + * 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 . + */ + +#include +#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; + } + + return rc; +} + +Result ldrDmntAtmosphereHasLaunchedTitle(bool *out, u64 tid) { + return _ldrAtmosphereHasLaunchedTitle(ldrDmntGetServiceSession(), out, tid); +} + +Result ldrPmAtmosphereHasLaunchedTitle(bool *out, u64 tid) { + return _ldrAtmosphereHasLaunchedTitle(ldrPmGetServiceSession(), out, tid); +} diff --git a/source/ldr/ldr_ams.h b/source/ldr/ldr_ams.h new file mode 100644 index 00000000..9ca154a2 --- /dev/null +++ b/source/ldr/ldr_ams.h @@ -0,0 +1,19 @@ +/** + * @file ldr_ams.h + * @brief Loader (ldr:*) IPC wrapper for Atmosphere extensions. + * @author SciresM + * @copyright libnx Authors + */ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +Result ldrPmAtmosphereHasLaunchedTitle(bool *out, u64 tid); +Result ldrDmntAtmosphereHasLaunchedTitle(bool *out, u64 tid); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/source/ldr/ldr_pm_api.cpp b/source/ldr/ldr_pm_api.cpp new file mode 100644 index 00000000..4f4e5e0f --- /dev/null +++ b/source/ldr/ldr_pm_api.cpp @@ -0,0 +1,48 @@ +/* + * 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 . + */ +#include +#include +#include +#include +#include + +#include "ldr_ams.h" + +namespace sts::ldr::pm { + + /* Information API. */ + Result CreateProcess(Handle *out, PinId pin_id, u32 flags, Handle reslimit) { + return ldrPmCreateProcess(flags, pin_id.value, reslimit, out); + } + + Result GetProgramInfo(ProgramInfo *out, const ncm::TitleLocation &loc) { + return ldrPmGetProgramInfo(static_cast(loc.title_id), static_cast(loc.storage_id), reinterpret_cast(out)); + } + + Result PinTitle(PinId *out, const ncm::TitleLocation &loc) { + static_assert(sizeof(*out) == sizeof(u64), "PinId definition!"); + return ldrPmRegisterTitle(static_cast(loc.title_id), static_cast(loc.storage_id), reinterpret_cast(out)); + } + + Result UnpinTitle(PinId pin_id) { + return ldrPmUnregisterTitle(pin_id.value); + } + + Result HasLaunchedTitle(bool *out, ncm::TitleId title_id) { + return ldrPmAtmosphereHasLaunchedTitle(out, static_cast(title_id)); + } + +} diff --git a/source/map/map_api.cpp b/source/map/map_api.cpp index 60fdccd0..f6d70442 100644 --- a/source/map/map_api.cpp +++ b/source/map/map_api.cpp @@ -23,11 +23,6 @@ namespace sts::map { namespace { /* Convenience defines. */ - constexpr uintptr_t Deprecated64BitAslrBase = 0x08000000ul; - constexpr size_t Deprecated64BitAslrSize = 0x78000000ul; - constexpr uintptr_t Deprecated32BitAslrBase = 0x00200000ul; - constexpr size_t Deprecated32BitAslrSize = 0x3FE00000ul; - constexpr size_t GuardRegionSize = 0x4000; constexpr size_t LocateRetryCount = 0x200; @@ -194,12 +189,12 @@ namespace sts::map { R_TRY(svcGetInfo(&out->aslr_size, InfoType_AslrRegionSize, process_h, 0)); } else { /* Auto-detect 32-bit vs 64-bit. */ - if (out->heap_base < Deprecated64BitAslrBase || out->alias_base < Deprecated64BitAslrBase) { - out->aslr_base = Deprecated32BitAslrBase; - out->aslr_size = Deprecated32BitAslrSize; + if (out->heap_base < AslrBase64BitDeprecated || out->alias_base < AslrBase64BitDeprecated) { + out->aslr_base = AslrBase32Bit; + out->aslr_size = AslrSize32Bit; } else { - out->aslr_base = Deprecated64BitAslrBase; - out->aslr_size = Deprecated64BitAslrSize; + out->aslr_base = AslrBase64BitDeprecated; + out->aslr_size = AslrSize64BitDeprecated; } } diff --git a/source/pm/pm_ams.c b/source/pm/pm_ams.c new file mode 100644 index 00000000..46882eb0 --- /dev/null +++ b/source/pm/pm_ams.c @@ -0,0 +1,96 @@ +/* + * 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 . + */ + +#include +#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; +} + +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; + } + } + + return rc; +} diff --git a/source/pm/pm_ams.h b/source/pm/pm_ams.h new file mode 100644 index 00000000..78bc9ce9 --- /dev/null +++ b/source/pm/pm_ams.h @@ -0,0 +1,19 @@ +/** + * @file pm_ams.h + * @brief Process Manager (pm:*) IPC wrapper for Atmosphere extensions. + * @author SciresM + * @copyright libnx Authors + */ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +Result pminfoAtmosphereGetProcessId(u64 *out_pid, u64 tid); +Result pminfoAtmosphereHasLaunchedTitle(bool *out, u64 tid); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/source/pm/pm_info_api.cpp b/source/pm/pm_info_api.cpp new file mode 100644 index 00000000..3b62c341 --- /dev/null +++ b/source/pm/pm_info_api.cpp @@ -0,0 +1,70 @@ +/* + * 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 . + */ +#include +#include +#include +#include + +#include "pm_ams.h" + +namespace sts::pm::info { + + namespace { + + /* Global lock. */ + HosMutex g_info_lock; + std::set g_cached_launched_titles; + + } + + /* Information API. */ + Result GetTitleId(u64 *out_title_id, u64 process_id) { + std::scoped_lock lk(g_info_lock); + + return pminfoGetTitleId(out_title_id, process_id); + } + + Result GetProcessId(u64 *out_process_id, u64 title_id) { + std::scoped_lock lk(g_info_lock); + + return pminfoAtmosphereGetProcessId(out_process_id, title_id); + } + + Result __attribute__((weak)) HasLaunchedTitle(bool *out, u64 title_id) { + std::scoped_lock lk(g_info_lock); + + if (g_cached_launched_titles.find(title_id) != g_cached_launched_titles.end()) { + *out = true; + return ResultSuccess; + } + + bool has_launched = false; + R_TRY(pminfoAtmosphereHasLaunchedTitle(&has_launched, title_id)); + if (has_launched) { + g_cached_launched_titles.insert(title_id); + } + + *out = has_launched; + return ResultSuccess; + } + + bool HasLaunchedTitle(u64 title_id) { + bool has_launched = false; + R_ASSERT(HasLaunchedTitle(&has_launched, title_id)); + return has_launched; + } + +}