summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/core.cpp30
-rw-r--r--src/core/core.h31
-rw-r--r--src/core/crypto/key_manager.cpp44
-rw-r--r--src/core/crypto/key_manager.h9
-rw-r--r--src/core/file_sys/content_archive.cpp33
-rw-r--r--src/core/file_sys/content_archive.h7
-rw-r--r--src/core/file_sys/control_metadata.cpp6
-rw-r--r--src/core/file_sys/control_metadata.h1
-rw-r--r--src/core/file_sys/fsmitm_romfsbuild.h1
-rw-r--r--src/core/file_sys/ips_layer.cpp4
-rw-r--r--src/core/file_sys/patch_manager.cpp9
-rw-r--r--src/core/file_sys/registered_cache.cpp62
-rw-r--r--src/core/file_sys/registered_cache.h23
-rw-r--r--src/core/file_sys/savedata_factory.cpp32
-rw-r--r--src/core/file_sys/savedata_factory.h3
-rw-r--r--src/core/file_sys/vfs.cpp4
-rw-r--r--src/core/file_sys/vfs.h8
-rw-r--r--src/core/file_sys/vfs_offset.cpp4
-rw-r--r--src/core/file_sys/vfs_offset.h2
-rw-r--r--src/core/file_sys/vfs_static.h4
-rw-r--r--src/core/hle/ipc_helpers.h3
-rw-r--r--src/core/hle/kernel/hle_ipc.h8
-rw-r--r--src/core/hle/kernel/kernel.cpp4
-rw-r--r--src/core/hle/kernel/mutex.cpp2
-rw-r--r--src/core/hle/kernel/process.cpp82
-rw-r--r--src/core/hle/kernel/process.h22
-rw-r--r--src/core/hle/kernel/server_session.cpp4
-rw-r--r--src/core/hle/kernel/svc.cpp42
-rw-r--r--src/core/hle/kernel/thread.cpp8
-rw-r--r--src/core/hle/kernel/vm_manager.cpp82
-rw-r--r--src/core/hle/kernel/vm_manager.h15
-rw-r--r--src/core/hle/service/acc/acc.cpp24
-rw-r--r--src/core/hle/service/acc/acc.h1
-rw-r--r--src/core/hle/service/acc/acc_su.cpp2
-rw-r--r--src/core/hle/service/acc/acc_u0.cpp2
-rw-r--r--src/core/hle/service/acc/acc_u1.cpp2
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp27
-rw-r--r--src/core/hle/service/acc/profile_manager.h16
-rw-r--r--src/core/hle/service/am/am.cpp79
-rw-r--r--src/core/hle/service/am/am.h29
-rw-r--r--src/core/hle/service/am/applet_ae.cpp34
-rw-r--r--src/core/hle/service/am/applet_ae.h6
-rw-r--r--src/core/hle/service/am/applet_oe.cpp21
-rw-r--r--src/core/hle/service/am/applet_oe.h6
-rw-r--r--src/core/hle/service/audio/audren_u.cpp31
-rw-r--r--src/core/hle/service/audio/hwopus.cpp2
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp10
-rw-r--r--src/core/hle/service/filesystem/filesystem.h1
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp153
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.h1
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp6
-rw-r--r--src/core/hle/service/hid/hid.cpp2
-rw-r--r--src/core/hle/service/nfp/nfp.cpp2
-rw-r--r--src/core/hle/service/ns/ns.cpp64
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp8
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h11
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp12
-rw-r--r--src/core/hle/service/service.cpp4
-rw-r--r--src/core/hle/service/spl/module.cpp9
-rw-r--r--src/core/hle/service/spl/module.h4
-rw-r--r--src/core/hle/service/time/interface.cpp2
-rw-r--r--src/core/hle/service/time/time.cpp132
-rw-r--r--src/core/hle/service/time/time.h19
-rw-r--r--src/core/hle/service/usb/usb.cpp6
-rw-r--r--src/core/hle/service/vi/vi.cpp9
-rw-r--r--src/core/loader/loader.h5
-rw-r--r--src/core/loader/nro.cpp5
-rw-r--r--src/core/memory.cpp2
-rw-r--r--src/core/memory_hook.h15
-rw-r--r--src/core/settings.h6
-rw-r--r--src/core/telemetry_session.cpp9
-rw-r--r--src/core/telemetry_session.h6
72 files changed, 1012 insertions, 362 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 7cb86ed92..6d5b5a2d0 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -185,7 +185,7 @@ struct System::Impl {
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
return ResultStatus::ErrorGetLoader;
}
- std::pair<boost::optional<u32>, Loader::ResultStatus> system_mode =
+ std::pair<std::optional<u32>, Loader::ResultStatus> system_mode =
app_loader->LoadKernelSystemMode();
if (system_mode.second != Loader::ResultStatus::Success) {
@@ -312,6 +312,10 @@ Cpu& System::CurrentCpuCore() {
return impl->CurrentCpuCore();
}
+const Cpu& System::CurrentCpuCore() const {
+ return impl->CurrentCpuCore();
+}
+
System::ResultStatus System::RunLoop(bool tight_loop) {
return impl->RunLoop(tight_loop);
}
@@ -342,7 +346,11 @@ PerfStatsResults System::GetAndResetPerfStats() {
return impl->GetAndResetPerfStats();
}
-Core::TelemetrySession& System::TelemetrySession() const {
+TelemetrySession& System::TelemetrySession() {
+ return *impl->telemetry_session;
+}
+
+const TelemetrySession& System::TelemetrySession() const {
return *impl->telemetry_session;
}
@@ -350,7 +358,11 @@ ARM_Interface& System::CurrentArmInterface() {
return CurrentCpuCore().ArmInterface();
}
-std::size_t System::CurrentCoreIndex() {
+const ARM_Interface& System::CurrentArmInterface() const {
+ return CurrentCpuCore().ArmInterface();
+}
+
+std::size_t System::CurrentCoreIndex() const {
return CurrentCpuCore().CoreIndex();
}
@@ -358,6 +370,10 @@ Kernel::Scheduler& System::CurrentScheduler() {
return CurrentCpuCore().Scheduler();
}
+const Kernel::Scheduler& System::CurrentScheduler() const {
+ return CurrentCpuCore().Scheduler();
+}
+
Kernel::Scheduler& System::Scheduler(std::size_t core_index) {
return CpuCore(core_index).Scheduler();
}
@@ -378,6 +394,10 @@ ARM_Interface& System::ArmInterface(std::size_t core_index) {
return CpuCore(core_index).ArmInterface();
}
+const ARM_Interface& System::ArmInterface(std::size_t core_index) const {
+ return CpuCore(core_index).ArmInterface();
+}
+
Cpu& System::CpuCore(std::size_t core_index) {
ASSERT(core_index < NUM_CPU_CORES);
return *impl->cpu_cores[core_index];
@@ -392,6 +412,10 @@ ExclusiveMonitor& System::Monitor() {
return *impl->cpu_exclusive_monitor;
}
+const ExclusiveMonitor& System::Monitor() const {
+ return *impl->cpu_exclusive_monitor;
+}
+
Tegra::GPU& System::GPU() {
return *impl->gpu_core;
}
diff --git a/src/core/core.h b/src/core/core.h
index 173be45f8..cfacceb81 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -129,11 +129,11 @@ public:
*/
bool IsPoweredOn() const;
- /**
- * Returns a reference to the telemetry session for this emulation session.
- * @returns Reference to the telemetry session.
- */
- Core::TelemetrySession& TelemetrySession() const;
+ /// Gets a reference to the telemetry session for this emulation session.
+ Core::TelemetrySession& TelemetrySession();
+
+ /// Gets a reference to the telemetry session for this emulation session.
+ const Core::TelemetrySession& TelemetrySession() const;
/// Prepare the core emulation for a reschedule
void PrepareReschedule();
@@ -144,24 +144,36 @@ public:
/// Gets an ARM interface to the CPU core that is currently running
ARM_Interface& CurrentArmInterface();
+ /// Gets an ARM interface to the CPU core that is currently running
+ const ARM_Interface& CurrentArmInterface() const;
+
/// Gets the index of the currently running CPU core
- std::size_t CurrentCoreIndex();
+ std::size_t CurrentCoreIndex() const;
/// Gets the scheduler for the CPU core that is currently running
Kernel::Scheduler& CurrentScheduler();
- /// Gets an ARM interface to the CPU core with the specified index
+ /// Gets the scheduler for the CPU core that is currently running
+ const Kernel::Scheduler& CurrentScheduler() const;
+
+ /// Gets a reference to an ARM interface for the CPU core with the specified index
ARM_Interface& ArmInterface(std::size_t core_index);
+ /// Gets a const reference to an ARM interface from the CPU core with the specified index
+ const ARM_Interface& ArmInterface(std::size_t core_index) const;
+
/// Gets a CPU interface to the CPU core with the specified index
Cpu& CpuCore(std::size_t core_index);
/// Gets a CPU interface to the CPU core with the specified index
const Cpu& CpuCore(std::size_t core_index) const;
- /// Gets the exclusive monitor
+ /// Gets a reference to the exclusive monitor
ExclusiveMonitor& Monitor();
+ /// Gets a constant reference to the exclusive monitor
+ const ExclusiveMonitor& Monitor() const;
+
/// Gets a mutable reference to the GPU interface
Tegra::GPU& GPU();
@@ -230,6 +242,9 @@ private:
/// Returns the currently running CPU core
Cpu& CurrentCpuCore();
+ /// Returns the currently running CPU core
+ const Cpu& CurrentCpuCore() const;
+
/**
* Initialize the emulated system.
* @param emu_window Reference to the host-system window used for video output and keyboard
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index 89ae79eb3..904afa039 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -141,28 +141,28 @@ Key128 DeriveKeyblobMACKey(const Key128& keyblob_key, const Key128& mac_source)
return mac_key;
}
-boost::optional<Key128> DeriveSDSeed() {
+std::optional<Key128> DeriveSDSeed() {
const FileUtil::IOFile save_43(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
"/system/save/8000000000000043",
"rb+");
if (!save_43.IsOpen())
- return boost::none;
+ return {};
const FileUtil::IOFile sd_private(
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) + "/Nintendo/Contents/private", "rb+");
if (!sd_private.IsOpen())
- return boost::none;
+ return {};
std::array<u8, 0x10> private_seed{};
if (sd_private.ReadBytes(private_seed.data(), private_seed.size()) != private_seed.size()) {
- return boost::none;
+ return {};
}
std::array<u8, 0x10> buffer{};
std::size_t offset = 0;
for (; offset + 0x10 < save_43.GetSize(); ++offset) {
if (!save_43.Seek(offset, SEEK_SET)) {
- return boost::none;
+ return {};
}
save_43.ReadBytes(buffer.data(), buffer.size());
@@ -172,12 +172,12 @@ boost::optional<Key128> DeriveSDSeed() {
}
if (!save_43.Seek(offset + 0x10, SEEK_SET)) {
- return boost::none;
+ return {};
}
Key128 seed{};
if (save_43.ReadBytes(seed.data(), seed.size()) != seed.size()) {
- return boost::none;
+ return {};
}
return seed;
}
@@ -291,26 +291,26 @@ static std::array<u8, target_size> MGF1(const std::array<u8, in_size>& seed) {
}
template <size_t size>
-static boost::optional<u64> FindTicketOffset(const std::array<u8, size>& data) {
+static std::optional<u64> FindTicketOffset(const std::array<u8, size>& data) {
u64 offset = 0;
for (size_t i = 0x20; i < data.size() - 0x10; ++i) {
if (data[i] == 0x1) {
offset = i + 1;
break;
} else if (data[i] != 0x0) {
- return boost::none;
+ return {};
}
}
return offset;
}
-boost::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket,
- const RSAKeyPair<2048>& key) {
+std::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket,
+ const RSAKeyPair<2048>& key) {
u32 cert_authority;
std::memcpy(&cert_authority, ticket.data() + 0x140, sizeof(cert_authority));
if (cert_authority == 0)
- return boost::none;
+ return {};
if (cert_authority != Common::MakeMagic('R', 'o', 'o', 't')) {
LOG_INFO(Crypto,
"Attempting to parse ticket with non-standard certificate authority {:08X}.",
@@ -321,7 +321,7 @@ boost::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket,
std::memcpy(rights_id.data(), ticket.data() + 0x2A0, sizeof(Key128));
if (rights_id == Key128{})
- return boost::none;
+ return {};
Key128 key_temp{};
@@ -356,17 +356,17 @@ boost::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket,
std::memcpy(m_2.data(), rsa_step.data() + 0x21, m_2.size());
if (m_0 != 0)
- return boost::none;
+ return {};
m_1 = m_1 ^ MGF1<0x20>(m_2);
m_2 = m_2 ^ MGF1<0xDF>(m_1);
const auto offset = FindTicketOffset(m_2);
- if (offset == boost::none)
- return boost::none;
- ASSERT(offset.get() > 0);
+ if (!offset)
+ return {};
+ ASSERT(*offset > 0);
- std::memcpy(key_temp.data(), m_2.data() + offset.get(), key_temp.size());
+ std::memcpy(key_temp.data(), m_2.data() + *offset, key_temp.size());
return std::make_pair(rights_id, key_temp);
}
@@ -661,8 +661,8 @@ void KeyManager::DeriveSDSeedLazy() {
return;
const auto res = DeriveSDSeed();
- if (res != boost::none)
- SetKey(S128KeyType::SDSeed, res.get());
+ if (res)
+ SetKey(S128KeyType::SDSeed, *res);
}
static Key128 CalculateCMAC(const u8* source, size_t size, const Key128& key) {
@@ -889,9 +889,9 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) {
for (const auto& raw : res) {
const auto pair = ParseTicket(raw, rsa_key);
- if (pair == boost::none)
+ if (!pair)
continue;
- const auto& [rid, key] = pair.value();
+ const auto& [rid, key] = *pair;
u128 rights_id;
std::memcpy(rights_id.data(), rid.data(), rid.size());
SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h
index cccb3c0ae..22f268c65 100644
--- a/src/core/crypto/key_manager.h
+++ b/src/core/crypto/key_manager.h
@@ -6,9 +6,10 @@
#include <array>
#include <map>
+#include <optional>
#include <string>
+
#include <boost/container/flat_map.hpp>
-#include <boost/optional.hpp>
#include <fmt/format.h>
#include "common/common_types.h"
#include "core/crypto/partition_data_manager.h"
@@ -191,14 +192,14 @@ Key128 DeriveMasterKey(const std::array<u8, 0x90>& keyblob, const Key128& master
std::array<u8, 0x90> DecryptKeyblob(const std::array<u8, 0xB0>& encrypted_keyblob,
const Key128& key);
-boost::optional<Key128> DeriveSDSeed();
+std::optional<Key128> DeriveSDSeed();
Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& keys);
std::vector<TicketRaw> GetTicketblob(const FileUtil::IOFile& ticket_save);
// Returns a pair of {rights_id, titlekey}. Fails if the ticket has no certificate authority (offset
// 0x140-0x144 is zero)
-boost::optional<std::pair<Key128, Key128>> ParseTicket(
- const TicketRaw& ticket, const RSAKeyPair<2048>& eticket_extended_key);
+std::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket,
+ const RSAKeyPair<2048>& eticket_extended_key);
} // namespace Core::Crypto
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index 77e04704e..b46fe893c 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -4,10 +4,9 @@
#include <algorithm>
#include <cstring>
+#include <optional>
#include <utility>
-#include <boost/optional.hpp>
-
#include "common/logging/log.h"
#include "core/crypto/aes_util.h"
#include "core/crypto/ctr_encryption_layer.h"
@@ -306,18 +305,18 @@ bool NCA::ReadRomFSSection(const NCASectionHeader& section, const NCASectionTabl
subsection_buckets.back().entries.push_back({section.bktr.relocation.offset, {0}, ctr_low});
subsection_buckets.back().entries.push_back({size, {0}, 0});
- boost::optional<Core::Crypto::Key128> key = boost::none;
+ std::optional<Core::Crypto::Key128> key = {};
if (encrypted) {
if (has_rights_id) {
status = Loader::ResultStatus::Success;
key = GetTitlekey();
- if (key == boost::none) {
+ if (!key) {
status = Loader::ResultStatus::ErrorMissingTitlekey;
return false;
}
} else {
key = GetKeyAreaKey(NCASectionCryptoType::BKTR);
- if (key == boost::none) {
+ if (!key) {
status = Loader::ResultStatus::ErrorMissingKeyAreaKey;
return false;
}
@@ -332,7 +331,7 @@ bool NCA::ReadRomFSSection(const NCASectionHeader& section, const NCASectionTabl
auto bktr = std::make_shared<BKTR>(
bktr_base_romfs, std::make_shared<OffsetVfsFile>(file, romfs_size, base_offset),
relocation_block, relocation_buckets, subsection_block, subsection_buckets, encrypted,
- encrypted ? key.get() : Core::Crypto::Key128{}, base_offset, bktr_base_ivfc_offset,
+ encrypted ? *key : Core::Crypto::Key128{}, base_offset, bktr_base_ivfc_offset,
section.raw.section_ctr);
// BKTR applies to entire IVFC, so make an offset version to level 6
@@ -388,11 +387,11 @@ u8 NCA::GetCryptoRevision() const {
return master_key_id;
}
-boost::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType type) const {
+std::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType type) const {
const auto master_key_id = GetCryptoRevision();
if (!keys.HasKey(Core::Crypto::S128KeyType::KeyArea, master_key_id, header.key_index))
- return boost::none;
+ return {};
std::vector<u8> key_area(header.key_area.begin(), header.key_area.end());
Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(
@@ -416,25 +415,25 @@ boost::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType ty
return out;
}
-boost::optional<Core::Crypto::Key128> NCA::GetTitlekey() {
+std::optional<Core::Crypto::Key128> NCA::GetTitlekey() {
const auto master_key_id = GetCryptoRevision();
u128 rights_id{};
memcpy(rights_id.data(), header.rights_id.data(), 16);
if (rights_id == u128{}) {
status = Loader::ResultStatus::ErrorInvalidRightsID;
- return boost::none;
+ return {};
}
auto titlekey = keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id[1], rights_id[0]);
if (titlekey == Core::Crypto::Key128{}) {
status = Loader::ResultStatus::ErrorMissingTitlekey;
- return boost::none;
+ return {};
}
if (!keys.HasKey(Core::Crypto::S128KeyType::Titlekek, master_key_id)) {
status = Loader::ResultStatus::ErrorMissingTitlekek;
- return boost::none;
+ return {};
}
Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(
@@ -458,25 +457,25 @@ VirtualFile NCA::Decrypt(const NCASectionHeader& s_header, VirtualFile in, u64 s
case NCASectionCryptoType::BKTR:
LOG_DEBUG(Crypto, "called with mode=CTR, starting_offset={:016X}", starting_offset);
{
- boost::optional<Core::Crypto::Key128> key = boost::none;
+ std::optional<Core::Crypto::Key128> key = {};
if (has_rights_id) {
status = Loader::ResultStatus::Success;
key = GetTitlekey();
- if (key == boost::none) {
+ if (!key) {
if (status == Loader::ResultStatus::Success)
status = Loader::ResultStatus::ErrorMissingTitlekey;
return nullptr;
}
} else {
key = GetKeyAreaKey(NCASectionCryptoType::CTR);
- if (key == boost::none) {
+ if (!key) {
status = Loader::ResultStatus::ErrorMissingKeyAreaKey;
return nullptr;
}
}
- auto out = std::make_shared<Core::Crypto::CTREncryptionLayer>(
- std::move(in), key.value(), starting_offset);
+ auto out = std::make_shared<Core::Crypto::CTREncryptionLayer>(std::move(in), *key,
+ starting_offset);
std::vector<u8> iv(16);
for (u8 i = 0; i < 8; ++i)
iv[i] = s_header.raw.section_ctr[0x8 - i - 1];
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h
index 211946686..4bba55607 100644
--- a/src/core/file_sys/content_archive.h
+++ b/src/core/file_sys/content_archive.h
@@ -6,9 +6,10 @@
#include <array>
#include <memory>
+#include <optional>
#include <string>
#include <vector>
-#include <boost/optional.hpp>
+
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
@@ -111,8 +112,8 @@ private:
bool ReadPFS0Section(const NCASectionHeader& section, const NCASectionTableEntry& entry);
u8 GetCryptoRevision() const;
- boost::optional<Core::Crypto::Key128> GetKeyAreaKey(NCASectionCryptoType type) const;
- boost::optional<Core::Crypto::Key128> GetTitlekey();
+ std::optional<Core::Crypto::Key128> GetKeyAreaKey(NCASectionCryptoType type) const;
+ std::optional<Core::Crypto::Key128> GetTitlekey();
VirtualFile Decrypt(const NCASectionHeader& header, VirtualFile in, u64 starting_offset);
std::vector<VirtualDir> dirs;
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp
index a012c2be9..c8fa912bf 100644
--- a/src/core/file_sys/control_metadata.cpp
+++ b/src/core/file_sys/control_metadata.cpp
@@ -66,4 +66,10 @@ std::string NACP::GetVersionString() const {
return Common::StringFromFixedZeroTerminatedBuffer(raw->version_string.data(),
raw->version_string.size());
}
+
+std::vector<u8> NACP::GetRawBytes() const {
+ std::vector<u8> out(sizeof(RawNACP));
+ std::memcpy(out.data(), raw.get(), sizeof(RawNACP));
+ return out;
+}
} // namespace FileSys
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h
index 141f7e056..bfaad46b4 100644
--- a/src/core/file_sys/control_metadata.h
+++ b/src/core/file_sys/control_metadata.h
@@ -81,6 +81,7 @@ public:
u64 GetTitleId() const;
u64 GetDLCBaseTitleId() const;
std::string GetVersionString() const;
+ std::vector<u8> GetRawBytes() const;
private:
std::unique_ptr<RawNACP> raw;
diff --git a/src/core/file_sys/fsmitm_romfsbuild.h b/src/core/file_sys/fsmitm_romfsbuild.h
index 3d377b0af..a62502193 100644
--- a/src/core/file_sys/fsmitm_romfsbuild.h
+++ b/src/core/file_sys/fsmitm_romfsbuild.h
@@ -27,7 +27,6 @@
#include <map>
#include <memory>
#include <string>
-#include <boost/detail/container_fwd.hpp>
#include "common/common_types.h"
#include "core/file_sys/vfs.h"
diff --git a/src/core/file_sys/ips_layer.cpp b/src/core/file_sys/ips_layer.cpp
index 999939d5a..485c4913a 100644
--- a/src/core/file_sys/ips_layer.cpp
+++ b/src/core/file_sys/ips_layer.cpp
@@ -103,12 +103,12 @@ VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips) {
offset += sizeof(u16);
const auto data = ips->ReadByte(offset++);
- if (data == boost::none)
+ if (!data)
return nullptr;
if (real_offset + rle_size > in_data.size())
rle_size = static_cast<u16>(in_data.size() - real_offset);
- std::memset(in_data.data() + real_offset, data.get(), rle_size);
+ std::memset(in_data.data() + real_offset, *data, rle_size);
} else { // Standard Patch
auto read = data_size;
if (real_offset + read > in_data.size())
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index 3a1623ca0..8d062eb3e 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -66,7 +66,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
if (update != nullptr && update->GetExeFS() != nullptr &&
update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully",
- FormatTitleVersion(installed->GetEntryVersion(update_tid).get_value_or(0)));
+ FormatTitleVersion(installed->GetEntryVersion(update_tid).value_or(0)));
exefs = update->GetExeFS();
}
@@ -249,7 +249,7 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
if (new_nca->GetStatus() == Loader::ResultStatus::Success &&
new_nca->GetRomFS() != nullptr) {
LOG_INFO(Loader, " RomFS: Update ({}) applied successfully",
- FormatTitleVersion(installed->GetEntryVersion(update_tid).get_value_or(0)));
+ FormatTitleVersion(installed->GetEntryVersion(update_tid).value_or(0)));
romfs = new_nca->GetRomFS();
}
} else if (update_raw != nullptr) {
@@ -293,12 +293,11 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
} else {
if (installed->HasEntry(update_tid, ContentRecordType::Program)) {
const auto meta_ver = installed->GetEntryVersion(update_tid);
- if (meta_ver == boost::none || meta_ver.get() == 0) {
+ if (meta_ver.value_or(0) == 0) {
out.insert_or_assign("Update", "");
} else {
out.insert_or_assign(
- "Update",
- FormatTitleVersion(meta_ver.get(), TitleVersionFormat::ThreeElements));
+ "Update", FormatTitleVersion(*meta_ver, TitleVersionFormat::ThreeElements));
}
} else if (update_raw != nullptr) {
out.insert_or_assign("Update", "PACKED");
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 29b100414..96302a241 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -159,28 +159,28 @@ VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
return file;
}
-static boost::optional<NcaID> CheckMapForContentRecord(
+static std::optional<NcaID> CheckMapForContentRecord(
const boost::container::flat_map<u64, CNMT>& map, u64 title_id, ContentRecordType type) {
if (map.find(title_id) == map.end())
- return boost::none;
+ return {};
const auto& cnmt = map.at(title_id);
const auto iter = std::find_if(cnmt.GetContentRecords().begin(), cnmt.GetContentRecords().end(),
[type](const ContentRecord& rec) { return rec.type == type; });
if (iter == cnmt.GetContentRecords().end())
- return boost::none;
+ return {};
- return boost::make_optional(iter->nca_id);
+ return std::make_optional(iter->nca_id);
}
-boost::optional<NcaID> RegisteredCache::GetNcaIDFromMetadata(u64 title_id,
- ContentRecordType type) const {
+std::optional<NcaID> RegisteredCache::GetNcaIDFromMetadata(u64 title_id,
+ ContentRecordType type) const {
if (type == ContentRecordType::Meta && meta_id.find(title_id) != meta_id.end())
return meta_id.at(title_id);
const auto res1 = CheckMapForContentRecord(yuzu_meta, title_id, type);
- if (res1 != boost::none)
+ if (res1)
return res1;
return CheckMapForContentRecord(meta, title_id, type);
}
@@ -283,17 +283,14 @@ bool RegisteredCache::HasEntry(RegisteredCacheEntry entry) const {
VirtualFile RegisteredCache::GetEntryUnparsed(u64 title_id, ContentRecordType type) const {
const auto id = GetNcaIDFromMetadata(title_id, type);
- if (id == boost::none)
- return nullptr;
-
- return GetFileAtID(id.get());
+ return id ? GetFileAtID(*id) : nullptr;
}
VirtualFile RegisteredCache::GetEntryUnparsed(RegisteredCacheEntry entry) const {
return GetEntryUnparsed(entry.title_id, entry.type);
}
-boost::optional<u32> RegisteredCache::GetEntryVersion(u64 title_id) const {
+std::optional<u32> RegisteredCache::GetEntryVersion(u64 title_id) const {
const auto meta_iter = meta.find(title_id);
if (meta_iter != meta.end())
return meta_iter->second.GetTitleVersion();
@@ -302,15 +299,12 @@ boost::optional<u32> RegisteredCache::GetEntryVersion(u64 title_id) const {
if (yuzu_meta_iter != yuzu_meta.end())
return yuzu_meta_iter->second.GetTitleVersion();
- return boost::none;
+ return {};
}
VirtualFile RegisteredCache::GetEntryRaw(u64 title_id, ContentRecordType type) const {
const auto id = GetNcaIDFromMetadata(title_id, type);
- if (id == boost::none)
- return nullptr;
-
- return parser(GetFileAtID(id.get()), id.get());
+ return id ? parser(GetFileAtID(*id), *id) : nullptr;
}
VirtualFile RegisteredCache::GetEntryRaw(RegisteredCacheEntry entry) const {
@@ -364,8 +358,8 @@ std::vector<RegisteredCacheEntry> RegisteredCache::ListEntries() const {
}
std::vector<RegisteredCacheEntry> RegisteredCache::ListEntriesFilter(
- boost::optional<TitleType> title_type, boost::optional<ContentRecordType> record_type,
- boost::optional<u64> title_id) const {
+ std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type,
+ std::optional<u64> title_id) const {
std::vector<RegisteredCacheEntry> out;
IterateAllMetadata<RegisteredCacheEntry>(
out,
@@ -373,11 +367,11 @@ std::vector<RegisteredCacheEntry> RegisteredCache::ListEntriesFilter(
return RegisteredCacheEntry{c.GetTitleID(), r.type};
},
[&title_type, &record_type, &title_id](const CNMT& c, const ContentRecord& r) {
- if (title_type != boost::none && title_type.get() != c.GetType())
+ if (title_type && *title_type != c.GetType())
return false;
- if (record_type != boost::none && record_type.get() != r.type)
+ if (record_type && *record_type != r.type)
return false;
- if (title_id != boost::none && title_id.get() != c.GetTitleID())
+ if (title_id && *title_id != c.GetTitleID())
return false;
return true;
});
@@ -459,7 +453,7 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType
InstallResult RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy,
bool overwrite_if_exists,
- boost::optional<NcaID> override_id) {
+ std::optional<NcaID> override_id) {
const auto in = nca->GetBaseFile();
Core::Crypto::SHA256Hash hash{};
@@ -468,12 +462,12 @@ InstallResult RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const Vfs
// game is massive), we're going to cheat and only hash the first MB of the NCA.
// Also, for XCIs the NcaID matters, so if the override id isn't none, use that.
NcaID id{};
- if (override_id == boost::none) {
+ if (override_id) {
+ id = *override_id;
+ } else {
const auto& data = in->ReadBytes(0x100000);
mbedtls_sha256(data.data(), data.size(), hash.data(), 0);
memcpy(id.data(), hash.data(), 16);
- } else {
- id = override_id.get();
}
std::string path = GetRelativePathFromNcaID(id, false, true);
@@ -543,14 +537,14 @@ bool RegisteredCacheUnion::HasEntry(RegisteredCacheEntry entry) const {
return HasEntry(entry.title_id, entry.type);
}
-boost::optional<u32> RegisteredCacheUnion::GetEntryVersion(u64 title_id) const {
+std::optional<u32> RegisteredCacheUnion::GetEntryVersion(u64 title_id) const {
for (const auto& c : caches) {
const auto res = c->GetEntryVersion(title_id);
- if (res != boost::none)
+ if (res)
return res;
}
- return boost::none;
+ return {};
}
VirtualFile RegisteredCacheUnion::GetEntryUnparsed(u64 title_id, ContentRecordType type) const {
@@ -609,8 +603,8 @@ std::vector<RegisteredCacheEntry> RegisteredCacheUnion::ListEntries() const {
}
std::vector<RegisteredCacheEntry> RegisteredCacheUnion::ListEntriesFilter(
- boost::optional<TitleType> title_type, boost::optional<ContentRecordType> record_type,
- boost::optional<u64> title_id) const {
+ std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type,
+ std::optional<u64> title_id) const {
std::vector<RegisteredCacheEntry> out;
for (const auto& c : caches) {
c->IterateAllMetadata<RegisteredCacheEntry>(
@@ -619,11 +613,11 @@ std::vector<RegisteredCacheEntry> RegisteredCacheUnion::ListEntriesFilter(
return RegisteredCacheEntry{c.GetTitleID(), r.type};
},
[&title_type, &record_type, &title_id](const CNMT& c, const ContentRecord& r) {
- if (title_type != boost::none && title_type.get() != c.GetType())
+ if (title_type && *title_type != c.GetType())
return false;
- if (record_type != boost::none && record_type.get() != r.type)
+ if (record_type && *record_type != r.type)
return false;
- if (title_id != boost::none && title_id.get() != c.GetTitleID())
+ if (title_id && *title_id != c.GetTitleID())
return false;
return true;
});
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h
index 5beceffb3..6cfb16017 100644
--- a/src/core/file_sys/registered_cache.h
+++ b/src/core/file_sys/registered_cache.h
@@ -84,7 +84,7 @@ public:
bool HasEntry(u64 title_id, ContentRecordType type) const;
bool HasEntry(RegisteredCacheEntry entry) const;
- boost::optional<u32> GetEntryVersion(u64 title_id) const;
+ std::optional<u32> GetEntryVersion(u64 title_id) const;
VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const;
VirtualFile GetEntryUnparsed(RegisteredCacheEntry entry) const;
@@ -96,11 +96,10 @@ public:
std::unique_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const;
std::vector<RegisteredCacheEntry> ListEntries() const;
- // If a parameter is not boost::none, it will be filtered for from all entries.
+ // If a parameter is not std::nullopt, it will be filtered for from all entries.
std::vector<RegisteredCacheEntry> ListEntriesFilter(
- boost::optional<TitleType> title_type = boost::none,
- boost::optional<ContentRecordType> record_type = boost::none,
- boost::optional<u64> title_id = boost::none) const;
+ std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
+ std::optional<u64> title_id = {}) const;
// Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure
// there is a meta NCA and all of them are accessible.
@@ -125,12 +124,11 @@ private:
std::vector<NcaID> AccumulateFiles() const;
void ProcessFiles(const std::vector<NcaID>& ids);
void AccumulateYuzuMeta();
- boost::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const;
+ std::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const;
VirtualFile GetFileAtID(NcaID id) const;
VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const;
InstallResult RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy,
- bool overwrite_if_exists,
- boost::optional<NcaID> override_id = boost::none);
+ bool overwrite_if_exists, std::optional<NcaID> override_id = {});
bool RawInstallYuzuMeta(const CNMT& cnmt);
VirtualDir dir;
@@ -153,7 +151,7 @@ public:
bool HasEntry(u64 title_id, ContentRecordType type) const;
bool HasEntry(RegisteredCacheEntry entry) const;
- boost::optional<u32> GetEntryVersion(u64 title_id) const;
+ std::optional<u32> GetEntryVersion(u64 title_id) const;
VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const;
VirtualFile GetEntryUnparsed(RegisteredCacheEntry entry) const;
@@ -165,11 +163,10 @@ public:
std::unique_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const;
std::vector<RegisteredCacheEntry> ListEntries() const;
- // If a parameter is not boost::none, it will be filtered for from all entries.
+ // If a parameter is not std::nullopt, it will be filtered for from all entries.
std::vector<RegisteredCacheEntry> ListEntriesFilter(
- boost::optional<TitleType> title_type = boost::none,
- boost::optional<ContentRecordType> record_type = boost::none,
- boost::optional<u64> title_id = boost::none) const;
+ std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
+ std::optional<u64> title_id = {}) const;
private:
std::vector<RegisteredCache*> caches;
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index ef1aaebbb..5434f2149 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -83,28 +83,32 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, SaveDataDescr
return MakeResult<VirtualDir>(std::move(out));
}
-std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id,
- u128 user_id, u64 save_id) {
- // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
- // be interpreted as the title id of the current process.
- if (type == SaveDataType::SaveData && title_id == 0)
- title_id = Core::CurrentProcess()->GetTitleID();
-
- std::string out;
+VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) const {
+ return dir->GetDirectoryRelative(GetSaveDataSpaceIdPath(space));
+}
+std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) {
switch (space) {
case SaveDataSpaceId::NandSystem:
- out = "/system/";
- break;
+ return "/system/";
case SaveDataSpaceId::NandUser:
- out = "/user/";
- break;
+ return "/user/";
case SaveDataSpaceId::TemporaryStorage:
- out = "/temp/";
- break;
+ return "/temp/";
default:
ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space));
+ return "/unrecognized/"; ///< To prevent corruption when ignoring asserts.
}
+}
+
+std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id,
+ u128 user_id, u64 save_id) {
+ // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
+ // be interpreted as the title id of the current process.
+ if (type == SaveDataType::SaveData && title_id == 0)
+ title_id = Core::CurrentProcess()->GetTitleID();
+
+ std::string out = GetSaveDataSpaceIdPath(space);
switch (type) {
case SaveDataType::SystemSaveData:
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h
index d69ef6741..2a0088040 100644
--- a/src/core/file_sys/savedata_factory.h
+++ b/src/core/file_sys/savedata_factory.h
@@ -52,6 +52,9 @@ public:
ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta);
+ VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;
+
+ static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space);
static std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id,
u128 user_id, u64 save_id);
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp
index 3824c74e0..7b584de7f 100644
--- a/src/core/file_sys/vfs.cpp
+++ b/src/core/file_sys/vfs.cpp
@@ -167,13 +167,13 @@ std::string VfsFile::GetExtension() const {
VfsDirectory::~VfsDirectory() = default;
-boost::optional<u8> VfsFile::ReadByte(std::size_t offset) const {
+std::optional<u8> VfsFile::ReadByte(std::size_t offset) const {
u8 out{};
std::size_t size = Read(&out, 1, offset);
if (size == 1)
return out;
- return boost::none;
+ return {};
}
std::vector<u8> VfsFile::ReadBytes(std::size_t size, std::size_t offset) const {
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h
index 09dc9f288..002f99d4e 100644
--- a/src/core/file_sys/vfs.h
+++ b/src/core/file_sys/vfs.h
@@ -4,13 +4,15 @@
#pragma once
+#include <functional>
#include <map>
#include <memory>
+#include <optional>
#include <string>
#include <string_view>
#include <type_traits>
#include <vector>
-#include <boost/optional.hpp>
+
#include "common/common_types.h"
#include "core/file_sys/vfs_types.h"
@@ -103,8 +105,8 @@ public:
// into file. Returns number of bytes successfully written.
virtual std::size_t Write(const u8* data, std::size_t length, std::size_t offset = 0) = 0;
- // Reads exactly one byte at the offset provided, returning boost::none on error.
- virtual boost::optional<u8> ReadByte(std::size_t offset = 0) const;
+ // Reads exactly one byte at the offset provided, returning std::nullopt on error.
+ virtual std::optional<u8> ReadByte(std::size_t offset = 0) const;
// Reads size bytes starting at offset in file into a vector.
virtual std::vector<u8> ReadBytes(std::size_t size, std::size_t offset = 0) const;
// Reads all the bytes from the file into a vector. Equivalent to 'file->Read(file->GetSize(),
diff --git a/src/core/file_sys/vfs_offset.cpp b/src/core/file_sys/vfs_offset.cpp
index a4c6719a0..c96f88488 100644
--- a/src/core/file_sys/vfs_offset.cpp
+++ b/src/core/file_sys/vfs_offset.cpp
@@ -57,11 +57,11 @@ std::size_t OffsetVfsFile::Write(const u8* data, std::size_t length, std::size_t
return file->Write(data, TrimToFit(length, r_offset), offset + r_offset);
}
-boost::optional<u8> OffsetVfsFile::ReadByte(std::size_t r_offset) const {
+std::optional<u8> OffsetVfsFile::ReadByte(std::size_t r_offset) const {
if (r_offset < size)
return file->ReadByte(offset + r_offset);
- return boost::none;
+ return {};
}
std::vector<u8> OffsetVfsFile::ReadBytes(std::size_t r_size, std::size_t r_offset) const {
diff --git a/src/core/file_sys/vfs_offset.h b/src/core/file_sys/vfs_offset.h
index 8062702a7..f7b7a3256 100644
--- a/src/core/file_sys/vfs_offset.h
+++ b/src/core/file_sys/vfs_offset.h
@@ -29,7 +29,7 @@ public:
bool IsReadable() const override;
std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override;
- boost::optional<u8> ReadByte(std::size_t offset) const override;
+ std::optional<u8> ReadByte(std::size_t offset) const override;
std::vector<u8> ReadBytes(std::size_t size, std::size_t offset) const override;
std::vector<u8> ReadAllBytes() const override;
bool WriteByte(u8 data, std::size_t offset) override;
diff --git a/src/core/file_sys/vfs_static.h b/src/core/file_sys/vfs_static.h
index 44fab51d1..9f5a90b1b 100644
--- a/src/core/file_sys/vfs_static.h
+++ b/src/core/file_sys/vfs_static.h
@@ -53,10 +53,10 @@ public:
return 0;
}
- boost::optional<u8> ReadByte(std::size_t offset) const override {
+ std::optional<u8> ReadByte(std::size_t offset) const override {
if (offset < size)
return value;
- return boost::none;
+ return {};
}
std::vector<u8> ReadBytes(std::size_t length, std::size_t offset) const override {
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index a4bfe2eb0..0a7142ada 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -117,8 +117,7 @@ public:
AlignWithPadding();
- const bool request_has_domain_header{context.GetDomainMessageHeader() != nullptr};
- if (context.Session()->IsDomain() && request_has_domain_header) {
+ if (context.Session()->IsDomain() && context.HasDomainMessageHeader()) {
IPC::DomainMessageHeader domain_header{};
domain_header.num_objects = num_domain_objects;
PushRaw(domain_header);
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index f01491daa..a38e34b74 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -161,8 +161,12 @@ public:
return buffer_c_desciptors;
}
- const std::shared_ptr<IPC::DomainMessageHeader>& GetDomainMessageHeader() const {
- return domain_message_header;
+ const IPC::DomainMessageHeader* GetDomainMessageHeader() const {
+ return domain_message_header.get();
+ }
+
+ bool HasDomainMessageHeader() const {
+ return domain_message_header != nullptr;
}
/// Helper function to read a buffer using the appropriate buffer descriptor
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 4b6b32dd5..1fd4ba5d2 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -32,7 +32,7 @@ namespace Kernel {
*/
static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] int cycles_late) {
const auto proper_handle = static_cast<Handle>(thread_handle);
- auto& system = Core::System::GetInstance();
+ const auto& system = Core::System::GetInstance();
// Lock the global kernel mutex when we enter the kernel HLE.
std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
@@ -90,7 +90,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] int cycles_
/// The timer callback event, called when a timer is fired
static void TimerCallback(u64 timer_handle, int cycles_late) {
const auto proper_handle = static_cast<Handle>(timer_handle);
- auto& system = Core::System::GetInstance();
+ const auto& system = Core::System::GetInstance();
SharedPtr<Timer> timer = system.Kernel().RetrieveTimerFromCallbackHandleTable(proper_handle);
if (timer == nullptr) {
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index dd541ffcc..0743670ad 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -6,8 +6,6 @@
#include <utility>
#include <vector>
-#include <boost/range/algorithm_ext/erase.hpp>
-
#include "common/assert.h"
#include "core/core.h"
#include "core/hle/kernel/errors.h"
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 420218d59..f06b6bb55 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -5,11 +5,9 @@
#include <algorithm>
#include <memory>
#include "common/assert.h"
-#include "common/common_funcs.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/file_sys/program_metadata.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"
@@ -17,6 +15,7 @@
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/vm_manager.h"
#include "core/memory.h"
+#include "core/settings.h"
namespace Kernel {
@@ -35,6 +34,11 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) {
process->process_id = kernel.CreateNewProcessID();
process->svc_access_mask.set();
+ std::mt19937 rng(Settings::values.rng_seed.value_or(0));
+ std::uniform_int_distribution<u64> distribution;
+ std::generate(process->random_entropy.begin(), process->random_entropy.end(),
+ [&] { return distribution(rng); });
+
kernel.AppendNewProcess(process);
return process;
}
@@ -241,83 +245,15 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) {
}
ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
- if (target < vm_manager.GetHeapRegionBaseAddress() ||
- target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) {
- return ERR_INVALID_ADDRESS;
- }
-
- if (heap_memory == nullptr) {
- // Initialize heap
- heap_memory = std::make_shared<std::vector<u8>>();
- heap_start = heap_end = target;
- } else {
- vm_manager.UnmapRange(heap_start, heap_end - heap_start);
- }
-
- // If necessary, expand backing vector to cover new heap extents.
- if (target < heap_start) {
- heap_memory->insert(begin(*heap_memory), heap_start - target, 0);
- heap_start = target;
- vm_manager.RefreshMemoryBlockMappings(heap_memory.get());
- }
- if (target + size > heap_end) {
- heap_memory->insert(end(*heap_memory), (target + size) - heap_end, 0);
- heap_end = target + size;
- vm_manager.RefreshMemoryBlockMappings(heap_memory.get());
- }
- ASSERT(heap_end - heap_start == heap_memory->size());
-
- CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, heap_memory, target - heap_start,
- size, MemoryState::Heap));
- vm_manager.Reprotect(vma, perms);
-
- heap_used = size;
-
- return MakeResult<VAddr>(heap_end - size);
+ return vm_manager.HeapAllocate(target, size, perms);
}
ResultCode Process::HeapFree(VAddr target, u32 size) {
- if (target < vm_manager.GetHeapRegionBaseAddress() ||
- target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) {
- return ERR_INVALID_ADDRESS;
- }
-
- if (size == 0) {
- return RESULT_SUCCESS;
- }
-
- ResultCode result = vm_manager.UnmapRange(target, size);
- if (result.IsError())
- return result;
-
- heap_used -= size;
-
- return RESULT_SUCCESS;
+ return vm_manager.HeapFree(target, size);
}
ResultCode Process::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
- auto vma = vm_manager.FindVMA(src_addr);
-
- ASSERT_MSG(vma != vm_manager.vma_map.end(), "Invalid memory address");
- ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address");
-
- // The returned VMA might be a bigger one encompassing the desired address.
- auto vma_offset = src_addr - vma->first;
- ASSERT_MSG(vma_offset + size <= vma->second.size,
- "Shared memory exceeds bounds of mapped block");
-
- const std::shared_ptr<std::vector<u8>>& backing_block = vma->second.backing_block;
- std::size_t backing_block_offset = vma->second.offset + vma_offset;
-
- CASCADE_RESULT(auto new_vma,
- vm_manager.MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size,
- MemoryState::Mapped));
- // Protect mirror with permissions from old region
- vm_manager.Reprotect(new_vma, vma->second.permissions);
- // Remove permissions from old region
- vm_manager.Reprotect(vma, VMAPermission::None);
-
- return RESULT_SUCCESS;
+ return vm_manager.MirrorMemory(dst_addr, src_addr, size);
}
ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) {
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 8d2616c79..cf48787ce 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -8,6 +8,7 @@
#include <bitset>
#include <cstddef>
#include <memory>
+#include <random>
#include <string>
#include <vector>
#include <boost/container/static_vector.hpp>
@@ -119,6 +120,8 @@ struct CodeSet final {
class Process final : public Object {
public:
+ static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4;
+
static SharedPtr<Process> Create(KernelCore& kernel, std::string&& name);
std::string GetTypeName() const override {
@@ -212,6 +215,11 @@ public:
total_process_running_time_ticks += ticks;
}
+ /// Gets 8 bytes of random data for svcGetInfo RandomEntropy
+ u64 GetRandomEntropy(std::size_t index) const {
+ return random_entropy.at(index);
+ }
+
/**
* Loads process-specifics configuration info with metadata provided
* by an executable.
@@ -292,17 +300,6 @@ private:
u32 allowed_thread_priority_mask = 0xFFFFFFFF;
u32 is_virtual_address_memory_enabled = 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
- // in the emulator address space, allowing Memory::GetPointer to be reasonably safe.
- std::shared_ptr<std::vector<u8>> heap_memory;
-
- // The left/right bounds of the address space covered by heap_memory.
- VAddr heap_start = 0;
- VAddr heap_end = 0;
- u64 heap_used = 0;
-
/// The Thread Local Storage area is allocated as processes create threads,
/// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part
/// holds the TLS for a specific thread. This vector contains which parts are in use for each
@@ -321,6 +318,9 @@ private:
/// Per-process handle table for storing created object handles in.
HandleTable handle_table;
+ /// Random values for svcGetInfo RandomEntropy
+ std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy;
+
std::string name;
};
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 5fc320403..80897f3a4 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -63,7 +63,7 @@ void ServerSession::Acquire(Thread* thread) {
}
ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) {
- auto& domain_message_header = context.GetDomainMessageHeader();
+ auto* const domain_message_header = context.GetDomainMessageHeader();
if (domain_message_header) {
// Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs
context.SetDomainRequestHandlers(domain_request_handlers);
@@ -111,7 +111,7 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
ResultCode result = RESULT_SUCCESS;
// If the session has been converted to a domain, handle the domain request
- if (IsDomain() && context.GetDomainMessageHeader()) {
+ if (IsDomain() && context.HasDomainMessageHeader()) {
result = HandleDomainSyncRequest(context);
// If there is no domain header, the regular session handler is used
} else if (hle_handler != nullptr) {
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 4e490e2b5..b0b6508d9 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -34,6 +34,7 @@
#include "core/hle/lock.h"
#include "core/hle/result.h"
#include "core/hle/service/service.h"
+#include "core/settings.h"
namespace Kernel {
namespace {
@@ -395,16 +396,42 @@ struct BreakReason {
/// Break program execution
static void Break(u32 reason, u64 info1, u64 info2) {
BreakReason break_reason{reason};
+ bool has_dumped_buffer{};
+ const auto handle_debug_buffer = [&](VAddr addr, u64 sz) {
+ if (sz == 0 || addr == 0 || has_dumped_buffer) {
+ return;
+ }
+
+ // This typically is an error code so we're going to assume this is the case
+ if (sz == sizeof(u32)) {
+ LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", Memory::Read32(addr));
+ } else {
+ // We don't know what's in here so we'll hexdump it
+ std::vector<u8> debug_buffer(sz);
+ Memory::ReadBlock(addr, debug_buffer.data(), sz);
+ std::string hexdump;
+ for (std::size_t i = 0; i < debug_buffer.size(); i++) {
+ hexdump += fmt::format("{:02X} ", debug_buffer[i]);
+ if (i != 0 && i % 16 == 0) {
+ hexdump += '\n';
+ }
+ }
+ LOG_CRITICAL(Debug_Emulated, "debug_buffer=\n{}", hexdump);
+ }
+ has_dumped_buffer = true;
+ };
switch (break_reason.break_type) {
case BreakType::Panic:
LOG_CRITICAL(Debug_Emulated, "Signalling debugger, PANIC! info1=0x{:016X}, info2=0x{:016X}",
info1, info2);
+ handle_debug_buffer(info1, info2);
break;
case BreakType::AssertionFailed:
LOG_CRITICAL(Debug_Emulated,
"Signalling debugger, Assertion failed! info1=0x{:016X}, info2=0x{:016X}",
info1, info2);
+ handle_debug_buffer(info1, info2);
break;
case BreakType::PreNROLoad:
LOG_WARNING(
@@ -433,6 +460,7 @@ static void Break(u32 reason, u64 info1, u64 info2) {
Debug_Emulated,
"Signalling debugger, Unknown break reason {}, info1=0x{:016X}, info2=0x{:016X}",
static_cast<u32>(break_reason.break_type.Value()), info1, info2);
+ handle_debug_buffer(info1, info2);
break;
}
@@ -441,6 +469,7 @@ static void Break(u32 reason, u64 info1, u64 info2) {
Debug_Emulated,
"Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}",
reason, info1, info2);
+ handle_debug_buffer(info1, info2);
ASSERT(false);
Core::CurrentProcess()->PrepareForTermination();
@@ -530,7 +559,16 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
*result = 0;
break;
case GetInfoType::RandomEntropy:
- *result = 0;
+ if (handle != 0) {
+ return ERR_INVALID_HANDLE;
+ }
+
+ if (info_sub_id >= Process::RANDOM_ENTROPY_SIZE) {
+ return ERR_INVALID_COMBINATION_KERNEL;
+ }
+
+ *result = current_process->GetRandomEntropy(info_sub_id);
+ return RESULT_SUCCESS;
break;
case GetInfoType::ASLRRegionBaseAddr:
*result = vm_manager.GetASLRRegionBaseAddress();
@@ -572,7 +610,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
return ERR_INVALID_HANDLE;
}
- auto& system = Core::System::GetInstance();
+ const auto& system = Core::System::GetInstance();
const auto& scheduler = system.CurrentScheduler();
const auto* const current_thread = scheduler.GetCurrentThread();
const bool same_thread = current_thread == thread;
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 59bc9e0af..dd5cd9ced 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -4,9 +4,9 @@
#include <algorithm>
#include <cinttypes>
+#include <optional>
#include <vector>
-#include <boost/optional.hpp>
#include <boost/range/algorithm_ext/erase.hpp>
#include "common/assert.h"
@@ -94,7 +94,7 @@ void Thread::CancelWakeupTimer() {
CoreTiming::UnscheduleEventThreadsafe(kernel.ThreadWakeupCallbackEventType(), callback_handle);
}
-static boost::optional<s32> GetNextProcessorId(u64 mask) {
+static std::optional<s32> GetNextProcessorId(u64 mask) {
for (s32 index = 0; index < Core::NUM_CPU_CORES; ++index) {
if (mask & (1ULL << index)) {
if (!Core::System::GetInstance().Scheduler(index).GetCurrentThread()) {
@@ -142,7 +142,7 @@ void Thread::ResumeFromWait() {
status = ThreadStatus::Ready;
- boost::optional<s32> new_processor_id = GetNextProcessorId(affinity_mask);
+ std::optional<s32> new_processor_id = GetNextProcessorId(affinity_mask);
if (!new_processor_id) {
new_processor_id = processor_id;
}
@@ -369,7 +369,7 @@ void Thread::ChangeCore(u32 core, u64 mask) {
return;
}
- boost::optional<s32> new_processor_id{GetNextProcessorId(affinity_mask)};
+ std::optional<s32> new_processor_id{GetNextProcessorId(affinity_mask)};
if (!new_processor_id) {
new_processor_id = processor_id;
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 1a92c8f70..ec7fd6150 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -243,6 +243,85 @@ ResultCode VMManager::ReprotectRange(VAddr target, u64 size, VMAPermission new_p
return RESULT_SUCCESS;
}
+ResultVal<VAddr> VMManager::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
+ if (target < GetHeapRegionBaseAddress() || target + size > GetHeapRegionEndAddress() ||
+ target + size < target) {
+ return ERR_INVALID_ADDRESS;
+ }
+
+ if (heap_memory == nullptr) {
+ // Initialize heap
+ heap_memory = std::make_shared<std::vector<u8>>();
+ heap_start = heap_end = target;
+ } else {
+ UnmapRange(heap_start, heap_end - heap_start);
+ }
+
+ // If necessary, expand backing vector to cover new heap extents.
+ if (target < heap_start) {
+ heap_memory->insert(begin(*heap_memory), heap_start - target, 0);
+ heap_start = target;
+ RefreshMemoryBlockMappings(heap_memory.get());
+ }
+ if (target + size > heap_end) {
+ heap_memory->insert(end(*heap_memory), (target + size) - heap_end, 0);
+ heap_end = target + size;
+ RefreshMemoryBlockMappings(heap_memory.get());
+ }
+ ASSERT(heap_end - heap_start == heap_memory->size());
+
+ CASCADE_RESULT(auto vma, MapMemoryBlock(target, heap_memory, target - heap_start, size,
+ MemoryState::Heap));
+ Reprotect(vma, perms);
+
+ heap_used = size;
+
+ return MakeResult<VAddr>(heap_end - size);
+}
+
+ResultCode VMManager::HeapFree(VAddr target, u64 size) {
+ if (target < GetHeapRegionBaseAddress() || target + size > GetHeapRegionEndAddress() ||
+ target + size < target) {
+ return ERR_INVALID_ADDRESS;
+ }
+
+ if (size == 0) {
+ return RESULT_SUCCESS;
+ }
+
+ const ResultCode result = UnmapRange(target, size);
+ if (result.IsError()) {
+ return result;
+ }
+
+ heap_used -= size;
+ return RESULT_SUCCESS;
+}
+
+ResultCode VMManager::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
+ const auto vma = FindVMA(src_addr);
+
+ ASSERT_MSG(vma != vma_map.end(), "Invalid memory address");
+ ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address");
+
+ // The returned VMA might be a bigger one encompassing the desired address.
+ const auto vma_offset = src_addr - vma->first;
+ ASSERT_MSG(vma_offset + size <= vma->second.size,
+ "Shared memory exceeds bounds of mapped block");
+
+ const std::shared_ptr<std::vector<u8>>& backing_block = vma->second.backing_block;
+ const std::size_t backing_block_offset = vma->second.offset + vma_offset;
+
+ CASCADE_RESULT(auto new_vma, MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size,
+ MemoryState::Mapped));
+ // Protect mirror with permissions from old region
+ Reprotect(new_vma, vma->second.permissions);
+ // Remove permissions from old region
+ Reprotect(vma, VMAPermission::None);
+
+ return RESULT_SUCCESS;
+}
+
void VMManager::RefreshMemoryBlockMappings(const std::vector<u8>* block) {
// If this ever proves to have a noticeable performance impact, allow users of the function to
// specify a specific range of addresses to limit the scan to.
@@ -495,8 +574,7 @@ u64 VMManager::GetTotalMemoryUsage() const {
}
u64 VMManager::GetTotalHeapUsage() const {
- LOG_WARNING(Kernel, "(STUBBED) called");
- return 0x0;
+ return heap_used;
}
VAddr VMManager::GetAddressSpaceBaseAddress() const {
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 2447cbb8f..248cc46dc 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -186,6 +186,11 @@ public:
/// Changes the permissions of a range of addresses, splitting VMAs as necessary.
ResultCode ReprotectRange(VAddr target, u64 size, VMAPermission new_perms);
+ ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
+ ResultCode HeapFree(VAddr target, u64 size);
+
+ ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size);
+
/**
* Scans all VMAs and updates the page table range of any that use the given vector as backing
* memory. This should be called after any operation that causes reallocation of the vector.
@@ -343,5 +348,15 @@ private:
VAddr tls_io_region_base = 0;
VAddr tls_io_region_end = 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
+ // in the emulator address space, allowing Memory::GetPointer to be reasonably safe.
+ std::shared_ptr<std::vector<u8>> heap_memory;
+ // The left/right bounds of the address space covered by heap_memory.
+ VAddr heap_start = 0;
+ VAddr heap_end = 0;
+ u64 heap_used = 0;
};
} // namespace Kernel
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index c6437a671..c629f9357 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -242,6 +242,30 @@ void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestCo
LOG_DEBUG(Service_ACC, "called");
}
+void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_ACC, "called");
+ // A u8 is passed into this function which we can safely ignore. It's to determine if we have
+ // access to use the network or not by the looks of it
+ IPC::ResponseBuilder rb{ctx, 6};
+ if (profile_manager->GetUserCount() != 1) {
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw<u128>(INVALID_UUID);
+ return;
+ }
+
+ const auto user_list = profile_manager->GetAllUsers();
+ if (std::all_of(user_list.begin(), user_list.end(),
+ [](const auto& user) { return user.uuid == INVALID_UUID; })) {
+ rb.Push(ResultCode(-1)); // TODO(ogniK): Find the correct error code
+ rb.PushRaw<u128>(INVALID_UUID);
+ return;
+ }
+
+ // Select the first user we have
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw<u128>(profile_manager->GetUser(0)->uuid);
+}
+
Module::Interface::Interface(std::shared_ptr<Module> module,
std::shared_ptr<ProfileManager> profile_manager, const char* name)
: ServiceFramework(name), module(std::move(module)),
diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h
index c7ed74351..89b2104fa 100644
--- a/src/core/hle/service/acc/acc.h
+++ b/src/core/hle/service/acc/acc.h
@@ -27,6 +27,7 @@ public:
void InitializeApplicationInfo(Kernel::HLERequestContext& ctx);
void GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx);
void IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx);
+ void TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx);
protected:
std::shared_ptr<Module> module;
diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp
index ad455c3a7..5e2030355 100644
--- a/src/core/hle/service/acc/acc_su.cpp
+++ b/src/core/hle/service/acc/acc_su.cpp
@@ -17,7 +17,7 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
{5, &ACC_SU::GetProfile, "GetProfile"},
{6, nullptr, "GetProfileDigest"},
{50, &ACC_SU::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
- {51, nullptr, "TrySelectUserWithoutInteraction"},
+ {51, &ACC_SU::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
{60, nullptr, "ListOpenContextStoredUsers"},
{100, nullptr, "GetUserRegistrationNotifier"},
{101, nullptr, "GetUserStateChangeNotifier"},
diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp
index 72d4adf35..a4d705b45 100644
--- a/src/core/hle/service/acc/acc_u0.cpp
+++ b/src/core/hle/service/acc/acc_u0.cpp
@@ -17,7 +17,7 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
{5, &ACC_U0::GetProfile, "GetProfile"},
{6, nullptr, "GetProfileDigest"},
{50, &ACC_U0::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
- {51, nullptr, "TrySelectUserWithoutInteraction"},
+ {51, &ACC_U0::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
{60, nullptr, "ListOpenContextStoredUsers"},
{100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"},
{101, &ACC_U0::GetBaasAccountManagerForApplication, "GetBaasAccountManagerForApplication"},
diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp
index d480f08e5..8fffc93b5 100644
--- a/src/core/hle/service/acc/acc_u1.cpp
+++ b/src/core/hle/service/acc/acc_u1.cpp
@@ -17,7 +17,7 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
{5, &ACC_U1::GetProfile, "GetProfile"},
{6, nullptr, "GetProfileDigest"},
{50, &ACC_U1::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
- {51, nullptr, "TrySelectUserWithoutInteraction"},
+ {51, &ACC_U1::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
{60, nullptr, "ListOpenContextStoredUsers"},
{100, nullptr, "GetUserRegistrationNotifier"},
{101, nullptr, "GetUserStateChangeNotifier"},
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index 3cac1b4ff..968263846 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -2,8 +2,11 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cstring>
#include <random>
+#include <fmt/format.h>
+
#include "common/file_util.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/settings.h"
@@ -39,6 +42,19 @@ UUID UUID::Generate() {
return UUID{distribution(gen), distribution(gen)};
}
+std::string UUID::Format() const {
+ return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]);
+}
+
+std::string UUID::FormatSwitch() const {
+ std::array<u8, 16> s{};
+ std::memcpy(s.data(), uuid.data(), sizeof(u128));
+ return fmt::format("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{"
+ ":02x}{:02x}{:02x}{:02x}{:02x}",
+ s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11],
+ s[12], s[13], s[14], s[15]);
+}
+
ProfileManager::ProfileManager() {
ParseUserSaveFile();
@@ -195,7 +211,7 @@ std::size_t ProfileManager::GetOpenUserCount() const {
/// Checks if a user id exists in our profile manager
bool ProfileManager::UserExists(UUID uuid) const {
- return GetUserIndex(uuid) != std::nullopt;
+ return GetUserIndex(uuid).has_value();
}
bool ProfileManager::UserExistsIndex(std::size_t index) const {
@@ -325,11 +341,12 @@ void ProfileManager::ParseUserSaveFile() {
return;
}
- for (std::size_t i = 0; i < MAX_USERS; ++i) {
- const auto& user = data.users[i];
+ for (const auto& user : data.users) {
+ if (user.uuid == UUID(INVALID_UUID)) {
+ continue;
+ }
- if (user.uuid != UUID(INVALID_UUID))
- AddUser({user.uuid, user.username, user.timestamp, {}, false});
+ AddUser({user.uuid, user.username, user.timestamp, {}, false});
}
std::stable_partition(profiles.begin(), profiles.end(),
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h
index 1cd2e51b2..d2d8e6c6b 100644
--- a/src/core/hle/service/acc/profile_manager.h
+++ b/src/core/hle/service/acc/profile_manager.h
@@ -42,22 +42,14 @@ struct UUID {
void Invalidate() {
uuid = INVALID_UUID;
}
- std::string Format() const {
- return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]);
- }
- std::string FormatSwitch() const {
- std::array<u8, 16> s{};
- std::memcpy(s.data(), uuid.data(), sizeof(u128));
- return fmt::format("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{"
- ":02x}{:02x}{:02x}{:02x}{:02x}",
- s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11],
- s[12], s[13], s[14], s[15]);
- }
+ std::string Format() const;
+ std::string FormatSwitch() const;
};
static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
-using ProfileUsername = std::array<u8, 0x20>;
+constexpr std::size_t profile_username_size = 32;
+using ProfileUsername = std::array<u8, profile_username_size>;
using ProfileData = std::array<u8, MAX_DATA>;
using UserIDArray = std::array<UUID, MAX_USERS>;
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 59aafd616..0477ce66e 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -338,7 +338,54 @@ void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& c
LOG_WARNING(Service_AM, "(STUBBED) called");
}
-ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter") {
+AppletMessageQueue::AppletMessageQueue() {
+ auto& kernel = Core::System::GetInstance().Kernel();
+ on_new_message = Kernel::Event::Create(kernel, Kernel::ResetType::Sticky,
+ "AMMessageQueue:OnMessageRecieved");
+ on_operation_mode_changed = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
+ "AMMessageQueue:OperationModeChanged");
+}
+
+AppletMessageQueue::~AppletMessageQueue() = default;
+
+const Kernel::SharedPtr<Kernel::Event>& AppletMessageQueue::GetMesssageRecieveEvent() const {
+ return on_new_message;
+}
+
+const Kernel::SharedPtr<Kernel::Event>& AppletMessageQueue::GetOperationModeChangedEvent() const {
+ return on_operation_mode_changed;
+}
+
+void AppletMessageQueue::PushMessage(AppletMessage msg) {
+ messages.push(msg);
+ on_new_message->Signal();
+}
+
+AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() {
+ if (messages.empty()) {
+ on_new_message->Clear();
+ return AppletMessage::NoMessage;
+ }
+ auto msg = messages.front();
+ messages.pop();
+ if (messages.empty()) {
+ on_new_message->Clear();
+ }
+ return msg;
+}
+
+std::size_t AppletMessageQueue::GetMessageCount() const {
+ return messages.size();
+}
+
+void AppletMessageQueue::OperationModeChanged() {
+ PushMessage(AppletMessage::OperationModeChanged);
+ PushMessage(AppletMessage::PerformanceModeChanged);
+ on_operation_mode_changed->Signal();
+}
+
+ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue)
+ : ServiceFramework("ICommonStateGetter"), msg_queue(std::move(msg_queue)) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
@@ -388,21 +435,19 @@ void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) {
}
void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) {
- event->Signal();
-
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(event);
+ rb.PushCopyObjects(msg_queue->GetMesssageRecieveEvent());
- LOG_WARNING(Service_AM, "(STUBBED) called");
+ LOG_DEBUG(Service_AM, "called");
}
void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- rb.Push<u32>(15);
+ rb.PushEnum<AppletMessageQueue::AppletMessage>(msg_queue->PopMessage());
- LOG_WARNING(Service_AM, "(STUBBED) called");
+ LOG_DEBUG(Service_AM, "called");
}
void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
@@ -414,13 +459,11 @@ void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
}
void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) {
- event->Signal();
-
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(event);
+ rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent());
- LOG_WARNING(Service_AM, "(STUBBED) called");
+ LOG_DEBUG(Service_AM, "called");
}
void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx) {
@@ -444,7 +487,7 @@ void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld));
- LOG_WARNING(Service_AM, "(STUBBED) called");
+ LOG_DEBUG(Service_AM, "called");
}
void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
@@ -454,7 +497,7 @@ void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked
: APM::PerformanceMode::Handheld));
- LOG_WARNING(Service_AM, "(STUBBED) called");
+ LOG_DEBUG(Service_AM, "called");
}
class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
@@ -743,7 +786,7 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
Account::ProfileManager profile_manager{};
const auto uuid = profile_manager.GetUser(Settings::values.current_user);
- ASSERT(uuid != std::nullopt);
+ ASSERT(uuid);
params.current_user = uuid->uuid;
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -840,8 +883,12 @@ void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) {
void InstallInterfaces(SM::ServiceManager& service_manager,
std::shared_ptr<NVFlinger::NVFlinger> nvflinger) {
- std::make_shared<AppletAE>(nvflinger)->InstallAsService(service_manager);
- std::make_shared<AppletOE>(nvflinger)->InstallAsService(service_manager);
+ auto message_queue = std::make_shared<AppletMessageQueue>();
+ message_queue->PushMessage(
+ AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on game boot
+
+ std::make_shared<AppletAE>(nvflinger, message_queue)->InstallAsService(service_manager);
+ std::make_shared<AppletOE>(nvflinger, message_queue)->InstallAsService(service_manager);
std::make_shared<IdleSys>()->InstallAsService(service_manager);
std::make_shared<OMM>()->InstallAsService(service_manager);
std::make_shared<SPSM>()->InstallAsService(service_manager);
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 095f94851..2f1c20bce 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -5,6 +5,7 @@
#pragma once
#include <memory>
+#include <queue>
#include "core/hle/service/service.h"
namespace Kernel {
@@ -39,6 +40,31 @@ enum SystemLanguage {
TraditionalChinese = 16,
};
+class AppletMessageQueue {
+public:
+ enum class AppletMessage : u32 {
+ NoMessage = 0,
+ FocusStateChanged = 15,
+ OperationModeChanged = 30,
+ PerformanceModeChanged = 31,
+ };
+
+ AppletMessageQueue();
+ ~AppletMessageQueue();
+
+ const Kernel::SharedPtr<Kernel::Event>& GetMesssageRecieveEvent() const;
+ const Kernel::SharedPtr<Kernel::Event>& GetOperationModeChangedEvent() const;
+ void PushMessage(AppletMessage msg);
+ AppletMessage PopMessage();
+ std::size_t GetMessageCount() const;
+ void OperationModeChanged();
+
+private:
+ std::queue<AppletMessage> messages;
+ Kernel::SharedPtr<Kernel::Event> on_new_message;
+ Kernel::SharedPtr<Kernel::Event> on_operation_mode_changed;
+};
+
class IWindowController final : public ServiceFramework<IWindowController> {
public:
IWindowController();
@@ -102,7 +128,7 @@ private:
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
public:
- ICommonStateGetter();
+ explicit ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue);
~ICommonStateGetter() override;
private:
@@ -126,6 +152,7 @@ private:
void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx);
Kernel::SharedPtr<Kernel::Event> event;
+ std::shared_ptr<AppletMessageQueue> msg_queue;
};
class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp
index 68ea778e8..ec93e3529 100644
--- a/src/core/hle/service/am/applet_ae.cpp
+++ b/src/core/hle/service/am/applet_ae.cpp
@@ -12,8 +12,10 @@ namespace Service::AM {
class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
public:
- explicit ILibraryAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
- : ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)) {
+ explicit ILibraryAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
+ std::shared_ptr<AppletMessageQueue> msg_queue)
+ : ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)),
+ msg_queue(std::move(msg_queue)) {
static const FunctionInfo functions[] = {
{0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
{1, &ILibraryAppletProxy::GetSelfController, "GetSelfController"},
@@ -32,7 +34,7 @@ private:
void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ICommonStateGetter>();
+ rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
LOG_DEBUG(Service_AM, "called");
}
@@ -93,12 +95,15 @@ private:
}
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
+ std::shared_ptr<AppletMessageQueue> msg_queue;
};
class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
public:
- explicit ISystemAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
- : ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)) {
+ explicit ISystemAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
+ std::shared_ptr<AppletMessageQueue> msg_queue)
+ : ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)),
+ msg_queue(std::move(msg_queue)) {
static const FunctionInfo functions[] = {
{0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
{1, &ISystemAppletProxy::GetSelfController, "GetSelfController"},
@@ -119,7 +124,7 @@ private:
void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ICommonStateGetter>();
+ rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
LOG_DEBUG(Service_AM, "called");
}
@@ -186,31 +191,34 @@ private:
LOG_DEBUG(Service_AM, "called");
}
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
+ std::shared_ptr<AppletMessageQueue> msg_queue;
};
void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ISystemAppletProxy>(nvflinger);
+ rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue);
LOG_DEBUG(Service_AM, "called");
}
void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger);
+ rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue);
LOG_DEBUG(Service_AM, "called");
}
void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger);
+ rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue);
LOG_DEBUG(Service_AM, "called");
}
-AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
- : ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)) {
+AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
+ std::shared_ptr<AppletMessageQueue> msg_queue)
+ : ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)),
+ msg_queue(std::move(msg_queue)) {
// clang-format off
static const FunctionInfo functions[] = {
{100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"},
@@ -228,4 +236,8 @@ AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
AppletAE::~AppletAE() = default;
+const std::shared_ptr<AppletMessageQueue>& AppletAE::GetMessageQueue() const {
+ return msg_queue;
+}
+
} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h
index 1ed77baa4..902db2665 100644
--- a/src/core/hle/service/am/applet_ae.h
+++ b/src/core/hle/service/am/applet_ae.h
@@ -17,15 +17,19 @@ namespace AM {
class AppletAE final : public ServiceFramework<AppletAE> {
public:
- explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
+ explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
+ std::shared_ptr<AppletMessageQueue> msg_queue);
~AppletAE() override;
+ const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
+
private:
void OpenSystemAppletProxy(Kernel::HLERequestContext& ctx);
void OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx);
void OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx);
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
+ std::shared_ptr<AppletMessageQueue> msg_queue;
};
} // namespace AM
diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp
index 60717afd9..20c8d5fff 100644
--- a/src/core/hle/service/am/applet_oe.cpp
+++ b/src/core/hle/service/am/applet_oe.cpp
@@ -12,8 +12,10 @@ namespace Service::AM {
class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
public:
- explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
- : ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)) {
+ explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
+ std::shared_ptr<AppletMessageQueue> msg_queue)
+ : ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)),
+ msg_queue(std::move(msg_queue)) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"},
@@ -70,7 +72,7 @@ private:
void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ICommonStateGetter>();
+ rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
LOG_DEBUG(Service_AM, "called");
}
@@ -89,17 +91,20 @@ private:
}
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
+ std::shared_ptr<AppletMessageQueue> msg_queue;
};
void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IApplicationProxy>(nvflinger);
+ rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue);
LOG_DEBUG(Service_AM, "called");
}
-AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
- : ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)) {
+AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
+ std::shared_ptr<AppletMessageQueue> msg_queue)
+ : ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)),
+ msg_queue(std::move(msg_queue)) {
static const FunctionInfo functions[] = {
{0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"},
};
@@ -108,4 +113,8 @@ AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
AppletOE::~AppletOE() = default;
+const std::shared_ptr<AppletMessageQueue>& AppletOE::GetMessageQueue() const {
+ return msg_queue;
+}
+
} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h
index 60cfdfd9d..bbd0108ef 100644
--- a/src/core/hle/service/am/applet_oe.h
+++ b/src/core/hle/service/am/applet_oe.h
@@ -17,13 +17,17 @@ namespace AM {
class AppletOE final : public ServiceFramework<AppletOE> {
public:
- explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
+ explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
+ std::shared_ptr<AppletMessageQueue> msg_queue);
~AppletOE() override;
+ const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
+
private:
void OpenApplicationProxy(Kernel::HLERequestContext& ctx);
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
+ std::shared_ptr<AppletMessageQueue> msg_queue;
};
} // namespace AM
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index fac6785a5..d3ea57ea7 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -28,13 +28,13 @@ public:
{1, &IAudioRenderer::GetSampleCount, "GetSampleCount"},
{2, &IAudioRenderer::GetMixBufferCount, "GetMixBufferCount"},
{3, &IAudioRenderer::GetState, "GetState"},
- {4, &IAudioRenderer::RequestUpdate, "RequestUpdate"},
+ {4, &IAudioRenderer::RequestUpdateImpl, "RequestUpdate"},
{5, &IAudioRenderer::Start, "Start"},
{6, &IAudioRenderer::Stop, "Stop"},
{7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"},
- {8, nullptr, "SetRenderingTimeLimit"},
- {9, nullptr, "GetRenderingTimeLimit"},
- {10, nullptr, "RequestUpdateAuto"},
+ {8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"},
+ {9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"},
+ {10, &IAudioRenderer::RequestUpdateImpl, "RequestUpdateAuto"},
{11, nullptr, "ExecuteAudioRendererRendering"},
};
// clang-format on
@@ -79,7 +79,7 @@ private:
LOG_DEBUG(Service_Audio, "called");
}
- void RequestUpdate(Kernel::HLERequestContext& ctx) {
+ void RequestUpdateImpl(Kernel::HLERequestContext& ctx) {
ctx.WriteBuffer(renderer->UpdateAudioRenderer(ctx.ReadBuffer()));
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -110,8 +110,29 @@ private:
LOG_WARNING(Service_Audio, "(STUBBED) called");
}
+ void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ rendering_time_limit_percent = rp.Pop<u32>();
+ ASSERT(rendering_time_limit_percent >= 0 && rendering_time_limit_percent <= 100);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+
+ LOG_DEBUG(Service_Audio, "called. rendering_time_limit_percent={}",
+ rendering_time_limit_percent);
+ }
+
+ void GetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Audio, "called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(rendering_time_limit_percent);
+ }
+
Kernel::SharedPtr<Kernel::Event> system_event;
std::unique_ptr<AudioCore::AudioRenderer> renderer;
+ u32 rendering_time_limit_percent = 100;
};
class IAudioDevice final : public ServiceFramework<IAudioDevice> {
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index 7168c6a10..783c39503 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -161,7 +161,7 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) {
ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count");
std::size_t worker_sz = WorkerBufferSize(channel_count);
- ASSERT_MSG(buffer_sz < worker_sz, "Worker buffer too large");
+ ASSERT_MSG(buffer_sz >= worker_sz, "Worker buffer too large");
std::unique_ptr<OpusDecoder, OpusDeleter> decoder{
static_cast<OpusDecoder*>(operator new(worker_sz))};
if (opus_decoder_init(decoder.get(), sample_rate, channel_count)) {
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 234a8687b..a92cf7815 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -309,6 +309,16 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
return save_data_factory->Open(space, save_struct);
}
+ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) {
+ LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", static_cast<u8>(space));
+
+ if (save_data_factory == nullptr) {
+ return ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound);
+ }
+
+ return MakeResult(save_data_factory->GetSaveDataSpaceDirectory(space));
+}
+
ResultVal<FileSys::VirtualDir> OpenSDMC() {
LOG_TRACE(Service_FS, "Opening SDMC");
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index b18652a68..e38f02869 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -45,6 +45,7 @@ ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId stora
FileSys::ContentRecordType type);
ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
FileSys::SaveDataDescriptor save_struct);
+ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space);
ResultVal<FileSys::VirtualDir> OpenSDMC();
std::unique_ptr<FileSys::RegisteredCacheUnion> GetUnionContents();
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index c1c83a11d..b9a1d5105 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -11,6 +11,7 @@
#include "common/assert.h"
#include "common/common_types.h"
+#include "common/hex_util.h"
#include "common/logging/log.h"
#include "common/string_util.h"
#include "core/file_sys/directory.h"
@@ -451,7 +452,147 @@ private:
VfsDirectoryServiceWrapper backend;
};
+class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
+public:
+ explicit ISaveDataInfoReader(FileSys::SaveDataSpaceId space)
+ : ServiceFramework("ISaveDataInfoReader") {
+ static const FunctionInfo functions[] = {
+ {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
+ };
+ RegisterHandlers(functions);
+
+ FindAllSaves(space);
+ }
+
+ void ReadSaveDataInfo(Kernel::HLERequestContext& ctx) {
+ // Calculate how many entries we can fit in the output buffer
+ const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(SaveDataInfo);
+
+ // Cap at total number of entries.
+ const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index);
+
+ // Determine data start and end
+ const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index);
+ const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries);
+ const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
+
+ next_entry_index += actual_entries;
+
+ // Write the data to memory
+ ctx.WriteBuffer(begin, range_size);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(static_cast<u32>(actual_entries));
+ }
+
+private:
+ static u64 stoull_be(std::string_view str) {
+ if (str.size() != 16)
+ return 0;
+
+ const auto bytes = Common::HexStringToArray<0x8>(str);
+ u64 out{};
+ std::memcpy(&out, bytes.data(), sizeof(u64));
+
+ return Common::swap64(out);
+ }
+
+ void FindAllSaves(FileSys::SaveDataSpaceId space) {
+ const auto save_root = OpenSaveDataSpace(space);
+ ASSERT(save_root.Succeeded());
+
+ for (const auto& type : (*save_root)->GetSubdirectories()) {
+ if (type->GetName() == "save") {
+ for (const auto& save_id : type->GetSubdirectories()) {
+ for (const auto& user_id : save_id->GetSubdirectories()) {
+ const auto save_id_numeric = stoull_be(save_id->GetName());
+ auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
+ std::reverse(user_id_numeric.begin(), user_id_numeric.end());
+
+ if (save_id_numeric != 0) {
+ // System Save Data
+ info.emplace_back(SaveDataInfo{
+ 0,
+ space,
+ FileSys::SaveDataType::SystemSaveData,
+ {},
+ user_id_numeric,
+ save_id_numeric,
+ 0,
+ user_id->GetSize(),
+ {},
+ });
+
+ continue;
+ }
+
+ for (const auto& title_id : user_id->GetSubdirectories()) {
+ const auto device =
+ std::all_of(user_id_numeric.begin(), user_id_numeric.end(),
+ [](u8 val) { return val == 0; });
+ info.emplace_back(SaveDataInfo{
+ 0,
+ space,
+ device ? FileSys::SaveDataType::DeviceSaveData
+ : FileSys::SaveDataType::SaveData,
+ {},
+ user_id_numeric,
+ save_id_numeric,
+ stoull_be(title_id->GetName()),
+ title_id->GetSize(),
+ {},
+ });
+ }
+ }
+ }
+ } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) {
+ // Temporary Storage
+ for (const auto& user_id : type->GetSubdirectories()) {
+ for (const auto& title_id : user_id->GetSubdirectories()) {
+ if (!title_id->GetFiles().empty() ||
+ !title_id->GetSubdirectories().empty()) {
+ auto user_id_numeric =
+ Common::HexStringToArray<0x10>(user_id->GetName());
+ std::reverse(user_id_numeric.begin(), user_id_numeric.end());
+
+ info.emplace_back(SaveDataInfo{
+ 0,
+ space,
+ FileSys::SaveDataType::TemporaryStorage,
+ {},
+ user_id_numeric,
+ stoull_be(type->GetName()),
+ stoull_be(title_id->GetName()),
+ title_id->GetSize(),
+ {},
+ });
+ }
+ }
+ }
+ }
+ }
+ }
+
+ struct SaveDataInfo {
+ u64_le save_id_unknown;
+ FileSys::SaveDataSpaceId space;
+ FileSys::SaveDataType type;
+ INSERT_PADDING_BYTES(0x6);
+ std::array<u8, 0x10> user_id;
+ u64_le save_id;
+ u64_le title_id;
+ u64_le save_image_size;
+ INSERT_PADDING_BYTES(0x28);
+ };
+ static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
+
+ std::vector<SaveDataInfo> info;
+ u64 next_entry_index = 0;
+};
+
FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
+ // clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "MountContent"},
{1, &FSP_SRV::Initialize, "Initialize"},
@@ -485,7 +626,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
{58, nullptr, "ReadSaveDataFileSystemExtraData"},
{59, nullptr, "WriteSaveDataFileSystemExtraData"},
{60, nullptr, "OpenSaveDataInfoReader"},
- {61, nullptr, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
+ {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
{62, nullptr, "OpenCacheStorageList"},
{64, nullptr, "OpenSaveDataInternalStorageFileSystem"},
{65, nullptr, "UpdateSaveDataMacForDebug"},
@@ -544,6 +685,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
{1009, nullptr, "GetAndClearMemoryReportInfo"},
{1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
};
+ // clang-format on
RegisterHandlers(functions);
}
@@ -618,6 +760,15 @@ void FSP_SRV::OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx) {
MountSaveData(ctx);
}
+void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>();
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space));
+}
+
void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_FS, "(STUBBED) called");
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h
index 4aa0358cb..e7abec0a3 100644
--- a/src/core/hle/service/filesystem/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp_srv.h
@@ -25,6 +25,7 @@ private:
void CreateSaveData(Kernel::HLERequestContext& ctx);
void MountSaveData(Kernel::HLERequestContext& ctx);
void OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx);
+ void OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx);
void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 4b4d1324f..56c415e4e 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -310,6 +310,7 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
dual_entry.pad_states.raw = pad_state.raw;
dual_entry.l_stick = lstick_entry;
dual_entry.r_stick = rstick_entry;
+ break;
case NPadControllerType::JoyLeft:
left_entry.connection_status.raw = 0;
@@ -392,8 +393,10 @@ std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const {
}
void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) {
+ styleset_changed_event->Signal();
hold_type = joy_hold_type;
}
+
Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const {
return hold_type;
}
@@ -427,6 +430,9 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
}
Kernel::SharedPtr<Kernel::Event> Controller_NPad::GetStyleSetChangedEvent() const {
+ // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should
+ // be signalled at least once, and signaled after a new controller is connected?
+ styleset_changed_event->Signal();
return styleset_changed_event;
}
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index a9aa9ec78..a45fd4954 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -96,6 +96,8 @@ public:
// TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event);
+
+ ReloadInputDevices();
}
void ActivateController(HidController controller) {
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index c1af878fe..1d6e7756f 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -212,7 +212,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2};
auto amiibo = nfp_interface.GetAmiiboBuffer();
TagInfo tag_info{};
- std::memcpy(tag_info.uuid.data(), amiibo.uuid.data(), sizeof(tag_info.uuid.size()));
+ tag_info.uuid = amiibo.uuid;
tag_info.uuid_length = static_cast<u8>(tag_info.uuid.size());
tag_info.protocol = 1; // TODO(ogniK): Figure out actual values
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index 07c1381fe..1d2978f24 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -2,6 +2,9 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+#include "core/file_sys/control_metadata.h"
+#include "core/file_sys/patch_manager.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/ns/ns.h"
@@ -118,7 +121,7 @@ public:
{305, nullptr, "TerminateSystemApplet"},
{306, nullptr, "LaunchOverlayApplet"},
{307, nullptr, "TerminateOverlayApplet"},
- {400, nullptr, "GetApplicationControlData"},
+ {400, &IApplicationManagerInterface::GetApplicationControlData, "GetApplicationControlData"},
{401, nullptr, "InvalidateAllApplicationControlCache"},
{402, nullptr, "RequestDownloadApplicationControlData"},
{403, nullptr, "GetMaxApplicationControlCacheCount"},
@@ -243,6 +246,65 @@ public:
RegisterHandlers(functions);
}
+
+ void GetApplicationControlData(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto flag = rp.PopRaw<u64>();
+ LOG_DEBUG(Service_NS, "called with flag={:016X}", flag);
+
+ const auto title_id = rp.PopRaw<u64>();
+
+ const auto size = ctx.GetWriteBufferSize();
+
+ const FileSys::PatchManager pm{title_id};
+ const auto control = pm.GetControlMetadata();
+
+ std::vector<u8> out;
+
+ if (control.first != nullptr) {
+ if (size < 0x4000) {
+ LOG_ERROR(Service_NS,
+ "output buffer is too small! (actual={:016X}, expected_min=0x4000)",
+ size);
+ IPC::ResponseBuilder rb{ctx, 2};
+ // TODO(DarkLordZach): Find a better error code for this.
+ rb.Push(ResultCode(-1));
+ return;
+ }
+
+ out.resize(0x4000);
+ const auto bytes = control.first->GetRawBytes();
+ std::memcpy(out.data(), bytes.data(), bytes.size());
+ } else {
+ LOG_WARNING(Service_NS, "missing NACP data for title_id={:016X}, defaulting to zeros.",
+ title_id);
+ out.resize(std::min<u64>(0x4000, size));
+ }
+
+ if (control.second != nullptr) {
+ if (size < 0x4000 + control.second->GetSize()) {
+ LOG_ERROR(Service_NS,
+ "output buffer is too small! (actual={:016X}, expected_min={:016X})",
+ size, 0x4000 + control.second->GetSize());
+ IPC::ResponseBuilder rb{ctx, 2};
+ // TODO(DarkLordZach): Find a better error code for this.
+ rb.Push(ResultCode(-1));
+ return;
+ }
+
+ out.resize(0x4000 + control.second->GetSize());
+ control.second->Read(out.data() + 0x4000, control.second->GetSize());
+ } else {
+ LOG_WARNING(Service_NS, "missing icon data for title_id={:016X}, defaulting to zeros.",
+ title_id);
+ }
+
+ ctx.WriteBuffer(out);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(static_cast<u32>(out.size()));
+ }
};
class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> {
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index fd98d541d..630ebbfc7 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -31,7 +31,7 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer)
buffer_wait_event->Signal();
}
-boost::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) {
+std::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) {
auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) {
// Only consider free buffers. Buffers become free once again after they've been Acquired
// and Released by the compositor, see the NVFlinger::Compose method.
@@ -44,7 +44,7 @@ boost::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) {
});
if (itr == queue.end()) {
- return boost::none;
+ return {};
}
itr->status = Buffer::Status::Dequeued;
@@ -70,12 +70,12 @@ void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform,
itr->crop_rect = crop_rect;
}
-boost::optional<const BufferQueue::Buffer&> BufferQueue::AcquireBuffer() {
+std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() {
auto itr = std::find_if(queue.begin(), queue.end(), [](const Buffer& buffer) {
return buffer.status == Buffer::Status::Queued;
});
if (itr == queue.end())
- return boost::none;
+ return {};
itr->status = Buffer::Status::Acquired;
return *itr;
}
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 50b767732..8cff5eb71 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -4,8 +4,9 @@
#pragma once
+#include <optional>
#include <vector>
-#include <boost/optional.hpp>
+
#include "common/common_funcs.h"
#include "common/math_util.h"
#include "common/swap.h"
@@ -57,9 +58,9 @@ public:
/// Rotate source image 90 degrees clockwise
Rotate90 = 0x04,
/// Rotate source image 180 degrees
- Roate180 = 0x03,
+ Rotate180 = 0x03,
/// Rotate source image 270 degrees clockwise
- Roate270 = 0x07,
+ Rotate270 = 0x07,
};
struct Buffer {
@@ -73,11 +74,11 @@ public:
};
void SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer);
- boost::optional<u32> DequeueBuffer(u32 width, u32 height);
+ std::optional<u32> DequeueBuffer(u32 width, u32 height);
const IGBPBuffer& RequestBuffer(u32 slot) const;
void QueueBuffer(u32 slot, BufferTransformFlags transform,
const MathUtil::Rectangle<int>& crop_rect);
- boost::optional<const Buffer&> AcquireBuffer();
+ std::optional<std::reference_wrapper<const Buffer>> AcquireBuffer();
void ReleaseBuffer(u32 slot);
u32 Query(QueryType type);
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index d47b6f659..214e6d1b3 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -3,7 +3,7 @@
// Refer to the license.txt file included.
#include <algorithm>
-#include <boost/optional.hpp>
+#include <optional>
#include "common/alignment.h"
#include "common/assert.h"
@@ -134,7 +134,7 @@ void NVFlinger::Compose() {
MicroProfileFlip();
- if (buffer == boost::none) {
+ if (!buffer) {
auto& system_instance = Core::System::GetInstance();
// There was no queued buffer to draw, render previous frame
@@ -143,7 +143,7 @@ void NVFlinger::Compose() {
continue;
}
- auto& igbp_buffer = buffer->igbp_buffer;
+ auto& igbp_buffer = buffer->get().igbp_buffer;
// Now send the buffer to the GPU for drawing.
// TODO(Subv): Support more than just disp0. The display device selection is probably based
@@ -152,10 +152,10 @@ void NVFlinger::Compose() {
ASSERT(nvdisp);
nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.format,
- igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride, buffer->transform,
- buffer->crop_rect);
+ igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride,
+ buffer->get().transform, buffer->get().crop_rect);
- buffer_queue->ReleaseBuffer(buffer->slot);
+ buffer_queue->ReleaseBuffer(buffer->get().slot);
}
}
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index a4cf45267..1ec340466 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -80,8 +80,8 @@ namespace Service {
* Creates a function string for logging, complete with the name (or header code, depending
* on what's passed in) the port name, and all the cmd_buff arguments.
*/
-static std::string MakeFunctionString(const char* name, const char* port_name,
- const u32* cmd_buff) {
+[[maybe_unused]] static std::string MakeFunctionString(const char* name, const char* port_name,
+ const u32* cmd_buff) {
// Number of params == bits 0-5 + bits 6-11
int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F);
diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp
index 44a6717d0..69c260408 100644
--- a/src/core/hle/service/spl/module.cpp
+++ b/src/core/hle/service/spl/module.cpp
@@ -3,18 +3,23 @@
// Refer to the license.txt file included.
#include <algorithm>
+#include <chrono>
#include <cstdlib>
+#include <ctime>
+#include <functional>
#include <vector>
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/service/spl/csrng.h"
#include "core/hle/service/spl/module.h"
#include "core/hle/service/spl/spl.h"
+#include "core/settings.h"
namespace Service::SPL {
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
- : ServiceFramework(name), module(std::move(module)) {}
+ : ServiceFramework(name), module(std::move(module)),
+ rng(Settings::values.rng_seed.value_or(std::time(nullptr))) {}
Module::Interface::~Interface() = default;
@@ -24,7 +29,7 @@ void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) {
std::size_t size = ctx.GetWriteBufferSize();
std::vector<u8> data(size);
- std::generate(data.begin(), data.end(), std::rand);
+ std::generate(data.begin(), data.end(), rng);
ctx.WriteBuffer(data);
diff --git a/src/core/hle/service/spl/module.h b/src/core/hle/service/spl/module.h
index 48fda6099..afa1f0295 100644
--- a/src/core/hle/service/spl/module.h
+++ b/src/core/hle/service/spl/module.h
@@ -4,6 +4,7 @@
#pragma once
+#include <random>
#include "core/hle/service/service.h"
namespace Service::SPL {
@@ -19,6 +20,9 @@ public:
protected:
std::shared_ptr<Module> module;
+
+ private:
+ std::mt19937 rng;
};
};
diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp
index 18a5d71d5..e3cbd7004 100644
--- a/src/core/hle/service/time/interface.cpp
+++ b/src/core/hle/service/time/interface.cpp
@@ -21,7 +21,7 @@ Time::Time(std::shared_ptr<Module> time, const char* name)
{102, nullptr, "GetStandardUserSystemClockInitialYear"},
{200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"},
{300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"},
- {400, nullptr, "GetClockSnapshot"},
+ {400, &Time::GetClockSnapshot, "GetClockSnapshot"},
{401, nullptr, "GetClockSnapshotFromSystemClockContext"},
{500, nullptr, "CalculateStandardUserSystemClockDifferenceByUser"},
{501, nullptr, "CalculateSpanBetween"},
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 28fd8debc..85e7b1195 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -15,6 +15,44 @@
namespace Service::Time {
+static void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time,
+ CalendarAdditionalInfo& additional_info,
+ [[maybe_unused]] const TimeZoneRule& /*rule*/) {
+ const std::time_t time(posix_time);
+ const std::tm* tm = std::localtime(&time);
+ if (tm == nullptr) {
+ calendar_time = {};
+ additional_info = {};
+ return;
+ }
+ calendar_time.year = tm->tm_year + 1900;
+ calendar_time.month = tm->tm_mon + 1;
+ calendar_time.day = tm->tm_mday;
+ calendar_time.hour = tm->tm_hour;
+ calendar_time.minute = tm->tm_min;
+ calendar_time.second = tm->tm_sec;
+
+ additional_info.day_of_week = tm->tm_wday;
+ additional_info.day_of_year = tm->tm_yday;
+ std::memcpy(additional_info.name.data(), "UTC", sizeof("UTC"));
+ additional_info.utc_offset = 0;
+}
+
+static u64 CalendarToPosix(const CalendarTime& calendar_time,
+ [[maybe_unused]] const TimeZoneRule& /*rule*/) {
+ std::tm time{};
+ time.tm_year = calendar_time.year - 1900;
+ time.tm_mon = calendar_time.month - 1;
+ time.tm_mday = calendar_time.day;
+
+ time.tm_hour = calendar_time.hour;
+ time.tm_min = calendar_time.minute;
+ time.tm_sec = calendar_time.second;
+
+ std::time_t epoch_time = std::mktime(&time);
+ return static_cast<u64>(epoch_time);
+}
+
class ISystemClock final : public ServiceFramework<ISystemClock> {
public:
ISystemClock() : ServiceFramework("ISystemClock") {
@@ -80,8 +118,8 @@ public:
{5, nullptr, "GetTimeZoneRuleVersion"},
{100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
{101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
- {201, nullptr, "ToPosixTime"},
- {202, nullptr, "ToPosixTimeWithMyRule"},
+ {201, &ITimeZoneService::ToPosixTime, "ToPosixTime"},
+ {202, &ITimeZoneService::ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"},
};
RegisterHandlers(functions);
}
@@ -151,24 +189,29 @@ private:
rb.PushRaw(additional_info);
}
- void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time,
- CalendarAdditionalInfo& additional_info, const TimeZoneRule& /*rule*/) {
- std::time_t t(posix_time);
- std::tm* tm = std::localtime(&t);
- if (!tm) {
- return;
- }
- calendar_time.year = tm->tm_year + 1900;
- calendar_time.month = tm->tm_mon + 1;
- calendar_time.day = tm->tm_mday;
- calendar_time.hour = tm->tm_hour;
- calendar_time.minute = tm->tm_min;
- calendar_time.second = tm->tm_sec;
-
- additional_info.day_of_week = tm->tm_wday;
- additional_info.day_of_year = tm->tm_yday;
- std::memcpy(additional_info.name.data(), "UTC", sizeof("UTC"));
- additional_info.utc_offset = 0;
+ void ToPosixTime(Kernel::HLERequestContext& ctx) {
+ // TODO(ogniK): Figure out how to handle multiple times
+ LOG_WARNING(Service_Time, "(STUBBED) called");
+ IPC::RequestParser rp{ctx};
+ auto calendar_time = rp.PopRaw<CalendarTime>();
+ auto posix_time = CalendarToPosix(calendar_time, {});
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw<u32>(1); // Amount of times we're returning
+ ctx.WriteBuffer(&posix_time, sizeof(u64));
+ }
+
+ void ToPosixTimeWithMyRule(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_Time, "(STUBBED) called");
+ IPC::RequestParser rp{ctx};
+ auto calendar_time = rp.PopRaw<CalendarTime>();
+ auto posix_time = CalendarToPosix(calendar_time, {});
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw<u32>(1); // Amount of times we're returning
+ ctx.WriteBuffer(&posix_time, sizeof(u64));
}
};
@@ -207,6 +250,55 @@ void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& c
LOG_DEBUG(Service_Time, "called");
}
+void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Time, "called");
+
+ IPC::RequestParser rp{ctx};
+ auto unknown_u8 = rp.PopRaw<u8>();
+
+ ClockSnapshot clock_snapshot{};
+
+ const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>(
+ std::chrono::system_clock::now().time_since_epoch())
+ .count()};
+ CalendarTime calendar_time{};
+ const std::time_t time(time_since_epoch);
+ const std::tm* tm = std::localtime(&time);
+ if (tm == nullptr) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultCode(-1)); // TODO(ogniK): Find appropriate error code
+ return;
+ }
+ SteadyClockTimePoint steady_clock_time_point{CoreTiming::cyclesToMs(CoreTiming::GetTicks()) /
+ 1000};
+
+ LocationName location_name{"UTC"};
+ calendar_time.year = tm->tm_year + 1900;
+ calendar_time.month = tm->tm_mon + 1;
+ calendar_time.day = tm->tm_mday;
+ calendar_time.hour = tm->tm_hour;
+ calendar_time.minute = tm->tm_min;
+ calendar_time.second = tm->tm_sec;
+ clock_snapshot.system_posix_time = time_since_epoch;
+ clock_snapshot.network_posix_time = time_since_epoch;
+ clock_snapshot.system_calendar_time = calendar_time;
+ clock_snapshot.network_calendar_time = calendar_time;
+
+ CalendarAdditionalInfo additional_info{};
+ PosixToCalendar(time_since_epoch, calendar_time, additional_info, {});
+
+ clock_snapshot.system_calendar_info = additional_info;
+ clock_snapshot.network_calendar_info = additional_info;
+
+ clock_snapshot.steady_clock_timepoint = steady_clock_time_point;
+ clock_snapshot.location_name = location_name;
+ clock_snapshot.clock_auto_adjustment_enabled = 1;
+ clock_snapshot.ipc_u8 = unknown_u8;
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ ctx.WriteBuffer(&clock_snapshot, sizeof(ClockSnapshot));
+}
+
Module::Interface::Interface(std::shared_ptr<Module> time, const char* name)
: ServiceFramework(name), time(std::move(time)) {}
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h
index 5659ecad3..77871ae07 100644
--- a/src/core/hle/service/time/time.h
+++ b/src/core/hle/service/time/time.h
@@ -5,6 +5,7 @@
#pragma once
#include <array>
+#include "common/common_funcs.h"
#include "core/hle/service/service.h"
namespace Service::Time {
@@ -53,6 +54,23 @@ struct SystemClockContext {
static_assert(sizeof(SystemClockContext) == 0x20,
"SystemClockContext structure has incorrect size");
+struct ClockSnapshot {
+ SystemClockContext user_clock_context;
+ SystemClockContext network_clock_context;
+ s64_le system_posix_time;
+ s64_le network_posix_time;
+ CalendarTime system_calendar_time;
+ CalendarTime network_calendar_time;
+ CalendarAdditionalInfo system_calendar_info;
+ CalendarAdditionalInfo network_calendar_info;
+ SteadyClockTimePoint steady_clock_timepoint;
+ LocationName location_name;
+ u8 clock_auto_adjustment_enabled;
+ u8 ipc_u8;
+ INSERT_PADDING_BYTES(2);
+};
+static_assert(sizeof(ClockSnapshot) == 0xd0, "ClockSnapshot is an invalid size");
+
class Module final {
public:
class Interface : public ServiceFramework<Interface> {
@@ -65,6 +83,7 @@ public:
void GetStandardSteadyClock(Kernel::HLERequestContext& ctx);
void GetTimeZoneService(Kernel::HLERequestContext& ctx);
void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx);
+ void GetClockSnapshot(Kernel::HLERequestContext& ctx);
protected:
std::shared_ptr<Module> time;
diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp
index c489da071..f0a831d45 100644
--- a/src/core/hle/service/usb/usb.cpp
+++ b/src/core/hle/service/usb/usb.cpp
@@ -132,11 +132,11 @@ public:
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "BindNoticeEvent"},
- {1, nullptr, "Unknown1"},
+ {1, nullptr, "UnbindNoticeEvent"},
{2, nullptr, "GetStatus"},
{3, nullptr, "GetNotice"},
- {4, nullptr, "Unknown2"},
- {5, nullptr, "Unknown3"},
+ {4, nullptr, "EnablePowerRequestNotice"},
+ {5, nullptr, "DisablePowerRequestNotice"},
{6, nullptr, "ReplyPowerRequest"},
};
// clang-format on
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 184537daa..d764b2406 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -6,9 +6,10 @@
#include <array>
#include <cstring>
#include <memory>
+#include <optional>
#include <type_traits>
#include <utility>
-#include <boost/optional.hpp>
+
#include "common/alignment.h"
#include "common/assert.h"
#include "common/common_funcs.h"
@@ -506,9 +507,9 @@ private:
IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()};
const u32 width{request.data.width};
const u32 height{request.data.height};
- boost::optional<u32> slot = buffer_queue->DequeueBuffer(width, height);
+ std::optional<u32> slot = buffer_queue->DequeueBuffer(width, height);
- if (slot != boost::none) {
+ if (slot) {
// Buffer is available
IGBPDequeueBufferResponseParcel response{*slot};
ctx.WriteBuffer(response.Serialize());
@@ -520,7 +521,7 @@ private:
Kernel::ThreadWakeupReason reason) {
// Repeat TransactParcel DequeueBuffer when a buffer is available
auto buffer_queue = nv_flinger->GetBufferQueue(id);
- boost::optional<u32> slot = buffer_queue->DequeueBuffer(width, height);
+ std::optional<u32> slot = buffer_queue->DequeueBuffer(width, height);
IGBPDequeueBufferResponseParcel response{*slot};
ctx.WriteBuffer(response.Serialize());
IPC::ResponseBuilder rb{ctx, 2};
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index e562b3a04..7686634bf 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -6,10 +6,11 @@
#include <iosfwd>
#include <memory>
+#include <optional>
#include <string>
#include <utility>
#include <vector>
-#include <boost/optional.hpp>
+
#include "common/common_types.h"
#include "core/file_sys/vfs.h"
@@ -145,7 +146,7 @@ public:
* information.
* @returns A pair with the optional system mode, and and the status.
*/
- virtual std::pair<boost::optional<u32>, ResultStatus> LoadKernelSystemMode() {
+ virtual std::pair<std::optional<u32>, ResultStatus> LoadKernelSystemMode() {
// 96MB allocated to the application.
return std::make_pair(2, ResultStatus::Success);
}
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index bc8e402a8..c8e491fec 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -12,10 +12,12 @@
#include "common/swap.h"
#include "core/core.h"
#include "core/file_sys/control_metadata.h"
+#include "core/file_sys/romfs_factory.h"
#include "core/file_sys/vfs_offset.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/vm_manager.h"
+#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/nro.h"
#include "core/loader/nso.h"
#include "core/memory.h"
@@ -208,6 +210,9 @@ ResultStatus AppLoader_NRO::Load(Kernel::Process& process) {
return ResultStatus::ErrorLoadingNRO;
}
+ if (romfs != nullptr)
+ Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this));
+
process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
is_loaded = true;
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 014298ed6..70abd856a 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -4,9 +4,9 @@
#include <algorithm>
#include <cstring>
+#include <optional>
#include <utility>
-#include <boost/optional.hpp>
#include "common/assert.h"
#include "common/common_types.h"
#include "common/logging/log.h"
diff --git a/src/core/memory_hook.h b/src/core/memory_hook.h
index 0269c7ff1..940777107 100644
--- a/src/core/memory_hook.h
+++ b/src/core/memory_hook.h
@@ -5,7 +5,8 @@
#pragma once
#include <memory>
-#include <boost/optional.hpp>
+#include <optional>
+
#include "common/common_types.h"
namespace Memory {
@@ -18,19 +19,19 @@ namespace Memory {
*
* A hook may be mapped to multiple regions of memory.
*
- * If a boost::none or false is returned from a function, the read/write request is passed through
+ * If a std::nullopt or false is returned from a function, the read/write request is passed through
* to the underlying memory region.
*/
class MemoryHook {
public:
virtual ~MemoryHook();
- virtual boost::optional<bool> IsValidAddress(VAddr addr) = 0;
+ virtual std::optional<bool> IsValidAddress(VAddr addr) = 0;
- virtual boost::optional<u8> Read8(VAddr addr) = 0;
- virtual boost::optional<u16> Read16(VAddr addr) = 0;
- virtual boost::optional<u32> Read32(VAddr addr) = 0;
- virtual boost::optional<u64> Read64(VAddr addr) = 0;
+ virtual std::optional<u8> Read8(VAddr addr) = 0;
+ virtual std::optional<u16> Read16(VAddr addr) = 0;
+ virtual std::optional<u32> Read32(VAddr addr) = 0;
+ virtual std::optional<u64> Read64(VAddr addr) = 0;
virtual bool ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) = 0;
diff --git a/src/core/settings.h b/src/core/settings.h
index 0af9dd416..e424479f2 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -6,6 +6,7 @@
#include <array>
#include <atomic>
+#include <optional>
#include <string>
#include "common/common_types.h"
@@ -114,8 +115,9 @@ struct Values {
// System
bool use_docked_mode;
bool enable_nfc;
- int current_user;
- int language_index;
+ std::optional<u32> rng_seed;
+ s32 current_user;
+ s32 language_index;
// Controls
std::array<std::string, NativeButton::NumButtons> buttons;
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 0de13edd3..a3b08c740 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -184,4 +184,13 @@ TelemetrySession::~TelemetrySession() {
backend = nullptr;
}
+bool TelemetrySession::SubmitTestcase() {
+#ifdef ENABLE_WEB_SERVICE
+ field_collection.Accept(*backend);
+ return backend->SubmitTestcase();
+#else
+ return false;
+#endif
+}
+
} // namespace Core
diff --git a/src/core/telemetry_session.h b/src/core/telemetry_session.h
index 2a4845797..023612b79 100644
--- a/src/core/telemetry_session.h
+++ b/src/core/telemetry_session.h
@@ -31,6 +31,12 @@ public:
field_collection.AddField(type, name, std::move(value));
}
+ /**
+ * Submits a Testcase.
+ * @returns A bool indicating whether the submission succeeded
+ */
+ bool SubmitTestcase();
+
private:
Telemetry::FieldCollection field_collection; ///< Tracks all added fields for the session
std::unique_ptr<Telemetry::VisitorInterface> backend; ///< Backend interface that logs fields