Compare commits
1 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4e68bbb32 |
@@ -54,9 +54,8 @@ std::vector<s16> Interpolate(InterpolationState& state, std::vector<s16> input,
|
||||
double l = 0.0;
|
||||
double r = 0.0;
|
||||
for (std::size_t j = 0; j < h.size(); j++) {
|
||||
const double lanczos_calc = Lanczos(taps, pos + j - taps + 1);
|
||||
l += lanczos_calc * h[j][0];
|
||||
r += lanczos_calc * h[j][1];
|
||||
l += Lanczos(taps, pos + j - taps + 1) * h[j][0];
|
||||
r += Lanczos(taps, pos + j - taps + 1) * h[j][1];
|
||||
}
|
||||
output.emplace_back(static_cast<s16>(std::clamp(l, -32768.0, 32767.0)));
|
||||
output.emplace_back(static_cast<s16>(std::clamp(r, -32768.0, 32767.0)));
|
||||
|
||||
@@ -30,7 +30,8 @@ static Stream::Format ChannelsToStreamFormat(u32 num_channels) {
|
||||
StreamPtr AudioOut::OpenStream(u32 sample_rate, u32 num_channels, std::string&& name,
|
||||
Stream::ReleaseCallback&& release_callback) {
|
||||
if (!sink) {
|
||||
sink = CreateSinkFromID(Settings::values.sink_id, Settings::values.audio_device_id);
|
||||
const SinkDetails& sink_details = GetSinkDetails(Settings::values.sink_id);
|
||||
sink = sink_details.factory(Settings::values.audio_device_id);
|
||||
}
|
||||
|
||||
return std::make_shared<Stream>(
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "audio_core/codec.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace AudioCore {
|
||||
@@ -72,7 +72,7 @@ private:
|
||||
EffectInStatus info{};
|
||||
};
|
||||
AudioRenderer::AudioRenderer(AudioRendererParameter params,
|
||||
Kernel::SharedPtr<Kernel::WritableEvent> buffer_event)
|
||||
Kernel::SharedPtr<Kernel::Event> buffer_event)
|
||||
: worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count),
|
||||
effects(params.effect_count) {
|
||||
|
||||
@@ -285,11 +285,8 @@ void AudioRenderer::VoiceState::RefreshBuffer() {
|
||||
break;
|
||||
}
|
||||
|
||||
// Only interpolate when necessary, expensive.
|
||||
if (GetInfo().sample_rate != STREAM_SAMPLE_RATE) {
|
||||
samples = Interpolate(interp_state, std::move(samples), GetInfo().sample_rate,
|
||||
STREAM_SAMPLE_RATE);
|
||||
}
|
||||
samples =
|
||||
Interpolate(interp_state, std::move(samples), GetInfo().sample_rate, STREAM_SAMPLE_RATE);
|
||||
|
||||
is_refresh_pending = false;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "core/hle/kernel/object.h"
|
||||
|
||||
namespace Kernel {
|
||||
class WritableEvent;
|
||||
class Event;
|
||||
}
|
||||
|
||||
namespace AudioCore {
|
||||
@@ -208,8 +208,7 @@ static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size
|
||||
|
||||
class AudioRenderer {
|
||||
public:
|
||||
AudioRenderer(AudioRendererParameter params,
|
||||
Kernel::SharedPtr<Kernel::WritableEvent> buffer_event);
|
||||
AudioRenderer(AudioRendererParameter params, Kernel::SharedPtr<Kernel::Event> buffer_event);
|
||||
~AudioRenderer();
|
||||
|
||||
std::vector<u8> UpdateAudioRenderer(const std::vector<u8>& input_params);
|
||||
@@ -225,7 +224,7 @@ private:
|
||||
class VoiceState;
|
||||
|
||||
AudioRendererParameter worker_params;
|
||||
Kernel::SharedPtr<Kernel::WritableEvent> buffer_event;
|
||||
Kernel::SharedPtr<Kernel::Event> buffer_event;
|
||||
std::vector<VoiceState> voices;
|
||||
std::vector<EffectState> effects;
|
||||
std::unique_ptr<AudioOut> audio_out;
|
||||
|
||||
@@ -107,7 +107,7 @@ private:
|
||||
static void StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state);
|
||||
};
|
||||
|
||||
CubebSink::CubebSink(std::string_view target_device_name) {
|
||||
CubebSink::CubebSink(std::string target_device_name) {
|
||||
if (cubeb_init(&ctx, "yuzu", nullptr) != CUBEB_OK) {
|
||||
LOG_CRITICAL(Audio_Sink, "cubeb_init failed");
|
||||
return;
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace AudioCore {
|
||||
|
||||
class CubebSink final : public Sink {
|
||||
public:
|
||||
explicit CubebSink(std::string_view device_id);
|
||||
explicit CubebSink(std::string device_id);
|
||||
~CubebSink() override;
|
||||
|
||||
SinkStream& AcquireSinkStream(u32 sample_rate, u32 num_channels,
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace AudioCore {
|
||||
|
||||
class NullSink final : public Sink {
|
||||
public:
|
||||
explicit NullSink(std::string_view) {}
|
||||
explicit NullSink(std::string){};
|
||||
~NullSink() override = default;
|
||||
|
||||
SinkStream& AcquireSinkStream(u32 /*sample_rate*/, u32 /*num_channels*/,
|
||||
|
||||
@@ -14,68 +14,31 @@
|
||||
#include "common/logging/log.h"
|
||||
|
||||
namespace AudioCore {
|
||||
namespace {
|
||||
struct SinkDetails {
|
||||
using FactoryFn = std::unique_ptr<Sink> (*)(std::string_view);
|
||||
using ListDevicesFn = std::vector<std::string> (*)();
|
||||
|
||||
/// Name for this sink.
|
||||
const char* id;
|
||||
/// A method to call to construct an instance of this type of sink.
|
||||
FactoryFn factory;
|
||||
/// A method to call to list available devices.
|
||||
ListDevicesFn list_devices;
|
||||
};
|
||||
|
||||
// sink_details is ordered in terms of desirability, with the best choice at the top.
|
||||
constexpr SinkDetails sink_details[] = {
|
||||
// g_sink_details is ordered in terms of desirability, with the best choice at the top.
|
||||
const std::vector<SinkDetails> g_sink_details = {
|
||||
#ifdef HAVE_CUBEB
|
||||
SinkDetails{"cubeb",
|
||||
[](std::string_view device_id) -> std::unique_ptr<Sink> {
|
||||
return std::make_unique<CubebSink>(device_id);
|
||||
},
|
||||
&ListCubebSinkDevices},
|
||||
SinkDetails{"cubeb", &std::make_unique<CubebSink, std::string>, &ListCubebSinkDevices},
|
||||
#endif
|
||||
SinkDetails{"null",
|
||||
[](std::string_view device_id) -> std::unique_ptr<Sink> {
|
||||
return std::make_unique<NullSink>(device_id);
|
||||
},
|
||||
SinkDetails{"null", &std::make_unique<NullSink, std::string>,
|
||||
[] { return std::vector<std::string>{"null"}; }},
|
||||
};
|
||||
|
||||
const SinkDetails& GetSinkDetails(std::string_view sink_id) {
|
||||
auto iter =
|
||||
std::find_if(std::begin(sink_details), std::end(sink_details),
|
||||
std::find_if(g_sink_details.begin(), g_sink_details.end(),
|
||||
[sink_id](const auto& sink_detail) { return sink_detail.id == sink_id; });
|
||||
|
||||
if (sink_id == "auto" || iter == std::end(sink_details)) {
|
||||
if (sink_id == "auto" || iter == g_sink_details.end()) {
|
||||
if (sink_id != "auto") {
|
||||
LOG_ERROR(Audio, "AudioCore::SelectSink given invalid sink_id {}", sink_id);
|
||||
}
|
||||
// Auto-select.
|
||||
// sink_details is ordered in terms of desirability, with the best choice at the front.
|
||||
iter = std::begin(sink_details);
|
||||
// g_sink_details is ordered in terms of desirability, with the best choice at the front.
|
||||
iter = g_sink_details.begin();
|
||||
}
|
||||
|
||||
return *iter;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
std::vector<const char*> GetSinkIDs() {
|
||||
std::vector<const char*> sink_ids(std::size(sink_details));
|
||||
|
||||
std::transform(std::begin(sink_details), std::end(sink_details), std::begin(sink_ids),
|
||||
[](const auto& sink) { return sink.id; });
|
||||
|
||||
return sink_ids;
|
||||
}
|
||||
|
||||
std::vector<std::string> GetDeviceListForSink(std::string_view sink_id) {
|
||||
return GetSinkDetails(sink_id).list_devices();
|
||||
}
|
||||
|
||||
std::unique_ptr<Sink> CreateSinkFromID(std::string_view sink_id, std::string_view device_id) {
|
||||
return GetSinkDetails(sink_id).factory(device_id);
|
||||
}
|
||||
|
||||
} // namespace AudioCore
|
||||
|
||||
@@ -4,21 +4,34 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace AudioCore {
|
||||
|
||||
class Sink;
|
||||
|
||||
/// Retrieves the IDs for all available audio sinks.
|
||||
std::vector<const char*> GetSinkIDs();
|
||||
struct SinkDetails {
|
||||
using FactoryFn = std::function<std::unique_ptr<Sink>(std::string)>;
|
||||
using ListDevicesFn = std::function<std::vector<std::string>()>;
|
||||
|
||||
/// Gets the list of devices for a particular sink identified by the given ID.
|
||||
std::vector<std::string> GetDeviceListForSink(std::string_view sink_id);
|
||||
SinkDetails(const char* id_, FactoryFn factory_, ListDevicesFn list_devices_)
|
||||
: id(id_), factory(std::move(factory_)), list_devices(std::move(list_devices_)) {}
|
||||
|
||||
/// Creates an audio sink identified by the given device ID.
|
||||
std::unique_ptr<Sink> CreateSinkFromID(std::string_view sink_id, std::string_view device_id);
|
||||
/// Name for this sink.
|
||||
const char* id;
|
||||
/// A method to call to construct an instance of this type of sink.
|
||||
FactoryFn factory;
|
||||
/// A method to call to list available devices.
|
||||
ListDevicesFn list_devices;
|
||||
};
|
||||
|
||||
extern const std::vector<SinkDetails> g_sink_details;
|
||||
|
||||
const SinkDetails& GetSinkDetails(std::string_view sink_id);
|
||||
|
||||
} // namespace AudioCore
|
||||
|
||||
@@ -41,6 +41,13 @@ __declspec(noinline, noreturn)
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define UNIMPLEMENTED_IF_MSG(_a_, ...) \
|
||||
do \
|
||||
if (!(_a_)) { \
|
||||
LOG_CRITICAL(Debug, "Unimplemented Code:\n" __VA_ARGS__); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define UNREACHABLE() ASSERT_MSG(false, "Unreachable code!")
|
||||
#define UNREACHABLE_MSG(...) ASSERT_MSG(false, __VA_ARGS__)
|
||||
|
||||
@@ -52,8 +59,7 @@ __declspec(noinline, noreturn)
|
||||
#define DEBUG_ASSERT_MSG(_a_, _desc_, ...)
|
||||
#endif
|
||||
|
||||
#define UNIMPLEMENTED() ASSERT_MSG(false, "Unimplemented code!")
|
||||
#define UNIMPLEMENTED_MSG(...) ASSERT_MSG(false, __VA_ARGS__)
|
||||
#define UNIMPLEMENTED() UNIMPLEMENTED_IF_MSG(false, "Unimplemented code!")
|
||||
#define UNIMPLEMENTED_MSG(...) UNIMPLEMENTED_IF_MSG(false, __VA_ARGS__)
|
||||
|
||||
#define UNIMPLEMENTED_IF(cond) ASSERT_MSG(!(cond), "Unimplemented code!")
|
||||
#define UNIMPLEMENTED_IF_MSG(cond, ...) ASSERT_MSG(!(cond), __VA_ARGS__)
|
||||
#define UNIMPLEMENTED_IF(cond) UNIMPLEMENTED_IF_MSG(!(cond), "Unimplemented code!")
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <vector>
|
||||
#ifdef _WIN32
|
||||
#include <share.h> // For _SH_DENYWR
|
||||
#include <windows.h> // For OutputDebugStringW
|
||||
#include <windows.h> // For OutputDebugStringA
|
||||
#else
|
||||
#define _SH_DENYWR 0
|
||||
#endif
|
||||
@@ -148,7 +148,7 @@ void FileBackend::Write(const Entry& entry) {
|
||||
|
||||
void DebuggerBackend::Write(const Entry& entry) {
|
||||
#ifdef _WIN32
|
||||
::OutputDebugStringW(Common::UTF8ToUTF16W(FormatLogMessage(entry).append(1, '\n')).c_str());
|
||||
::OutputDebugStringA(FormatLogMessage(entry).append(1, '\n').c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ template <typename T>
|
||||
class Quaternion {
|
||||
public:
|
||||
Math::Vec3<T> xyz;
|
||||
T w{};
|
||||
T w;
|
||||
|
||||
Quaternion<decltype(-T{})> Inverse() const {
|
||||
return {-xyz, w};
|
||||
|
||||
@@ -49,22 +49,6 @@ struct ThreadQueueList {
|
||||
return T();
|
||||
}
|
||||
|
||||
template <typename UnaryPredicate>
|
||||
T get_first_filter(UnaryPredicate filter) const {
|
||||
const Queue* cur = first;
|
||||
while (cur != nullptr) {
|
||||
if (!cur->data.empty()) {
|
||||
for (const auto& item : cur->data) {
|
||||
if (filter(item))
|
||||
return item;
|
||||
}
|
||||
}
|
||||
cur = cur->next_nonempty;
|
||||
}
|
||||
|
||||
return T();
|
||||
}
|
||||
|
||||
T pop_first() {
|
||||
Queue* cur = first;
|
||||
while (cur != nullptr) {
|
||||
|
||||
@@ -63,10 +63,6 @@ add_library(core STATIC
|
||||
file_sys/sdmc_factory.h
|
||||
file_sys/submission_package.cpp
|
||||
file_sys/submission_package.h
|
||||
file_sys/system_archive/ng_word.cpp
|
||||
file_sys/system_archive/ng_word.h
|
||||
file_sys/system_archive/system_archive.cpp
|
||||
file_sys/system_archive/system_archive.h
|
||||
file_sys/vfs.cpp
|
||||
file_sys/vfs.h
|
||||
file_sys/vfs_concat.cpp
|
||||
@@ -83,8 +79,6 @@ add_library(core STATIC
|
||||
file_sys/vfs_vector.h
|
||||
file_sys/xts_archive.cpp
|
||||
file_sys/xts_archive.h
|
||||
frontend/applets/profile_select.cpp
|
||||
frontend/applets/profile_select.h
|
||||
frontend/applets/software_keyboard.cpp
|
||||
frontend/applets/software_keyboard.h
|
||||
frontend/emu_window.cpp
|
||||
@@ -103,6 +97,8 @@ add_library(core STATIC
|
||||
hle/kernel/client_session.cpp
|
||||
hle/kernel/client_session.h
|
||||
hle/kernel/errors.h
|
||||
hle/kernel/event.cpp
|
||||
hle/kernel/event.h
|
||||
hle/kernel/handle_table.cpp
|
||||
hle/kernel/handle_table.h
|
||||
hle/kernel/hle_ipc.cpp
|
||||
@@ -115,8 +111,6 @@ add_library(core STATIC
|
||||
hle/kernel/object.h
|
||||
hle/kernel/process.cpp
|
||||
hle/kernel/process.h
|
||||
hle/kernel/readable_event.cpp
|
||||
hle/kernel/readable_event.h
|
||||
hle/kernel/resource_limit.cpp
|
||||
hle/kernel/resource_limit.h
|
||||
hle/kernel/scheduler.cpp
|
||||
@@ -139,8 +133,6 @@ add_library(core STATIC
|
||||
hle/kernel/vm_manager.h
|
||||
hle/kernel/wait_object.cpp
|
||||
hle/kernel/wait_object.h
|
||||
hle/kernel/writable_event.cpp
|
||||
hle/kernel/writable_event.h
|
||||
hle/lock.cpp
|
||||
hle/lock.h
|
||||
hle/result.h
|
||||
@@ -164,8 +156,6 @@ add_library(core STATIC
|
||||
hle/service/am/applet_oe.h
|
||||
hle/service/am/applets/applets.cpp
|
||||
hle/service/am/applets/applets.h
|
||||
hle/service/am/applets/profile_select.cpp
|
||||
hle/service/am/applets/profile_select.h
|
||||
hle/service/am/applets/software_keyboard.cpp
|
||||
hle/service/am/applets/software_keyboard.h
|
||||
hle/service/am/applets/stub_applet.cpp
|
||||
|
||||
@@ -151,7 +151,6 @@ std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const {
|
||||
config.tpidr_el0 = &cb->tpidr_el0;
|
||||
config.dczid_el0 = 4;
|
||||
config.ctr_el0 = 0x8444c004;
|
||||
config.cntfrq_el0 = 19200000; // Value from fusee.
|
||||
|
||||
// Unpredictable instructions
|
||||
config.define_unpredictable_behaviour = true;
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/arm/exclusive_monitor.h"
|
||||
@@ -41,6 +40,7 @@ namespace Core {
|
||||
|
||||
/*static*/ System System::s_instance;
|
||||
|
||||
namespace {
|
||||
FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
|
||||
const std::string& path) {
|
||||
// To account for split 00+01+etc files.
|
||||
@@ -69,13 +69,11 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
|
||||
return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(concat, dir->GetName());
|
||||
}
|
||||
|
||||
if (FileUtil::IsDirectory(path))
|
||||
return vfs->OpenFile(path + "/" + "main", FileSys::Mode::Read);
|
||||
|
||||
return vfs->OpenFile(path, FileSys::Mode::Read);
|
||||
}
|
||||
struct System::Impl {
|
||||
} // Anonymous namespace
|
||||
|
||||
struct System::Impl {
|
||||
Cpu& CurrentCpuCore() {
|
||||
return cpu_core_manager.GetCurrentCore();
|
||||
}
|
||||
@@ -99,8 +97,6 @@ struct System::Impl {
|
||||
virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
|
||||
|
||||
/// Create default implementations of applets if one is not provided.
|
||||
if (profile_selector == nullptr)
|
||||
profile_selector = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>();
|
||||
if (software_keyboard == nullptr)
|
||||
software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
|
||||
|
||||
@@ -231,7 +227,6 @@ struct System::Impl {
|
||||
bool is_powered_on = false;
|
||||
|
||||
/// Frontend applets
|
||||
std::unique_ptr<Core::Frontend::ProfileSelectApplet> profile_selector;
|
||||
std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard;
|
||||
|
||||
/// Service manager
|
||||
@@ -427,14 +422,6 @@ std::shared_ptr<FileSys::VfsFilesystem> System::GetFilesystem() const {
|
||||
return impl->virtual_filesystem;
|
||||
}
|
||||
|
||||
void System::SetProfileSelector(std::unique_ptr<Core::Frontend::ProfileSelectApplet> applet) {
|
||||
impl->profile_selector = std::move(applet);
|
||||
}
|
||||
|
||||
const Core::Frontend::ProfileSelectApplet& System::GetProfileSelector() const {
|
||||
return *impl->profile_selector;
|
||||
}
|
||||
|
||||
void System::SetSoftwareKeyboard(std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> applet) {
|
||||
impl->software_keyboard = std::move(applet);
|
||||
}
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/vfs_types.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "frontend/applets/profile_select.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
class EmuWindow;
|
||||
@@ -57,9 +55,6 @@ class TelemetrySession;
|
||||
|
||||
struct PerfStatsResults;
|
||||
|
||||
FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
|
||||
const std::string& path);
|
||||
|
||||
class System {
|
||||
public:
|
||||
System(const System&) = delete;
|
||||
@@ -242,10 +237,6 @@ public:
|
||||
|
||||
std::shared_ptr<FileSys::VfsFilesystem> GetFilesystem() const;
|
||||
|
||||
void SetProfileSelector(std::unique_ptr<Core::Frontend::ProfileSelectApplet> applet);
|
||||
|
||||
const Core::Frontend::ProfileSelectApplet& GetProfileSelector() const;
|
||||
|
||||
void SetSoftwareKeyboard(std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> applet);
|
||||
|
||||
const Core::Frontend::SoftwareKeyboardApplet& GetSoftwareKeyboard() const;
|
||||
|
||||
@@ -246,6 +246,7 @@ std::vector<TicketRaw> GetTicketblob(const FileUtil::IOFile& ticket_save) {
|
||||
}
|
||||
|
||||
std::vector<TicketRaw> out;
|
||||
u32 magic{};
|
||||
for (std::size_t offset = 0; offset + 0x4 < buffer.size(); ++offset) {
|
||||
if (buffer[offset] == 0x4 && buffer[offset + 1] == 0x0 && buffer[offset + 2] == 0x1 &&
|
||||
buffer[offset + 3] == 0x0) {
|
||||
@@ -793,7 +794,7 @@ void KeyManager::DeriveBase() {
|
||||
|
||||
void KeyManager::DeriveETicket(PartitionDataManager& data) {
|
||||
// ETicket keys
|
||||
const auto es = Service::FileSystem::GetUnionContents().GetEntry(
|
||||
const auto es = Service::FileSystem::GetUnionContents()->GetEntry(
|
||||
0x0100000000000033, FileSys::ContentRecordType::Program);
|
||||
|
||||
if (es == nullptr)
|
||||
|
||||
@@ -8,23 +8,13 @@
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
const std::array<const char*, 15> LANGUAGE_NAMES{{
|
||||
"AmericanEnglish",
|
||||
"BritishEnglish",
|
||||
"Japanese",
|
||||
"French",
|
||||
"German",
|
||||
"LatinAmericanSpanish",
|
||||
"Spanish",
|
||||
"Italian",
|
||||
"Dutch",
|
||||
"CanadianFrench",
|
||||
"Portuguese",
|
||||
"Russian",
|
||||
"Korean",
|
||||
"Taiwanese",
|
||||
"Chinese",
|
||||
}};
|
||||
const std::array<const char*, 15> LANGUAGE_NAMES = {
|
||||
"AmericanEnglish", "BritishEnglish", "Japanese",
|
||||
"French", "German", "LatinAmericanSpanish",
|
||||
"Spanish", "Italian", "Dutch",
|
||||
"CanadianFrench", "Portugese", "Russian",
|
||||
"Korean", "Taiwanese", "Chinese",
|
||||
};
|
||||
|
||||
std::string LanguageEntry::GetApplicationName() const {
|
||||
return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(),
|
||||
|
||||
@@ -29,8 +29,8 @@ struct Entry {
|
||||
filename[copy_size] = '\0';
|
||||
}
|
||||
|
||||
char filename[0x301];
|
||||
INSERT_PADDING_BYTES(3);
|
||||
char filename[0x300];
|
||||
INSERT_PADDING_BYTES(4);
|
||||
EntryType type;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
u64 file_size;
|
||||
|
||||
@@ -56,10 +56,6 @@ PatchManager::PatchManager(u64 title_id) : title_id(title_id) {}
|
||||
|
||||
PatchManager::~PatchManager() = default;
|
||||
|
||||
u64 PatchManager::GetTitleID() const {
|
||||
return title_id;
|
||||
}
|
||||
|
||||
VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
|
||||
LOG_INFO(Loader, "Patching ExeFS for title_id={:016X}", title_id);
|
||||
|
||||
@@ -77,18 +73,14 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
|
||||
|
||||
const auto installed = Service::FileSystem::GetUnionContents();
|
||||
|
||||
const auto& disabled = Settings::values.disabled_addons[title_id];
|
||||
const auto update_disabled =
|
||||
std::find(disabled.begin(), disabled.end(), "Update") != disabled.end();
|
||||
|
||||
// Game Updates
|
||||
const auto update_tid = GetUpdateTitleID(title_id);
|
||||
const auto update = installed.GetEntry(update_tid, ContentRecordType::Program);
|
||||
const auto update = installed->GetEntry(update_tid, ContentRecordType::Program);
|
||||
|
||||
if (!update_disabled && update != nullptr && update->GetExeFS() != nullptr &&
|
||||
if (update != nullptr && update->GetExeFS() != nullptr &&
|
||||
update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
|
||||
LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully",
|
||||
FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0)));
|
||||
FormatTitleVersion(installed->GetEntryVersion(update_tid).value_or(0)));
|
||||
exefs = update->GetExeFS();
|
||||
}
|
||||
|
||||
@@ -103,9 +95,6 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
|
||||
std::vector<VirtualDir> layers;
|
||||
layers.reserve(patch_dirs.size() + 1);
|
||||
for (const auto& subdir : patch_dirs) {
|
||||
if (std::find(disabled.begin(), disabled.end(), subdir->GetName()) != disabled.end())
|
||||
continue;
|
||||
|
||||
auto exefs_dir = subdir->GetSubdirectory("exefs");
|
||||
if (exefs_dir != nullptr)
|
||||
layers.push_back(std::move(exefs_dir));
|
||||
@@ -122,16 +111,11 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
|
||||
return exefs;
|
||||
}
|
||||
|
||||
std::vector<VirtualFile> PatchManager::CollectPatches(const std::vector<VirtualDir>& patch_dirs,
|
||||
const std::string& build_id) const {
|
||||
const auto& disabled = Settings::values.disabled_addons[title_id];
|
||||
|
||||
static std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs,
|
||||
const std::string& build_id) {
|
||||
std::vector<VirtualFile> out;
|
||||
out.reserve(patch_dirs.size());
|
||||
for (const auto& subdir : patch_dirs) {
|
||||
if (std::find(disabled.begin(), disabled.end(), subdir->GetName()) != disabled.end())
|
||||
continue;
|
||||
|
||||
auto exefs_dir = subdir->GetSubdirectory("exefs");
|
||||
if (exefs_dir != nullptr) {
|
||||
for (const auto& file : exefs_dir->GetFiles()) {
|
||||
@@ -244,7 +228,6 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& disabled = Settings::values.disabled_addons[title_id];
|
||||
auto patch_dirs = load_dir->GetSubdirectories();
|
||||
std::sort(patch_dirs.begin(), patch_dirs.end(),
|
||||
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
|
||||
@@ -254,9 +237,6 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
|
||||
layers.reserve(patch_dirs.size() + 1);
|
||||
layers_ext.reserve(patch_dirs.size() + 1);
|
||||
for (const auto& subdir : patch_dirs) {
|
||||
if (std::find(disabled.begin(), disabled.end(), subdir->GetName()) != disabled.end())
|
||||
continue;
|
||||
|
||||
auto romfs_dir = subdir->GetSubdirectory("romfs");
|
||||
if (romfs_dir != nullptr)
|
||||
layers.push_back(std::move(romfs_dir));
|
||||
@@ -286,12 +266,13 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
|
||||
VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, ContentRecordType type,
|
||||
VirtualFile update_raw) const {
|
||||
const auto log_string = fmt::format("Patching RomFS for title_id={:016X}, type={:02X}",
|
||||
title_id, static_cast<u8>(type));
|
||||
title_id, static_cast<u8>(type))
|
||||
.c_str();
|
||||
|
||||
if (type == ContentRecordType::Program || type == ContentRecordType::Data)
|
||||
LOG_INFO(Loader, "{}", log_string);
|
||||
LOG_INFO(Loader, log_string);
|
||||
else
|
||||
LOG_DEBUG(Loader, "{}", log_string);
|
||||
LOG_DEBUG(Loader, log_string);
|
||||
|
||||
if (romfs == nullptr)
|
||||
return romfs;
|
||||
@@ -300,21 +281,16 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
|
||||
|
||||
// Game Updates
|
||||
const auto update_tid = GetUpdateTitleID(title_id);
|
||||
const auto update = installed.GetEntryRaw(update_tid, type);
|
||||
|
||||
const auto& disabled = Settings::values.disabled_addons[title_id];
|
||||
const auto update_disabled =
|
||||
std::find(disabled.begin(), disabled.end(), "Update") != disabled.end();
|
||||
|
||||
if (!update_disabled && update != nullptr) {
|
||||
const auto update = installed->GetEntryRaw(update_tid, type);
|
||||
if (update != nullptr) {
|
||||
const auto new_nca = std::make_shared<NCA>(update, romfs, ivfc_offset);
|
||||
if (new_nca->GetStatus() == Loader::ResultStatus::Success &&
|
||||
new_nca->GetRomFS() != nullptr) {
|
||||
LOG_INFO(Loader, " RomFS: Update ({}) applied successfully",
|
||||
FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0)));
|
||||
FormatTitleVersion(installed->GetEntryVersion(update_tid).value_or(0)));
|
||||
romfs = new_nca->GetRomFS();
|
||||
}
|
||||
} else if (!update_disabled && update_raw != nullptr) {
|
||||
} else if (update_raw != nullptr) {
|
||||
const auto new_nca = std::make_shared<NCA>(update_raw, romfs, ivfc_offset);
|
||||
if (new_nca->GetStatus() == Loader::ResultStatus::Success &&
|
||||
new_nca->GetRomFS() != nullptr) {
|
||||
@@ -344,30 +320,25 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
|
||||
VirtualFile update_raw) const {
|
||||
std::map<std::string, std::string, std::less<>> out;
|
||||
const auto installed = Service::FileSystem::GetUnionContents();
|
||||
const auto& disabled = Settings::values.disabled_addons[title_id];
|
||||
|
||||
// Game Updates
|
||||
const auto update_tid = GetUpdateTitleID(title_id);
|
||||
PatchManager update{update_tid};
|
||||
auto [nacp, discard_icon_file] = update.GetControlMetadata();
|
||||
|
||||
const auto update_disabled =
|
||||
std::find(disabled.begin(), disabled.end(), "Update") != disabled.end();
|
||||
const auto update_label = update_disabled ? "[D] Update" : "Update";
|
||||
|
||||
if (nacp != nullptr) {
|
||||
out.insert_or_assign(update_label, nacp->GetVersionString());
|
||||
out.insert_or_assign("Update", nacp->GetVersionString());
|
||||
} else {
|
||||
if (installed.HasEntry(update_tid, ContentRecordType::Program)) {
|
||||
const auto meta_ver = installed.GetEntryVersion(update_tid);
|
||||
if (installed->HasEntry(update_tid, ContentRecordType::Program)) {
|
||||
const auto meta_ver = installed->GetEntryVersion(update_tid);
|
||||
if (meta_ver.value_or(0) == 0) {
|
||||
out.insert_or_assign(update_label, "");
|
||||
out.insert_or_assign("Update", "");
|
||||
} else {
|
||||
out.insert_or_assign(
|
||||
update_label, FormatTitleVersion(*meta_ver, TitleVersionFormat::ThreeElements));
|
||||
"Update", FormatTitleVersion(*meta_ver, TitleVersionFormat::ThreeElements));
|
||||
}
|
||||
} else if (update_raw != nullptr) {
|
||||
out.insert_or_assign(update_label, "PACKED");
|
||||
out.insert_or_assign("Update", "PACKED");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,20 +378,19 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
|
||||
if (types.empty())
|
||||
continue;
|
||||
|
||||
const auto mod_disabled =
|
||||
std::find(disabled.begin(), disabled.end(), mod->GetName()) != disabled.end();
|
||||
out.insert_or_assign(mod_disabled ? "[D] " + mod->GetName() : mod->GetName(), types);
|
||||
out.insert_or_assign(mod->GetName(), types);
|
||||
}
|
||||
}
|
||||
|
||||
// DLC
|
||||
const auto dlc_entries = installed.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data);
|
||||
const auto dlc_entries = installed->ListEntriesFilter(TitleType::AOC, ContentRecordType::Data);
|
||||
std::vector<RegisteredCacheEntry> dlc_match;
|
||||
dlc_match.reserve(dlc_entries.size());
|
||||
std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match),
|
||||
[this, &installed](const RegisteredCacheEntry& entry) {
|
||||
return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == title_id &&
|
||||
installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success;
|
||||
installed->GetEntry(entry)->GetStatus() ==
|
||||
Loader::ResultStatus::Success;
|
||||
});
|
||||
if (!dlc_match.empty()) {
|
||||
// Ensure sorted so DLC IDs show in order.
|
||||
@@ -432,9 +402,7 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
|
||||
|
||||
list += fmt::format("{}", dlc_match.back().title_id & 0x7FF);
|
||||
|
||||
const auto dlc_disabled =
|
||||
std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end();
|
||||
out.insert_or_assign(dlc_disabled ? "[D] DLC" : "DLC", std::move(list));
|
||||
out.insert_or_assign("DLC", std::move(list));
|
||||
}
|
||||
|
||||
return out;
|
||||
@@ -443,7 +411,7 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
|
||||
std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const {
|
||||
const auto installed{Service::FileSystem::GetUnionContents()};
|
||||
|
||||
const auto base_control_nca = installed.GetEntry(title_id, ContentRecordType::Control);
|
||||
const auto base_control_nca = installed->GetEntry(title_id, ContentRecordType::Control);
|
||||
if (base_control_nca == nullptr)
|
||||
return {};
|
||||
|
||||
|
||||
@@ -30,8 +30,6 @@ public:
|
||||
explicit PatchManager(u64 title_id);
|
||||
~PatchManager();
|
||||
|
||||
u64 GetTitleID() const;
|
||||
|
||||
// Currently tracked ExeFS patches:
|
||||
// - Game Updates
|
||||
VirtualDir PatchExeFS(VirtualDir exefs) const;
|
||||
@@ -65,9 +63,6 @@ public:
|
||||
std::pair<std::unique_ptr<NACP>, VirtualFile> ParseControlNCA(const NCA& nca) const;
|
||||
|
||||
private:
|
||||
std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs,
|
||||
const std::string& build_id) const;
|
||||
|
||||
u64 title_id;
|
||||
};
|
||||
|
||||
|
||||
@@ -107,41 +107,42 @@ static ContentRecordType GetCRTypeFromNCAType(NCAContentType type) {
|
||||
VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
|
||||
std::string_view path) const {
|
||||
const auto file = dir->GetFileRelative(path);
|
||||
if (file != nullptr) {
|
||||
if (file != nullptr)
|
||||
return file;
|
||||
}
|
||||
|
||||
const auto nca_dir = dir->GetDirectoryRelative(path);
|
||||
if (nca_dir == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (nca_dir != nullptr) {
|
||||
const auto nca_dir = dir->GetDirectoryRelative(path);
|
||||
VirtualFile file = nullptr;
|
||||
|
||||
const auto files = nca_dir->GetFiles();
|
||||
if (files.size() == 1 && files[0]->GetName() == "00") {
|
||||
return files[0];
|
||||
}
|
||||
|
||||
std::vector<VirtualFile> concat;
|
||||
// Since the files are a two-digit hex number, max is FF.
|
||||
for (std::size_t i = 0; i < 0x100; ++i) {
|
||||
auto next = nca_dir->GetFile(fmt::format("{:02X}", i));
|
||||
if (next != nullptr) {
|
||||
concat.push_back(std::move(next));
|
||||
const auto files = nca_dir->GetFiles();
|
||||
if (files.size() == 1 && files[0]->GetName() == "00") {
|
||||
file = files[0];
|
||||
} else {
|
||||
next = nca_dir->GetFile(fmt::format("{:02x}", i));
|
||||
if (next != nullptr) {
|
||||
concat.push_back(std::move(next));
|
||||
} else {
|
||||
break;
|
||||
std::vector<VirtualFile> concat;
|
||||
// Since the files are a two-digit hex number, max is FF.
|
||||
for (std::size_t i = 0; i < 0x100; ++i) {
|
||||
auto next = nca_dir->GetFile(fmt::format("{:02X}", i));
|
||||
if (next != nullptr) {
|
||||
concat.push_back(std::move(next));
|
||||
} else {
|
||||
next = nca_dir->GetFile(fmt::format("{:02x}", i));
|
||||
if (next != nullptr)
|
||||
concat.push_back(std::move(next));
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (concat.empty())
|
||||
return nullptr;
|
||||
|
||||
file = ConcatenatedVfsFile::MakeConcatenatedFile(concat, concat.front()->GetName());
|
||||
}
|
||||
}
|
||||
|
||||
if (concat.empty()) {
|
||||
return nullptr;
|
||||
return file;
|
||||
}
|
||||
|
||||
return ConcatenatedVfsFile::MakeConcatenatedFile(concat, concat.front()->GetName());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
|
||||
@@ -380,22 +381,22 @@ std::vector<RegisteredCacheEntry> RegisteredCache::ListEntriesFilter(
|
||||
return out;
|
||||
}
|
||||
|
||||
static std::shared_ptr<NCA> GetNCAFromNSPForID(const NSP& nsp, const NcaID& id) {
|
||||
const auto file = nsp.GetFile(fmt::format("{}.nca", Common::HexArrayToString(id, false)));
|
||||
static std::shared_ptr<NCA> GetNCAFromNSPForID(std::shared_ptr<NSP> nsp, const NcaID& id) {
|
||||
const auto file = nsp->GetFile(fmt::format("{}.nca", Common::HexArrayToString(id, false)));
|
||||
if (file == nullptr)
|
||||
return nullptr;
|
||||
return std::make_shared<NCA>(file);
|
||||
}
|
||||
|
||||
InstallResult RegisteredCache::InstallEntry(const XCI& xci, bool overwrite_if_exists,
|
||||
InstallResult RegisteredCache::InstallEntry(std::shared_ptr<XCI> xci, bool overwrite_if_exists,
|
||||
const VfsCopyFunction& copy) {
|
||||
return InstallEntry(*xci.GetSecurePartitionNSP(), overwrite_if_exists, copy);
|
||||
return InstallEntry(xci->GetSecurePartitionNSP(), overwrite_if_exists, copy);
|
||||
}
|
||||
|
||||
InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_exists,
|
||||
InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overwrite_if_exists,
|
||||
const VfsCopyFunction& copy) {
|
||||
const auto ncas = nsp.GetNCAsCollapsed();
|
||||
const auto meta_iter = std::find_if(ncas.begin(), ncas.end(), [](const auto& nca) {
|
||||
const auto& ncas = nsp->GetNCAsCollapsed();
|
||||
const auto& meta_iter = std::find_if(ncas.begin(), ncas.end(), [](std::shared_ptr<NCA> nca) {
|
||||
return nca->GetType() == NCAContentType::Meta;
|
||||
});
|
||||
|
||||
@@ -409,7 +410,7 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex
|
||||
const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32);
|
||||
const auto meta_id = Common::HexStringToArray<16>(meta_id_raw);
|
||||
|
||||
const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id);
|
||||
const auto res = RawInstallNCA(*meta_iter, copy, overwrite_if_exists, meta_id);
|
||||
if (res != InstallResult::Success)
|
||||
return res;
|
||||
|
||||
@@ -421,7 +422,7 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex
|
||||
const auto nca = GetNCAFromNSPForID(nsp, record.nca_id);
|
||||
if (nca == nullptr)
|
||||
return InstallResult::ErrorCopyFailed;
|
||||
const auto res2 = RawInstallNCA(*nca, copy, overwrite_if_exists, record.nca_id);
|
||||
const auto res2 = RawInstallNCA(nca, copy, overwrite_if_exists, record.nca_id);
|
||||
if (res2 != InstallResult::Success)
|
||||
return res2;
|
||||
}
|
||||
@@ -430,21 +431,21 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex
|
||||
return InstallResult::Success;
|
||||
}
|
||||
|
||||
InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type,
|
||||
InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType type,
|
||||
bool overwrite_if_exists, const VfsCopyFunction& copy) {
|
||||
CNMTHeader header{
|
||||
nca.GetTitleId(), ///< Title ID
|
||||
0, ///< Ignore/Default title version
|
||||
type, ///< Type
|
||||
{}, ///< Padding
|
||||
0x10, ///< Default table offset
|
||||
1, ///< 1 Content Entry
|
||||
0, ///< No Meta Entries
|
||||
{}, ///< Padding
|
||||
nca->GetTitleId(), ///< Title ID
|
||||
0, ///< Ignore/Default title version
|
||||
type, ///< Type
|
||||
{}, ///< Padding
|
||||
0x10, ///< Default table offset
|
||||
1, ///< 1 Content Entry
|
||||
0, ///< No Meta Entries
|
||||
{}, ///< Padding
|
||||
};
|
||||
OptionalHeader opt_header{0, 0};
|
||||
ContentRecord c_rec{{}, {}, {}, GetCRTypeFromNCAType(nca.GetType()), {}};
|
||||
const auto& data = nca.GetBaseFile()->ReadBytes(0x100000);
|
||||
ContentRecord c_rec{{}, {}, {}, GetCRTypeFromNCAType(nca->GetType()), {}};
|
||||
const auto& data = nca->GetBaseFile()->ReadBytes(0x100000);
|
||||
mbedtls_sha256(data.data(), data.size(), c_rec.hash.data(), 0);
|
||||
memcpy(&c_rec.nca_id, &c_rec.hash, 16);
|
||||
const CNMT new_cnmt(header, opt_header, {c_rec}, {});
|
||||
@@ -453,10 +454,10 @@ InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type,
|
||||
return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id);
|
||||
}
|
||||
|
||||
InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy,
|
||||
InstallResult RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy,
|
||||
bool overwrite_if_exists,
|
||||
std::optional<NcaID> override_id) {
|
||||
const auto in = nca.GetBaseFile();
|
||||
const auto in = nca->GetBaseFile();
|
||||
Core::Crypto::SHA256Hash hash{};
|
||||
|
||||
// Calculate NcaID
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -103,16 +104,17 @@ public:
|
||||
|
||||
// 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.
|
||||
InstallResult InstallEntry(const XCI& xci, bool overwrite_if_exists = false,
|
||||
InstallResult InstallEntry(std::shared_ptr<XCI> xci, bool overwrite_if_exists = false,
|
||||
const VfsCopyFunction& copy = &VfsRawCopy);
|
||||
InstallResult InstallEntry(const NSP& nsp, bool overwrite_if_exists = false,
|
||||
InstallResult InstallEntry(std::shared_ptr<NSP> nsp, bool overwrite_if_exists = false,
|
||||
const VfsCopyFunction& copy = &VfsRawCopy);
|
||||
|
||||
// Due to the fact that we must use Meta-type NCAs to determine the existance of files, this
|
||||
// poses quite a challenge. Instead of creating a new meta NCA for this file, yuzu will create a
|
||||
// dir inside the NAND called 'yuzu_meta' and store the raw CNMT there.
|
||||
// TODO(DarkLordZach): Author real meta-type NCAs and install those.
|
||||
InstallResult InstallEntry(const NCA& nca, TitleType type, bool overwrite_if_exists = false,
|
||||
InstallResult InstallEntry(std::shared_ptr<NCA> nca, TitleType type,
|
||||
bool overwrite_if_exists = false,
|
||||
const VfsCopyFunction& copy = &VfsRawCopy);
|
||||
|
||||
private:
|
||||
@@ -126,7 +128,7 @@ private:
|
||||
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(const NCA& nca, const VfsCopyFunction& copy,
|
||||
InstallResult RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy,
|
||||
bool overwrite_if_exists, std::optional<NcaID> override_id = {});
|
||||
bool RawInstallYuzuMeta(const CNMT& cnmt);
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, Conte
|
||||
|
||||
switch (storage) {
|
||||
case StorageId::None:
|
||||
res = Service::FileSystem::GetUnionContents().GetEntry(title_id, type);
|
||||
res = Service::FileSystem::GetUnionContents()->GetEntry(title_id, type);
|
||||
break;
|
||||
case StorageId::NandSystem:
|
||||
res = Service::FileSystem::GetSystemNANDContents()->GetEntry(title_id, type);
|
||||
|
||||
@@ -18,11 +18,7 @@ std::string SaveDataDescriptor::DebugInfo() const {
|
||||
static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id);
|
||||
}
|
||||
|
||||
SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {
|
||||
// Delete all temporary storages
|
||||
// On hardware, it is expected that temporary storage be empty at first use.
|
||||
dir->DeleteSubdirectoryRecursive("temp");
|
||||
}
|
||||
SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {}
|
||||
|
||||
SaveDataFactory::~SaveDataFactory() = default;
|
||||
|
||||
@@ -124,11 +120,8 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ
|
||||
case SaveDataType::TemporaryStorage:
|
||||
return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
|
||||
title_id);
|
||||
case SaveDataType::CacheStorage:
|
||||
return fmt::format("{}save/cache/{:016X}", out, title_id);
|
||||
default:
|
||||
ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type));
|
||||
return fmt::format("{}save/unknown_{:X}/{:016X}", out, static_cast<u8>(type), title_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,10 +17,8 @@ namespace FileSys {
|
||||
enum class SaveDataSpaceId : u8 {
|
||||
NandSystem = 0,
|
||||
NandUser = 1,
|
||||
SdCardSystem = 2,
|
||||
SdCard = 2,
|
||||
TemporaryStorage = 3,
|
||||
SdCardUser = 4,
|
||||
ProperSystem = 100,
|
||||
};
|
||||
|
||||
enum class SaveDataType : u8 {
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/system_archive/ng_word.h"
|
||||
#include "core/file_sys/vfs_vector.h"
|
||||
|
||||
namespace FileSys::SystemArchive {
|
||||
|
||||
namespace NgWord1Data {
|
||||
|
||||
constexpr std::size_t NUMBER_WORD_TXT_FILES = 0x10;
|
||||
|
||||
// Should this archive replacement mysteriously not work on a future game, consider updating.
|
||||
constexpr std::array<u8, 4> VERSION_DAT{0x0, 0x0, 0x0, 0x19}; // 5.1.0 System Version
|
||||
|
||||
constexpr std::array<u8, 30> WORD_TXT{
|
||||
0xFE, 0xFF, 0x00, 0x5E, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x79, 0x00, 0x62, 0x00,
|
||||
0x61, 0x00, 0x64, 0x00, 0x77, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x64, 0x00, 0x24, 0x00, 0x0A,
|
||||
}; // "^verybadword$" in UTF-16
|
||||
|
||||
} // namespace NgWord1Data
|
||||
|
||||
VirtualDir NgWord1() {
|
||||
std::vector<VirtualFile> files(NgWord1Data::NUMBER_WORD_TXT_FILES);
|
||||
|
||||
for (std::size_t i = 0; i < files.size(); ++i) {
|
||||
files[i] = std::make_shared<ArrayVfsFile<NgWord1Data::WORD_TXT.size()>>(
|
||||
NgWord1Data::WORD_TXT, fmt::format("{}.txt", i));
|
||||
}
|
||||
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord1Data::WORD_TXT.size()>>(
|
||||
NgWord1Data::WORD_TXT, "common.txt"));
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord1Data::VERSION_DAT.size()>>(
|
||||
NgWord1Data::VERSION_DAT, "version.dat"));
|
||||
|
||||
return std::make_shared<VectorVfsDirectory>(files, std::vector<VirtualDir>{}, "data");
|
||||
}
|
||||
|
||||
namespace NgWord2Data {
|
||||
|
||||
constexpr std::size_t NUMBER_AC_NX_FILES = 0x10;
|
||||
|
||||
// Should this archive replacement mysteriously not work on a future game, consider updating.
|
||||
constexpr std::array<u8, 4> VERSION_DAT{0x0, 0x0, 0x0, 0x15}; // 5.1.0 System Version
|
||||
|
||||
constexpr std::array<u8, 0x2C> AC_NX_DATA{
|
||||
0x1F, 0x8B, 0x08, 0x08, 0xD5, 0x2C, 0x09, 0x5C, 0x04, 0x00, 0x61, 0x63, 0x72, 0x61, 0x77,
|
||||
0x00, 0xED, 0xC1, 0x01, 0x0D, 0x00, 0x00, 0x00, 0xC2, 0x20, 0xFB, 0xA7, 0xB6, 0xC7, 0x07,
|
||||
0x0C, 0x00, 0x00, 0x00, 0xC8, 0x3B, 0x11, 0x00, 0x1C, 0xC7, 0x00, 0x10, 0x00, 0x00,
|
||||
}; // Deserializes to no bad words
|
||||
|
||||
} // namespace NgWord2Data
|
||||
|
||||
VirtualDir NgWord2() {
|
||||
std::vector<VirtualFile> files(NgWord2Data::NUMBER_AC_NX_FILES * 3);
|
||||
|
||||
for (std::size_t i = 0; i < NgWord2Data::NUMBER_AC_NX_FILES; ++i) {
|
||||
files[3 * i] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b1_nx", i));
|
||||
files[3 * i + 1] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b2_nx", i));
|
||||
files[3 * i + 2] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_not_b_nx", i));
|
||||
}
|
||||
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, "ac_common_b1_nx"));
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, "ac_common_b2_nx"));
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, "ac_common_not_b_nx"));
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::VERSION_DAT.size()>>(
|
||||
NgWord2Data::VERSION_DAT, "version.dat"));
|
||||
|
||||
return std::make_shared<VectorVfsDirectory>(files, std::vector<VirtualDir>{}, "data");
|
||||
}
|
||||
|
||||
} // namespace FileSys::SystemArchive
|
||||
@@ -1,14 +0,0 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/file_sys/vfs_types.h"
|
||||
|
||||
namespace FileSys::SystemArchive {
|
||||
|
||||
VirtualDir NgWord1();
|
||||
VirtualDir NgWord2();
|
||||
|
||||
} // namespace FileSys::SystemArchive
|
||||
@@ -1,90 +0,0 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/file_sys/romfs.h"
|
||||
#include "core/file_sys/system_archive/ng_word.h"
|
||||
#include "core/file_sys/system_archive/system_archive.h"
|
||||
|
||||
namespace FileSys::SystemArchive {
|
||||
|
||||
constexpr u64 SYSTEM_ARCHIVE_BASE_TITLE_ID = 0x0100000000000800;
|
||||
constexpr std::size_t SYSTEM_ARCHIVE_COUNT = 0x28;
|
||||
|
||||
using SystemArchiveSupplier = VirtualDir (*)();
|
||||
|
||||
struct SystemArchiveDescriptor {
|
||||
u64 title_id;
|
||||
const char* name;
|
||||
SystemArchiveSupplier supplier;
|
||||
};
|
||||
|
||||
constexpr std::array<SystemArchiveDescriptor, SYSTEM_ARCHIVE_COUNT> SYSTEM_ARCHIVES{{
|
||||
{0x0100000000000800, "CertStore", nullptr},
|
||||
{0x0100000000000801, "ErrorMessage", nullptr},
|
||||
{0x0100000000000802, "MiiModel", nullptr},
|
||||
{0x0100000000000803, "BrowserDll", nullptr},
|
||||
{0x0100000000000804, "Help", nullptr},
|
||||
{0x0100000000000805, "SharedFont", nullptr},
|
||||
{0x0100000000000806, "NgWord", &NgWord1},
|
||||
{0x0100000000000807, "SsidList", nullptr},
|
||||
{0x0100000000000808, "Dictionary", nullptr},
|
||||
{0x0100000000000809, "SystemVersion", nullptr},
|
||||
{0x010000000000080A, "AvatarImage", nullptr},
|
||||
{0x010000000000080B, "LocalNews", nullptr},
|
||||
{0x010000000000080C, "Eula", nullptr},
|
||||
{0x010000000000080D, "UrlBlackList", nullptr},
|
||||
{0x010000000000080E, "TimeZoneBinary", nullptr},
|
||||
{0x010000000000080F, "CertStoreCruiser", nullptr},
|
||||
{0x0100000000000810, "FontNintendoExtension", nullptr},
|
||||
{0x0100000000000811, "FontStandard", nullptr},
|
||||
{0x0100000000000812, "FontKorean", nullptr},
|
||||
{0x0100000000000813, "FontChineseTraditional", nullptr},
|
||||
{0x0100000000000814, "FontChineseSimple", nullptr},
|
||||
{0x0100000000000815, "FontBfcpx", nullptr},
|
||||
{0x0100000000000816, "SystemUpdate", nullptr},
|
||||
{0x0100000000000817, "0100000000000817", nullptr},
|
||||
{0x0100000000000818, "FirmwareDebugSettings", nullptr},
|
||||
{0x0100000000000819, "BootImagePackage", nullptr},
|
||||
{0x010000000000081A, "BootImagePackageSafe", nullptr},
|
||||
{0x010000000000081B, "BootImagePackageExFat", nullptr},
|
||||
{0x010000000000081C, "BootImagePackageExFatSafe", nullptr},
|
||||
{0x010000000000081D, "FatalMessage", nullptr},
|
||||
{0x010000000000081E, "ControllerIcon", nullptr},
|
||||
{0x010000000000081F, "PlatformConfigIcosa", nullptr},
|
||||
{0x0100000000000820, "PlatformConfigCopper", nullptr},
|
||||
{0x0100000000000821, "PlatformConfigHoag", nullptr},
|
||||
{0x0100000000000822, "ControllerFirmware", nullptr},
|
||||
{0x0100000000000823, "NgWord2", &NgWord2},
|
||||
{0x0100000000000824, "PlatformConfigIcosaMariko", nullptr},
|
||||
{0x0100000000000825, "ApplicationBlackList", nullptr},
|
||||
{0x0100000000000826, "RebootlessSystemUpdateVersion", nullptr},
|
||||
{0x0100000000000827, "ContentActionTable", nullptr},
|
||||
}};
|
||||
|
||||
VirtualFile SynthesizeSystemArchive(const u64 title_id) {
|
||||
if (title_id < SYSTEM_ARCHIVES.front().title_id || title_id > SYSTEM_ARCHIVES.back().title_id)
|
||||
return nullptr;
|
||||
|
||||
const auto& desc = SYSTEM_ARCHIVES[title_id - SYSTEM_ARCHIVE_BASE_TITLE_ID];
|
||||
|
||||
LOG_INFO(Service_FS, "Synthesizing system archive '{}' (0x{:016X}).", desc.name, desc.title_id);
|
||||
|
||||
if (desc.supplier == nullptr)
|
||||
return nullptr;
|
||||
|
||||
const auto dir = desc.supplier();
|
||||
|
||||
if (dir == nullptr)
|
||||
return nullptr;
|
||||
|
||||
const auto romfs = CreateRomFS(dir);
|
||||
|
||||
if (romfs == nullptr)
|
||||
return nullptr;
|
||||
|
||||
LOG_INFO(Service_FS, " - System archive generation successful!");
|
||||
return romfs;
|
||||
}
|
||||
} // namespace FileSys::SystemArchive
|
||||
@@ -1,14 +0,0 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/vfs_types.h"
|
||||
|
||||
namespace FileSys::SystemArchive {
|
||||
|
||||
VirtualFile SynthesizeSystemArchive(u64 title_id);
|
||||
|
||||
} // namespace FileSys::SystemArchive
|
||||
@@ -384,28 +384,6 @@ bool VfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
|
||||
return success;
|
||||
}
|
||||
|
||||
bool VfsDirectory::CleanSubdirectoryRecursive(std::string_view name) {
|
||||
auto dir = GetSubdirectory(name);
|
||||
if (dir == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = true;
|
||||
for (const auto& file : dir->GetFiles()) {
|
||||
if (!dir->DeleteFile(file->GetName())) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& sdir : dir->GetSubdirectories()) {
|
||||
if (!dir->DeleteSubdirectoryRecursive(sdir->GetName())) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool VfsDirectory::Copy(std::string_view src, std::string_view dest) {
|
||||
const auto f1 = GetFile(src);
|
||||
auto f2 = CreateFile(dest);
|
||||
@@ -453,34 +431,10 @@ std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFile(std::string_view name)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFileAbsolute(std::string_view path) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFileRelative(std::string_view path) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateDirectoryAbsolute(std::string_view path) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateDirectoryRelative(std::string_view path) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ReadOnlyVfsDirectory::DeleteSubdirectory(std::string_view name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReadOnlyVfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReadOnlyVfsDirectory::CleanSubdirectoryRecursive(std::string_view name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReadOnlyVfsDirectory::DeleteFile(std::string_view name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -245,18 +245,12 @@ public:
|
||||
// any failure.
|
||||
virtual std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path);
|
||||
|
||||
// Deletes the subdirectory with the given name and returns true on success.
|
||||
// Deletes the subdirectory with name and returns true on success.
|
||||
virtual bool DeleteSubdirectory(std::string_view name) = 0;
|
||||
|
||||
// Deletes all subdirectories and files within the provided directory and then deletes
|
||||
// the directory itself. Returns true on success.
|
||||
// Deletes all subdirectories and files of subdirectory with name recirsively and then deletes
|
||||
// the subdirectory. Returns true on success.
|
||||
virtual bool DeleteSubdirectoryRecursive(std::string_view name);
|
||||
|
||||
// Deletes all subdirectories and files within the provided directory.
|
||||
// Unlike DeleteSubdirectoryRecursive, this does not delete the provided directory.
|
||||
virtual bool CleanSubdirectoryRecursive(std::string_view name);
|
||||
|
||||
// Returns whether or not the file with name name was deleted successfully.
|
||||
// Returnes whether or not the file with name name was deleted successfully.
|
||||
virtual bool DeleteFile(std::string_view name) = 0;
|
||||
|
||||
// Returns whether or not this directory was renamed to name.
|
||||
@@ -282,13 +276,7 @@ public:
|
||||
bool IsReadable() const override;
|
||||
std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override;
|
||||
std::shared_ptr<VfsFile> CreateFile(std::string_view name) override;
|
||||
std::shared_ptr<VfsFile> CreateFileAbsolute(std::string_view path) override;
|
||||
std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path) override;
|
||||
std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path) override;
|
||||
std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path) override;
|
||||
bool DeleteSubdirectory(std::string_view name) override;
|
||||
bool DeleteSubdirectoryRecursive(std::string_view name) override;
|
||||
bool CleanSubdirectoryRecursive(std::string_view name) override;
|
||||
bool DeleteFile(std::string_view name) override;
|
||||
bool Rename(std::string_view name) override;
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
#include "core/file_sys/vfs_vector.h"
|
||||
|
||||
|
||||
@@ -4,63 +4,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include "core/file_sys/vfs.h"
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
// An implementation of VfsFile that is backed by a statically-sized array
|
||||
template <std::size_t size>
|
||||
class ArrayVfsFile : public VfsFile {
|
||||
public:
|
||||
ArrayVfsFile(std::array<u8, size> data, std::string name = "", VirtualDir parent = nullptr)
|
||||
: data(data), name(std::move(name)), parent(std::move(parent)) {}
|
||||
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
std::size_t GetSize() const override {
|
||||
return size;
|
||||
}
|
||||
|
||||
bool Resize(std::size_t new_size) override {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsDirectory> GetContainingDirectory() const override {
|
||||
return parent;
|
||||
}
|
||||
|
||||
bool IsWritable() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsReadable() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t Read(u8* data_, std::size_t length, std::size_t offset) const override {
|
||||
const auto read = std::min(length, size - offset);
|
||||
std::memcpy(data_, data.data() + offset, read);
|
||||
return read;
|
||||
}
|
||||
|
||||
std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Rename(std::string_view name) override {
|
||||
this->name = name;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<u8, size> data;
|
||||
std::string name;
|
||||
VirtualDir parent;
|
||||
};
|
||||
|
||||
// An implementation of VfsFile that is backed by a vector optionally supplied upon construction
|
||||
class VectorVfsFile : public VfsFile {
|
||||
public:
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/frontend/applets/profile_select.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
||||
ProfileSelectApplet::~ProfileSelectApplet() = default;
|
||||
|
||||
void DefaultProfileSelectApplet::SelectProfile(
|
||||
std::function<void(std::optional<Service::Account::UUID>)> callback) const {
|
||||
Service::Account::ProfileManager manager;
|
||||
callback(manager.GetUser(Settings::values.current_user).value_or(Service::Account::UUID{}));
|
||||
LOG_INFO(Service_ACC, "called, selecting current user instead of prompting...");
|
||||
}
|
||||
|
||||
} // namespace Core::Frontend
|
||||
@@ -1,27 +0,0 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
||||
class ProfileSelectApplet {
|
||||
public:
|
||||
virtual ~ProfileSelectApplet();
|
||||
|
||||
virtual void SelectProfile(
|
||||
std::function<void(std::optional<Service::Account::UUID>)> callback) const = 0;
|
||||
};
|
||||
|
||||
class DefaultProfileSelectApplet final : public ProfileSelectApplet {
|
||||
public:
|
||||
void SelectProfile(
|
||||
std::function<void(std::optional<Service::Account::UUID>)> callback) const override;
|
||||
};
|
||||
|
||||
} // namespace Core::Frontend
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "core/frontend/framebuffer_layout.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Layout {
|
||||
|
||||
@@ -43,18 +42,4 @@ FramebufferLayout DefaultFrameLayout(unsigned width, unsigned height) {
|
||||
return res;
|
||||
}
|
||||
|
||||
FramebufferLayout FrameLayoutFromResolutionScale(u16 res_scale) {
|
||||
int width, height;
|
||||
|
||||
if (Settings::values.use_docked_mode) {
|
||||
width = ScreenDocked::WidthDocked * res_scale;
|
||||
height = ScreenDocked::HeightDocked * res_scale;
|
||||
} else {
|
||||
width = ScreenUndocked::Width * res_scale;
|
||||
height = ScreenUndocked::Height * res_scale;
|
||||
}
|
||||
|
||||
return DefaultFrameLayout(width, height);
|
||||
}
|
||||
|
||||
} // namespace Layout
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
namespace Layout {
|
||||
|
||||
enum ScreenUndocked : unsigned { Width = 1280, Height = 720 };
|
||||
enum ScreenDocked : unsigned { WidthDocked = 1920, HeightDocked = 1080 };
|
||||
|
||||
/// Describes the layout of the window framebuffer
|
||||
struct FramebufferLayout {
|
||||
@@ -35,10 +34,4 @@ struct FramebufferLayout {
|
||||
*/
|
||||
FramebufferLayout DefaultFrameLayout(unsigned width, unsigned height);
|
||||
|
||||
/**
|
||||
* Convenience method to get frame layout by resolution scale
|
||||
* @param res_scale resolution scale factor
|
||||
*/
|
||||
FramebufferLayout FrameLayoutFromResolutionScale(u16 res_scale);
|
||||
|
||||
} // namespace Layout
|
||||
|
||||
@@ -201,11 +201,11 @@ void RegisterModule(std::string name, VAddr beg, VAddr end, bool add_elf_ext) {
|
||||
modules.push_back(std::move(module));
|
||||
}
|
||||
|
||||
static Kernel::Thread* FindThreadById(s64 id) {
|
||||
static Kernel::Thread* FindThreadById(int id) {
|
||||
for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) {
|
||||
const auto& threads = Core::System::GetInstance().Scheduler(core).GetThreadList();
|
||||
for (auto& thread : threads) {
|
||||
if (thread->GetThreadID() == static_cast<u64>(id)) {
|
||||
if (thread->GetThreadID() == static_cast<u32>(id)) {
|
||||
current_core = core;
|
||||
return thread.get();
|
||||
}
|
||||
@@ -282,7 +282,7 @@ static void FpuWrite(std::size_t id, u128 val, Kernel::Thread* thread = nullptr)
|
||||
if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
|
||||
thread_context.vector_registers[id - UC_ARM64_REG_Q0] = val;
|
||||
} else if (id == FPCR_REGISTER) {
|
||||
thread_context.fpcr = static_cast<u32>(val[0]);
|
||||
thread_context.fpcr = val[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ constexpr ResultCode ERR_SYNCHRONIZATION_CANCELED{ErrorModule::Kernel, 118};
|
||||
constexpr ResultCode ERR_OUT_OF_RANGE{ErrorModule::Kernel, 119};
|
||||
constexpr ResultCode ERR_INVALID_ENUM_VALUE{ErrorModule::Kernel, 120};
|
||||
constexpr ResultCode ERR_NOT_FOUND{ErrorModule::Kernel, 121};
|
||||
constexpr ResultCode ERR_BUSY{ErrorModule::Kernel, 122};
|
||||
constexpr ResultCode ERR_ALREADY_REGISTERED{ErrorModule::Kernel, 122};
|
||||
constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE{ErrorModule::Kernel, 123};
|
||||
constexpr ResultCode ERR_INVALID_STATE{ErrorModule::Kernel, 125};
|
||||
constexpr ResultCode ERR_RESOURCE_LIMIT_EXCEEDED{ErrorModule::Kernel, 132};
|
||||
|
||||
@@ -4,47 +4,46 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include "common/assert.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
ReadableEvent::ReadableEvent(KernelCore& kernel) : WaitObject{kernel} {}
|
||||
ReadableEvent::~ReadableEvent() = default;
|
||||
Event::Event(KernelCore& kernel) : WaitObject{kernel} {}
|
||||
Event::~Event() = default;
|
||||
|
||||
bool ReadableEvent::ShouldWait(Thread* thread) const {
|
||||
SharedPtr<Event> Event::Create(KernelCore& kernel, ResetType reset_type, std::string name) {
|
||||
SharedPtr<Event> evt(new Event(kernel));
|
||||
|
||||
evt->signaled = false;
|
||||
evt->reset_type = reset_type;
|
||||
evt->name = std::move(name);
|
||||
|
||||
return evt;
|
||||
}
|
||||
|
||||
bool Event::ShouldWait(Thread* thread) const {
|
||||
return !signaled;
|
||||
}
|
||||
|
||||
void ReadableEvent::Acquire(Thread* thread) {
|
||||
void Event::Acquire(Thread* thread) {
|
||||
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
|
||||
|
||||
if (reset_type == ResetType::OneShot)
|
||||
signaled = false;
|
||||
}
|
||||
|
||||
void ReadableEvent::Signal() {
|
||||
void Event::Signal() {
|
||||
signaled = true;
|
||||
WakeupAllWaitingThreads();
|
||||
}
|
||||
|
||||
void ReadableEvent::Clear() {
|
||||
void Event::Clear() {
|
||||
signaled = false;
|
||||
}
|
||||
|
||||
ResultCode ReadableEvent::Reset() {
|
||||
if (!signaled) {
|
||||
return ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
Clear();
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
void ReadableEvent::WakeupAllWaitingThreads() {
|
||||
void Event::WakeupAllWaitingThreads() {
|
||||
WaitObject::WakeupAllWaitingThreads();
|
||||
|
||||
if (reset_type == ResetType::Pulse)
|
||||
@@ -11,52 +11,49 @@
|
||||
namespace Kernel {
|
||||
|
||||
class KernelCore;
|
||||
class ReadableEvent;
|
||||
class WritableEvent;
|
||||
|
||||
struct EventPair {
|
||||
SharedPtr<ReadableEvent> readable;
|
||||
SharedPtr<WritableEvent> writable;
|
||||
};
|
||||
|
||||
class WritableEvent final : public Object {
|
||||
class Event final : public WaitObject {
|
||||
public:
|
||||
~WritableEvent() override;
|
||||
|
||||
/**
|
||||
* Creates an event
|
||||
* @param kernel The kernel instance to create this event under.
|
||||
* @param reset_type ResetType describing how to create event
|
||||
* @param name Optional name of event
|
||||
*/
|
||||
static EventPair CreateEventPair(KernelCore& kernel, ResetType reset_type,
|
||||
std::string name = "Unknown");
|
||||
static SharedPtr<Event> Create(KernelCore& kernel, ResetType reset_type,
|
||||
std::string name = "Unknown");
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
return "WritableEvent";
|
||||
return "Event";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::WritableEvent;
|
||||
static const HandleType HANDLE_TYPE = HandleType::Event;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
SharedPtr<ReadableEvent> GetReadableEvent() const;
|
||||
ResetType GetResetType() const {
|
||||
return reset_type;
|
||||
}
|
||||
|
||||
ResetType GetResetType() const;
|
||||
bool ShouldWait(Thread* thread) const override;
|
||||
void Acquire(Thread* thread) override;
|
||||
|
||||
void WakeupAllWaitingThreads() override;
|
||||
|
||||
void Signal();
|
||||
void Clear();
|
||||
bool IsSignaled() const;
|
||||
|
||||
private:
|
||||
explicit WritableEvent(KernelCore& kernel);
|
||||
explicit Event(KernelCore& kernel);
|
||||
~Event() override;
|
||||
|
||||
SharedPtr<ReadableEvent> readable;
|
||||
ResetType reset_type; ///< Current ResetType
|
||||
|
||||
bool signaled; ///< Whether the event has already been signaled
|
||||
std::string name; ///< Name of event (optional)
|
||||
};
|
||||
|
||||
@@ -42,10 +42,9 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
|
||||
u16 generation = next_generation++;
|
||||
|
||||
// Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
|
||||
// Horizon OS uses zero to represent an invalid handle, so skip to 1.
|
||||
if (next_generation >= (1 << 15)) {
|
||||
// CTR-OS doesn't use generation 0, so skip straight to 1.
|
||||
if (next_generation >= (1 << 15))
|
||||
next_generation = 1;
|
||||
}
|
||||
|
||||
generations[slot] = generation;
|
||||
objects[slot] = std::move(obj);
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
namespace Kernel {
|
||||
|
||||
enum KernelHandle : Handle {
|
||||
InvalidHandle = 0,
|
||||
CurrentThread = 0xFFFF8000,
|
||||
CurrentProcess = 0xFFFF8001,
|
||||
};
|
||||
|
||||
@@ -15,14 +15,13 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/handle_table.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/server_session.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Kernel {
|
||||
@@ -37,9 +36,11 @@ void SessionRequestHandler::ClientDisconnected(const SharedPtr<ServerSession>& s
|
||||
boost::range::remove_erase(connected_sessions, server_session);
|
||||
}
|
||||
|
||||
SharedPtr<WritableEvent> HLERequestContext::SleepClientThread(
|
||||
SharedPtr<Thread> thread, const std::string& reason, u64 timeout, WakeupCallback&& callback,
|
||||
SharedPtr<WritableEvent> writable_event) {
|
||||
SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
|
||||
const std::string& reason, u64 timeout,
|
||||
WakeupCallback&& callback,
|
||||
Kernel::SharedPtr<Kernel::Event> event) {
|
||||
|
||||
// Put the client thread to sleep until the wait event is signaled or the timeout expires.
|
||||
thread->SetWakeupCallback([context = *this, callback](
|
||||
ThreadWakeupReason reason, SharedPtr<Thread> thread,
|
||||
@@ -50,25 +51,23 @@ SharedPtr<WritableEvent> HLERequestContext::SleepClientThread(
|
||||
return true;
|
||||
});
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
if (!writable_event) {
|
||||
if (!event) {
|
||||
// Create event if not provided
|
||||
const auto pair = WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
|
||||
"HLE Pause Event: " + reason);
|
||||
writable_event = pair.writable;
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
event =
|
||||
Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "HLE Pause Event: " + reason);
|
||||
}
|
||||
|
||||
const auto readable_event{writable_event->GetReadableEvent()};
|
||||
writable_event->Clear();
|
||||
event->Clear();
|
||||
thread->SetStatus(ThreadStatus::WaitHLEEvent);
|
||||
thread->SetWaitObjects({readable_event});
|
||||
readable_event->AddWaitingThread(thread);
|
||||
thread->SetWaitObjects({event});
|
||||
event->AddWaitingThread(thread);
|
||||
|
||||
if (timeout > 0) {
|
||||
thread->WakeAfterDelay(timeout);
|
||||
}
|
||||
|
||||
return writable_event;
|
||||
return event;
|
||||
}
|
||||
|
||||
HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session)
|
||||
|
||||
@@ -24,11 +24,10 @@ class ServiceFrameworkBase;
|
||||
namespace Kernel {
|
||||
|
||||
class Domain;
|
||||
class Event;
|
||||
class HandleTable;
|
||||
class HLERequestContext;
|
||||
class Process;
|
||||
class ReadableEvent;
|
||||
class WritableEvent;
|
||||
|
||||
/**
|
||||
* Interface implemented by HLE Session handlers.
|
||||
@@ -120,13 +119,12 @@ public:
|
||||
* @param callback Callback to be invoked when the thread is resumed. This callback must write
|
||||
* the entire command response once again, regardless of the state of it before this function
|
||||
* was called.
|
||||
* @param writable_event Event to use to wake up the thread. If unspecified, an event will be
|
||||
* created.
|
||||
* @param event Event to use to wake up the thread. If unspecified, an event will be created.
|
||||
* @returns Event that when signaled will resume the thread and call the callback function.
|
||||
*/
|
||||
SharedPtr<WritableEvent> SleepClientThread(SharedPtr<Thread> thread, const std::string& reason,
|
||||
u64 timeout, WakeupCallback&& callback,
|
||||
SharedPtr<WritableEvent> writable_event = nullptr);
|
||||
SharedPtr<Event> SleepClientThread(SharedPtr<Thread> thread, const std::string& reason,
|
||||
u64 timeout, WakeupCallback&& callback,
|
||||
Kernel::SharedPtr<Kernel::Event> event = nullptr);
|
||||
|
||||
/// Populates this context with data from the requesting process/thread.
|
||||
ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table,
|
||||
|
||||
@@ -112,7 +112,7 @@ struct KernelCore::Impl {
|
||||
|
||||
void Shutdown() {
|
||||
next_object_id = 0;
|
||||
next_process_id = Process::ProcessIDMin;
|
||||
next_process_id = 10;
|
||||
next_thread_id = 1;
|
||||
|
||||
process_list.clear();
|
||||
@@ -153,8 +153,10 @@ struct KernelCore::Impl {
|
||||
}
|
||||
|
||||
std::atomic<u32> next_object_id{0};
|
||||
std::atomic<u64> next_process_id{Process::ProcessIDMin};
|
||||
std::atomic<u64> next_thread_id{1};
|
||||
// TODO(Subv): Start the process ids from 10 for now, as lower PIDs are
|
||||
// reserved for low-level services
|
||||
std::atomic<u32> next_process_id{10};
|
||||
std::atomic<u32> next_thread_id{1};
|
||||
|
||||
// Lists all processes that exist in the current session.
|
||||
std::vector<SharedPtr<Process>> process_list;
|
||||
@@ -240,11 +242,11 @@ u32 KernelCore::CreateNewObjectID() {
|
||||
return impl->next_object_id++;
|
||||
}
|
||||
|
||||
u64 KernelCore::CreateNewThreadID() {
|
||||
u32 KernelCore::CreateNewThreadID() {
|
||||
return impl->next_thread_id++;
|
||||
}
|
||||
|
||||
u64 KernelCore::CreateNewProcessID() {
|
||||
u32 KernelCore::CreateNewProcessID() {
|
||||
return impl->next_process_id++;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,10 +88,10 @@ private:
|
||||
u32 CreateNewObjectID();
|
||||
|
||||
/// Creates a new process ID, incrementing the internal process ID counter;
|
||||
u64 CreateNewProcessID();
|
||||
u32 CreateNewProcessID();
|
||||
|
||||
/// Creates a new thread ID, incrementing the internal thread ID counter.
|
||||
u64 CreateNewThreadID();
|
||||
u32 CreateNewThreadID();
|
||||
|
||||
/// Creates a timer callback handle for the given timer.
|
||||
ResultVal<Handle> CreateTimerCallbackHandle(const SharedPtr<Timer>& timer);
|
||||
|
||||
@@ -13,17 +13,16 @@ Object::~Object() = default;
|
||||
|
||||
bool Object::IsWaitable() const {
|
||||
switch (GetHandleType()) {
|
||||
case HandleType::ReadableEvent:
|
||||
case HandleType::Event:
|
||||
case HandleType::Thread:
|
||||
case HandleType::Process:
|
||||
case HandleType::Timer:
|
||||
case HandleType::ServerPort:
|
||||
case HandleType::ServerSession:
|
||||
return true;
|
||||
|
||||
case HandleType::Unknown:
|
||||
case HandleType::WritableEvent:
|
||||
case HandleType::SharedMemory:
|
||||
case HandleType::Process:
|
||||
case HandleType::AddressArbiter:
|
||||
case HandleType::ResourceLimit:
|
||||
case HandleType::ClientPort:
|
||||
@@ -32,7 +31,6 @@ bool Object::IsWaitable() const {
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -19,8 +19,7 @@ using Handle = u32;
|
||||
|
||||
enum class HandleType : u32 {
|
||||
Unknown,
|
||||
WritableEvent,
|
||||
ReadableEvent,
|
||||
Event,
|
||||
SharedMemory,
|
||||
Thread,
|
||||
Process,
|
||||
@@ -34,9 +33,9 @@ enum class HandleType : u32 {
|
||||
};
|
||||
|
||||
enum class ResetType {
|
||||
OneShot, ///< Reset automatically on object acquisition
|
||||
Sticky, ///< Never reset automatically
|
||||
Pulse, ///< Reset automatically on wakeup
|
||||
OneShot,
|
||||
Sticky,
|
||||
Pulse,
|
||||
};
|
||||
|
||||
class Object : NonCopyable {
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#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"
|
||||
@@ -45,28 +44,8 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) {
|
||||
return process;
|
||||
}
|
||||
|
||||
SharedPtr<ResourceLimit> Process::GetResourceLimit() const {
|
||||
return resource_limit;
|
||||
}
|
||||
|
||||
ResultCode Process::ClearSignalState() {
|
||||
if (status == ProcessStatus::Exited) {
|
||||
LOG_ERROR(Kernel, "called on a terminated process instance.");
|
||||
return ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (!is_signaled) {
|
||||
LOG_ERROR(Kernel, "called on a process instance that isn't signaled.");
|
||||
return ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
is_signaled = false;
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
|
||||
program_id = metadata.GetTitleID();
|
||||
ideal_processor = metadata.GetMainThreadCore();
|
||||
is_64bit_process = metadata.Is64BitProgram();
|
||||
vm_manager.Reset(metadata.GetAddressSpaceType());
|
||||
}
|
||||
@@ -150,17 +129,17 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
|
||||
vm_manager
|
||||
.MapMemoryBlock(vm_manager.GetTLSIORegionEndAddress() - stack_size,
|
||||
std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size,
|
||||
MemoryState::Stack)
|
||||
MemoryState::Mapped)
|
||||
.Unwrap();
|
||||
|
||||
vm_manager.LogLayout();
|
||||
ChangeStatus(ProcessStatus::Running);
|
||||
status = ProcessStatus::Running;
|
||||
|
||||
Kernel::SetupMainThread(kernel, entry_point, main_thread_priority, *this);
|
||||
}
|
||||
|
||||
void Process::PrepareForTermination() {
|
||||
ChangeStatus(ProcessStatus::Exiting);
|
||||
status = ProcessStatus::Exited;
|
||||
|
||||
const auto stop_threads = [this](const std::vector<SharedPtr<Thread>>& thread_list) {
|
||||
for (auto& thread : thread_list) {
|
||||
@@ -184,8 +163,6 @@ void Process::PrepareForTermination() {
|
||||
stop_threads(system.Scheduler(1).GetThreadList());
|
||||
stop_threads(system.Scheduler(2).GetThreadList());
|
||||
stop_threads(system.Scheduler(3).GetThreadList());
|
||||
|
||||
ChangeStatus(ProcessStatus::Exited);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -284,25 +261,7 @@ ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) {
|
||||
return vm_manager.UnmapRange(dst_addr, size);
|
||||
}
|
||||
|
||||
Kernel::Process::Process(KernelCore& kernel) : WaitObject{kernel} {}
|
||||
Kernel::Process::Process(KernelCore& kernel) : Object{kernel} {}
|
||||
Kernel::Process::~Process() {}
|
||||
|
||||
void Process::Acquire(Thread* thread) {
|
||||
ASSERT_MSG(!ShouldWait(thread), "Object unavailable!");
|
||||
}
|
||||
|
||||
bool Process::ShouldWait(Thread* thread) const {
|
||||
return !is_signaled;
|
||||
}
|
||||
|
||||
void Process::ChangeStatus(ProcessStatus new_status) {
|
||||
if (status == new_status) {
|
||||
return;
|
||||
}
|
||||
|
||||
status = new_status;
|
||||
is_signaled = true;
|
||||
WakeupAllWaitingThreads();
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -14,10 +14,9 @@
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/handle_table.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/kernel/vm_manager.h"
|
||||
#include "core/hle/kernel/wait_object.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace FileSys {
|
||||
class ProgramMetadata;
|
||||
@@ -118,20 +117,8 @@ struct CodeSet final {
|
||||
VAddr entrypoint = 0;
|
||||
};
|
||||
|
||||
class Process final : public WaitObject {
|
||||
class Process final : public Object {
|
||||
public:
|
||||
enum : u64 {
|
||||
/// Lowest allowed process ID for a kernel initial process.
|
||||
InitialKIPIDMin = 1,
|
||||
/// Highest allowed process ID for a kernel initial process.
|
||||
InitialKIPIDMax = 80,
|
||||
|
||||
/// Lowest allowed process ID for a userland process.
|
||||
ProcessIDMin = 81,
|
||||
/// Highest allowed process ID for a userland process.
|
||||
ProcessIDMax = 0xFFFFFFFFFFFFFFFF,
|
||||
};
|
||||
|
||||
static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4;
|
||||
|
||||
static SharedPtr<Process> Create(KernelCore& kernel, std::string&& name);
|
||||
@@ -174,7 +161,7 @@ public:
|
||||
}
|
||||
|
||||
/// Gets the unique ID that identifies this particular process.
|
||||
u64 GetProcessID() const {
|
||||
u32 GetProcessID() const {
|
||||
return process_id;
|
||||
}
|
||||
|
||||
@@ -184,7 +171,14 @@ public:
|
||||
}
|
||||
|
||||
/// Gets the resource limit descriptor for this process
|
||||
SharedPtr<ResourceLimit> GetResourceLimit() const;
|
||||
ResourceLimit& GetResourceLimit() {
|
||||
return *resource_limit;
|
||||
}
|
||||
|
||||
/// Gets the resource limit descriptor for this process
|
||||
const ResourceLimit& GetResourceLimit() const {
|
||||
return *resource_limit;
|
||||
}
|
||||
|
||||
/// Gets the default CPU ID for this process
|
||||
u8 GetDefaultProcessorID() const {
|
||||
@@ -225,16 +219,6 @@ public:
|
||||
return random_entropy.at(index);
|
||||
}
|
||||
|
||||
/// Clears the signaled state of the process if and only if it's signaled.
|
||||
///
|
||||
/// @pre The process must not be already terminated. If this is called on a
|
||||
/// terminated process, then ERR_INVALID_STATE will be returned.
|
||||
///
|
||||
/// @pre The process must be in a signaled state. If this is called on a
|
||||
/// process instance that is not signaled, ERR_INVALID_STATE will be
|
||||
/// returned.
|
||||
ResultCode ClearSignalState();
|
||||
|
||||
/**
|
||||
* Loads process-specifics configuration info with metadata provided
|
||||
* by an executable.
|
||||
@@ -274,7 +258,8 @@ public:
|
||||
ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
|
||||
ResultCode HeapFree(VAddr target, u32 size);
|
||||
|
||||
ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state);
|
||||
ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size,
|
||||
MemoryState state = MemoryState::Mapped);
|
||||
|
||||
ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
|
||||
|
||||
@@ -282,17 +267,6 @@ private:
|
||||
explicit Process(KernelCore& kernel);
|
||||
~Process() override;
|
||||
|
||||
/// Checks if the specified thread should wait until this process is available.
|
||||
bool ShouldWait(Thread* thread) const override;
|
||||
|
||||
/// Acquires/locks this process for the specified thread if it's available.
|
||||
void Acquire(Thread* thread) override;
|
||||
|
||||
/// Changes the process status. If the status is different
|
||||
/// from the current process status, then this will trigger
|
||||
/// a process signal.
|
||||
void ChangeStatus(ProcessStatus new_status);
|
||||
|
||||
/// Memory manager for this process.
|
||||
Kernel::VMManager vm_manager;
|
||||
|
||||
@@ -300,10 +274,10 @@ private:
|
||||
ProcessStatus status;
|
||||
|
||||
/// The ID of this process
|
||||
u64 process_id = 0;
|
||||
u32 process_id = 0;
|
||||
|
||||
/// Title ID corresponding to the process
|
||||
u64 program_id = 0;
|
||||
u64 program_id;
|
||||
|
||||
/// Resource limit descriptor for this process
|
||||
SharedPtr<ResourceLimit> resource_limit;
|
||||
@@ -338,10 +312,6 @@ private:
|
||||
/// specified by metadata provided to the process during loading.
|
||||
bool is_64bit_process = true;
|
||||
|
||||
/// Whether or not this process is signaled. This occurs
|
||||
/// upon the process changing to a different state.
|
||||
bool is_signaled = false;
|
||||
|
||||
/// Total running time for the process in ticks.
|
||||
u64 total_process_running_time_ticks = 0;
|
||||
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/wait_object.h"
|
||||
|
||||
union ResultCode;
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KernelCore;
|
||||
class WritableEvent;
|
||||
|
||||
class ReadableEvent final : public WaitObject {
|
||||
friend class WritableEvent;
|
||||
|
||||
public:
|
||||
~ReadableEvent() override;
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
return "ReadableEvent";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
ResetType GetResetType() const {
|
||||
return reset_type;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::ReadableEvent;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
bool ShouldWait(Thread* thread) const override;
|
||||
void Acquire(Thread* thread) override;
|
||||
|
||||
void WakeupAllWaitingThreads() override;
|
||||
|
||||
/// Unconditionally clears the readable event's state.
|
||||
void Clear();
|
||||
|
||||
/// Clears the readable event's state if and only if it
|
||||
/// has already been signaled.
|
||||
///
|
||||
/// @pre The event must be in a signaled state. If this event
|
||||
/// is in an unsignaled state and this function is called,
|
||||
/// then ERR_INVALID_STATE will be returned.
|
||||
ResultCode Reset();
|
||||
|
||||
private:
|
||||
explicit ReadableEvent(KernelCore& kernel);
|
||||
|
||||
void Signal();
|
||||
|
||||
ResetType reset_type;
|
||||
bool signaled;
|
||||
|
||||
std::string name; ///< Name of event (optional)
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -14,7 +14,7 @@ namespace Kernel {
|
||||
|
||||
class KernelCore;
|
||||
|
||||
enum class ResourceType : u32 {
|
||||
enum class ResourceType {
|
||||
PhysicalMemory,
|
||||
Threads,
|
||||
Events,
|
||||
@@ -25,10 +25,6 @@ enum class ResourceType : u32 {
|
||||
ResourceTypeCount
|
||||
};
|
||||
|
||||
constexpr bool IsValidResourceType(ResourceType type) {
|
||||
return type < ResourceType::ResourceTypeCount;
|
||||
}
|
||||
|
||||
class ResourceLimit final : public Object {
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_cpu.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
@@ -180,69 +179,4 @@ void Scheduler::SetThreadPriority(Thread* thread, u32 priority) {
|
||||
ready_queue.prepare(priority);
|
||||
}
|
||||
|
||||
Thread* Scheduler::GetNextSuggestedThread(u32 core, u32 maximum_priority) const {
|
||||
std::lock_guard<std::mutex> lock(scheduler_mutex);
|
||||
|
||||
const u32 mask = 1U << core;
|
||||
return ready_queue.get_first_filter([mask, maximum_priority](Thread const* thread) {
|
||||
return (thread->GetAffinityMask() & mask) != 0 && thread->GetPriority() < maximum_priority;
|
||||
});
|
||||
}
|
||||
|
||||
void Scheduler::YieldWithoutLoadBalancing(Thread* thread) {
|
||||
ASSERT(thread != nullptr);
|
||||
// Avoid yielding if the thread isn't even running.
|
||||
ASSERT(thread->GetStatus() == ThreadStatus::Running);
|
||||
|
||||
// Sanity check that the priority is valid
|
||||
ASSERT(thread->GetPriority() < THREADPRIO_COUNT);
|
||||
|
||||
// Yield this thread -- sleep for zero time and force reschedule to different thread
|
||||
WaitCurrentThread_Sleep();
|
||||
GetCurrentThread()->WakeAfterDelay(0);
|
||||
}
|
||||
|
||||
void Scheduler::YieldWithLoadBalancing(Thread* thread) {
|
||||
ASSERT(thread != nullptr);
|
||||
const auto priority = thread->GetPriority();
|
||||
const auto core = static_cast<u32>(thread->GetProcessorID());
|
||||
|
||||
// Avoid yielding if the thread isn't even running.
|
||||
ASSERT(thread->GetStatus() == ThreadStatus::Running);
|
||||
|
||||
// Sanity check that the priority is valid
|
||||
ASSERT(priority < THREADPRIO_COUNT);
|
||||
|
||||
// Sleep for zero time to be able to force reschedule to different thread
|
||||
WaitCurrentThread_Sleep();
|
||||
GetCurrentThread()->WakeAfterDelay(0);
|
||||
|
||||
Thread* suggested_thread = nullptr;
|
||||
|
||||
// Search through all of the cpu cores (except this one) for a suggested thread.
|
||||
// Take the first non-nullptr one
|
||||
for (unsigned cur_core = 0; cur_core < Core::NUM_CPU_CORES; ++cur_core) {
|
||||
const auto res =
|
||||
Core::System::GetInstance().CpuCore(cur_core).Scheduler().GetNextSuggestedThread(
|
||||
core, priority);
|
||||
|
||||
// If scheduler provides a suggested thread
|
||||
if (res != nullptr) {
|
||||
// And its better than the current suggested thread (or is the first valid one)
|
||||
if (suggested_thread == nullptr ||
|
||||
suggested_thread->GetPriority() > res->GetPriority()) {
|
||||
suggested_thread = res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If a suggested thread was found, queue that for this core
|
||||
if (suggested_thread != nullptr)
|
||||
suggested_thread->ChangeCore(core, suggested_thread->GetAffinityMask());
|
||||
}
|
||||
|
||||
void Scheduler::YieldAndWaitForLoadBalancing(Thread* thread) {
|
||||
UNIMPLEMENTED_MSG("Wait for load balancing thread yield type is not implemented!");
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -51,75 +51,6 @@ public:
|
||||
/// Sets the priority of a thread in the scheduler
|
||||
void SetThreadPriority(Thread* thread, u32 priority);
|
||||
|
||||
/// Gets the next suggested thread for load balancing
|
||||
Thread* GetNextSuggestedThread(u32 core, u32 minimum_priority) const;
|
||||
|
||||
/**
|
||||
* YieldWithoutLoadBalancing -- analogous to normal yield on a system
|
||||
* Moves the thread to the end of the ready queue for its priority, and then reschedules the
|
||||
* system to the new head of the queue.
|
||||
*
|
||||
* Example (Single Core -- but can be extrapolated to multi):
|
||||
* ready_queue[prio=0]: ThreadA, ThreadB, ThreadC (->exec order->)
|
||||
* Currently Running: ThreadR
|
||||
*
|
||||
* ThreadR calls YieldWithoutLoadBalancing
|
||||
*
|
||||
* ThreadR is moved to the end of ready_queue[prio=0]:
|
||||
* ready_queue[prio=0]: ThreadA, ThreadB, ThreadC, ThreadR (->exec order->)
|
||||
* Currently Running: Nothing
|
||||
*
|
||||
* System is rescheduled (ThreadA is popped off of queue):
|
||||
* ready_queue[prio=0]: ThreadB, ThreadC, ThreadR (->exec order->)
|
||||
* Currently Running: ThreadA
|
||||
*
|
||||
* If the queue is empty at time of call, no yielding occurs. This does not cross between cores
|
||||
* or priorities at all.
|
||||
*/
|
||||
void YieldWithoutLoadBalancing(Thread* thread);
|
||||
|
||||
/**
|
||||
* YieldWithLoadBalancing -- yield but with better selection of the new running thread
|
||||
* Moves the current thread to the end of the ready queue for its priority, then selects a
|
||||
* 'suggested thread' (a thread on a different core that could run on this core) from the
|
||||
* scheduler, changes its core, and reschedules the current core to that thread.
|
||||
*
|
||||
* Example (Dual Core -- can be extrapolated to Quad Core, this is just normal yield if it were
|
||||
* single core):
|
||||
* ready_queue[core=0][prio=0]: ThreadA, ThreadB (affinities not pictured as irrelevant
|
||||
* ready_queue[core=1][prio=0]: ThreadC[affinity=both], ThreadD[affinity=core1only]
|
||||
* Currently Running: ThreadQ on Core 0 || ThreadP on Core 1
|
||||
*
|
||||
* ThreadQ calls YieldWithLoadBalancing
|
||||
*
|
||||
* ThreadQ is moved to the end of ready_queue[core=0][prio=0]:
|
||||
* ready_queue[core=0][prio=0]: ThreadA, ThreadB
|
||||
* ready_queue[core=1][prio=0]: ThreadC[affinity=both], ThreadD[affinity=core1only]
|
||||
* Currently Running: ThreadQ on Core 0 || ThreadP on Core 1
|
||||
*
|
||||
* A list of suggested threads for each core is compiled
|
||||
* Suggested Threads: {ThreadC on Core 1}
|
||||
* If this were quad core (as the switch is), there could be between 0 and 3 threads in this
|
||||
* list. If there are more than one, the thread is selected by highest prio.
|
||||
*
|
||||
* ThreadC is core changed to Core 0:
|
||||
* ready_queue[core=0][prio=0]: ThreadC, ThreadA, ThreadB, ThreadQ
|
||||
* ready_queue[core=1][prio=0]: ThreadD
|
||||
* Currently Running: None on Core 0 || ThreadP on Core 1
|
||||
*
|
||||
* System is rescheduled (ThreadC is popped off of queue):
|
||||
* ready_queue[core=0][prio=0]: ThreadA, ThreadB, ThreadQ
|
||||
* ready_queue[core=1][prio=0]: ThreadD
|
||||
* Currently Running: ThreadC on Core 0 || ThreadP on Core 1
|
||||
*
|
||||
* If no suggested threads can be found this will behave just as normal yield. If there are
|
||||
* multiple candidates for the suggested thread on a core, the highest prio is taken.
|
||||
*/
|
||||
void YieldWithLoadBalancing(Thread* thread);
|
||||
|
||||
/// Currently unknown -- asserts as unimplemented on call
|
||||
void YieldAndWaitForLoadBalancing(Thread* thread);
|
||||
|
||||
/// Returns a list of all threads managed by the scheduler
|
||||
const std::vector<SharedPtr<Thread>>& GetThreadList() const {
|
||||
return thread_list;
|
||||
|
||||
@@ -17,13 +17,13 @@ namespace Kernel {
|
||||
SharedMemory::SharedMemory(KernelCore& kernel) : Object{kernel} {}
|
||||
SharedMemory::~SharedMemory() = default;
|
||||
|
||||
SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, Process* owner_process, u64 size,
|
||||
MemoryPermission permissions,
|
||||
SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, SharedPtr<Process> owner_process,
|
||||
u64 size, MemoryPermission permissions,
|
||||
MemoryPermission other_permissions, VAddr address,
|
||||
MemoryRegion region, std::string name) {
|
||||
SharedPtr<SharedMemory> shared_memory(new SharedMemory(kernel));
|
||||
|
||||
shared_memory->owner_process = owner_process;
|
||||
shared_memory->owner_process = std::move(owner_process);
|
||||
shared_memory->name = std::move(name);
|
||||
shared_memory->size = size;
|
||||
shared_memory->permissions = permissions;
|
||||
@@ -39,15 +39,15 @@ SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, Process* owner_
|
||||
shared_memory->backing_block.get());
|
||||
}
|
||||
} else {
|
||||
const auto& vm_manager = shared_memory->owner_process->VMManager();
|
||||
auto& vm_manager = shared_memory->owner_process->VMManager();
|
||||
|
||||
// The memory is already available and mapped in the owner process.
|
||||
const auto vma = vm_manager.FindVMA(address);
|
||||
ASSERT_MSG(vm_manager.IsValidHandle(vma), "Invalid memory address");
|
||||
auto vma = vm_manager.FindVMA(address);
|
||||
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.
|
||||
const auto vma_offset = address - vma->first;
|
||||
auto vma_offset = address - vma->first;
|
||||
ASSERT_MSG(vma_offset + size <= vma->second.size,
|
||||
"Shared memory exceeds bounds of mapped block");
|
||||
|
||||
|
||||
@@ -45,8 +45,8 @@ public:
|
||||
* linear heap.
|
||||
* @param name Optional object name, used for debugging purposes.
|
||||
*/
|
||||
static SharedPtr<SharedMemory> Create(KernelCore& kernel, Process* owner_process, u64 size,
|
||||
MemoryPermission permissions,
|
||||
static SharedPtr<SharedMemory> Create(KernelCore& kernel, SharedPtr<Process> owner_process,
|
||||
u64 size, MemoryPermission permissions,
|
||||
MemoryPermission other_permissions, VAddr address = 0,
|
||||
MemoryRegion region = MemoryRegion::BASE,
|
||||
std::string name = "Unknown");
|
||||
@@ -139,7 +139,7 @@ private:
|
||||
/// Permission restrictions applied to other processes mapping the block.
|
||||
MemoryPermission other_permissions{};
|
||||
/// Process that created this shared memory block.
|
||||
Process* owner_process;
|
||||
SharedPtr<Process> owner_process;
|
||||
/// Address of shared memory block in the owner process if specified.
|
||||
VAddr base_address = 0;
|
||||
/// Name of shared memory object.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,22 @@
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
struct MemoryInfo {
|
||||
u64 base_address;
|
||||
u64 size;
|
||||
u32 type;
|
||||
u32 attributes;
|
||||
u32 permission;
|
||||
u32 device_refcount;
|
||||
u32 ipc_refcount;
|
||||
INSERT_PADDING_WORDS(1);
|
||||
};
|
||||
static_assert(sizeof(MemoryInfo) == 0x28, "MemoryInfo has incorrect size.");
|
||||
|
||||
struct PageInfo {
|
||||
u64 flags;
|
||||
};
|
||||
|
||||
void CallSVC(u32 immediate);
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
#include "common/common_types.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/svc.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
@@ -41,14 +43,6 @@ void SvcWrap() {
|
||||
FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1))).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*)>
|
||||
void SvcWrap() {
|
||||
u32 param = 0;
|
||||
const u32 retval = func(¶m).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*, u32)>
|
||||
void SvcWrap() {
|
||||
u32 param_1 = 0;
|
||||
@@ -57,31 +51,10 @@ void SvcWrap() {
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*, u32*)>
|
||||
void SvcWrap() {
|
||||
u32 param_1 = 0;
|
||||
u32 param_2 = 0;
|
||||
const u32 retval = func(¶m_1, ¶m_2).raw;
|
||||
|
||||
auto& arm_interface = Core::CurrentArmInterface();
|
||||
arm_interface.SetReg(1, param_1);
|
||||
arm_interface.SetReg(2, param_2);
|
||||
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*, u64)>
|
||||
void SvcWrap() {
|
||||
u32 param_1 = 0;
|
||||
const u32 retval = func(¶m_1, Param(1)).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64*, u32)>
|
||||
void SvcWrap() {
|
||||
u64 param_1 = 0;
|
||||
const u32 retval = func(¶m_1, static_cast<u32>(Param(1))).raw;
|
||||
u32 retval = func(¶m_1, Param(1)).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
@@ -135,12 +108,7 @@ void SvcWrap() {
|
||||
template <ResultCode func(u64, u64, u32, u32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(
|
||||
func(Param(0), Param(1), static_cast<u32>(Param(2)), static_cast<u32>(Param(3))).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, u64, u32, u64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(Param(0), Param(1), static_cast<u32>(Param(2)), Param(3)).raw);
|
||||
func(Param(0), Param(1), static_cast<u32>(Param(3)), static_cast<u32>(Param(3))).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u64, u32)>
|
||||
@@ -202,6 +170,21 @@ void SvcWrap() {
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(MemoryInfo*, PageInfo*, u64)>
|
||||
void SvcWrap() {
|
||||
MemoryInfo memory_info = {};
|
||||
PageInfo page_info = {};
|
||||
u32 retval = func(&memory_info, &page_info, Param(2)).raw;
|
||||
|
||||
Memory::Write64(Param(0), memory_info.base_address);
|
||||
Memory::Write64(Param(0) + 8, memory_info.size);
|
||||
Memory::Write32(Param(0) + 16, memory_info.type);
|
||||
Memory::Write32(Param(0) + 20, memory_info.attributes);
|
||||
Memory::Write32(Param(0) + 24, memory_info.permission);
|
||||
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*, u64, u64, u32)>
|
||||
void SvcWrap() {
|
||||
u32 param_1 = 0;
|
||||
|
||||
@@ -50,7 +50,7 @@ void Thread::Stop() {
|
||||
|
||||
// Clean up thread from ready queue
|
||||
// This is only needed when the thread is terminated forcefully (SVC TerminateProcess)
|
||||
if (status == ThreadStatus::Ready || status == ThreadStatus::Paused) {
|
||||
if (status == ThreadStatus::Ready) {
|
||||
scheduler->UnscheduleThread(this, current_priority);
|
||||
}
|
||||
|
||||
@@ -140,11 +140,6 @@ void Thread::ResumeFromWait() {
|
||||
|
||||
wakeup_callback = nullptr;
|
||||
|
||||
if (activity == ThreadActivity::Paused) {
|
||||
status = ThreadStatus::Paused;
|
||||
return;
|
||||
}
|
||||
|
||||
status = ThreadStatus::Ready;
|
||||
|
||||
ChangeScheduler();
|
||||
@@ -163,9 +158,6 @@ static void ResetThreadContext(Core::ARM_Interface::ThreadContext& context, VAdd
|
||||
context.cpu_registers[0] = arg;
|
||||
context.pc = entry_point;
|
||||
context.sp = stack_top;
|
||||
// TODO(merry): Perform a hardware test to determine the below value.
|
||||
// AHP = 0, DN = 1, FTZ = 1, RMode = Round towards zero
|
||||
context.fpcr = 0x03C00000;
|
||||
}
|
||||
|
||||
ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name, VAddr entry_point,
|
||||
@@ -396,23 +388,6 @@ bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> t
|
||||
return wakeup_callback(reason, std::move(thread), std::move(object), index);
|
||||
}
|
||||
|
||||
void Thread::SetActivity(ThreadActivity value) {
|
||||
activity = value;
|
||||
|
||||
if (value == ThreadActivity::Paused) {
|
||||
// Set status if not waiting
|
||||
if (status == ThreadStatus::Ready) {
|
||||
status = ThreadStatus::Paused;
|
||||
} else if (status == ThreadStatus::Running) {
|
||||
status = ThreadStatus::Paused;
|
||||
Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule();
|
||||
}
|
||||
} else if (status == ThreadStatus::Paused) {
|
||||
// Ready to reschedule
|
||||
ResumeFromWait();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,7 +26,6 @@ enum ThreadPriority : u32 {
|
||||
THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps
|
||||
THREADPRIO_DEFAULT = 44, ///< Default thread priority for userland apps
|
||||
THREADPRIO_LOWEST = 63, ///< Lowest thread priority
|
||||
THREADPRIO_COUNT = 64, ///< Total number of possible thread priorities.
|
||||
};
|
||||
|
||||
enum ThreadProcessorId : s32 {
|
||||
@@ -45,7 +44,6 @@ enum ThreadProcessorId : s32 {
|
||||
enum class ThreadStatus {
|
||||
Running, ///< Currently running
|
||||
Ready, ///< Ready to run
|
||||
Paused, ///< Paused by SetThreadActivity or debug
|
||||
WaitHLEEvent, ///< Waiting for hle event to finish
|
||||
WaitSleep, ///< Waiting due to a SleepThread SVC
|
||||
WaitIPC, ///< Waiting for the reply from an IPC request
|
||||
@@ -62,11 +60,6 @@ enum class ThreadWakeupReason {
|
||||
Timeout // The thread was woken up due to a wait timeout.
|
||||
};
|
||||
|
||||
enum class ThreadActivity : u32 {
|
||||
Normal = 0,
|
||||
Paused = 1,
|
||||
};
|
||||
|
||||
class Thread final : public WaitObject {
|
||||
public:
|
||||
using TLSMemory = std::vector<u8>;
|
||||
@@ -157,7 +150,7 @@ public:
|
||||
* Gets the thread's thread ID
|
||||
* @return The thread's ID
|
||||
*/
|
||||
u64 GetThreadID() const {
|
||||
u32 GetThreadID() const {
|
||||
return thread_id;
|
||||
}
|
||||
|
||||
@@ -377,12 +370,6 @@ public:
|
||||
return affinity_mask;
|
||||
}
|
||||
|
||||
ThreadActivity GetActivity() const {
|
||||
return activity;
|
||||
}
|
||||
|
||||
void SetActivity(ThreadActivity value);
|
||||
|
||||
private:
|
||||
explicit Thread(KernelCore& kernel);
|
||||
~Thread() override;
|
||||
@@ -391,7 +378,7 @@ private:
|
||||
|
||||
Core::ARM_Interface::ThreadContext context{};
|
||||
|
||||
u64 thread_id = 0;
|
||||
u32 thread_id = 0;
|
||||
|
||||
ThreadStatus status = ThreadStatus::Dormant;
|
||||
|
||||
@@ -451,8 +438,6 @@ private:
|
||||
TLSMemoryPtr tls_memory = std::make_shared<TLSMemory>();
|
||||
|
||||
std::string name;
|
||||
|
||||
ThreadActivity activity = ThreadActivity::Normal;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,19 +25,19 @@ static const char* GetMemoryStateName(MemoryState state) {
|
||||
"CodeMutable", "Heap",
|
||||
"Shared", "Unknown1",
|
||||
"ModuleCodeStatic", "ModuleCodeMutable",
|
||||
"IpcBuffer0", "Stack",
|
||||
"IpcBuffer0", "Mapped",
|
||||
"ThreadLocal", "TransferMemoryIsolated",
|
||||
"TransferMemory", "ProcessMemory",
|
||||
"Inaccessible", "IpcBuffer1",
|
||||
"Unknown2", "IpcBuffer1",
|
||||
"IpcBuffer3", "KernelStack",
|
||||
};
|
||||
|
||||
return names[ToSvcMemoryState(state)];
|
||||
return names[static_cast<int>(state)];
|
||||
}
|
||||
|
||||
bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
|
||||
ASSERT(base + size == next.base);
|
||||
if (permissions != next.permissions || state != next.state || attribute != next.attribute ||
|
||||
if (permissions != next.permissions || meminfo_state != next.meminfo_state ||
|
||||
type != next.type) {
|
||||
return false;
|
||||
}
|
||||
@@ -87,10 +87,6 @@ VMManager::VMAHandle VMManager::FindVMA(VAddr target) const {
|
||||
}
|
||||
}
|
||||
|
||||
bool VMManager::IsValidHandle(VMAHandle handle) const {
|
||||
return handle != vma_map.cend();
|
||||
}
|
||||
|
||||
ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
|
||||
std::shared_ptr<std::vector<u8>> block,
|
||||
std::size_t offset, u64 size,
|
||||
@@ -115,7 +111,7 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
|
||||
|
||||
final_vma.type = VMAType::AllocatedMemoryBlock;
|
||||
final_vma.permissions = VMAPermission::ReadWrite;
|
||||
final_vma.state = state;
|
||||
final_vma.meminfo_state = state;
|
||||
final_vma.backing_block = std::move(block);
|
||||
final_vma.offset = offset;
|
||||
UpdatePageTableForVMA(final_vma);
|
||||
@@ -140,7 +136,7 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* me
|
||||
|
||||
final_vma.type = VMAType::BackingMemory;
|
||||
final_vma.permissions = VMAPermission::ReadWrite;
|
||||
final_vma.state = state;
|
||||
final_vma.meminfo_state = state;
|
||||
final_vma.backing_memory = memory;
|
||||
UpdatePageTableForVMA(final_vma);
|
||||
|
||||
@@ -177,7 +173,7 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u6
|
||||
|
||||
final_vma.type = VMAType::MMIO;
|
||||
final_vma.permissions = VMAPermission::ReadWrite;
|
||||
final_vma.state = state;
|
||||
final_vma.meminfo_state = state;
|
||||
final_vma.paddr = paddr;
|
||||
final_vma.mmio_handler = std::move(mmio_handler);
|
||||
UpdatePageTableForVMA(final_vma);
|
||||
@@ -189,7 +185,7 @@ VMManager::VMAIter VMManager::Unmap(VMAIter vma_handle) {
|
||||
VirtualMemoryArea& vma = vma_handle->second;
|
||||
vma.type = VMAType::Free;
|
||||
vma.permissions = VMAPermission::None;
|
||||
vma.state = MemoryState::Unmapped;
|
||||
vma.meminfo_state = MemoryState::Unmapped;
|
||||
|
||||
vma.backing_block = nullptr;
|
||||
vma.offset = 0;
|
||||
@@ -302,54 +298,6 @@ ResultCode VMManager::HeapFree(VAddr target, u64 size) {
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
MemoryInfo VMManager::QueryMemory(VAddr address) const {
|
||||
const auto vma = FindVMA(address);
|
||||
MemoryInfo memory_info{};
|
||||
|
||||
if (IsValidHandle(vma)) {
|
||||
memory_info.base_address = vma->second.base;
|
||||
memory_info.attributes = ToSvcMemoryAttribute(vma->second.attribute);
|
||||
memory_info.permission = static_cast<u32>(vma->second.permissions);
|
||||
memory_info.size = vma->second.size;
|
||||
memory_info.state = ToSvcMemoryState(vma->second.state);
|
||||
} else {
|
||||
memory_info.base_address = address_space_end;
|
||||
memory_info.permission = static_cast<u32>(VMAPermission::None);
|
||||
memory_info.size = 0 - address_space_end;
|
||||
memory_info.state = static_cast<u32>(MemoryState::Inaccessible);
|
||||
}
|
||||
|
||||
return memory_info;
|
||||
}
|
||||
|
||||
ResultCode VMManager::SetMemoryAttribute(VAddr address, u64 size, MemoryAttribute mask,
|
||||
MemoryAttribute attribute) {
|
||||
constexpr auto ignore_mask = MemoryAttribute::Uncached | MemoryAttribute::DeviceMapped;
|
||||
constexpr auto attribute_mask = ~ignore_mask;
|
||||
|
||||
const auto result = CheckRangeState(
|
||||
address, size, MemoryState::FlagUncached, MemoryState::FlagUncached, VMAPermission::None,
|
||||
VMAPermission::None, attribute_mask, MemoryAttribute::None, ignore_mask);
|
||||
|
||||
if (result.Failed()) {
|
||||
return result.Code();
|
||||
}
|
||||
|
||||
const auto [prev_state, prev_permissions, prev_attributes] = *result;
|
||||
const auto new_attribute = (prev_attributes & ~mask) | (mask & attribute);
|
||||
|
||||
const auto carve_result = CarveVMARange(address, size);
|
||||
if (carve_result.Failed()) {
|
||||
return carve_result.Code();
|
||||
}
|
||||
|
||||
auto vma_iter = *carve_result;
|
||||
vma_iter->second.attribute = new_attribute;
|
||||
|
||||
MergeAdjacent(vma_iter);
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultCode VMManager::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state) {
|
||||
const auto vma = FindVMA(src_addr);
|
||||
|
||||
@@ -393,7 +341,7 @@ void VMManager::LogLayout() const {
|
||||
(u8)vma.permissions & (u8)VMAPermission::Read ? 'R' : '-',
|
||||
(u8)vma.permissions & (u8)VMAPermission::Write ? 'W' : '-',
|
||||
(u8)vma.permissions & (u8)VMAPermission::Execute ? 'X' : '-',
|
||||
GetMemoryStateName(vma.state));
|
||||
GetMemoryStateName(vma.meminfo_state));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -620,66 +568,6 @@ void VMManager::ClearPageTable() {
|
||||
Memory::PageType::Unmapped);
|
||||
}
|
||||
|
||||
VMManager::CheckResults VMManager::CheckRangeState(VAddr address, u64 size, MemoryState state_mask,
|
||||
MemoryState state, VMAPermission permission_mask,
|
||||
VMAPermission permissions,
|
||||
MemoryAttribute attribute_mask,
|
||||
MemoryAttribute attribute,
|
||||
MemoryAttribute ignore_mask) const {
|
||||
auto iter = FindVMA(address);
|
||||
|
||||
// If we don't have a valid VMA handle at this point, then it means this is
|
||||
// being called with an address outside of the address space, which is definitely
|
||||
// indicative of a bug, as this function only operates on mapped memory regions.
|
||||
DEBUG_ASSERT(IsValidHandle(iter));
|
||||
|
||||
const VAddr end_address = address + size - 1;
|
||||
const MemoryAttribute initial_attributes = iter->second.attribute;
|
||||
const VMAPermission initial_permissions = iter->second.permissions;
|
||||
const MemoryState initial_state = iter->second.state;
|
||||
|
||||
while (true) {
|
||||
// The iterator should be valid throughout the traversal. Hitting the end of
|
||||
// the mapped VMA regions is unquestionably indicative of a bug.
|
||||
DEBUG_ASSERT(IsValidHandle(iter));
|
||||
|
||||
const auto& vma = iter->second;
|
||||
|
||||
if (vma.state != initial_state) {
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
|
||||
if ((vma.state & state_mask) != state) {
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
|
||||
if (vma.permissions != initial_permissions) {
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
|
||||
if ((vma.permissions & permission_mask) != permissions) {
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
|
||||
if ((vma.attribute | ignore_mask) != (initial_attributes | ignore_mask)) {
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
|
||||
if ((vma.attribute & attribute_mask) != attribute) {
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
|
||||
if (end_address <= vma.EndAddress()) {
|
||||
break;
|
||||
}
|
||||
|
||||
++iter;
|
||||
}
|
||||
|
||||
return MakeResult(
|
||||
std::make_tuple(initial_state, initial_permissions, initial_attributes & ~ignore_mask));
|
||||
}
|
||||
|
||||
u64 VMManager::GetTotalMemoryUsage() const {
|
||||
LOG_WARNING(Kernel, "(STUBBED) called");
|
||||
return 0xF8000000;
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/result.h"
|
||||
@@ -44,211 +43,26 @@ enum class VMAPermission : u8 {
|
||||
ReadWriteExecute = Read | Write | Execute,
|
||||
};
|
||||
|
||||
constexpr VMAPermission operator|(VMAPermission lhs, VMAPermission rhs) {
|
||||
return static_cast<VMAPermission>(u32(lhs) | u32(rhs));
|
||||
}
|
||||
|
||||
constexpr VMAPermission operator&(VMAPermission lhs, VMAPermission rhs) {
|
||||
return static_cast<VMAPermission>(u32(lhs) & u32(rhs));
|
||||
}
|
||||
|
||||
constexpr VMAPermission operator^(VMAPermission lhs, VMAPermission rhs) {
|
||||
return static_cast<VMAPermission>(u32(lhs) ^ u32(rhs));
|
||||
}
|
||||
|
||||
constexpr VMAPermission operator~(VMAPermission permission) {
|
||||
return static_cast<VMAPermission>(~u32(permission));
|
||||
}
|
||||
|
||||
constexpr VMAPermission& operator|=(VMAPermission& lhs, VMAPermission rhs) {
|
||||
lhs = lhs | rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
constexpr VMAPermission& operator&=(VMAPermission& lhs, VMAPermission rhs) {
|
||||
lhs = lhs & rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
constexpr VMAPermission& operator^=(VMAPermission& lhs, VMAPermission rhs) {
|
||||
lhs = lhs ^ rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
/// Attribute flags that can be applied to a VMA
|
||||
enum class MemoryAttribute : u32 {
|
||||
Mask = 0xFF,
|
||||
|
||||
/// No particular qualities
|
||||
None = 0,
|
||||
/// Memory locked/borrowed for use. e.g. This would be used by transfer memory.
|
||||
Locked = 1,
|
||||
/// Memory locked for use by IPC-related internals.
|
||||
LockedForIPC = 2,
|
||||
/// Mapped as part of the device address space.
|
||||
DeviceMapped = 4,
|
||||
/// Uncached memory
|
||||
Uncached = 8,
|
||||
};
|
||||
|
||||
constexpr MemoryAttribute operator|(MemoryAttribute lhs, MemoryAttribute rhs) {
|
||||
return static_cast<MemoryAttribute>(u32(lhs) | u32(rhs));
|
||||
}
|
||||
|
||||
constexpr MemoryAttribute operator&(MemoryAttribute lhs, MemoryAttribute rhs) {
|
||||
return static_cast<MemoryAttribute>(u32(lhs) & u32(rhs));
|
||||
}
|
||||
|
||||
constexpr MemoryAttribute operator^(MemoryAttribute lhs, MemoryAttribute rhs) {
|
||||
return static_cast<MemoryAttribute>(u32(lhs) ^ u32(rhs));
|
||||
}
|
||||
|
||||
constexpr MemoryAttribute operator~(MemoryAttribute attribute) {
|
||||
return static_cast<MemoryAttribute>(~u32(attribute));
|
||||
}
|
||||
|
||||
constexpr MemoryAttribute& operator|=(MemoryAttribute& lhs, MemoryAttribute rhs) {
|
||||
lhs = lhs | rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
constexpr MemoryAttribute& operator&=(MemoryAttribute& lhs, MemoryAttribute rhs) {
|
||||
lhs = lhs & rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
constexpr MemoryAttribute& operator^=(MemoryAttribute& lhs, MemoryAttribute rhs) {
|
||||
lhs = lhs ^ rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
constexpr u32 ToSvcMemoryAttribute(MemoryAttribute attribute) {
|
||||
return static_cast<u32>(attribute & MemoryAttribute::Mask);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
/// Represents memory states and any relevant flags, as used by the kernel.
|
||||
/// svcQueryMemory interprets these by masking away all but the first eight
|
||||
/// bits when storing memory state into a MemoryInfo instance.
|
||||
/// Set of values returned in MemoryInfo.state by svcQueryMemory.
|
||||
enum class MemoryState : u32 {
|
||||
Mask = 0xFF,
|
||||
FlagProtect = 1U << 8,
|
||||
FlagDebug = 1U << 9,
|
||||
FlagIPC0 = 1U << 10,
|
||||
FlagIPC3 = 1U << 11,
|
||||
FlagIPC1 = 1U << 12,
|
||||
FlagMapped = 1U << 13,
|
||||
FlagCode = 1U << 14,
|
||||
FlagAlias = 1U << 15,
|
||||
FlagModule = 1U << 16,
|
||||
FlagTransfer = 1U << 17,
|
||||
FlagQueryPhysicalAddressAllowed = 1U << 18,
|
||||
FlagSharedDevice = 1U << 19,
|
||||
FlagSharedDeviceAligned = 1U << 20,
|
||||
FlagIPCBuffer = 1U << 21,
|
||||
FlagMemoryPoolAllocated = 1U << 22,
|
||||
FlagMapProcess = 1U << 23,
|
||||
FlagUncached = 1U << 24,
|
||||
FlagCodeMemory = 1U << 25,
|
||||
|
||||
// Convenience flag sets to reduce repetition
|
||||
IPCFlags = FlagIPC0 | FlagIPC3 | FlagIPC1,
|
||||
|
||||
CodeFlags = FlagDebug | IPCFlags | FlagMapped | FlagCode | FlagQueryPhysicalAddressAllowed |
|
||||
FlagSharedDevice | FlagSharedDeviceAligned | FlagMemoryPoolAllocated,
|
||||
|
||||
DataFlags = FlagProtect | IPCFlags | FlagMapped | FlagAlias | FlagTransfer |
|
||||
FlagQueryPhysicalAddressAllowed | FlagSharedDevice | FlagSharedDeviceAligned |
|
||||
FlagMemoryPoolAllocated | FlagIPCBuffer | FlagUncached,
|
||||
|
||||
Unmapped = 0x00,
|
||||
Io = 0x01 | FlagMapped,
|
||||
Normal = 0x02 | FlagMapped | FlagQueryPhysicalAddressAllowed,
|
||||
CodeStatic = 0x03 | CodeFlags | FlagMapProcess,
|
||||
CodeMutable = 0x04 | CodeFlags | FlagMapProcess | FlagCodeMemory,
|
||||
Heap = 0x05 | DataFlags | FlagCodeMemory,
|
||||
Shared = 0x06 | FlagMapped | FlagMemoryPoolAllocated,
|
||||
ModuleCodeStatic = 0x08 | CodeFlags | FlagModule | FlagMapProcess,
|
||||
ModuleCodeMutable = 0x09 | DataFlags | FlagModule | FlagMapProcess | FlagCodeMemory,
|
||||
|
||||
IpcBuffer0 = 0x0A | FlagMapped | FlagQueryPhysicalAddressAllowed | FlagMemoryPoolAllocated |
|
||||
IPCFlags | FlagSharedDevice | FlagSharedDeviceAligned,
|
||||
|
||||
Stack = 0x0B | FlagMapped | IPCFlags | FlagQueryPhysicalAddressAllowed |
|
||||
FlagSharedDevice | FlagSharedDeviceAligned | FlagMemoryPoolAllocated,
|
||||
|
||||
ThreadLocal = 0x0C | FlagMapped | FlagMemoryPoolAllocated,
|
||||
|
||||
TransferMemoryIsolated = 0x0D | IPCFlags | FlagMapped | FlagQueryPhysicalAddressAllowed |
|
||||
FlagSharedDevice | FlagSharedDeviceAligned | FlagMemoryPoolAllocated |
|
||||
FlagUncached,
|
||||
|
||||
TransferMemory = 0x0E | FlagIPC3 | FlagIPC1 | FlagMapped | FlagQueryPhysicalAddressAllowed |
|
||||
FlagSharedDevice | FlagSharedDeviceAligned | FlagMemoryPoolAllocated,
|
||||
|
||||
ProcessMemory = 0x0F | FlagIPC3 | FlagIPC1 | FlagMapped | FlagMemoryPoolAllocated,
|
||||
|
||||
// Used to signify an inaccessible or invalid memory region with memory queries
|
||||
Inaccessible = 0x10,
|
||||
|
||||
IpcBuffer1 = 0x11 | FlagIPC3 | FlagIPC1 | FlagMapped | FlagQueryPhysicalAddressAllowed |
|
||||
FlagSharedDevice | FlagSharedDeviceAligned | FlagMemoryPoolAllocated,
|
||||
|
||||
IpcBuffer3 = 0x12 | FlagIPC3 | FlagMapped | FlagQueryPhysicalAddressAllowed |
|
||||
FlagSharedDeviceAligned | FlagMemoryPoolAllocated,
|
||||
|
||||
KernelStack = 0x13 | FlagMapped,
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
constexpr MemoryState operator|(MemoryState lhs, MemoryState rhs) {
|
||||
return static_cast<MemoryState>(u32(lhs) | u32(rhs));
|
||||
}
|
||||
|
||||
constexpr MemoryState operator&(MemoryState lhs, MemoryState rhs) {
|
||||
return static_cast<MemoryState>(u32(lhs) & u32(rhs));
|
||||
}
|
||||
|
||||
constexpr MemoryState operator^(MemoryState lhs, MemoryState rhs) {
|
||||
return static_cast<MemoryState>(u32(lhs) ^ u32(rhs));
|
||||
}
|
||||
|
||||
constexpr MemoryState operator~(MemoryState lhs) {
|
||||
return static_cast<MemoryState>(~u32(lhs));
|
||||
}
|
||||
|
||||
constexpr MemoryState& operator|=(MemoryState& lhs, MemoryState rhs) {
|
||||
lhs = lhs | rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
constexpr MemoryState& operator&=(MemoryState& lhs, MemoryState rhs) {
|
||||
lhs = lhs & rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
constexpr MemoryState& operator^=(MemoryState& lhs, MemoryState rhs) {
|
||||
lhs = lhs ^ rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
constexpr u32 ToSvcMemoryState(MemoryState state) {
|
||||
return static_cast<u32>(state & MemoryState::Mask);
|
||||
}
|
||||
|
||||
struct MemoryInfo {
|
||||
u64 base_address;
|
||||
u64 size;
|
||||
u32 state;
|
||||
u32 attributes;
|
||||
u32 permission;
|
||||
u32 ipc_ref_count;
|
||||
u32 device_ref_count;
|
||||
};
|
||||
static_assert(sizeof(MemoryInfo) == 0x28, "MemoryInfo has incorrect size.");
|
||||
|
||||
struct PageInfo {
|
||||
u32 flags;
|
||||
Unmapped = 0x0,
|
||||
Io = 0x1,
|
||||
Normal = 0x2,
|
||||
CodeStatic = 0x3,
|
||||
CodeMutable = 0x4,
|
||||
Heap = 0x5,
|
||||
Shared = 0x6,
|
||||
ModuleCodeStatic = 0x8,
|
||||
ModuleCodeMutable = 0x9,
|
||||
IpcBuffer0 = 0xA,
|
||||
Mapped = 0xB,
|
||||
ThreadLocal = 0xC,
|
||||
TransferMemoryIsolated = 0xD,
|
||||
TransferMemory = 0xE,
|
||||
ProcessMemory = 0xF,
|
||||
IpcBuffer1 = 0x11,
|
||||
IpcBuffer3 = 0x12,
|
||||
KernelStack = 0x13,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -257,16 +71,6 @@ struct PageInfo {
|
||||
* also backed by a single host memory allocation.
|
||||
*/
|
||||
struct VirtualMemoryArea {
|
||||
/// Gets the starting (base) address of this VMA.
|
||||
VAddr StartAddress() const {
|
||||
return base;
|
||||
}
|
||||
|
||||
/// Gets the ending address of this VMA.
|
||||
VAddr EndAddress() const {
|
||||
return base + size - 1;
|
||||
}
|
||||
|
||||
/// Virtual base address of the region.
|
||||
VAddr base = 0;
|
||||
/// Size of the region.
|
||||
@@ -274,8 +78,8 @@ struct VirtualMemoryArea {
|
||||
|
||||
VMAType type = VMAType::Free;
|
||||
VMAPermission permissions = VMAPermission::None;
|
||||
MemoryState state = MemoryState::Unmapped;
|
||||
MemoryAttribute attribute = MemoryAttribute::None;
|
||||
/// Tag returned by svcQueryMemory. Not otherwise used.
|
||||
MemoryState meminfo_state = MemoryState::Unmapped;
|
||||
|
||||
// Settings for type = AllocatedMemoryBlock
|
||||
/// Memory block backing this VMA.
|
||||
@@ -309,10 +113,16 @@ struct VirtualMemoryArea {
|
||||
* - http://duartes.org/gustavo/blog/post/page-cache-the-affair-between-memory-and-files/
|
||||
*/
|
||||
class VMManager final {
|
||||
using VMAMap = std::map<VAddr, VirtualMemoryArea>;
|
||||
|
||||
public:
|
||||
using VMAHandle = VMAMap::const_iterator;
|
||||
/**
|
||||
* A map covering the entirety of the managed address space, keyed by the `base` field of each
|
||||
* VMA. It must always be modified by splitting or merging VMAs, so that the invariant
|
||||
* `elem.base + elem.size == next.base` is preserved, and mergeable regions must always be
|
||||
* merged when possible so that no two similar and adjacent regions exist that have not been
|
||||
* merged.
|
||||
*/
|
||||
std::map<VAddr, VirtualMemoryArea> vma_map;
|
||||
using VMAHandle = decltype(vma_map)::const_iterator;
|
||||
|
||||
VMManager();
|
||||
~VMManager();
|
||||
@@ -323,9 +133,6 @@ public:
|
||||
/// Finds the VMA in which the given address is included in, or `vma_map.end()`.
|
||||
VMAHandle FindVMA(VAddr target) const;
|
||||
|
||||
/// Indicates whether or not the given handle is within the VMA map.
|
||||
bool IsValidHandle(VMAHandle handle) const;
|
||||
|
||||
// TODO(yuriks): Should these functions actually return the handle?
|
||||
|
||||
/**
|
||||
@@ -382,28 +189,8 @@ public:
|
||||
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, MemoryState state);
|
||||
|
||||
/// Queries the memory manager for information about the given address.
|
||||
///
|
||||
/// @param address The address to query the memory manager about for information.
|
||||
///
|
||||
/// @return A MemoryInfo instance containing information about the given address.
|
||||
///
|
||||
MemoryInfo QueryMemory(VAddr address) const;
|
||||
|
||||
/// Sets an attribute across the given address range.
|
||||
///
|
||||
/// @param address The starting address
|
||||
/// @param size The size of the range to set the attribute on.
|
||||
/// @param mask The attribute mask
|
||||
/// @param attribute The attribute to set across the given address range
|
||||
///
|
||||
/// @returns RESULT_SUCCESS if successful
|
||||
/// @returns ERR_INVALID_ADDRESS_STATE if the attribute could not be set.
|
||||
///
|
||||
ResultCode SetMemoryAttribute(VAddr address, u64 size, MemoryAttribute mask,
|
||||
MemoryAttribute attribute);
|
||||
ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size,
|
||||
MemoryState state = MemoryState::Mapped);
|
||||
|
||||
/**
|
||||
* Scans all VMAs and updates the page table range of any that use the given vector as backing
|
||||
@@ -494,7 +281,7 @@ public:
|
||||
Memory::PageTable page_table;
|
||||
|
||||
private:
|
||||
using VMAIter = VMAMap::iterator;
|
||||
using VMAIter = decltype(vma_map)::iterator;
|
||||
|
||||
/// Converts a VMAHandle to a mutable VMAIter.
|
||||
VMAIter StripIterConstness(const VMAHandle& iter);
|
||||
@@ -541,44 +328,6 @@ private:
|
||||
/// Clears out the page table
|
||||
void ClearPageTable();
|
||||
|
||||
using CheckResults = ResultVal<std::tuple<MemoryState, VMAPermission, MemoryAttribute>>;
|
||||
|
||||
/// Checks if an address range adheres to the specified states provided.
|
||||
///
|
||||
/// @param address The starting address of the address range.
|
||||
/// @param size The size of the address range.
|
||||
/// @param state_mask The memory state mask.
|
||||
/// @param state The state to compare the individual VMA states against,
|
||||
/// which is done in the form of: (vma.state & state_mask) != state.
|
||||
/// @param permission_mask The memory permissions mask.
|
||||
/// @param permissions The permission to compare the individual VMA permissions against,
|
||||
/// which is done in the form of:
|
||||
/// (vma.permission & permission_mask) != permission.
|
||||
/// @param attribute_mask The memory attribute mask.
|
||||
/// @param attribute The memory attributes to compare the individual VMA attributes
|
||||
/// against, which is done in the form of:
|
||||
/// (vma.attributes & attribute_mask) != attribute.
|
||||
/// @param ignore_mask The memory attributes to ignore during the check.
|
||||
///
|
||||
/// @returns If successful, returns a tuple containing the memory attributes
|
||||
/// (with ignored bits specified by ignore_mask unset), memory permissions, and
|
||||
/// memory state across the memory range.
|
||||
/// @returns If not successful, returns ERR_INVALID_ADDRESS_STATE.
|
||||
///
|
||||
CheckResults CheckRangeState(VAddr address, u64 size, MemoryState state_mask, MemoryState state,
|
||||
VMAPermission permission_mask, VMAPermission permissions,
|
||||
MemoryAttribute attribute_mask, MemoryAttribute attribute,
|
||||
MemoryAttribute ignore_mask) const;
|
||||
|
||||
/**
|
||||
* A map covering the entirety of the managed address space, keyed by the `base` field of each
|
||||
* VMA. It must always be modified by splitting or merging VMAs, so that the invariant
|
||||
* `elem.base + elem.size == next.base` is preserved, and mergeable regions must always be
|
||||
* merged when possible so that no two similar and adjacent regions exist that have not been
|
||||
* merged.
|
||||
*/
|
||||
VMAMap vma_map;
|
||||
|
||||
u32 address_space_width = 0;
|
||||
VAddr address_space_base = 0;
|
||||
VAddr address_space_end = 0;
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include "common/assert.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
WritableEvent::WritableEvent(KernelCore& kernel) : Object{kernel} {}
|
||||
WritableEvent::~WritableEvent() = default;
|
||||
|
||||
EventPair WritableEvent::CreateEventPair(KernelCore& kernel, ResetType reset_type,
|
||||
std::string name) {
|
||||
SharedPtr<WritableEvent> writable_event(new WritableEvent(kernel));
|
||||
SharedPtr<ReadableEvent> readable_event(new ReadableEvent(kernel));
|
||||
|
||||
writable_event->name = name + ":Writable";
|
||||
writable_event->readable = readable_event;
|
||||
readable_event->name = name + ":Readable";
|
||||
readable_event->signaled = false;
|
||||
readable_event->reset_type = reset_type;
|
||||
|
||||
return {std::move(readable_event), std::move(writable_event)};
|
||||
}
|
||||
|
||||
SharedPtr<ReadableEvent> WritableEvent::GetReadableEvent() const {
|
||||
return readable;
|
||||
}
|
||||
|
||||
ResetType WritableEvent::GetResetType() const {
|
||||
return readable->reset_type;
|
||||
}
|
||||
|
||||
void WritableEvent::Signal() {
|
||||
readable->Signal();
|
||||
}
|
||||
|
||||
void WritableEvent::Clear() {
|
||||
readable->Clear();
|
||||
}
|
||||
|
||||
bool WritableEvent::IsSignaled() const {
|
||||
return readable->signaled;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -21,6 +21,17 @@
|
||||
|
||||
namespace Service::Account {
|
||||
|
||||
// TODO: RE this structure
|
||||
struct UserData {
|
||||
INSERT_PADDING_WORDS(1);
|
||||
u32 icon_id;
|
||||
u8 bg_color_id;
|
||||
INSERT_PADDING_BYTES(0x7);
|
||||
INSERT_PADDING_BYTES(0x10);
|
||||
INSERT_PADDING_BYTES(0x60);
|
||||
};
|
||||
static_assert(sizeof(UserData) == 0x80, "UserData structure has incorrect size");
|
||||
|
||||
// Smallest JPEG https://github.com/mathiasbynens/small/blob/master/jpeg.jpg
|
||||
// used as a backup should the one on disk not exist
|
||||
constexpr u32 backup_jpeg_size = 107;
|
||||
@@ -61,11 +72,9 @@ private:
|
||||
void Get(Kernel::HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_ACC, "called user_id={}", user_id.Format());
|
||||
ProfileBase profile_base{};
|
||||
ProfileData data{};
|
||||
std::array<u8, MAX_DATA> data{};
|
||||
if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) {
|
||||
std::array<u8, sizeof(ProfileData)> raw_data;
|
||||
std::memcpy(raw_data.data(), &data, sizeof(ProfileData));
|
||||
ctx.WriteBuffer(raw_data);
|
||||
ctx.WriteBuffer(data);
|
||||
IPC::ResponseBuilder rb{ctx, 16};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw(profile_base);
|
||||
@@ -207,11 +216,10 @@ void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) {
|
||||
void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
UUID user_id = rp.PopRaw<UUID>();
|
||||
LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IProfile>(user_id, *profile_manager);
|
||||
LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
|
||||
}
|
||||
|
||||
void Module::Interface::IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx) {
|
||||
@@ -228,10 +236,10 @@ void Module::Interface::InitializeApplicationInfo(Kernel::HLERequestContext& ctx
|
||||
}
|
||||
|
||||
void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_ACC, "called");
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IManagerForApplication>();
|
||||
LOG_DEBUG(Service_ACC, "called");
|
||||
}
|
||||
|
||||
void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
@@ -18,7 +18,7 @@ struct UserRaw {
|
||||
UUID uuid2;
|
||||
u64 timestamp;
|
||||
ProfileUsername username;
|
||||
ProfileData extra_data;
|
||||
INSERT_PADDING_BYTES(0x80);
|
||||
};
|
||||
static_assert(sizeof(UserRaw) == 0xC8, "UserRaw has incorrect size.");
|
||||
|
||||
@@ -346,7 +346,7 @@ void ProfileManager::ParseUserSaveFile() {
|
||||
continue;
|
||||
}
|
||||
|
||||
AddUser({user.uuid, user.username, user.timestamp, user.extra_data, false});
|
||||
AddUser({user.uuid, user.username, user.timestamp, {}, false});
|
||||
}
|
||||
|
||||
std::stable_partition(profiles.begin(), profiles.end(),
|
||||
@@ -361,7 +361,6 @@ void ProfileManager::WriteUserSaveFile() {
|
||||
raw.users[i].uuid2 = profiles[i].user_uuid;
|
||||
raw.users[i].uuid = profiles[i].user_uuid;
|
||||
raw.users[i].timestamp = profiles[i].creation_time;
|
||||
raw.users[i].extra_data = profiles[i].data;
|
||||
}
|
||||
|
||||
const auto raw_path =
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
namespace Service::Account {
|
||||
constexpr std::size_t MAX_USERS = 8;
|
||||
constexpr std::size_t MAX_DATA = 128;
|
||||
constexpr u128 INVALID_UUID{{0, 0}};
|
||||
|
||||
struct UUID {
|
||||
@@ -49,20 +50,9 @@ static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
|
||||
|
||||
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>;
|
||||
|
||||
/// Contains extra data related to a user.
|
||||
/// TODO: RE this structure
|
||||
struct ProfileData {
|
||||
INSERT_PADDING_WORDS(1);
|
||||
u32 icon_id;
|
||||
u8 bg_color_id;
|
||||
INSERT_PADDING_BYTES(0x7);
|
||||
INSERT_PADDING_BYTES(0x10);
|
||||
INSERT_PADDING_BYTES(0x60);
|
||||
};
|
||||
static_assert(sizeof(ProfileData) == 0x80, "ProfileData structure has incorrect size");
|
||||
|
||||
/// This holds general information about a users profile. This is where we store all the information
|
||||
/// based on a specific user
|
||||
struct ProfileInfo {
|
||||
|
||||
@@ -9,17 +9,14 @@
|
||||
#include "audio_core/audio_renderer.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applet_ae.h"
|
||||
#include "core/hle/service/am/applet_oe.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/am/applets/profile_select.h"
|
||||
#include "core/hle/service/am/applets/software_keyboard.h"
|
||||
#include "core/hle/service/am/applets/stub_applet.h"
|
||||
#include "core/hle/service/am/idle.h"
|
||||
@@ -40,7 +37,6 @@ constexpr ResultCode ERR_NO_DATA_IN_CHANNEL{ErrorModule::AM, 0x2};
|
||||
constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7};
|
||||
|
||||
enum class AppletId : u32 {
|
||||
ProfileSelect = 0x10,
|
||||
SoftwareKeyboard = 0x11,
|
||||
};
|
||||
|
||||
@@ -73,13 +69,10 @@ IWindowController::IWindowController() : ServiceFramework("IWindowController") {
|
||||
IWindowController::~IWindowController() = default;
|
||||
|
||||
void IWindowController::GetAppletResourceUserId(Kernel::HLERequestContext& ctx) {
|
||||
const u64 process_id = Core::System::GetInstance().Kernel().CurrentProcess()->GetProcessID();
|
||||
|
||||
LOG_DEBUG(Service_AM, "called. Process ID=0x{:016X}", process_id);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(process_id);
|
||||
rb.Push<u64>(0);
|
||||
}
|
||||
|
||||
void IWindowController::AcquireForegroundRights(Kernel::HLERequestContext& ctx) {
|
||||
@@ -215,8 +208,8 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
|
||||
"ISelfController:LaunchableEvent");
|
||||
launchable_event =
|
||||
Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "ISelfController:LaunchableEvent");
|
||||
}
|
||||
|
||||
ISelfController::~ISelfController() = default;
|
||||
@@ -224,7 +217,6 @@ ISelfController::~ISelfController() = default;
|
||||
void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
|
||||
// Takes 3 input u8s with each field located immediately after the previous
|
||||
// u8, these are bool flags. No output.
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
@@ -237,40 +229,44 @@ void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ISelfController::SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
bool flag = rp.Pop<bool>();
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
|
||||
}
|
||||
|
||||
void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
bool flag = rp.Pop<bool>();
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
|
||||
}
|
||||
|
||||
void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx) {
|
||||
@@ -279,45 +275,45 @@ void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext&
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
bool enabled = rp.Pop<bool>();
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled);
|
||||
}
|
||||
|
||||
void ISelfController::LockExit(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
launchable_event.writable->Signal();
|
||||
launchable_event->Signal();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(launchable_event.readable);
|
||||
rb.PushCopyObjects(launchable_event);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
// TODO(Subv): Find out how AM determines the display to use, for now just
|
||||
// create the layer in the Default display.
|
||||
u64 display_id = nvflinger->OpenDisplay("Default");
|
||||
@@ -326,67 +322,66 @@ void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx)
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(layer_id);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ISelfController::SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
idle_time_detection_extension = rp.Pop<u32>();
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called idle_time_detection_extension={}",
|
||||
idle_time_detection_extension);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(idle_time_detection_extension);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
AppletMessageQueue::AppletMessageQueue() {
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
on_new_message = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
|
||||
"AMMessageQueue:OnMessageRecieved");
|
||||
on_operation_mode_changed = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::OneShot, "AMMessageQueue:OperationModeChanged");
|
||||
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::ReadableEvent>& AppletMessageQueue::GetMesssageRecieveEvent()
|
||||
const {
|
||||
return on_new_message.readable;
|
||||
const Kernel::SharedPtr<Kernel::Event>& AppletMessageQueue::GetMesssageRecieveEvent() const {
|
||||
return on_new_message;
|
||||
}
|
||||
|
||||
const Kernel::SharedPtr<Kernel::ReadableEvent>& AppletMessageQueue::GetOperationModeChangedEvent()
|
||||
const {
|
||||
return on_operation_mode_changed.readable;
|
||||
const Kernel::SharedPtr<Kernel::Event>& AppletMessageQueue::GetOperationModeChangedEvent() const {
|
||||
return on_operation_mode_changed;
|
||||
}
|
||||
|
||||
void AppletMessageQueue::PushMessage(AppletMessage msg) {
|
||||
messages.push(msg);
|
||||
on_new_message.writable->Signal();
|
||||
on_new_message->Signal();
|
||||
}
|
||||
|
||||
AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() {
|
||||
if (messages.empty()) {
|
||||
on_new_message.writable->Clear();
|
||||
on_new_message->Clear();
|
||||
return AppletMessage::NoMessage;
|
||||
}
|
||||
auto msg = messages.front();
|
||||
messages.pop();
|
||||
if (messages.empty()) {
|
||||
on_new_message.writable->Clear();
|
||||
on_new_message->Clear();
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
@@ -398,7 +393,7 @@ std::size_t AppletMessageQueue::GetMessageCount() const {
|
||||
void AppletMessageQueue::OperationModeChanged() {
|
||||
PushMessage(AppletMessage::OperationModeChanged);
|
||||
PushMessage(AppletMessage::PerformanceModeChanged);
|
||||
on_operation_mode_changed.writable->Signal();
|
||||
on_operation_mode_changed->Signal();
|
||||
}
|
||||
|
||||
ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue)
|
||||
@@ -435,54 +430,55 @@ ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_q
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "ICommonStateGetter:Event");
|
||||
}
|
||||
|
||||
ICommonStateGetter::~ICommonStateGetter() = default;
|
||||
|
||||
void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(msg_queue->GetMesssageRecieveEvent());
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum<AppletMessageQueue::AppletMessage>(msg_queue->PopMessage());
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(static_cast<u8>(FocusState::InFocus));
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent());
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
@@ -497,6 +493,8 @@ void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext&
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
}
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
IStorage::IStorage(std::vector<u8> buffer)
|
||||
@@ -519,21 +517,21 @@ const std::vector<u8>& IStorage::GetData() const {
|
||||
|
||||
void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
|
||||
const bool use_docked_mode{Settings::values.use_docked_mode};
|
||||
LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld));
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
|
||||
const bool use_docked_mode{Settings::values.use_docked_mode};
|
||||
LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked
|
||||
: APM::PerformanceMode::Handheld));
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
|
||||
@@ -568,33 +566,32 @@ public:
|
||||
|
||||
private:
|
||||
void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
const auto event = applet->GetBroker().GetStateChangedEvent();
|
||||
event->Signal();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(event);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void IsCompleted(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(applet->TransactionComplete());
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetResult(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(applet->GetStatus());
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void Start(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
ASSERT(applet != nullptr);
|
||||
|
||||
applet->Initialize();
|
||||
@@ -602,39 +599,36 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void PushInData(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
applet->GetBroker().PushNormalDataFromGame(*rp.PopIpcInterface<IStorage>());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void PopOutData(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
const auto storage = applet->GetBroker().PopNormalDataToGame();
|
||||
if (storage == nullptr) {
|
||||
LOG_ERROR(Service_AM,
|
||||
"storage is a nullptr. There is no data in the current normal channel");
|
||||
|
||||
rb.Push(ERR_NO_DATA_IN_CHANNEL);
|
||||
return;
|
||||
}
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IStorage>(std::move(*storage));
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void PushInteractiveInData(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
applet->GetBroker().PushInteractiveDataFromGame(*rp.PopIpcInterface<IStorage>());
|
||||
|
||||
@@ -644,52 +638,51 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void PopInteractiveOutData(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
const auto storage = applet->GetBroker().PopInteractiveDataToGame();
|
||||
if (storage == nullptr) {
|
||||
LOG_ERROR(Service_AM,
|
||||
"storage is a nullptr. There is no data in the current interactive channel");
|
||||
|
||||
rb.Push(ERR_NO_DATA_IN_CHANNEL);
|
||||
return;
|
||||
}
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IStorage>(std::move(*storage));
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(applet->GetBroker().GetNormalDataEvent());
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetPopInteractiveOutDataEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(applet->GetBroker().GetInteractiveDataEvent());
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
std::shared_ptr<Applets::Applet> applet;
|
||||
};
|
||||
|
||||
void IStorage::Open(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IStorageAccessor>(*this);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
IStorageAccessor::IStorageAccessor(IStorage& storage)
|
||||
@@ -708,27 +701,21 @@ IStorageAccessor::IStorageAccessor(IStorage& storage)
|
||||
IStorageAccessor::~IStorageAccessor() = default;
|
||||
|
||||
void IStorageAccessor::GetSize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(static_cast<u64>(backing.buffer.size()));
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const u64 offset{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_AM, "called, offset={}", offset);
|
||||
|
||||
const std::vector<u8> data{ctx.ReadBuffer()};
|
||||
|
||||
if (data.size() > backing.buffer.size() - offset) {
|
||||
LOG_ERROR(Service_AM,
|
||||
"offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}",
|
||||
backing.buffer.size(), data.size(), offset);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
|
||||
}
|
||||
@@ -737,20 +724,17 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called, offset={}", offset);
|
||||
}
|
||||
|
||||
void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const u64 offset{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_AM, "called, offset={}", offset);
|
||||
|
||||
const std::size_t size{ctx.GetWriteBufferSize()};
|
||||
|
||||
if (size > backing.buffer.size() - offset) {
|
||||
LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}",
|
||||
backing.buffer.size(), size, offset);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
|
||||
}
|
||||
@@ -759,6 +743,8 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called, offset={}", offset);
|
||||
}
|
||||
|
||||
ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryAppletCreator") {
|
||||
@@ -777,8 +763,6 @@ ILibraryAppletCreator::~ILibraryAppletCreator() = default;
|
||||
|
||||
static std::shared_ptr<Applets::Applet> GetAppletFromId(AppletId id) {
|
||||
switch (id) {
|
||||
case AppletId::ProfileSelect:
|
||||
return std::make_shared<Applets::ProfileSelect>();
|
||||
case AppletId::SoftwareKeyboard:
|
||||
return std::make_shared<Applets::SoftwareKeyboard>();
|
||||
default:
|
||||
@@ -799,8 +783,6 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx)
|
||||
const auto applet = GetAppletFromId(applet_id);
|
||||
|
||||
if (applet == nullptr) {
|
||||
LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultCode(-1));
|
||||
return;
|
||||
@@ -810,23 +792,23 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx)
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<AM::ILibraryAppletAccessor>(applet);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u64 size{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_AM, "called, size={}", size);
|
||||
|
||||
std::vector<u8> buffer(size);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<AM::IStorage>(std::move(buffer));
|
||||
|
||||
LOG_DEBUG(Service_AM, "called, size={}", size);
|
||||
}
|
||||
|
||||
void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
rp.SetCurrentOffset(3);
|
||||
@@ -837,7 +819,6 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
|
||||
handle);
|
||||
|
||||
if (shared_mem == nullptr) {
|
||||
LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultCode(-1));
|
||||
return;
|
||||
@@ -901,45 +882,38 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF
|
||||
IApplicationFunctions::~IApplicationFunctions() = default;
|
||||
|
||||
void IApplicationFunctions::EnableApplicationCrashReport(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(
|
||||
Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(
|
||||
Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::BeginBlockingHomeButton(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::EndBlockingHomeButton(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
LaunchParameters params{};
|
||||
|
||||
params.magic = POP_LAUNCH_PARAMETER_MAGIC;
|
||||
@@ -958,19 +932,21 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
|
||||
std::memcpy(buffer.data(), ¶ms, buffer.size());
|
||||
|
||||
rb.PushIpcInterface<AM::IStorage>(buffer);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(
|
||||
Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
u128 uid = rp.PopRaw<u128>(); // What does this do?
|
||||
|
||||
LOG_WARNING(Service, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
@@ -985,62 +961,60 @@ void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 result = rp.Pop<u32>();
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(1);
|
||||
rb.Push<u64>(0);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
|
||||
// TODO(bunnei): This should be configurable
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(
|
||||
static_cast<u64>(Service::Set::GetLanguageCodeFromIndex(Settings::values.language_index)));
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::SetGamePlayRecordingState(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u8>(0); // Unknown, seems to be ignored by official processes
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
// Returns a 128-bit UUID
|
||||
rb.Push<u64>(0);
|
||||
rb.Push<u64>(0);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager,
|
||||
@@ -1077,10 +1051,9 @@ IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions"
|
||||
IHomeMenuFunctions::~IHomeMenuFunctions() = default;
|
||||
|
||||
void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStateController") {
|
||||
|
||||
@@ -6,9 +6,12 @@
|
||||
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Kernel {
|
||||
class Event;
|
||||
}
|
||||
|
||||
namespace Service {
|
||||
namespace NVFlinger {
|
||||
class NVFlinger;
|
||||
@@ -49,8 +52,8 @@ public:
|
||||
AppletMessageQueue();
|
||||
~AppletMessageQueue();
|
||||
|
||||
const Kernel::SharedPtr<Kernel::ReadableEvent>& GetMesssageRecieveEvent() const;
|
||||
const Kernel::SharedPtr<Kernel::ReadableEvent>& GetOperationModeChangedEvent() const;
|
||||
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;
|
||||
@@ -58,8 +61,8 @@ public:
|
||||
|
||||
private:
|
||||
std::queue<AppletMessage> messages;
|
||||
Kernel::EventPair on_new_message;
|
||||
Kernel::EventPair on_operation_mode_changed;
|
||||
Kernel::SharedPtr<Kernel::Event> on_new_message;
|
||||
Kernel::SharedPtr<Kernel::Event> on_operation_mode_changed;
|
||||
};
|
||||
|
||||
class IWindowController final : public ServiceFramework<IWindowController> {
|
||||
@@ -119,7 +122,7 @@ private:
|
||||
void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
|
||||
Kernel::EventPair launchable_event;
|
||||
Kernel::SharedPtr<Kernel::Event> launchable_event;
|
||||
u32 idle_time_detection_extension = 0;
|
||||
};
|
||||
|
||||
@@ -148,6 +151,7 @@ private:
|
||||
void GetBootMode(Kernel::HLERequestContext& ctx);
|
||||
void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx);
|
||||
|
||||
Kernel::SharedPtr<Kernel::Event> event;
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue;
|
||||
};
|
||||
|
||||
|
||||
@@ -32,75 +32,66 @@ public:
|
||||
|
||||
private:
|
||||
void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetSelfController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISelfController>(nvflinger);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetWindowController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IWindowController>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetAudioController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IAudioController>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetDisplayController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IDisplayController>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetProcessWindingController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IProcessWindingController>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IDebugFunctions>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ILibraryAppletCreator>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IApplicationFunctions>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
|
||||
@@ -131,110 +122,97 @@ public:
|
||||
|
||||
private:
|
||||
void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetSelfController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISelfController>(nvflinger);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetWindowController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IWindowController>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetAudioController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IAudioController>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetDisplayController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IDisplayController>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IDebugFunctions>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ILibraryAppletCreator>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IHomeMenuFunctions>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetGlobalStateController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IGlobalStateController>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetApplicationCreator(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IApplicationCreator>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue;
|
||||
};
|
||||
|
||||
void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
|
||||
|
||||
@@ -35,67 +35,59 @@ public:
|
||||
|
||||
private:
|
||||
void GetAudioController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IAudioController>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetDisplayController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IDisplayController>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IDebugFunctions>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetWindowController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IWindowController>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetSelfController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISelfController>(nvflinger);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ILibraryAppletCreator>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IApplicationFunctions>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
|
||||
@@ -103,11 +95,10 @@ private:
|
||||
};
|
||||
|
||||
void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
|
||||
|
||||
@@ -5,9 +5,8 @@
|
||||
#include <cstring>
|
||||
#include "common/assert.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/server_port.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
|
||||
@@ -15,12 +14,12 @@ namespace Service::AM::Applets {
|
||||
|
||||
AppletDataBroker::AppletDataBroker() {
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
state_changed_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Sticky, "ILibraryAppletAccessor:StateChangedEvent");
|
||||
pop_out_data_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Sticky, "ILibraryAppletAccessor:PopDataOutEvent");
|
||||
pop_interactive_out_data_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Sticky, "ILibraryAppletAccessor:PopInteractiveDataOutEvent");
|
||||
state_changed_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
|
||||
"ILibraryAppletAccessor:StateChangedEvent");
|
||||
pop_out_data_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
|
||||
"ILibraryAppletAccessor:PopDataOutEvent");
|
||||
pop_interactive_out_data_event = Kernel::Event::Create(
|
||||
kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:PopInteractiveDataOutEvent");
|
||||
}
|
||||
|
||||
AppletDataBroker::~AppletDataBroker() = default;
|
||||
@@ -67,7 +66,7 @@ void AppletDataBroker::PushNormalDataFromGame(IStorage storage) {
|
||||
|
||||
void AppletDataBroker::PushNormalDataFromApplet(IStorage storage) {
|
||||
out_channel.push(std::make_unique<IStorage>(storage));
|
||||
pop_out_data_event.writable->Signal();
|
||||
pop_out_data_event->Signal();
|
||||
}
|
||||
|
||||
void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) {
|
||||
@@ -76,23 +75,23 @@ void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) {
|
||||
|
||||
void AppletDataBroker::PushInteractiveDataFromApplet(IStorage storage) {
|
||||
out_interactive_channel.push(std::make_unique<IStorage>(storage));
|
||||
pop_interactive_out_data_event.writable->Signal();
|
||||
pop_interactive_out_data_event->Signal();
|
||||
}
|
||||
|
||||
void AppletDataBroker::SignalStateChanged() const {
|
||||
state_changed_event.writable->Signal();
|
||||
state_changed_event->Signal();
|
||||
}
|
||||
|
||||
Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetNormalDataEvent() const {
|
||||
return pop_out_data_event.readable;
|
||||
Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetNormalDataEvent() const {
|
||||
return pop_out_data_event;
|
||||
}
|
||||
|
||||
Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetInteractiveDataEvent() const {
|
||||
return pop_interactive_out_data_event.readable;
|
||||
Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetInteractiveDataEvent() const {
|
||||
return pop_interactive_out_data_event;
|
||||
}
|
||||
|
||||
Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetStateChangedEvent() const {
|
||||
return state_changed_event.readable;
|
||||
Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetStateChangedEvent() const {
|
||||
return state_changed_event;
|
||||
}
|
||||
|
||||
Applet::Applet() = default;
|
||||
|
||||
@@ -8,10 +8,13 @@
|
||||
#include <queue>
|
||||
#include "common/swap.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
|
||||
union ResultCode;
|
||||
|
||||
namespace Kernel {
|
||||
class Event;
|
||||
}
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class IStorage;
|
||||
@@ -37,9 +40,9 @@ public:
|
||||
|
||||
void SignalStateChanged() const;
|
||||
|
||||
Kernel::SharedPtr<Kernel::ReadableEvent> GetNormalDataEvent() const;
|
||||
Kernel::SharedPtr<Kernel::ReadableEvent> GetInteractiveDataEvent() const;
|
||||
Kernel::SharedPtr<Kernel::ReadableEvent> GetStateChangedEvent() const;
|
||||
Kernel::SharedPtr<Kernel::Event> GetNormalDataEvent() const;
|
||||
Kernel::SharedPtr<Kernel::Event> GetInteractiveDataEvent() const;
|
||||
Kernel::SharedPtr<Kernel::Event> GetStateChangedEvent() const;
|
||||
|
||||
private:
|
||||
// Queues are named from applet's perspective
|
||||
@@ -56,13 +59,13 @@ private:
|
||||
// PopInteractiveDataToGame and PushInteractiveDataFromApplet
|
||||
std::queue<std::unique_ptr<IStorage>> out_interactive_channel;
|
||||
|
||||
Kernel::EventPair state_changed_event;
|
||||
Kernel::SharedPtr<Kernel::Event> state_changed_event;
|
||||
|
||||
// Signaled on PushNormalDataFromApplet
|
||||
Kernel::EventPair pop_out_data_event;
|
||||
Kernel::SharedPtr<Kernel::Event> pop_out_data_event;
|
||||
|
||||
// Signaled on PushInteractiveDataFromApplet
|
||||
Kernel::EventPair pop_interactive_out_data_event;
|
||||
Kernel::SharedPtr<Kernel::Event> pop_interactive_out_data_event;
|
||||
};
|
||||
|
||||
class Applet {
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/core.h"
|
||||
#include "core/frontend/applets/software_keyboard.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/profile_select.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1};
|
||||
|
||||
ProfileSelect::ProfileSelect() = default;
|
||||
ProfileSelect::~ProfileSelect() = default;
|
||||
|
||||
void ProfileSelect::Initialize() {
|
||||
complete = false;
|
||||
status = RESULT_SUCCESS;
|
||||
final_data.clear();
|
||||
|
||||
Applet::Initialize();
|
||||
|
||||
const auto user_config_storage = broker.PopNormalDataToApplet();
|
||||
ASSERT(user_config_storage != nullptr);
|
||||
const auto& user_config = user_config_storage->GetData();
|
||||
|
||||
ASSERT(user_config.size() >= sizeof(UserSelectionConfig));
|
||||
std::memcpy(&config, user_config.data(), sizeof(UserSelectionConfig));
|
||||
}
|
||||
|
||||
bool ProfileSelect::TransactionComplete() const {
|
||||
return complete;
|
||||
}
|
||||
|
||||
ResultCode ProfileSelect::GetStatus() const {
|
||||
return status;
|
||||
}
|
||||
|
||||
void ProfileSelect::ExecuteInteractive() {
|
||||
UNREACHABLE_MSG("Attempted to call interactive execution on non-interactive applet.");
|
||||
}
|
||||
|
||||
void ProfileSelect::Execute() {
|
||||
if (complete) {
|
||||
broker.PushNormalDataFromApplet(IStorage{final_data});
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& frontend{Core::System::GetInstance().GetProfileSelector()};
|
||||
|
||||
frontend.SelectProfile([this](std::optional<Account::UUID> uuid) { SelectionComplete(uuid); });
|
||||
}
|
||||
|
||||
void ProfileSelect::SelectionComplete(std::optional<Account::UUID> uuid) {
|
||||
UserSelectionOutput output{};
|
||||
|
||||
if (uuid.has_value() && uuid->uuid != Account::INVALID_UUID) {
|
||||
output.result = 0;
|
||||
output.uuid_selected = uuid->uuid;
|
||||
} else {
|
||||
status = ERR_USER_CANCELLED_SELECTION;
|
||||
output.result = ERR_USER_CANCELLED_SELECTION.raw;
|
||||
output.uuid_selected = Account::INVALID_UUID;
|
||||
}
|
||||
|
||||
final_data = std::vector<u8>(sizeof(UserSelectionOutput));
|
||||
std::memcpy(final_data.data(), &output, final_data.size());
|
||||
broker.PushNormalDataFromApplet(IStorage{final_data});
|
||||
broker.SignalStateChanged();
|
||||
}
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
@@ -1,50 +0,0 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
struct UserSelectionConfig {
|
||||
// TODO(DarkLordZach): RE this structure
|
||||
// It seems to be flags and the like that determine the UI of the applet on the switch... from
|
||||
// my research this is safe to ignore for now.
|
||||
INSERT_PADDING_BYTES(0xA0);
|
||||
};
|
||||
static_assert(sizeof(UserSelectionConfig) == 0xA0, "UserSelectionConfig has incorrect size.");
|
||||
|
||||
struct UserSelectionOutput {
|
||||
u64 result;
|
||||
u128 uuid_selected;
|
||||
};
|
||||
static_assert(sizeof(UserSelectionOutput) == 0x18, "UserSelectionOutput has incorrect size.");
|
||||
|
||||
class ProfileSelect final : public Applet {
|
||||
public:
|
||||
ProfileSelect();
|
||||
~ProfileSelect() override;
|
||||
|
||||
void Initialize() override;
|
||||
|
||||
bool TransactionComplete() const override;
|
||||
ResultCode GetStatus() const override;
|
||||
void ExecuteInteractive() override;
|
||||
void Execute() override;
|
||||
|
||||
void SelectionComplete(std::optional<Account::UUID> uuid);
|
||||
|
||||
private:
|
||||
UserSelectionConfig config;
|
||||
bool complete = false;
|
||||
ResultCode status = RESULT_SUCCESS;
|
||||
std::vector<u8> final_data;
|
||||
};
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
@@ -146,10 +146,11 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
|
||||
|
||||
if (complete) {
|
||||
broker.PushNormalDataFromApplet(IStorage{output_main});
|
||||
broker.SignalStateChanged();
|
||||
} else {
|
||||
broker.PushInteractiveDataFromApplet(IStorage{output_sub});
|
||||
}
|
||||
|
||||
broker.SignalStateChanged();
|
||||
} else {
|
||||
output_main[0] = 1;
|
||||
complete = true;
|
||||
|
||||
@@ -13,14 +13,11 @@
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/aoc/aoc_u.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Service::AOC {
|
||||
|
||||
@@ -35,14 +32,14 @@ static std::vector<u64> AccumulateAOCTitleIDs() {
|
||||
std::vector<u64> add_on_content;
|
||||
const auto rcu = FileSystem::GetUnionContents();
|
||||
const auto list =
|
||||
rcu.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
|
||||
rcu->ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
|
||||
std::transform(list.begin(), list.end(), std::back_inserter(add_on_content),
|
||||
[](const FileSys::RegisteredCacheEntry& rce) { return rce.title_id; });
|
||||
add_on_content.erase(
|
||||
std::remove_if(
|
||||
add_on_content.begin(), add_on_content.end(),
|
||||
[&rcu](u64 tid) {
|
||||
return rcu.GetEntry(tid, FileSys::ContentRecordType::Data)->GetStatus() !=
|
||||
return rcu->GetEntry(tid, FileSys::ContentRecordType::Data)->GetStatus() !=
|
||||
Loader::ResultStatus::Success;
|
||||
}),
|
||||
add_on_content.end());
|
||||
@@ -64,26 +61,17 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
aoc_change_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
|
||||
"GetAddOnContentListChanged:Event");
|
||||
aoc_change_event = Kernel::Event::Create(kernel, Kernel::ResetType::Sticky,
|
||||
"GetAddOnContentListChanged:Event");
|
||||
}
|
||||
|
||||
AOC_U::~AOC_U() = default;
|
||||
|
||||
void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AOC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID();
|
||||
|
||||
const auto& disabled = Settings::values.disabled_addons[current];
|
||||
if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) {
|
||||
rb.Push<u32>(0);
|
||||
return;
|
||||
}
|
||||
|
||||
rb.Push<u32>(static_cast<u32>(
|
||||
std::count_if(add_on_content.begin(), add_on_content.end(),
|
||||
[current](u64 tid) { return CheckAOCTitleIDMatchesBase(tid, current); })));
|
||||
@@ -94,7 +82,6 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
const auto offset = rp.PopRaw<u32>();
|
||||
auto count = rp.PopRaw<u32>();
|
||||
LOG_DEBUG(Service_AOC, "called with offset={}, count={}", offset, count);
|
||||
|
||||
const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID();
|
||||
|
||||
@@ -104,10 +91,6 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
|
||||
out.push_back(static_cast<u32>(add_on_content[i] & 0x7FF));
|
||||
}
|
||||
|
||||
const auto& disabled = Settings::values.disabled_addons[current];
|
||||
if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end())
|
||||
out = {};
|
||||
|
||||
if (out.size() < offset) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
// TODO(DarkLordZach): Find the correct error code.
|
||||
@@ -127,8 +110,6 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AOC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
const auto title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
|
||||
@@ -147,6 +128,7 @@ void AOC_U::PrepareAddOnContent(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const auto aoc_id = rp.PopRaw<u32>();
|
||||
|
||||
LOG_WARNING(Service_AOC, "(STUBBED) called with aoc_id={:08X}", aoc_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -158,7 +140,7 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(aoc_change_event.readable);
|
||||
rb.PushCopyObjects(aoc_change_event);
|
||||
}
|
||||
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager) {
|
||||
|
||||
@@ -6,10 +6,6 @@
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Kernel {
|
||||
class WritableEvent;
|
||||
}
|
||||
|
||||
namespace Service::AOC {
|
||||
|
||||
class AOC_U final : public ServiceFramework<AOC_U> {
|
||||
@@ -25,7 +21,7 @@ private:
|
||||
void GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx);
|
||||
|
||||
std::vector<u64> add_on_content;
|
||||
Kernel::EventPair aoc_change_event;
|
||||
Kernel::SharedPtr<Kernel::Event> aoc_change_event;
|
||||
};
|
||||
|
||||
/// Registers all AOC services with the specified service manager.
|
||||
|
||||
@@ -40,22 +40,24 @@ private:
|
||||
|
||||
auto mode = static_cast<PerformanceMode>(rp.Pop<u32>());
|
||||
u32 config = rp.Pop<u32>();
|
||||
LOG_WARNING(Service_APM, "(STUBBED) called mode={} config={}", static_cast<u32>(mode),
|
||||
config);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_APM, "(STUBBED) called mode={} config={}", static_cast<u32>(mode),
|
||||
config);
|
||||
}
|
||||
|
||||
void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
auto mode = static_cast<PerformanceMode>(rp.Pop<u32>());
|
||||
LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(static_cast<u32>(PerformanceConfiguration::Config1));
|
||||
|
||||
LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -71,11 +73,11 @@ APM::APM(std::shared_ptr<Module> apm, const char* name)
|
||||
APM::~APM() = default;
|
||||
|
||||
void APM::OpenSession(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_APM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISession>();
|
||||
|
||||
LOG_DEBUG(Service_APM, "called");
|
||||
}
|
||||
|
||||
APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} {
|
||||
@@ -96,11 +98,11 @@ APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} {
|
||||
APM_Sys::~APM_Sys() = default;
|
||||
|
||||
void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_APM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISession>();
|
||||
|
||||
LOG_DEBUG(Service_APM, "called");
|
||||
}
|
||||
|
||||
} // namespace Service::APM
|
||||
|
||||
@@ -59,11 +59,11 @@ public:
|
||||
|
||||
private:
|
||||
void AcquireRegistrar(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_ARP, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IRegistrar>();
|
||||
|
||||
LOG_DEBUG(Service_ARP, "called");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -13,10 +13,8 @@
|
||||
#include "common/swap.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/audio/audout_u.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
@@ -48,8 +46,8 @@ class IAudioOut final : public ServiceFramework<IAudioOut> {
|
||||
public:
|
||||
IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core, std::string&& device_name,
|
||||
std::string&& unique_name)
|
||||
: ServiceFramework("IAudioOut"), audio_core(audio_core),
|
||||
device_name(std::move(device_name)), audio_params(audio_params) {
|
||||
: ServiceFramework("IAudioOut"), audio_core(audio_core), audio_params(audio_params),
|
||||
device_name(std::move(device_name)) {
|
||||
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
|
||||
@@ -69,12 +67,11 @@ public:
|
||||
|
||||
// This is the event handle used to check if the audio buffer was released
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
|
||||
"IAudioOutBufferReleased");
|
||||
buffer_event =
|
||||
Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioOutBufferReleased");
|
||||
|
||||
stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count,
|
||||
std::move(unique_name),
|
||||
[=]() { buffer_event.writable->Signal(); });
|
||||
std::move(unique_name), [=]() { buffer_event->Signal(); });
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -89,7 +86,6 @@ private:
|
||||
|
||||
void GetAudioOutState(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(static_cast<u32>(stream->IsPlaying() ? AudioState::Started : AudioState::Stopped));
|
||||
@@ -124,7 +120,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(buffer_event.readable);
|
||||
rb.PushCopyObjects(buffer_event);
|
||||
}
|
||||
|
||||
void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
|
||||
@@ -152,7 +148,6 @@ private:
|
||||
|
||||
void GetReleasedAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called {}", ctx.Description());
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u64 max_count{ctx.GetWriteBufferSize() / sizeof(u64)};
|
||||
const auto released_buffers{audio_core.GetTagsAndReleaseBuffers(stream, max_count)};
|
||||
@@ -168,7 +163,6 @@ private:
|
||||
|
||||
void ContainsAudioOutBuffer(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u64 tag{rp.Pop<u64>()};
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
@@ -178,7 +172,6 @@ private:
|
||||
|
||||
void GetAudioOutBufferCount(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(static_cast<u32>(stream->GetQueueSize()));
|
||||
@@ -190,13 +183,12 @@ private:
|
||||
|
||||
AudoutParams audio_params{};
|
||||
|
||||
/// This is the event handle used to check if the audio buffer was released
|
||||
Kernel::EventPair buffer_event;
|
||||
/// This is the evend handle used to check if the audio buffer was released
|
||||
Kernel::SharedPtr<Kernel::Event> buffer_event;
|
||||
};
|
||||
|
||||
void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
ctx.WriteBuffer(DefaultDevice);
|
||||
|
||||
@@ -12,10 +12,8 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/audio/audren_u.h"
|
||||
|
||||
namespace Service::Audio {
|
||||
@@ -43,90 +41,85 @@ public:
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
system_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
|
||||
"IAudioRenderer:SystemEvent");
|
||||
renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event.writable);
|
||||
system_event =
|
||||
Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioRenderer:SystemEvent");
|
||||
renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event);
|
||||
}
|
||||
|
||||
private:
|
||||
void UpdateAudioCallback() {
|
||||
system_event.writable->Signal();
|
||||
system_event->Signal();
|
||||
}
|
||||
|
||||
void GetSampleRate(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(renderer->GetSampleRate());
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
}
|
||||
|
||||
void GetSampleCount(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(renderer->GetSampleCount());
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
}
|
||||
|
||||
void GetState(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(static_cast<u32>(renderer->GetStreamState()));
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
}
|
||||
|
||||
void GetMixBufferCount(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(renderer->GetMixBufferCount());
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
}
|
||||
|
||||
void RequestUpdateImpl(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
|
||||
ctx.WriteBuffer(renderer->UpdateAudioRenderer(ctx.ReadBuffer()));
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void Start(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void Stop(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void QuerySystemEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(system_event.readable);
|
||||
rb.PushCopyObjects(system_event);
|
||||
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
rendering_time_limit_percent = rp.Pop<u32>();
|
||||
LOG_DEBUG(Service_Audio, "called. rendering_time_limit_percent={}",
|
||||
rendering_time_limit_percent);
|
||||
|
||||
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) {
|
||||
@@ -137,7 +130,7 @@ private:
|
||||
rb.Push(rendering_time_limit_percent);
|
||||
}
|
||||
|
||||
Kernel::EventPair system_event;
|
||||
Kernel::SharedPtr<Kernel::Event> system_event;
|
||||
std::unique_ptr<AudioCore::AudioRenderer> renderer;
|
||||
u32 rendering_time_limit_percent = 100;
|
||||
};
|
||||
@@ -164,8 +157,8 @@ public:
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
|
||||
"IAudioOutBufferReleasedEvent");
|
||||
buffer_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
|
||||
"IAudioOutBufferReleasedEvent");
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -209,22 +202,21 @@ private:
|
||||
void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
|
||||
buffer_event.writable->Signal();
|
||||
buffer_event->Signal();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(buffer_event.readable);
|
||||
rb.PushCopyObjects(buffer_event);
|
||||
}
|
||||
|
||||
void GetActiveChannelCount(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(1);
|
||||
}
|
||||
|
||||
Kernel::EventPair buffer_event;
|
||||
Kernel::SharedPtr<Kernel::Event> buffer_event;
|
||||
|
||||
}; // namespace Audio
|
||||
|
||||
@@ -243,20 +235,19 @@ AudRenU::AudRenU() : ServiceFramework("audren:u") {
|
||||
AudRenU::~AudRenU() = default;
|
||||
|
||||
void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto params = rp.PopRaw<AudioCore::AudioRendererParameter>();
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<Audio::IAudioRenderer>(std::move(params));
|
||||
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
}
|
||||
|
||||
void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto params = rp.PopRaw<AudioCore::AudioRendererParameter>();
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
u64 buffer_sz = Common::AlignUp(4 * params.mix_buffer_count, 0x40);
|
||||
buffer_sz += params.unknown_c * 1024;
|
||||
@@ -310,26 +301,26 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(output_sz);
|
||||
|
||||
LOG_DEBUG(Service_Audio, "buffer_size=0x{:X}", output_sz);
|
||||
LOG_DEBUG(Service_Audio, "called, buffer_size=0x{:X}", output_sz);
|
||||
}
|
||||
|
||||
void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<Audio::IAudioDevice>();
|
||||
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
}
|
||||
|
||||
void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<Audio::IAudioDevice>(); // TODO(ogniK): Figure out what is different
|
||||
// based on the current revision
|
||||
rb.PushIpcInterface<Audio::IAudioDevice>();
|
||||
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called"); // TODO(ogniK): Figure out what is different
|
||||
// based on the current revision
|
||||
}
|
||||
|
||||
bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const {
|
||||
|
||||
@@ -46,13 +46,10 @@ public:
|
||||
|
||||
private:
|
||||
void DecodeInterleaved(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Audio, "called");
|
||||
|
||||
u32 consumed = 0;
|
||||
u32 sample_count = 0;
|
||||
std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16));
|
||||
if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples)) {
|
||||
LOG_ERROR(Audio, "Failed to decode opus data");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
// TODO(ogniK): Use correct error code
|
||||
rb.Push(ResultCode(-1));
|
||||
@@ -66,15 +63,12 @@ private:
|
||||
}
|
||||
|
||||
void DecodeInterleavedWithPerformance(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Audio, "called");
|
||||
|
||||
u32 consumed = 0;
|
||||
u32 sample_count = 0;
|
||||
u64 performance = 0;
|
||||
std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16));
|
||||
if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples,
|
||||
performance)) {
|
||||
LOG_ERROR(Audio, "Failed to decode opus data");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
// TODO(ogniK): Use correct error code
|
||||
rb.Push(ResultCode(-1));
|
||||
@@ -94,39 +88,24 @@ private:
|
||||
std::optional<std::reference_wrapper<u64>> performance_time = std::nullopt) {
|
||||
const auto start_time = std::chrono::high_resolution_clock::now();
|
||||
std::size_t raw_output_sz = output.size() * sizeof(opus_int16);
|
||||
if (sizeof(OpusHeader) > input.size()) {
|
||||
LOG_ERROR(Audio, "Input is smaller than the header size, header_sz={}, input_sz={}",
|
||||
sizeof(OpusHeader), input.size());
|
||||
if (sizeof(OpusHeader) > input.size())
|
||||
return false;
|
||||
}
|
||||
OpusHeader hdr{};
|
||||
std::memcpy(&hdr, input.data(), sizeof(OpusHeader));
|
||||
if (sizeof(OpusHeader) + static_cast<u32>(hdr.sz) > input.size()) {
|
||||
LOG_ERROR(Audio, "Input does not fit in the opus header size. data_sz={}, input_sz={}",
|
||||
sizeof(OpusHeader) + static_cast<u32>(hdr.sz), input.size());
|
||||
return false;
|
||||
}
|
||||
auto frame = input.data() + sizeof(OpusHeader);
|
||||
auto decoded_sample_count = opus_packet_get_nb_samples(
|
||||
frame, static_cast<opus_int32>(input.size() - sizeof(OpusHeader)),
|
||||
static_cast<opus_int32>(sample_rate));
|
||||
if (decoded_sample_count * channel_count * sizeof(u16) > raw_output_sz) {
|
||||
LOG_ERROR(
|
||||
Audio,
|
||||
"Decoded data does not fit into the output data, decoded_sz={}, raw_output_sz={}",
|
||||
decoded_sample_count * channel_count * sizeof(u16), raw_output_sz);
|
||||
if (decoded_sample_count * channel_count * sizeof(u16) > raw_output_sz)
|
||||
return false;
|
||||
}
|
||||
const int frame_size = (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count));
|
||||
auto out_sample_count =
|
||||
opus_decode(decoder.get(), frame, hdr.sz, output.data(), frame_size, 0);
|
||||
if (out_sample_count < 0) {
|
||||
LOG_ERROR(Audio,
|
||||
"Incorrect sample count received from opus_decode, "
|
||||
"output_sample_count={}, frame_size={}, data_sz_from_hdr={}",
|
||||
out_sample_count, frame_size, static_cast<u32>(hdr.sz));
|
||||
opus_decode(decoder.get(), frame, hdr.sz, output.data(),
|
||||
(static_cast<int>(raw_output_sz / sizeof(s16) / channel_count)), 0);
|
||||
if (out_sample_count < 0)
|
||||
return false;
|
||||
}
|
||||
const auto end_time = std::chrono::high_resolution_clock::now() - start_time;
|
||||
sample_count = out_sample_count;
|
||||
consumed = static_cast<u32>(sizeof(OpusHeader) + hdr.sz);
|
||||
@@ -155,17 +134,14 @@ static std::size_t WorkerBufferSize(u32 channel_count) {
|
||||
|
||||
void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto sample_rate = rp.Pop<u32>();
|
||||
const auto channel_count = rp.Pop<u32>();
|
||||
LOG_DEBUG(Audio, "called with sample_rate={}, channel_count={}", sample_rate, channel_count);
|
||||
|
||||
auto sample_rate = rp.Pop<u32>();
|
||||
auto channel_count = rp.Pop<u32>();
|
||||
ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 ||
|
||||
sample_rate == 12000 || sample_rate == 8000,
|
||||
"Invalid sample rate");
|
||||
ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count");
|
||||
|
||||
const u32 worker_buffer_sz = static_cast<u32>(WorkerBufferSize(channel_count));
|
||||
LOG_DEBUG(Audio, "worker_buffer_sz={}", worker_buffer_sz);
|
||||
u32 worker_buffer_sz = static_cast<u32>(WorkerBufferSize(channel_count));
|
||||
LOG_DEBUG(Audio, "called worker_buffer_sz={}", worker_buffer_sz);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -179,7 +155,6 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) {
|
||||
auto buffer_sz = rp.Pop<u32>();
|
||||
LOG_DEBUG(Audio, "called sample_rate={}, channel_count={}, buffer_size={}", sample_rate,
|
||||
channel_count, buffer_sz);
|
||||
|
||||
ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 ||
|
||||
sample_rate == 12000 || sample_rate == 8000,
|
||||
"Invalid sample rate");
|
||||
@@ -189,8 +164,7 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) {
|
||||
ASSERT_MSG(buffer_sz >= worker_sz, "Worker buffer too large");
|
||||
std::unique_ptr<OpusDecoder, OpusDeleter> decoder{
|
||||
static_cast<OpusDecoder*>(operator new(worker_sz))};
|
||||
if (const int err = opus_decoder_init(decoder.get(), sample_rate, channel_count)) {
|
||||
LOG_ERROR(Audio, "Failed to init opus decoder with error={}", err);
|
||||
if (opus_decoder_init(decoder.get(), sample_rate, channel_count)) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
// TODO(ogniK): Use correct error code
|
||||
rb.Push(ResultCode(-1));
|
||||
|
||||
@@ -33,11 +33,10 @@ public:
|
||||
};
|
||||
|
||||
void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_BCAT, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IBcatService>();
|
||||
LOG_DEBUG(Service_BCAT, "called");
|
||||
}
|
||||
|
||||
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
|
||||
|
||||
@@ -4,10 +4,8 @@
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/btdrv/btdrv.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
@@ -32,22 +30,19 @@ public:
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
register_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
|
||||
"BT:RegisterEvent");
|
||||
}
|
||||
|
||||
private:
|
||||
void RegisterEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
register_event =
|
||||
Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "BT:RegisterEvent");
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(register_event.readable);
|
||||
rb.PushCopyObjects(register_event);
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
Kernel::EventPair register_event;
|
||||
Kernel::SharedPtr<Kernel::Event> register_event;
|
||||
};
|
||||
|
||||
class BtDrv final : public ServiceFramework<BtDrv> {
|
||||
|
||||
@@ -6,10 +6,8 @@
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/btm/btm.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
@@ -55,55 +53,49 @@ public:
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
scan_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
|
||||
"IBtmUserCore:ScanEvent");
|
||||
connection_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ConnectionEvent");
|
||||
service_discovery = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::OneShot, "IBtmUserCore:Discovery");
|
||||
config_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
|
||||
"IBtmUserCore:ConfigEvent");
|
||||
}
|
||||
|
||||
private:
|
||||
void GetScanEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
scan_event =
|
||||
Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ScanEvent");
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(scan_event.readable);
|
||||
rb.PushCopyObjects(scan_event);
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void GetConnectionEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
connection_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
|
||||
"IBtmUserCore:ConnectionEvent");
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(connection_event.readable);
|
||||
rb.PushCopyObjects(connection_event);
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void GetDiscoveryEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
service_discovery =
|
||||
Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:Discovery");
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(service_discovery.readable);
|
||||
rb.PushCopyObjects(service_discovery);
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void GetConfigEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
config_event =
|
||||
Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ConfigEvent");
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(config_event.readable);
|
||||
rb.PushCopyObjects(config_event);
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
Kernel::EventPair scan_event;
|
||||
Kernel::EventPair connection_event;
|
||||
Kernel::EventPair service_discovery;
|
||||
Kernel::EventPair config_event;
|
||||
Kernel::SharedPtr<Kernel::Event> scan_event;
|
||||
Kernel::SharedPtr<Kernel::Event> connection_event;
|
||||
Kernel::SharedPtr<Kernel::Event> service_discovery;
|
||||
Kernel::SharedPtr<Kernel::Event> config_event;
|
||||
};
|
||||
|
||||
class BTM_USR final : public ServiceFramework<BTM_USR> {
|
||||
@@ -119,11 +111,10 @@ public:
|
||||
|
||||
private:
|
||||
void GetCoreImpl(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_BTM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IBtmUserCore>();
|
||||
LOG_DEBUG(Service_BTM, "called");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -218,11 +209,11 @@ public:
|
||||
|
||||
private:
|
||||
void GetCoreImpl(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_BTM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IBtmSystemCore>();
|
||||
|
||||
LOG_DEBUG(Service_BTM, "called");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -17,13 +17,11 @@ public:
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "SubmitContext"},
|
||||
{1, nullptr, "CreateReport"},
|
||||
{2, nullptr, "SetInitialLaunchSettingsCompletionTime"},
|
||||
{3, nullptr, "ClearInitialLaunchSettingsCompletionTime"},
|
||||
{4, nullptr, "UpdatePowerOnTime"},
|
||||
{5, nullptr, "UpdateAwakeTime"},
|
||||
{6, nullptr, "SubmitMultipleCategoryContext"},
|
||||
{7, nullptr, "UpdateApplicationLaunchTime"},
|
||||
{8, nullptr, "ClearApplicationLaunchTime"},
|
||||
{2, nullptr, "Unknown1"},
|
||||
{3, nullptr, "Unknown2"},
|
||||
{4, nullptr, "Unknown3"},
|
||||
{5, nullptr, "Unknown4"},
|
||||
{6, nullptr, "Unknown5"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -42,11 +42,11 @@ public:
|
||||
|
||||
private:
|
||||
void Initialize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_FGM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IRequest>();
|
||||
|
||||
LOG_DEBUG(Service_FGM, "called");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -113,18 +113,6 @@ ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::str
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultCode VfsDirectoryServiceWrapper::CleanDirectoryRecursively(const std::string& path) const {
|
||||
const std::string sanitized_path(FileUtil::SanitizePath(path));
|
||||
auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(sanitized_path));
|
||||
|
||||
if (!dir->CleanSubdirectoryRecursive(FileUtil::GetFilename(sanitized_path))) {
|
||||
// TODO(DarkLordZach): Find a better error code for this
|
||||
return ResultCode(-1);
|
||||
}
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_,
|
||||
const std::string& dest_path_) const {
|
||||
std::string src_path(FileUtil::SanitizePath(src_path_));
|
||||
@@ -341,9 +329,20 @@ ResultVal<FileSys::VirtualDir> OpenSDMC() {
|
||||
return sdmc_factory->Open();
|
||||
}
|
||||
|
||||
FileSys::RegisteredCacheUnion GetUnionContents() {
|
||||
return FileSys::RegisteredCacheUnion{
|
||||
{GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()}};
|
||||
std::shared_ptr<FileSys::RegisteredCacheUnion> registered_cache_union;
|
||||
|
||||
std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() {
|
||||
if (registered_cache_union == nullptr) {
|
||||
registered_cache_union =
|
||||
std::make_shared<FileSys::RegisteredCacheUnion>(std::vector<FileSys::RegisteredCache*>{
|
||||
GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()});
|
||||
}
|
||||
|
||||
return registered_cache_union;
|
||||
}
|
||||
|
||||
void ClearUnionContents() {
|
||||
registered_cache_union = nullptr;
|
||||
}
|
||||
|
||||
FileSys::RegisteredCache* GetSystemNANDContents() {
|
||||
@@ -396,6 +395,7 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
|
||||
bis_factory = nullptr;
|
||||
save_data_factory = nullptr;
|
||||
sdmc_factory = nullptr;
|
||||
ClearUnionContents();
|
||||
}
|
||||
|
||||
auto nand_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir),
|
||||
|
||||
@@ -48,7 +48,8 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
|
||||
ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space);
|
||||
ResultVal<FileSys::VirtualDir> OpenSDMC();
|
||||
|
||||
FileSys::RegisteredCacheUnion GetUnionContents();
|
||||
std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents();
|
||||
void ClearUnionContents();
|
||||
|
||||
FileSys::RegisteredCache* GetSystemNANDContents();
|
||||
FileSys::RegisteredCache* GetUserNANDContents();
|
||||
@@ -112,18 +113,6 @@ public:
|
||||
*/
|
||||
ResultCode DeleteDirectoryRecursively(const std::string& path) const;
|
||||
|
||||
/**
|
||||
* Cleans the specified directory. This is similar to DeleteDirectoryRecursively,
|
||||
* in that it deletes all the contents of the specified directory, however, this
|
||||
* function does *not* delete the directory itself. It only deletes everything
|
||||
* within it.
|
||||
*
|
||||
* @param path Path relative to the archive.
|
||||
*
|
||||
* @return Result of the operation.
|
||||
*/
|
||||
ResultCode CleanDirectoryRecursively(const std::string& path) const;
|
||||
|
||||
/**
|
||||
* Rename a File specified by its path
|
||||
* @param src_path Source path relative to the archive
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "core/file_sys/nca_metadata.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/file_sys/savedata_factory.h"
|
||||
#include "core/file_sys/system_archive/system_archive.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
@@ -45,12 +44,8 @@ public:
|
||||
explicit IStorage(FileSys::VirtualFile backend_)
|
||||
: ServiceFramework("IStorage"), backend(std::move(backend_)) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IStorage::Read, "Read"},
|
||||
{1, nullptr, "Write"},
|
||||
{2, nullptr, "Flush"},
|
||||
{3, nullptr, "SetSize"},
|
||||
{4, &IStorage::GetSize, "GetSize"},
|
||||
{5, nullptr, "OperateRange"},
|
||||
{0, &IStorage::Read, "Read"}, {1, nullptr, "Write"}, {2, nullptr, "Flush"},
|
||||
{3, nullptr, "SetSize"}, {4, nullptr, "GetSize"}, {5, nullptr, "OperateRange"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
@@ -67,13 +62,11 @@ private:
|
||||
|
||||
// Error checking
|
||||
if (length < 0) {
|
||||
LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(FileSys::ERROR_INVALID_SIZE);
|
||||
return;
|
||||
}
|
||||
if (offset < 0) {
|
||||
LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(FileSys::ERROR_INVALID_OFFSET);
|
||||
return;
|
||||
@@ -87,15 +80,6 @@ private:
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void GetSize(Kernel::HLERequestContext& ctx) {
|
||||
const u64 size = backend->GetSize();
|
||||
LOG_DEBUG(Service_FS, "called, size={}", size);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(size);
|
||||
}
|
||||
};
|
||||
|
||||
class IFile final : public ServiceFramework<IFile> {
|
||||
@@ -123,13 +107,11 @@ private:
|
||||
|
||||
// Error checking
|
||||
if (length < 0) {
|
||||
LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(FileSys::ERROR_INVALID_SIZE);
|
||||
return;
|
||||
}
|
||||
if (offset < 0) {
|
||||
LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(FileSys::ERROR_INVALID_OFFSET);
|
||||
return;
|
||||
@@ -156,13 +138,11 @@ private:
|
||||
|
||||
// Error checking
|
||||
if (length < 0) {
|
||||
LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(FileSys::ERROR_INVALID_SIZE);
|
||||
return;
|
||||
}
|
||||
if (offset < 0) {
|
||||
LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(FileSys::ERROR_INVALID_OFFSET);
|
||||
return;
|
||||
@@ -200,9 +180,8 @@ private:
|
||||
void SetSize(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u64 size = rp.Pop<u64>();
|
||||
LOG_DEBUG(Service_FS, "called, size={}", size);
|
||||
|
||||
backend->Resize(size);
|
||||
LOG_DEBUG(Service_FS, "called, size={}", size);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -305,7 +284,7 @@ public:
|
||||
{10, &IFileSystem::Commit, "Commit"},
|
||||
{11, nullptr, "GetFreeSpaceSize"},
|
||||
{12, nullptr, "GetTotalSpaceSize"},
|
||||
{13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"},
|
||||
{13, nullptr, "CleanDirectoryRecursively"},
|
||||
{14, nullptr, "GetFileTimeStampRaw"},
|
||||
{15, nullptr, "QueryEntry"},
|
||||
};
|
||||
@@ -375,16 +354,6 @@ public:
|
||||
rb.Push(backend.DeleteDirectoryRecursively(name));
|
||||
}
|
||||
|
||||
void CleanDirectoryRecursively(Kernel::HLERequestContext& ctx) {
|
||||
const auto file_buffer = ctx.ReadBuffer();
|
||||
const std::string name = Common::StringFromBuffer(file_buffer);
|
||||
|
||||
LOG_DEBUG(Service_FS, "called. Directory: {}", name);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(backend.CleanDirectoryRecursively(name));
|
||||
}
|
||||
|
||||
void RenameFile(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
@@ -496,8 +465,6 @@ public:
|
||||
}
|
||||
|
||||
void ReadSaveDataInfo(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_FS, "called");
|
||||
|
||||
// Calculate how many entries we can fit in the output buffer
|
||||
const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(SaveDataInfo);
|
||||
|
||||
@@ -736,8 +703,6 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
const auto type = rp.PopRaw<FileSystemType>();
|
||||
const auto title_id = rp.PopRaw<u64>();
|
||||
LOG_WARNING(Service_FS, "(STUBBED) called with type={}, title_id={:016X}",
|
||||
static_cast<u8>(type), title_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
|
||||
rb.Push(ResultCode(-1));
|
||||
@@ -773,7 +738,6 @@ void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) {
|
||||
auto space_id = rp.PopRaw<FileSys::SaveDataSpaceId>();
|
||||
auto unk = rp.Pop<u32>();
|
||||
LOG_INFO(Service_FS, "called with unknown={:08X}", unk);
|
||||
|
||||
auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>();
|
||||
|
||||
auto dir = OpenSaveData(space_id, save_struct);
|
||||
@@ -799,7 +763,6 @@ void FSP_SRV::OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx) {
|
||||
void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>();
|
||||
LOG_INFO(Service_FS, "called, space={}", static_cast<u8>(space));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -809,18 +772,9 @@ void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext&
|
||||
void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_FS, "(STUBBED) called");
|
||||
|
||||
enum class LogMode : u32 {
|
||||
Off,
|
||||
Log,
|
||||
RedirectToSdCard,
|
||||
LogToSdCard = Log | RedirectToSdCard,
|
||||
};
|
||||
|
||||
// Given we always want to receive logging information,
|
||||
// we always specify logging as enabled.
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum(LogMode::Log);
|
||||
rb.Push<u32>(5);
|
||||
}
|
||||
|
||||
void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
|
||||
@@ -854,15 +808,6 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
|
||||
auto data = OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
|
||||
|
||||
if (data.Failed()) {
|
||||
const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
|
||||
|
||||
if (archive != nullptr) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface(std::make_shared<IStorage>(archive));
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(DarkLordZach): Find the right error code to use here
|
||||
LOG_ERROR(Service_FS,
|
||||
"could not open data storage with title_id={:016X}, storage_id={:02X}", title_id,
|
||||
|
||||
@@ -12,9 +12,7 @@
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/frontend/input.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
@@ -169,8 +167,8 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
|
||||
|
||||
void Controller_NPad::OnInit() {
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
styleset_changed_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::OneShot, "npad:NpadStyleSetChanged");
|
||||
styleset_changed_event =
|
||||
Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "npad:NpadStyleSetChanged");
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
return;
|
||||
@@ -496,7 +494,7 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) {
|
||||
had_controller_update = true;
|
||||
}
|
||||
if (had_controller_update) {
|
||||
styleset_changed_event.writable->Signal();
|
||||
styleset_changed_event->Signal();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -511,7 +509,7 @@ std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const {
|
||||
}
|
||||
|
||||
void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) {
|
||||
styleset_changed_event.writable->Signal();
|
||||
styleset_changed_event->Signal();
|
||||
hold_type = joy_hold_type;
|
||||
}
|
||||
|
||||
@@ -520,15 +518,12 @@ Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const {
|
||||
}
|
||||
|
||||
void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) {
|
||||
const std::size_t npad_index = NPadIdToIndex(npad_id);
|
||||
ASSERT(npad_index < shared_memory_entries.size());
|
||||
shared_memory_entries[npad_index].pad_assignment = assignment_mode;
|
||||
ASSERT(npad_id < shared_memory_entries.size());
|
||||
shared_memory_entries[npad_id].pad_assignment = assignment_mode;
|
||||
}
|
||||
|
||||
void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
|
||||
const std::vector<Vibration>& vibrations) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
if (!can_controllers_vibrate) {
|
||||
return;
|
||||
}
|
||||
@@ -538,14 +533,15 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
|
||||
// TODO(ogniK): Vibrate the physical controller
|
||||
}
|
||||
}
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
last_processed_vibration = vibrations.back();
|
||||
}
|
||||
|
||||
Kernel::SharedPtr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent() const {
|
||||
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.writable->Signal();
|
||||
return styleset_changed_event.readable;
|
||||
styleset_changed_event->Signal();
|
||||
return styleset_changed_event;
|
||||
}
|
||||
|
||||
Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
|
||||
@@ -579,8 +575,8 @@ void Controller_NPad::AddNewControllerAt(NPadControllerType controller, u32 npad
|
||||
return;
|
||||
}
|
||||
|
||||
connected_controllers[NPadIdToIndex(npad_id)] = {controller, true};
|
||||
InitNewlyAddedControler(NPadIdToIndex(npad_id));
|
||||
connected_controllers[npad_id] = {controller, true};
|
||||
InitNewlyAddedControler(npad_id);
|
||||
}
|
||||
|
||||
void Controller_NPad::ConnectNPad(u32 npad_id) {
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/frontend/input.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
@@ -81,9 +80,9 @@ public:
|
||||
struct LedPattern {
|
||||
explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) {
|
||||
position1.Assign(light1);
|
||||
position2.Assign(light2);
|
||||
position3.Assign(light3);
|
||||
position4.Assign(light4);
|
||||
position1.Assign(light2);
|
||||
position1.Assign(light3);
|
||||
position1.Assign(light4);
|
||||
}
|
||||
union {
|
||||
u64 raw{};
|
||||
@@ -109,7 +108,7 @@ public:
|
||||
void VibrateController(const std::vector<u32>& controller_ids,
|
||||
const std::vector<Vibration>& vibrations);
|
||||
|
||||
Kernel::SharedPtr<Kernel::ReadableEvent> GetStyleSetChangedEvent() const;
|
||||
Kernel::SharedPtr<Kernel::Event> GetStyleSetChangedEvent() const;
|
||||
Vibration GetLastVibration() const;
|
||||
|
||||
void AddNewController(NPadControllerType controller);
|
||||
@@ -304,7 +303,7 @@ private:
|
||||
sticks;
|
||||
std::vector<u32> supported_npad_id_types{};
|
||||
NpadHoldType hold_type{NpadHoldType::Vertical};
|
||||
Kernel::EventPair styleset_changed_event;
|
||||
Kernel::SharedPtr<Kernel::Event> styleset_changed_event;
|
||||
Vibration last_processed_vibration{};
|
||||
std::array<ControllerHolder, 10> connected_controllers{};
|
||||
bool can_controllers_vibrate{true};
|
||||
|
||||
@@ -13,9 +13,8 @@
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/client_port.h"
|
||||
#include "core/hle/kernel/client_session.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
#include "core/hle/service/hid/irs.h"
|
||||
#include "core/hle/service/hid/xcd.h"
|
||||
@@ -125,11 +124,10 @@ public:
|
||||
|
||||
private:
|
||||
void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(shared_mem);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void UpdateControllers(u64 userdata, int cycles_late) {
|
||||
@@ -165,10 +163,9 @@ public:
|
||||
|
||||
private:
|
||||
void ActivateVibrationDevice(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -306,8 +303,6 @@ private:
|
||||
std::shared_ptr<IAppletResource> applet_resource;
|
||||
|
||||
void CreateAppletResource(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
if (applet_resource == nullptr) {
|
||||
applet_resource = std::make_shared<IAppletResource>();
|
||||
}
|
||||
@@ -315,228 +310,206 @@ private:
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IAppletResource>(applet_resource);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void ActivateXpad(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
applet_resource->ActivateController(HidController::XPad);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void ActivateDebugPad(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
applet_resource->ActivateController(HidController::DebugPad);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void ActivateTouchScreen(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
applet_resource->ActivateController(HidController::Touchscreen);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void ActivateMouse(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
applet_resource->ActivateController(HidController::Mouse);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void ActivateKeyboard(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
applet_resource->ActivateController(HidController::Keyboard);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void ActivateGesture(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
applet_resource->ActivateController(HidController::Gesture);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
|
||||
// Should have no effect with how our npad sets up the data
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
applet_resource->ActivateController(HidController::NPad);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto handle = rp.PopRaw<u32>();
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called with handle={}", handle);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
// TODO (Hexagon12): Properly implement reading gyroscope values from controllers.
|
||||
rb.Push(true);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto supported_styleset = rp.PopRaw<u32>();
|
||||
LOG_DEBUG(Service_HID, "called with supported_styleset={}", supported_styleset);
|
||||
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.SetSupportedStyleSet({supported_styleset});
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(controller.GetSupportedStyleSet().raw);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize());
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void ActivateNpad(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
applet_resource->ActivateController(HidController::NPad);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto npad_id = rp.PopRaw<u32>();
|
||||
LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.GetStyleSetChangedEvent());
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void DisconnectNpad(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto npad_id = rp.PopRaw<u32>();
|
||||
LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id);
|
||||
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.DisconnectNPad(npad_id);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto npad_id = rp.PopRaw<u32>();
|
||||
LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.GetLedPattern(npad_id)
|
||||
.raw);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
|
||||
auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto hold_type = rp.PopRaw<u64>();
|
||||
LOG_DEBUG(Service_HID, "called with hold_type={}", hold_type);
|
||||
|
||||
auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
|
||||
controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type});
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
const auto& controller =
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad);
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(static_cast<u64>(controller.GetHoldType()));
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto npad_id = rp.PopRaw<u32>();
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called with npad_id={}", npad_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.SetVibrationEnabled(true);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.SetVibrationEnabled(false);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void SendVibrationValue(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto controller_id = rp.PopRaw<u32>();
|
||||
const auto vibration_values = rp.PopRaw<Controller_NPad::Vibration>();
|
||||
LOG_DEBUG(Service_HID, "called with controller_id={}", controller_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.VibrateController({controller_id}, {vibration_values});
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void SendVibrationValues(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
const auto controllers = ctx.ReadBuffer(0);
|
||||
const auto vibrations = ctx.ReadBuffer(1);
|
||||
|
||||
@@ -554,96 +527,86 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void GetActualVibrationValue(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<Controller_NPad::Vibration>(
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.GetLastVibration());
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto npad_id = rp.PopRaw<u32>();
|
||||
LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id);
|
||||
|
||||
auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
|
||||
controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto mode = rp.PopRaw<u32>();
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called with mode={}", mode);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(1);
|
||||
rb.Push<u32>(0);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IActiveVibrationDeviceList>();
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void SetPalmaBoostMode(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -44,133 +44,115 @@ IRS::IRS() : ServiceFramework{"irs"} {
|
||||
}
|
||||
|
||||
void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_IRS, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(shared_mem);
|
||||
LOG_DEBUG(Service_IRS, "called");
|
||||
}
|
||||
|
||||
void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 5};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<u64>(CoreTiming::GetTicks());
|
||||
rb.PushRaw<u32>(0);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<u32>(device_handle);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
IRS::~IRS() = default;
|
||||
|
||||
@@ -55,29 +55,29 @@ public:
|
||||
|
||||
private:
|
||||
void EnableVrMode(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_LBL, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
vr_mode_enabled = true;
|
||||
|
||||
LOG_DEBUG(Service_LBL, "called");
|
||||
}
|
||||
|
||||
void DisableVrMode(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_LBL, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
vr_mode_enabled = false;
|
||||
|
||||
LOG_DEBUG(Service_LBL, "called");
|
||||
}
|
||||
|
||||
void IsVrModeEnabled(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_LBL, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(vr_mode_enabled);
|
||||
|
||||
LOG_DEBUG(Service_LBL, "called");
|
||||
}
|
||||
|
||||
bool vr_mode_enabled = false;
|
||||
|
||||
@@ -44,11 +44,11 @@ public:
|
||||
}
|
||||
|
||||
void CreateMonitorService(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_LDN, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IMonitorService>();
|
||||
|
||||
LOG_DEBUG(Service_LDN, "called");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -104,11 +104,11 @@ public:
|
||||
}
|
||||
|
||||
void CreateSystemLocalCommunicationService(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_LDN, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ILocalCommunicationService>("ISystemLocalCommunicationService");
|
||||
|
||||
LOG_DEBUG(Service_LDN, "called");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -125,11 +125,11 @@ public:
|
||||
}
|
||||
|
||||
void CreateUserLocalCommunicationService(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_LDN, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ILocalCommunicationService>("IUserLocalCommunicationService");
|
||||
|
||||
LOG_DEBUG(Service_LDN, "called");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user