summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/arm/arm_interface.h5
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp13
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h4
-rw-r--r--src/core/file_sys/content_archive.cpp2
-rw-r--r--src/core/file_sys/content_archive.h2
-rw-r--r--src/core/file_sys/control_metadata.cpp26
-rw-r--r--src/core/file_sys/control_metadata.h9
-rw-r--r--src/core/file_sys/nca_metadata.cpp2
-rw-r--r--src/core/file_sys/nca_metadata.h1
-rw-r--r--src/core/file_sys/partition_filesystem.cpp2
-rw-r--r--src/core/file_sys/partition_filesystem.h2
-rw-r--r--src/core/file_sys/patch_manager.cpp2
-rw-r--r--src/core/file_sys/patch_manager.h1
-rw-r--r--src/core/file_sys/program_metadata.cpp4
-rw-r--r--src/core/file_sys/program_metadata.h3
-rw-r--r--src/core/file_sys/romfs_factory.cpp2
-rw-r--r--src/core/file_sys/romfs_factory.h1
-rw-r--r--src/core/file_sys/savedata_factory.cpp13
-rw-r--r--src/core/file_sys/savedata_factory.h1
-rw-r--r--src/core/file_sys/submission_package.h2
-rw-r--r--src/core/file_sys/vfs_concat.cpp2
-rw-r--r--src/core/file_sys/vfs_concat.h2
-rw-r--r--src/core/file_sys/vfs_offset.cpp2
-rw-r--r--src/core/file_sys/vfs_offset.h1
-rw-r--r--src/core/file_sys/vfs_vector.cpp2
-rw-r--r--src/core/file_sys/vfs_vector.h1
-rw-r--r--src/core/file_sys/xts_archive.cpp13
-rw-r--r--src/core/file_sys/xts_archive.h5
-rw-r--r--src/core/gdbstub/gdbstub.cpp2
-rw-r--r--src/core/hle/kernel/mutex.cpp1
-rw-r--r--src/core/hle/kernel/process.cpp89
-rw-r--r--src/core/hle/kernel/process.h55
-rw-r--r--src/core/hle/kernel/svc.cpp32
-rw-r--r--src/core/hle/kernel/thread.cpp64
-rw-r--r--src/core/hle/kernel/thread.h15
-rw-r--r--src/core/hle/service/audio/audren_u.cpp9
-rw-r--r--src/core/hle/service/fatal/fatal.cpp141
-rw-r--r--src/core/hle/service/fatal/fatal.h1
-rw-r--r--src/core/hle/service/fatal/fatal_u.cpp2
-rw-r--r--src/core/hle/service/hid/irs.cpp158
-rw-r--r--src/core/hle/service/hid/irs.h27
-rw-r--r--src/core/hle/service/nifm/nifm.cpp10
-rw-r--r--src/core/hle/service/nim/nim.cpp102
-rw-r--r--src/core/hle/service/ssl/ssl.cpp6
-rw-r--r--src/core/loader/nax.cpp26
-rw-r--r--src/core/loader/nax.h4
-rw-r--r--src/core/loader/nso.cpp15
47 files changed, 705 insertions, 179 deletions
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 867e34932..16d528994 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -6,7 +6,10 @@
#include <array>
#include "common/common_types.h"
-#include "core/hle/kernel/vm_manager.h"
+
+namespace Kernel {
+enum class VMAPermission : u8;
+}
namespace Core {
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 3f072c51f..7be5a38de 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -12,8 +12,10 @@
#include "core/core.h"
#include "core/core_cpu.h"
#include "core/core_timing.h"
+#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/svc.h"
+#include "core/hle/kernel/vm_manager.h"
#include "core/memory.h"
namespace Core {
@@ -79,6 +81,17 @@ public:
case Dynarmic::A64::Exception::SendEventLocal:
case Dynarmic::A64::Exception::Yield:
return;
+ case Dynarmic::A64::Exception::Breakpoint:
+ if (GDBStub::IsServerEnabled()) {
+ parent.jit->HaltExecution();
+ parent.SetPC(pc);
+ Kernel::Thread* thread = Kernel::GetCurrentThread();
+ parent.SaveContext(thread->context);
+ GDBStub::Break();
+ GDBStub::SendTrap(thread, 5);
+ return;
+ }
+ [[fallthrough]];
default:
ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:X})",
static_cast<std::size_t>(exception), pc);
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index e61382d3d..4ee92ee27 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -12,6 +12,10 @@
#include "core/arm/exclusive_monitor.h"
#include "core/arm/unicorn/arm_unicorn.h"
+namespace Memory {
+struct PageTable;
+}
+
namespace Core {
class ARM_Dynarmic_Callbacks;
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index 45fc0b574..aa1b3c17d 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -463,6 +463,8 @@ NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_off
status = Loader::ResultStatus::Success;
}
+NCA::~NCA() = default;
+
Loader::ResultStatus NCA::GetStatus() const {
return status;
}
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h
index 00eca52da..f9f66cae9 100644
--- a/src/core/file_sys/content_archive.h
+++ b/src/core/file_sys/content_archive.h
@@ -81,6 +81,8 @@ class NCA : public ReadOnlyVfsDirectory {
public:
explicit NCA(VirtualFile file, VirtualFile bktr_base_romfs = nullptr,
u64 bktr_base_ivfc_offset = 0);
+ ~NCA() override;
+
Loader::ResultStatus GetStatus() const;
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp
index e76bf77bf..5b1177a03 100644
--- a/src/core/file_sys/control_metadata.cpp
+++ b/src/core/file_sys/control_metadata.cpp
@@ -8,6 +8,14 @@
namespace FileSys {
+const std::array<const char*, 15> LANGUAGE_NAMES = {
+ "AmericanEnglish", "BritishEnglish", "Japanese",
+ "French", "German", "LatinAmericanSpanish",
+ "Spanish", "Italian", "Dutch",
+ "CanadianFrench", "Portugese", "Russian",
+ "Korean", "Taiwanese", "Chinese",
+};
+
std::string LanguageEntry::GetApplicationName() const {
return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(), 0x200);
}
@@ -20,18 +28,20 @@ NACP::NACP(VirtualFile file) : raw(std::make_unique<RawNACP>()) {
file->ReadObject(raw.get());
}
+NACP::~NACP() = default;
+
const LanguageEntry& NACP::GetLanguageEntry(Language language) const {
if (language != Language::Default) {
return raw->language_entries.at(static_cast<u8>(language));
- } else {
- for (const auto& language_entry : raw->language_entries) {
- if (!language_entry.GetApplicationName().empty())
- return language_entry;
- }
-
- // Fallback to English
- return GetLanguageEntry(Language::AmericanEnglish);
}
+
+ for (const auto& language_entry : raw->language_entries) {
+ if (!language_entry.GetApplicationName().empty())
+ return language_entry;
+ }
+
+ // Fallback to English
+ return GetLanguageEntry(Language::AmericanEnglish);
}
std::string NACP::GetApplicationName(Language language) const {
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h
index 8a510bf46..43d6f0719 100644
--- a/src/core/file_sys/control_metadata.h
+++ b/src/core/file_sys/control_metadata.h
@@ -66,18 +66,15 @@ enum class Language : u8 {
Default = 255,
};
-static constexpr std::array<const char*, 15> LANGUAGE_NAMES = {
- "AmericanEnglish", "BritishEnglish", "Japanese",
- "French", "German", "LatinAmericanSpanish",
- "Spanish", "Italian", "Dutch",
- "CanadianFrench", "Portugese", "Russian",
- "Korean", "Taiwanese", "Chinese"};
+extern const std::array<const char*, 15> LANGUAGE_NAMES;
// A class representing the format used by NX metadata files, typically named Control.nacp.
// These store application name, dev name, title id, and other miscellaneous data.
class NACP {
public:
explicit NACP(VirtualFile file);
+ ~NACP();
+
const LanguageEntry& GetLanguageEntry(Language language = Language::Default) const;
std::string GetApplicationName(Language language = Language::Default) const;
std::string GetDeveloperName(Language language = Language::Default) const;
diff --git a/src/core/file_sys/nca_metadata.cpp b/src/core/file_sys/nca_metadata.cpp
index 479916b69..6f34b7836 100644
--- a/src/core/file_sys/nca_metadata.cpp
+++ b/src/core/file_sys/nca_metadata.cpp
@@ -51,6 +51,8 @@ CNMT::CNMT(CNMTHeader header, OptionalHeader opt_header, std::vector<ContentReco
: header(std::move(header)), opt_header(std::move(opt_header)),
content_records(std::move(content_records)), meta_records(std::move(meta_records)) {}
+CNMT::~CNMT() = default;
+
u64 CNMT::GetTitleID() const {
return header.title_id;
}
diff --git a/src/core/file_sys/nca_metadata.h b/src/core/file_sys/nca_metadata.h
index da5a8dbe8..a05d155f4 100644
--- a/src/core/file_sys/nca_metadata.h
+++ b/src/core/file_sys/nca_metadata.h
@@ -87,6 +87,7 @@ public:
explicit CNMT(VirtualFile file);
CNMT(CNMTHeader header, OptionalHeader opt_header, std::vector<ContentRecord> content_records,
std::vector<MetaRecord> meta_records);
+ ~CNMT();
u64 GetTitleID() const;
u32 GetTitleVersion() const;
diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp
index f5b3b0175..5791c76ff 100644
--- a/src/core/file_sys/partition_filesystem.cpp
+++ b/src/core/file_sys/partition_filesystem.cpp
@@ -72,6 +72,8 @@ PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) {
status = Loader::ResultStatus::Success;
}
+PartitionFilesystem::~PartitionFilesystem() = default;
+
Loader::ResultStatus PartitionFilesystem::GetStatus() const {
return status;
}
diff --git a/src/core/file_sys/partition_filesystem.h b/src/core/file_sys/partition_filesystem.h
index e80d2456b..739c63a7f 100644
--- a/src/core/file_sys/partition_filesystem.h
+++ b/src/core/file_sys/partition_filesystem.h
@@ -25,6 +25,8 @@ namespace FileSys {
class PartitionFilesystem : public ReadOnlyVfsDirectory {
public:
explicit PartitionFilesystem(std::shared_ptr<VfsFile> file);
+ ~PartitionFilesystem() override;
+
Loader::ResultStatus GetStatus() const;
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index b37b4c68b..aebc69d52 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -41,6 +41,8 @@ std::string FormatPatchTypeName(PatchType type) {
PatchManager::PatchManager(u64 title_id) : title_id(title_id) {}
+PatchManager::~PatchManager() = default;
+
VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
LOG_INFO(Loader, "Patching ExeFS for title_id={:016X}", title_id);
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h
index b521977b2..209cab1dc 100644
--- a/src/core/file_sys/patch_manager.h
+++ b/src/core/file_sys/patch_manager.h
@@ -34,6 +34,7 @@ std::string FormatPatchTypeName(PatchType type);
class PatchManager {
public:
explicit PatchManager(u64 title_id);
+ ~PatchManager();
// Currently tracked ExeFS patches:
// - Game Updates
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp
index 9d19aaa6d..02319ce0f 100644
--- a/src/core/file_sys/program_metadata.cpp
+++ b/src/core/file_sys/program_metadata.cpp
@@ -12,6 +12,10 @@
namespace FileSys {
+ProgramMetadata::ProgramMetadata() = default;
+
+ProgramMetadata::~ProgramMetadata() = default;
+
Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
std::size_t total_size = static_cast<std::size_t>(file->GetSize());
if (total_size < sizeof(Header))
diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h
index 3c0a49f16..1143e36c4 100644
--- a/src/core/file_sys/program_metadata.h
+++ b/src/core/file_sys/program_metadata.h
@@ -36,6 +36,9 @@ enum class ProgramFilePermission : u64 {
*/
class ProgramMetadata {
public:
+ ProgramMetadata();
+ ~ProgramMetadata();
+
Loader::ResultStatus Load(VirtualFile file);
bool Is64BitProgram() const;
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp
index d9d90939e..3d1a3685e 100644
--- a/src/core/file_sys/romfs_factory.cpp
+++ b/src/core/file_sys/romfs_factory.cpp
@@ -28,6 +28,8 @@ RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader) {
ivfc_offset = app_loader.ReadRomFSIVFCOffset();
}
+RomFSFactory::~RomFSFactory() = default;
+
ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() {
if (!updatable)
return MakeResult<VirtualFile>(file);
diff --git a/src/core/file_sys/romfs_factory.h b/src/core/file_sys/romfs_factory.h
index 26b8f46cc..2cace8180 100644
--- a/src/core/file_sys/romfs_factory.h
+++ b/src/core/file_sys/romfs_factory.h
@@ -30,6 +30,7 @@ enum class StorageId : u8 {
class RomFSFactory {
public:
explicit RomFSFactory(Loader::AppLoader& app_loader);
+ ~RomFSFactory();
ResultVal<VirtualFile> OpenCurrentProcess();
ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, ContentRecordType type);
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index e437d34e5..9b2c51bbd 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -20,6 +20,8 @@ std::string SaveDataDescriptor::DebugInfo() const {
SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {}
+SaveDataFactory::~SaveDataFactory() = default;
+
ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, SaveDataDescriptor meta) {
if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) {
if (meta.zero_1 != 0) {
@@ -85,10 +87,10 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ
switch (space) {
case SaveDataSpaceId::NandSystem:
- out = "/system/save/";
+ out = "/system/";
break;
case SaveDataSpaceId::NandUser:
- out = "/user/save/";
+ out = "/user/";
break;
default:
ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space));
@@ -96,9 +98,12 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ
switch (type) {
case SaveDataType::SystemSaveData:
- return fmt::format("{}{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]);
+ return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]);
case SaveDataType::SaveData:
- return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
+ return fmt::format("{}save/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
+ title_id);
+ case SaveDataType::TemporaryStorage:
+ return fmt::format("{}temp/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
title_id);
default:
ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type));
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h
index ba978695b..d69ef6741 100644
--- a/src/core/file_sys/savedata_factory.h
+++ b/src/core/file_sys/savedata_factory.h
@@ -48,6 +48,7 @@ static_assert(sizeof(SaveDataDescriptor) == 0x40, "SaveDataDescriptor has incorr
class SaveDataFactory {
public:
explicit SaveDataFactory(VirtualDir dir);
+ ~SaveDataFactory();
ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta);
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h
index 1120a4920..e85a2b76e 100644
--- a/src/core/file_sys/submission_package.h
+++ b/src/core/file_sys/submission_package.h
@@ -24,7 +24,7 @@ enum class ContentRecordType : u8;
class NSP : public ReadOnlyVfsDirectory {
public:
explicit NSP(VirtualFile file);
- ~NSP();
+ ~NSP() override;
Loader::ResultStatus GetStatus() const;
Loader::ResultStatus GetProgramStatus(u64 title_id) const;
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp
index 25a980cbb..dc7a279a9 100644
--- a/src/core/file_sys/vfs_concat.cpp
+++ b/src/core/file_sys/vfs_concat.cpp
@@ -27,6 +27,8 @@ ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::s
}
}
+ConcatenatedVfsFile::~ConcatenatedVfsFile() = default;
+
std::string ConcatenatedVfsFile::GetName() const {
if (files.empty())
return "";
diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h
index 31775db7e..717d04bdc 100644
--- a/src/core/file_sys/vfs_concat.h
+++ b/src/core/file_sys/vfs_concat.h
@@ -22,6 +22,8 @@ class ConcatenatedVfsFile : public VfsFile {
ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name);
public:
+ ~ConcatenatedVfsFile() override;
+
std::string GetName() const override;
std::size_t GetSize() const override;
bool Resize(std::size_t new_size) override;
diff --git a/src/core/file_sys/vfs_offset.cpp b/src/core/file_sys/vfs_offset.cpp
index f5ed291ea..a4c6719a0 100644
--- a/src/core/file_sys/vfs_offset.cpp
+++ b/src/core/file_sys/vfs_offset.cpp
@@ -14,6 +14,8 @@ OffsetVfsFile::OffsetVfsFile(std::shared_ptr<VfsFile> file_, std::size_t size_,
: file(file_), offset(offset_), size(size_), name(std::move(name_)),
parent(parent_ == nullptr ? file->GetContainingDirectory() : std::move(parent_)) {}
+OffsetVfsFile::~OffsetVfsFile() = default;
+
std::string OffsetVfsFile::GetName() const {
return name.empty() ? file->GetName() : name;
}
diff --git a/src/core/file_sys/vfs_offset.h b/src/core/file_sys/vfs_offset.h
index 34cb180b3..8062702a7 100644
--- a/src/core/file_sys/vfs_offset.h
+++ b/src/core/file_sys/vfs_offset.h
@@ -19,6 +19,7 @@ class OffsetVfsFile : public VfsFile {
public:
OffsetVfsFile(std::shared_ptr<VfsFile> file, std::size_t size, std::size_t offset = 0,
std::string new_name = "", VirtualDir new_parent = nullptr);
+ ~OffsetVfsFile() override;
std::string GetName() const override;
std::size_t GetSize() const override;
diff --git a/src/core/file_sys/vfs_vector.cpp b/src/core/file_sys/vfs_vector.cpp
index 98e7c4598..ec7f735b5 100644
--- a/src/core/file_sys/vfs_vector.cpp
+++ b/src/core/file_sys/vfs_vector.cpp
@@ -13,6 +13,8 @@ VectorVfsDirectory::VectorVfsDirectory(std::vector<VirtualFile> files_,
: files(std::move(files_)), dirs(std::move(dirs_)), parent(std::move(parent_)),
name(std::move(name_)) {}
+VectorVfsDirectory::~VectorVfsDirectory() = default;
+
std::vector<std::shared_ptr<VfsFile>> VectorVfsDirectory::GetFiles() const {
return files;
}
diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h
index 179f62e4b..cba44a7a6 100644
--- a/src/core/file_sys/vfs_vector.h
+++ b/src/core/file_sys/vfs_vector.h
@@ -15,6 +15,7 @@ public:
explicit VectorVfsDirectory(std::vector<VirtualFile> files = {},
std::vector<VirtualDir> dirs = {}, std::string name = "",
VirtualDir parent = nullptr);
+ ~VectorVfsDirectory() override;
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
diff --git a/src/core/file_sys/xts_archive.cpp b/src/core/file_sys/xts_archive.cpp
index 0173f71c1..b2b164368 100644
--- a/src/core/file_sys/xts_archive.cpp
+++ b/src/core/file_sys/xts_archive.cpp
@@ -30,9 +30,6 @@ static bool CalculateHMAC256(Destination* out, const SourceKey* key, std::size_t
mbedtls_md_context_t context;
mbedtls_md_init(&context);
- const auto key_f = reinterpret_cast<const u8*>(key);
- const std::vector<u8> key_v(key_f, key_f + key_length);
-
if (mbedtls_md_setup(&context, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1) ||
mbedtls_md_hmac_starts(&context, reinterpret_cast<const u8*>(key), key_length) ||
mbedtls_md_hmac_update(&context, reinterpret_cast<const u8*>(data), data_length) ||
@@ -45,7 +42,7 @@ static bool CalculateHMAC256(Destination* out, const SourceKey* key, std::size_t
return true;
}
-NAX::NAX(VirtualFile file_) : file(std::move(file_)), header(std::make_unique<NAXHeader>()) {
+NAX::NAX(VirtualFile file_) : header(std::make_unique<NAXHeader>()), file(std::move(file_)) {
std::string path = FileUtil::SanitizePath(file->GetFullPath());
static const std::regex nax_path_regex("/registered/(000000[0-9A-F]{2})/([0-9A-F]{32})\\.nca",
std::regex_constants::ECMAScript |
@@ -65,13 +62,15 @@ NAX::NAX(VirtualFile file_) : file(std::move(file_)), header(std::make_unique<NA
}
NAX::NAX(VirtualFile file_, std::array<u8, 0x10> nca_id)
- : file(std::move(file_)), header(std::make_unique<NAXHeader>()) {
+ : header(std::make_unique<NAXHeader>()), file(std::move(file_)) {
Core::Crypto::SHA256Hash hash{};
mbedtls_sha256(nca_id.data(), nca_id.size(), hash.data(), 0);
status = Parse(fmt::format("/registered/000000{:02X}/{}.nca", hash[0],
Common::HexArrayToString(nca_id, false)));
}
+NAX::~NAX() = default;
+
Loader::ResultStatus NAX::Parse(std::string_view path) {
if (file->ReadObject(header.get()) != sizeof(NAXHeader))
return Loader::ResultStatus::ErrorBadNAXHeader;
@@ -138,9 +137,9 @@ VirtualFile NAX::GetDecrypted() const {
return dec_file;
}
-std::shared_ptr<NCA> NAX::AsNCA() const {
+std::unique_ptr<NCA> NAX::AsNCA() const {
if (type == NAXContentType::NCA)
- return std::make_shared<NCA>(GetDecrypted());
+ return std::make_unique<NCA>(GetDecrypted());
return nullptr;
}
diff --git a/src/core/file_sys/xts_archive.h b/src/core/file_sys/xts_archive.h
index 55d2154a6..8fedd8585 100644
--- a/src/core/file_sys/xts_archive.h
+++ b/src/core/file_sys/xts_archive.h
@@ -33,12 +33,13 @@ class NAX : public ReadOnlyVfsDirectory {
public:
explicit NAX(VirtualFile file);
explicit NAX(VirtualFile file, std::array<u8, 0x10> nca_id);
+ ~NAX() override;
Loader::ResultStatus GetStatus() const;
VirtualFile GetDecrypted() const;
- std::shared_ptr<NCA> AsNCA() const;
+ std::unique_ptr<NCA> AsNCA() const;
NAXContentType GetContentType() const;
@@ -60,7 +61,7 @@ private:
VirtualFile file;
Loader::ResultStatus status;
- NAXContentType type;
+ NAXContentType type{};
VirtualFile dec_file;
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index 1b04f68bf..0ecdd9f82 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -995,7 +995,7 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) {
breakpoint.addr = addr;
breakpoint.len = len;
Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size());
- static constexpr std::array<u8, 4> btrap{{0xd4, 0x20, 0x7d, 0x0}};
+ static constexpr std::array<u8, 4> btrap{{0x00, 0x7d, 0x20, 0xd4}};
Memory::WriteBlock(addr, btrap.data(), btrap.size());
Core::System::GetInstance().InvalidateCpuInstructionCaches();
p.insert({addr, breakpoint});
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 51f4544be..81675eac5 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -16,6 +16,7 @@
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/result.h"
+#include "core/memory.h"
namespace Kernel {
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 7a272d031..121f741fd 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -7,10 +7,12 @@
#include "common/assert.h"
#include "common/common_funcs.h"
#include "common/logging/log.h"
+#include "core/core.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"
+#include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/vm_manager.h"
#include "core/memory.h"
@@ -125,7 +127,92 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
vm_manager.LogLayout();
status = ProcessStatus::Running;
- Kernel::SetupMainThread(kernel, entry_point, main_thread_priority, this);
+ Kernel::SetupMainThread(kernel, entry_point, main_thread_priority, *this);
+}
+
+void Process::PrepareForTermination() {
+ status = ProcessStatus::Exited;
+
+ const auto stop_threads = [this](const std::vector<SharedPtr<Thread>>& thread_list) {
+ for (auto& thread : thread_list) {
+ if (thread->owner_process != this)
+ continue;
+
+ if (thread == GetCurrentThread())
+ continue;
+
+ // TODO(Subv): When are the other running/ready threads terminated?
+ ASSERT_MSG(thread->status == ThreadStatus::WaitSynchAny ||
+ thread->status == ThreadStatus::WaitSynchAll,
+ "Exiting processes with non-waiting threads is currently unimplemented");
+
+ thread->Stop();
+ }
+ };
+
+ auto& system = Core::System::GetInstance();
+ stop_threads(system.Scheduler(0)->GetThreadList());
+ stop_threads(system.Scheduler(1)->GetThreadList());
+ stop_threads(system.Scheduler(2)->GetThreadList());
+ stop_threads(system.Scheduler(3)->GetThreadList());
+}
+
+/**
+ * Finds a free location for the TLS section of a thread.
+ * @param tls_slots The TLS page array of the thread's owner process.
+ * Returns a tuple of (page, slot, alloc_needed) where:
+ * page: The index of the first allocated TLS page that has free slots.
+ * slot: The index of the first free slot in the indicated page.
+ * alloc_needed: Whether there's a need to allocate a new TLS page (All pages are full).
+ */
+static std::tuple<std::size_t, std::size_t, bool> FindFreeThreadLocalSlot(
+ const std::vector<std::bitset<8>>& tls_slots) {
+ // Iterate over all the allocated pages, and try to find one where not all slots are used.
+ for (std::size_t page = 0; page < tls_slots.size(); ++page) {
+ const auto& page_tls_slots = tls_slots[page];
+ if (!page_tls_slots.all()) {
+ // We found a page with at least one free slot, find which slot it is
+ for (std::size_t slot = 0; slot < page_tls_slots.size(); ++slot) {
+ if (!page_tls_slots.test(slot)) {
+ return std::make_tuple(page, slot, false);
+ }
+ }
+ }
+ }
+
+ return std::make_tuple(0, 0, true);
+}
+
+VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) {
+ auto [available_page, available_slot, needs_allocation] = FindFreeThreadLocalSlot(tls_slots);
+
+ if (needs_allocation) {
+ tls_slots.emplace_back(0); // The page is completely available at the start
+ available_page = tls_slots.size() - 1;
+ available_slot = 0; // Use the first slot in the new page
+
+ // Allocate some memory from the end of the linear heap for this region.
+ auto& tls_memory = thread.GetTLSMemory();
+ tls_memory->insert(tls_memory->end(), Memory::PAGE_SIZE, 0);
+
+ vm_manager.RefreshMemoryBlockMappings(tls_memory.get());
+
+ vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
+ tls_memory, 0, Memory::PAGE_SIZE, MemoryState::ThreadLocal);
+ }
+
+ tls_slots[available_page].set(available_slot);
+
+ return Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE +
+ available_slot * Memory::TLS_ENTRY_SIZE;
+}
+
+void Process::FreeTLSSlot(VAddr tls_address) {
+ const VAddr tls_base = tls_address - Memory::TLS_AREA_VADDR;
+ const VAddr tls_page = tls_base / Memory::PAGE_SIZE;
+ const VAddr tls_slot = (tls_base % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
+
+ tls_slots[tls_page].reset(tls_slot);
}
void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) {
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 81538f70c..04d74e572 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -131,6 +131,16 @@ public:
return HANDLE_TYPE;
}
+ /// Gets the current status of the process
+ ProcessStatus GetStatus() const {
+ return status;
+ }
+
+ /// Gets the unique ID that identifies this particular process.
+ u32 GetProcessID() const {
+ return process_id;
+ }
+
/// Title ID corresponding to the process
u64 program_id;
@@ -154,11 +164,6 @@ public:
u32 allowed_processor_mask = THREADPROCESSORID_DEFAULT_MASK;
u32 allowed_thread_priority_mask = 0xFFFFFFFF;
u32 is_virtual_address_memory_enabled = 0;
- /// Current status of the process
- ProcessStatus status;
-
- /// The ID of this process
- u32 process_id = 0;
/**
* Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them
@@ -171,13 +176,42 @@ public:
*/
void Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size);
+ /**
+ * Prepares a process for termination by stopping all of its threads
+ * and clearing any other resources.
+ */
+ void PrepareForTermination();
+
void LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr);
///////////////////////////////////////////////////////////////////////////////////////////////
// Memory Management
+ // Marks the next available region as used and returns the address of the slot.
+ VAddr MarkNextAvailableTLSSlotAsUsed(Thread& thread);
+
+ // Frees a used TLS slot identified by the given address
+ void FreeTLSSlot(VAddr tls_address);
+
+ ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
+ ResultCode HeapFree(VAddr target, u32 size);
+
+ ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size);
+
+ ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
+
VMManager vm_manager;
+private:
+ explicit Process(KernelCore& kernel);
+ ~Process() override;
+
+ /// Current status of the process
+ ProcessStatus status;
+
+ /// The ID of this process
+ u32 process_id = 0;
+
// Memory used to back the allocations in the regular heap. A single vector is used to cover
// the entire virtual address space extents that bound the allocations, including any holes.
// This makes deallocation and reallocation of holes fast and keeps process memory contiguous
@@ -197,17 +231,6 @@ public:
std::vector<std::bitset<8>> tls_slots;
std::string name;
-
- ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
- ResultCode HeapFree(VAddr target, u32 size);
-
- ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size);
-
- ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
-
-private:
- explicit Process(KernelCore& kernel);
- ~Process() override;
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 822c1894f..c9d212a4c 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -169,7 +169,7 @@ static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
return ERR_INVALID_HANDLE;
}
- *process_id = process->process_id;
+ *process_id = process->GetProcessID();
return RESULT_SUCCESS;
}
@@ -530,35 +530,13 @@ static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, VAdd
/// Exits the current process
static void ExitProcess() {
- LOG_INFO(Kernel_SVC, "Process {} exiting", Core::CurrentProcess()->process_id);
+ auto& current_process = Core::CurrentProcess();
- ASSERT_MSG(Core::CurrentProcess()->status == ProcessStatus::Running,
+ LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->GetProcessID());
+ ASSERT_MSG(current_process->GetStatus() == ProcessStatus::Running,
"Process has already exited");
- Core::CurrentProcess()->status = ProcessStatus::Exited;
-
- auto stop_threads = [](const std::vector<SharedPtr<Thread>>& thread_list) {
- for (auto& thread : thread_list) {
- if (thread->owner_process != Core::CurrentProcess())
- continue;
-
- if (thread == GetCurrentThread())
- continue;
-
- // TODO(Subv): When are the other running/ready threads terminated?
- ASSERT_MSG(thread->status == ThreadStatus::WaitSynchAny ||
- thread->status == ThreadStatus::WaitSynchAll,
- "Exiting processes with non-waiting threads is currently unimplemented");
-
- thread->Stop();
- }
- };
-
- auto& system = Core::System::GetInstance();
- stop_threads(system.Scheduler(0)->GetThreadList());
- stop_threads(system.Scheduler(1)->GetThreadList());
- stop_threads(system.Scheduler(2)->GetThreadList());
- stop_threads(system.Scheduler(3)->GetThreadList());
+ current_process->PrepareForTermination();
// Kill the current thread
GetCurrentThread()->Stop();
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index d4183d6e3..315f65338 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -65,10 +65,7 @@ void Thread::Stop() {
wait_objects.clear();
// Mark the TLS slot in the thread's page as free.
- const u64 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE;
- const u64 tls_slot =
- ((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
- Core::CurrentProcess()->tls_slots[tls_page].reset(tls_slot);
+ owner_process->FreeTLSSlot(tls_address);
}
void WaitCurrentThread_Sleep() {
@@ -178,32 +175,6 @@ void Thread::ResumeFromWait() {
}
/**
- * Finds a free location for the TLS section of a thread.
- * @param tls_slots The TLS page array of the thread's owner process.
- * Returns a tuple of (page, slot, alloc_needed) where:
- * page: The index of the first allocated TLS page that has free slots.
- * slot: The index of the first free slot in the indicated page.
- * alloc_needed: Whether there's a need to allocate a new TLS page (All pages are full).
- */
-static std::tuple<std::size_t, std::size_t, bool> GetFreeThreadLocalSlot(
- const std::vector<std::bitset<8>>& tls_slots) {
- // Iterate over all the allocated pages, and try to find one where not all slots are used.
- for (std::size_t page = 0; page < tls_slots.size(); ++page) {
- const auto& page_tls_slots = tls_slots[page];
- if (!page_tls_slots.all()) {
- // We found a page with at least one free slot, find which slot it is
- for (std::size_t slot = 0; slot < page_tls_slots.size(); ++slot) {
- if (!page_tls_slots.test(slot)) {
- return std::make_tuple(page, slot, false);
- }
- }
- }
- }
-
- return std::make_tuple(0, 0, true);
-}
-
-/**
* Resets a thread context, making it ready to be scheduled and run by the CPU
* @param context Thread context to reset
* @param stack_top Address of the top of the stack
@@ -264,32 +235,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
thread->owner_process = owner_process;
thread->scheduler = Core::System::GetInstance().Scheduler(processor_id);
thread->scheduler->AddThread(thread, priority);
-
- // Find the next available TLS index, and mark it as used
- auto& tls_slots = owner_process->tls_slots;
-
- auto [available_page, available_slot, needs_allocation] = GetFreeThreadLocalSlot(tls_slots);
- if (needs_allocation) {
- tls_slots.emplace_back(0); // The page is completely available at the start
- available_page = tls_slots.size() - 1;
- available_slot = 0; // Use the first slot in the new page
-
- // Allocate some memory from the end of the linear heap for this region.
- const std::size_t offset = thread->tls_memory->size();
- thread->tls_memory->insert(thread->tls_memory->end(), Memory::PAGE_SIZE, 0);
-
- auto& vm_manager = owner_process->vm_manager;
- vm_manager.RefreshMemoryBlockMappings(thread->tls_memory.get());
-
- vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
- thread->tls_memory, 0, Memory::PAGE_SIZE,
- MemoryState::ThreadLocal);
- }
-
- // Mark the slot as used
- tls_slots[available_page].set(available_slot);
- thread->tls_address = Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE +
- available_slot * Memory::TLS_ENTRY_SIZE;
+ thread->tls_address = thread->owner_process->MarkNextAvailableTLSSlotAsUsed(*thread);
// TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
// to initialize the context
@@ -311,13 +257,13 @@ void Thread::BoostPriority(u32 priority) {
}
SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority,
- SharedPtr<Process> owner_process) {
+ Process& owner_process) {
// Setup page table so we can write to memory
- SetCurrentPageTable(&Core::CurrentProcess()->vm_manager.page_table);
+ SetCurrentPageTable(&owner_process.vm_manager.page_table);
// Initialize new "main" thread
auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0,
- Memory::STACK_AREA_VADDR_END, std::move(owner_process));
+ Memory::STACK_AREA_VADDR_END, &owner_process);
SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index df4748942..4250144c3 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -62,6 +62,9 @@ enum class ThreadWakeupReason {
class Thread final : public WaitObject {
public:
+ using TLSMemory = std::vector<u8>;
+ using TLSMemoryPtr = std::shared_ptr<TLSMemory>;
+
/**
* Creates and returns a new thread. The new thread is immediately scheduled
* @param kernel The kernel instance this thread will be created under.
@@ -134,6 +137,14 @@ public:
return thread_id;
}
+ TLSMemoryPtr& GetTLSMemory() {
+ return tls_memory;
+ }
+
+ const TLSMemoryPtr& GetTLSMemory() const {
+ return tls_memory;
+ }
+
/**
* Resumes a thread from waiting
*/
@@ -269,7 +280,7 @@ private:
explicit Thread(KernelCore& kernel);
~Thread() override;
- std::shared_ptr<std::vector<u8>> tls_memory = std::make_shared<std::vector<u8>>();
+ TLSMemoryPtr tls_memory = std::make_shared<TLSMemory>();
};
/**
@@ -281,7 +292,7 @@ private:
* @return A shared pointer to the main thread
*/
SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority,
- SharedPtr<Process> owner_process);
+ Process& owner_process);
/**
* Gets the current thread
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 06ac6372d..80ed4b152 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -25,7 +25,7 @@ public:
{0, &IAudioRenderer::GetAudioRendererSampleRate, "GetAudioRendererSampleRate"},
{1, &IAudioRenderer::GetAudioRendererSampleCount, "GetAudioRendererSampleCount"},
{2, &IAudioRenderer::GetAudioRendererMixBufferCount, "GetAudioRendererMixBufferCount"},
- {3, nullptr, "GetAudioRendererState"},
+ {3, &IAudioRenderer::GetAudioRendererState, "GetAudioRendererState"},
{4, &IAudioRenderer::RequestUpdateAudioRenderer, "RequestUpdateAudioRenderer"},
{5, &IAudioRenderer::StartAudioRenderer, "StartAudioRenderer"},
{6, &IAudioRenderer::StopAudioRenderer, "StopAudioRenderer"},
@@ -62,6 +62,13 @@ private:
LOG_DEBUG(Service_Audio, "called");
}
+ void GetAudioRendererState(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(renderer->GetState());
+ LOG_DEBUG(Service_Audio, "called");
+ }
+
void GetAudioRendererMixBufferCount(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp
index b436ce4e6..6de7edf9e 100644
--- a/src/core/hle/service/fatal/fatal.cpp
+++ b/src/core/hle/service/fatal/fatal.cpp
@@ -2,8 +2,17 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <array>
+#include <cstring>
+#include <ctime>
+#include <fmt/time.h>
+#include "common/common_paths.h"
+#include "common/file_util.h"
#include "common/logging/log.h"
+#include "common/scm_rev.h"
+#include "common/swap.h"
#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/process.h"
#include "core/hle/service/fatal/fatal.h"
#include "core/hle/service/fatal/fatal_p.h"
#include "core/hle/service/fatal/fatal_u.h"
@@ -15,16 +24,142 @@ Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
Module::Interface::~Interface() = default;
+struct FatalInfo {
+ std::array<u64_le, 31> registers{}; // TODO(ogniK): See if this actually is registers or
+ // not(find a game which has non zero valeus)
+ u64_le unk0{};
+ u64_le unk1{};
+ u64_le unk2{};
+ u64_le unk3{};
+ u64_le unk4{};
+ u64_le unk5{};
+ u64_le unk6{};
+
+ std::array<u64_le, 32> backtrace{};
+ u64_le unk7{};
+ u64_le unk8{};
+ u32_le backtrace_size{};
+ u32_le unk9{};
+ u32_le unk10{}; // TODO(ogniK): Is this even used or is it just padding?
+};
+static_assert(sizeof(FatalInfo) == 0x250, "FatalInfo is an invalid size");
+
+enum class FatalType : u32 {
+ ErrorReportAndScreen = 0,
+ ErrorReport = 1,
+ ErrorScreen = 2,
+};
+
+static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) {
+ const auto title_id = Core::CurrentProcess()->program_id;
+ std::string crash_report =
+ fmt::format("Yuzu {}-{} crash report\n"
+ "Title ID: {:016x}\n"
+ "Result: 0x{:X} ({:04}-{:04d})\n"
+ "\n",
+ Common::g_scm_branch, Common::g_scm_desc, title_id, error_code.raw,
+ 2000 + static_cast<u32>(error_code.module.Value()),
+ static_cast<u32>(error_code.description.Value()), info.unk8, info.unk7);
+ if (info.backtrace_size != 0x0) {
+ crash_report += "Registers:\n";
+ // TODO(ogniK): This is just a guess, find a game which actually has non zero values
+ for (size_t i = 0; i < info.registers.size(); i++) {
+ crash_report +=
+ fmt::format(" X[{:02d}]: {:016x}\n", i, info.registers[i]);
+ }
+ crash_report += fmt::format(" Unknown 0: {:016x}\n", info.unk0);
+ crash_report += fmt::format(" Unknown 1: {:016x}\n", info.unk1);
+ crash_report += fmt::format(" Unknown 2: {:016x}\n", info.unk2);
+ crash_report += fmt::format(" Unknown 3: {:016x}\n", info.unk3);
+ crash_report += fmt::format(" Unknown 4: {:016x}\n", info.unk4);
+ crash_report += fmt::format(" Unknown 5: {:016x}\n", info.unk5);
+ crash_report += fmt::format(" Unknown 6: {:016x}\n", info.unk6);
+ crash_report += "\nBacktrace:\n";
+ for (size_t i = 0; i < info.backtrace_size; i++) {
+ crash_report +=
+ fmt::format(" Backtrace[{:02d}]: {:016x}\n", i, info.backtrace[i]);
+ }
+ crash_report += fmt::format("\nUnknown 7: 0x{:016x}\n", info.unk7);
+ crash_report += fmt::format("Unknown 8: 0x{:016x}\n", info.unk8);
+ crash_report += fmt::format("Unknown 9: 0x{:016x}\n", info.unk9);
+ crash_report += fmt::format("Unknown 10: 0x{:016x}\n", info.unk10);
+ }
+
+ LOG_ERROR(Service_Fatal, "{}", crash_report);
+
+ const std::string crashreport_dir =
+ FileUtil::GetUserPath(FileUtil::UserPath::LogDir) + "crash_logs";
+
+ if (!FileUtil::CreateFullPath(crashreport_dir)) {
+ LOG_ERROR(
+ Service_Fatal,
+ "Unable to create crash report directory. Possible log directory permissions issue.");
+ return;
+ }
+
+ const std::time_t t = std::time(nullptr);
+ const std::string crashreport_filename =
+ fmt::format("{}/{:016x}-{:%F-%H%M%S}.log", crashreport_dir, title_id, *std::localtime(&t));
+
+ auto file = FileUtil::IOFile(crashreport_filename, "wb");
+ if (file.IsOpen()) {
+ file.WriteString(crash_report);
+ LOG_ERROR(Service_Fatal, "Saving error report to {}", crashreport_filename);
+ } else {
+ LOG_ERROR(Service_Fatal, "Failed to save error report to {}", crashreport_filename);
+ }
+}
+
+static void ThrowFatalError(ResultCode error_code, FatalType fatal_type, const FatalInfo& info) {
+ LOG_ERROR(Service_Fatal, "Threw fatal error type {}", static_cast<u32>(fatal_type));
+ switch (fatal_type) {
+ case FatalType::ErrorReportAndScreen:
+ GenerateErrorReport(error_code, info);
+ [[fallthrough]];
+ case FatalType::ErrorScreen:
+ // Since we have no fatal:u error screen. We should just kill execution instead
+ ASSERT(false);
+ break;
+ // Should not throw a fatal screen but should generate an error report
+ case FatalType::ErrorReport:
+ GenerateErrorReport(error_code, info);
+ break;
+ };
+}
+
+void Module::Interface::ThrowFatal(Kernel::HLERequestContext& ctx) {
+ LOG_ERROR(Service_Fatal, "called");
+ IPC::RequestParser rp{ctx};
+ auto error_code = rp.Pop<ResultCode>();
+
+ ThrowFatalError(error_code, FatalType::ErrorScreen, {});
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
void Module::Interface::ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx) {
+ LOG_ERROR(Service_Fatal, "called");
IPC::RequestParser rp(ctx);
- u32 error_code = rp.Pop<u32>();
- LOG_WARNING(Service_Fatal, "(STUBBED) called, error_code=0x{:X}", error_code);
+ auto error_code = rp.Pop<ResultCode>();
+ auto fatal_type = rp.PopEnum<FatalType>();
+
+ ThrowFatalError(error_code, fatal_type, {}); // No info is passed with ThrowFatalWithPolicy
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void Module::Interface::ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_Fatal, "(STUBBED) called");
+ LOG_ERROR(Service_Fatal, "called");
+ IPC::RequestParser rp(ctx);
+ auto error_code = rp.Pop<ResultCode>();
+ auto fatal_type = rp.PopEnum<FatalType>();
+ auto fatal_info = ctx.ReadBuffer();
+ FatalInfo info{};
+
+ ASSERT_MSG(fatal_info.size() == sizeof(FatalInfo), "Invalid fatal info buffer size!");
+ std::memcpy(&info, fatal_info.data(), sizeof(FatalInfo));
+
+ ThrowFatalError(error_code, fatal_type, info);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
diff --git a/src/core/hle/service/fatal/fatal.h b/src/core/hle/service/fatal/fatal.h
index 4d9a5be52..09371ff7f 100644
--- a/src/core/hle/service/fatal/fatal.h
+++ b/src/core/hle/service/fatal/fatal.h
@@ -15,6 +15,7 @@ public:
explicit Interface(std::shared_ptr<Module> module, const char* name);
~Interface() override;
+ void ThrowFatal(Kernel::HLERequestContext& ctx);
void ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx);
void ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/fatal/fatal_u.cpp b/src/core/hle/service/fatal/fatal_u.cpp
index befc307cf..1572a2051 100644
--- a/src/core/hle/service/fatal/fatal_u.cpp
+++ b/src/core/hle/service/fatal/fatal_u.cpp
@@ -8,7 +8,7 @@ namespace Service::Fatal {
Fatal_U::Fatal_U(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "fatal:u") {
static const FunctionInfo functions[] = {
- {0, nullptr, "ThrowFatal"},
+ {0, &Fatal_U::ThrowFatal, "ThrowFatal"},
{1, &Fatal_U::ThrowFatalWithPolicy, "ThrowFatalWithPolicy"},
{2, &Fatal_U::ThrowFatalWithCpuContext, "ThrowFatalWithCpuContext"},
};
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp
index e587ad0d8..872e3c344 100644
--- a/src/core/hle/service/hid/irs.cpp
+++ b/src/core/hle/service/hid/irs.cpp
@@ -2,6 +2,11 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/swap.h"
+#include "core/core.h"
+#include "core/core_timing.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/shared_memory.h"
#include "core/hle/service/hid/irs.h"
namespace Service::HID {
@@ -9,28 +14,145 @@ namespace Service::HID {
IRS::IRS() : ServiceFramework{"irs"} {
// clang-format off
static const FunctionInfo functions[] = {
- {302, nullptr, "ActivateIrsensor"},
- {303, nullptr, "DeactivateIrsensor"},
- {304, nullptr, "GetIrsensorSharedMemoryHandle"},
- {305, nullptr, "StopImageProcessor"},
- {306, nullptr, "RunMomentProcessor"},
- {307, nullptr, "RunClusteringProcessor"},
- {308, nullptr, "RunImageTransferProcessor"},
- {309, nullptr, "GetImageTransferProcessorState"},
- {310, nullptr, "RunTeraPluginProcessor"},
- {311, nullptr, "GetNpadIrCameraHandle"},
- {312, nullptr, "RunPointingProcessor"},
- {313, nullptr, "SuspendImageProcessor"},
- {314, nullptr, "CheckFirmwareVersion"},
- {315, nullptr, "SetFunctionLevel"},
- {316, nullptr, "RunImageTransferExProcessor"},
- {317, nullptr, "RunIrLedProcessor"},
- {318, nullptr, "StopImageProcessorAsync"},
- {319, nullptr, "ActivateIrsensorWithFunctionLevel"},
+ {302, &IRS::ActivateIrsensor, "ActivateIrsensor"},
+ {303, &IRS::DeactivateIrsensor, "DeactivateIrsensor"},
+ {304, &IRS::GetIrsensorSharedMemoryHandle, "GetIrsensorSharedMemoryHandle"},
+ {305, &IRS::StopImageProcessor, "StopImageProcessor"},
+ {306, &IRS::RunMomentProcessor, "RunMomentProcessor"},
+ {307, &IRS::RunClusteringProcessor, "RunClusteringProcessor"},
+ {308, &IRS::RunImageTransferProcessor, "RunImageTransferProcessor"},
+ {309, &IRS::GetImageTransferProcessorState, "GetImageTransferProcessorState"},
+ {310, &IRS::RunTeraPluginProcessor, "RunTeraPluginProcessor"},
+ {311, &IRS::GetNpadIrCameraHandle, "GetNpadIrCameraHandle"},
+ {312, &IRS::RunPointingProcessor, "RunPointingProcessor"},
+ {313, &IRS::SuspendImageProcessor, "SuspendImageProcessor"},
+ {314, &IRS::CheckFirmwareVersion, "CheckFirmwareVersion"},
+ {315, &IRS::SetFunctionLevel, "SetFunctionLevel"},
+ {316, &IRS::RunImageTransferExProcessor, "RunImageTransferExProcessor"},
+ {317, &IRS::RunIrLedProcessor, "RunIrLedProcessor"},
+ {318, &IRS::StopImageProcessorAsync, "StopImageProcessorAsync"},
+ {319, &IRS::ActivateIrsensorWithFunctionLevel, "ActivateIrsensorWithFunctionLevel"},
};
// clang-format on
RegisterHandlers(functions);
+
+ auto& kernel = Core::System::GetInstance().Kernel();
+ shared_mem = Kernel::SharedMemory::Create(
+ kernel, nullptr, 0x8000, Kernel::MemoryPermission::ReadWrite,
+ Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "IRS:SharedMemory");
+}
+
+void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(shared_mem);
+ LOG_DEBUG(Service_IRS, "called");
+}
+
+void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 5};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw<u64>(CoreTiming::GetTicks());
+ rb.PushRaw<u32>(0);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw<u32>(device_handle);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
}
IRS::~IRS() = default;
diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h
index 6fb16b45d..12de6bfb3 100644
--- a/src/core/hle/service/hid/irs.h
+++ b/src/core/hle/service/hid/irs.h
@@ -4,14 +4,41 @@
#pragma once
+#include "core/hle/kernel/object.h"
#include "core/hle/service/service.h"
+namespace Kernel {
+class SharedMemory;
+}
+
namespace Service::HID {
class IRS final : public ServiceFramework<IRS> {
public:
explicit IRS();
~IRS() override;
+
+private:
+ void ActivateIrsensor(Kernel::HLERequestContext& ctx);
+ void DeactivateIrsensor(Kernel::HLERequestContext& ctx);
+ void GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx);
+ void StopImageProcessor(Kernel::HLERequestContext& ctx);
+ void RunMomentProcessor(Kernel::HLERequestContext& ctx);
+ void RunClusteringProcessor(Kernel::HLERequestContext& ctx);
+ void RunImageTransferProcessor(Kernel::HLERequestContext& ctx);
+ void GetImageTransferProcessorState(Kernel::HLERequestContext& ctx);
+ void RunTeraPluginProcessor(Kernel::HLERequestContext& ctx);
+ void GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx);
+ void RunPointingProcessor(Kernel::HLERequestContext& ctx);
+ void SuspendImageProcessor(Kernel::HLERequestContext& ctx);
+ void CheckFirmwareVersion(Kernel::HLERequestContext& ctx);
+ void SetFunctionLevel(Kernel::HLERequestContext& ctx);
+ void RunImageTransferExProcessor(Kernel::HLERequestContext& ctx);
+ void RunIrLedProcessor(Kernel::HLERequestContext& ctx);
+ void StopImageProcessorAsync(Kernel::HLERequestContext& ctx);
+ void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx);
+ Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
+ const u32 device_handle{0xABCD};
};
class IRS_SYS final : public ServiceFramework<IRS_SYS> {
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index b6075f256..10611ed6a 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -31,7 +31,7 @@ public:
{1, &IRequest::GetResult, "GetResult"},
{2, &IRequest::GetSystemEventReadableHandles, "GetSystemEventReadableHandles"},
{3, &IRequest::Cancel, "Cancel"},
- {4, nullptr, "Submit"},
+ {4, &IRequest::Submit, "Submit"},
{5, nullptr, "SetRequirement"},
{6, nullptr, "SetRequirementPreset"},
{8, nullptr, "SetPriority"},
@@ -61,11 +61,17 @@ public:
}
private:
+ void Submit(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_NIFM, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
void GetRequestState(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- rb.Push<u32>(3);
+ rb.Push<u32>(0);
}
void GetResult(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp
index bd05b0a70..c1737defa 100644
--- a/src/core/hle/service/nim/nim.cpp
+++ b/src/core/hle/service/nim/nim.cpp
@@ -2,6 +2,10 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <chrono>
+#include <ctime>
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/event.h"
#include "core/hle/service/nim/nim.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
@@ -100,19 +104,111 @@ public:
}
};
+class IEnsureNetworkClockAvailabilityService final
+ : public ServiceFramework<IEnsureNetworkClockAvailabilityService> {
+public:
+ IEnsureNetworkClockAvailabilityService()
+ : ServiceFramework("IEnsureNetworkClockAvailabilityService") {
+ static const FunctionInfo functions[] = {
+ {0, &IEnsureNetworkClockAvailabilityService::StartTask, "StartTask"},
+ {1, &IEnsureNetworkClockAvailabilityService::GetFinishNotificationEvent,
+ "GetFinishNotificationEvent"},
+ {2, &IEnsureNetworkClockAvailabilityService::GetResult, "GetResult"},
+ {3, &IEnsureNetworkClockAvailabilityService::Cancel, "Cancel"},
+ {4, &IEnsureNetworkClockAvailabilityService::IsProcessing, "IsProcessing"},
+ {5, &IEnsureNetworkClockAvailabilityService::GetServerTime, "GetServerTime"},
+ };
+ RegisterHandlers(functions);
+
+ auto& kernel = Core::System::GetInstance().Kernel();
+ finished_event =
+ Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
+ "IEnsureNetworkClockAvailabilityService:FinishEvent");
+ }
+
+private:
+ Kernel::SharedPtr<Kernel::Event> finished_event;
+
+ void StartTask(Kernel::HLERequestContext& ctx) {
+ // No need to connect to the internet, just finish the task straight away.
+ finished_event->Signal();
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_DEBUG(Service_NIM, "called");
+ }
+
+ void GetFinishNotificationEvent(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(finished_event);
+ LOG_DEBUG(Service_NIM, "called");
+ }
+
+ void GetResult(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_DEBUG(Service_NIM, "called");
+ }
+
+ void Cancel(Kernel::HLERequestContext& ctx) {
+ finished_event->Clear();
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_DEBUG(Service_NIM, "called");
+ }
+
+ void IsProcessing(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw<u32>(0); // We instantly process the request
+ LOG_DEBUG(Service_NIM, "called");
+ }
+
+ void GetServerTime(Kernel::HLERequestContext& ctx) {
+ const s64 server_time{std::chrono::duration_cast<std::chrono::seconds>(
+ std::chrono::system_clock::now().time_since_epoch())
+ .count()};
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw<s64>(server_time);
+ LOG_DEBUG(Service_NIM, "called");
+ }
+};
+
class NTC final : public ServiceFramework<NTC> {
public:
explicit NTC() : ServiceFramework{"ntc"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "OpenEnsureNetworkClockAvailabilityService"},
- {100, nullptr, "SuspendAutonomicTimeCorrection"},
- {101, nullptr, "ResumeAutonomicTimeCorrection"},
+ {0, &NTC::OpenEnsureNetworkClockAvailabilityService, "OpenEnsureNetworkClockAvailabilityService"},
+ {100, &NTC::SuspendAutonomicTimeCorrection, "SuspendAutonomicTimeCorrection"},
+ {101, &NTC::ResumeAutonomicTimeCorrection, "ResumeAutonomicTimeCorrection"},
};
// clang-format on
RegisterHandlers(functions);
}
+
+private:
+ void OpenEnsureNetworkClockAvailabilityService(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>();
+ LOG_DEBUG(Service_NIM, "called");
+ }
+
+ // TODO(ogniK): Do we need these?
+ void SuspendAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_NIM, "(STUBBED) called");
+ }
+
+ void ResumeAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_NIM, "(STUBBED) called");
+ }
};
void InstallInterfaces(SM::ServiceManager& sm) {
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp
index fe0a318ee..bc4f7a437 100644
--- a/src/core/hle/service/ssl/ssl.cpp
+++ b/src/core/hle/service/ssl/ssl.cpp
@@ -103,6 +103,7 @@ public:
}
private:
+ u32 ssl_version{};
void CreateContext(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_SSL, "(STUBBED) called");
@@ -112,10 +113,9 @@ private:
}
void SetInterfaceVersion(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_SSL, "(STUBBED) called");
+ LOG_DEBUG(Service_SSL, "called");
IPC::RequestParser rp{ctx};
- u32 unk1 = rp.Pop<u32>(); // Probably minor/major?
- u32 unk2 = rp.Pop<u32>(); // TODO(ogniK): Figure out what this does
+ ssl_version = rp.Pop<u32>();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp
index b46d81c02..5d4380684 100644
--- a/src/core/loader/nax.cpp
+++ b/src/core/loader/nax.cpp
@@ -11,6 +11,20 @@
#include "core/loader/nca.h"
namespace Loader {
+namespace {
+FileType IdentifyTypeImpl(const FileSys::NAX& nax) {
+ if (nax.GetStatus() != ResultStatus::Success) {
+ return FileType::Error;
+ }
+
+ const auto nca = nax.AsNCA();
+ if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) {
+ return FileType::Error;
+ }
+
+ return FileType::NAX;
+}
+} // Anonymous namespace
AppLoader_NAX::AppLoader_NAX(FileSys::VirtualFile file)
: AppLoader(file), nax(std::make_unique<FileSys::NAX>(file)),
@@ -19,14 +33,12 @@ AppLoader_NAX::AppLoader_NAX(FileSys::VirtualFile file)
AppLoader_NAX::~AppLoader_NAX() = default;
FileType AppLoader_NAX::IdentifyType(const FileSys::VirtualFile& file) {
- FileSys::NAX nax(file);
-
- if (nax.GetStatus() == ResultStatus::Success && nax.AsNCA() != nullptr &&
- nax.AsNCA()->GetStatus() == ResultStatus::Success) {
- return FileType::NAX;
- }
+ const FileSys::NAX nax(file);
+ return IdentifyTypeImpl(nax);
+}
- return FileType::Error;
+FileType AppLoader_NAX::GetFileType() {
+ return IdentifyTypeImpl(*nax);
}
ResultStatus AppLoader_NAX::Load(Kernel::SharedPtr<Kernel::Process>& process) {
diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h
index 4dbae2918..56605fe45 100644
--- a/src/core/loader/nax.h
+++ b/src/core/loader/nax.h
@@ -31,9 +31,7 @@ public:
*/
static FileType IdentifyType(const FileSys::VirtualFile& file);
- FileType GetFileType() override {
- return IdentifyType(file);
- }
+ FileType GetFileType() override;
ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 3c6306818..78a4438c4 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -32,11 +32,18 @@ static_assert(sizeof(NsoSegmentHeader) == 0x10, "NsoSegmentHeader has incorrect
struct NsoHeader {
u32_le magic;
- INSERT_PADDING_BYTES(0xc);
+ u32_le version;
+ INSERT_PADDING_WORDS(1);
+ u8 flags;
std::array<NsoSegmentHeader, 3> segments; // Text, RoData, Data (in that order)
u32_le bss_size;
INSERT_PADDING_BYTES(0x1c);
std::array<u32_le, 3> segments_compressed_size;
+
+ bool IsSegmentCompressed(size_t segment_num) const {
+ ASSERT_MSG(segment_num < 3, "Invalid segment {}", segment_num);
+ return ((flags >> segment_num) & 1);
+ }
};
static_assert(sizeof(NsoHeader) == 0x6c, "NsoHeader has incorrect size.");
static_assert(std::is_trivially_copyable_v<NsoHeader>, "NsoHeader isn't trivially copyable.");
@@ -105,9 +112,11 @@ VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base) {
Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create(kernel, "");
std::vector<u8> program_image;
for (std::size_t i = 0; i < nso_header.segments.size(); ++i) {
- const std::vector<u8> compressed_data =
+ std::vector<u8> data =
file->ReadBytes(nso_header.segments_compressed_size[i], nso_header.segments[i].offset);
- std::vector<u8> data = DecompressSegment(compressed_data, nso_header.segments[i]);
+ if (nso_header.IsSegmentCompressed(i)) {
+ data = DecompressSegment(data, nso_header.segments[i]);
+ }
program_image.resize(nso_header.segments[i].location);
program_image.insert(program_image.end(), data.begin(), data.end());
codeset->segments[i].addr = nso_header.segments[i].location;