Compare commits

..

20 Commits

Author SHA1 Message Date
0f6f7fd552 Android #37 2023-08-12 00:57:15 +00:00
26ff214719 Merge pull request #11219 from zeltermann/title-id-search
Allow searching by a substring of the title ID
2023-08-11 16:53:27 -04:00
640f7cd945 Merge pull request #11253 from liamwhite/i-hate-this-toolchain
general: fix apple clang build
2023-08-11 16:53:20 -04:00
1ed9e8812b Allow searching by a substring of the title ID 2023-08-11 00:07:12 +07:00
9d3a293a4e Merge pull request #11093 from liamwhite/result-ergonomics
core: remove ResultVal type
2023-08-09 21:24:31 -07:00
3d6ce9dd2b Merge pull request #11247 from german77/pctl
service: pctl: Partially revert 11221
2023-08-09 21:24:06 -07:00
023b9b38cc general: fix apple clang build 2023-08-09 22:38:37 -04:00
6a43aff745 service: pctl: Partially revert 11221 2023-08-08 16:52:21 -06:00
1e394c6cdf fs: return result on null outputs 2023-08-08 16:12:04 -04:00
37b278a9a8 general: fix incorrect conversions 2023-08-08 11:09:37 -04:00
83eee1d226 ssl: remove ResultVal use 2023-08-08 11:09:37 -04:00
84cb20bc72 core: remove ResultVal type 2023-08-08 11:09:37 -04:00
85e3575496 Merge pull request #11216 from lat9nq/no-mesa-astc
gl_device: Detect Mesa to disable their ASTC
2023-08-07 11:34:22 -04:00
7f55c377b0 Merge pull request #11217 from german77/olsc
service: olsc: Implement IOlscServiceForSystemService ITransferTaskListController interfaces for QLaunch
2023-08-07 11:34:14 -04:00
9893a4d918 Merge pull request #11221 from german77/pctl
service: pctl: Implement functions needed for QLaunch
2023-08-07 11:34:07 -04:00
bed2fc8707 Merge pull request #11224 from german77/audio
service: audctl: Stub functions needed by Qlaunch
2023-08-07 11:33:55 -04:00
8d2f0dc707 service: audctl: Stub functions needed by Qlaunch 2023-08-05 20:16:26 -06:00
cb0b8442f0 gl_device: Filter more specifically for slow ASTC
Adds a check to find if the renderer is Intel DG (i.e. DG2).

gl_device: Detect Mesa to disable their ASTC

In our testing, our own ASTC decoder has shown itself to perform faster
than the included one from the driver. Disable theirs when Mesa is
detected.

Mesa detection depends on the vendor string. Some drivers never appear
outside of *nix contexts, so only check those in the *nix context.

gl_device: Internalize Intel DG detection
2023-08-05 15:19:16 -04:00
089e385944 service: olsc: Implement IOlscServiceForSystemService ITransferTaskListController interfaces for QLaunch 2023-08-05 11:47:51 -06:00
0d470b57ed service: pctl: Implement functions needed for QLaunch 2023-08-05 11:27:41 -06:00
50 changed files with 1000 additions and 705 deletions

View File

@ -1,7 +1,9 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <functional>
#include <string>
#include <vector>
#include "common/settings_common.h"
namespace Settings {

View File

@ -12,8 +12,8 @@ namespace Settings {
template <typename T>
struct EnumMetadata {
static constexpr std::vector<std::pair<std::string, T>> Canonicalizations();
static constexpr u32 Index();
static std::vector<std::pair<std::string, T>> Canonicalizations();
static u32 Index();
};
#define PAIR_45(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_46(N, __VA_ARGS__))
@ -66,11 +66,11 @@ struct EnumMetadata {
#define ENUM(NAME, ...) \
enum class NAME : u32 { __VA_ARGS__ }; \
template <> \
constexpr std::vector<std::pair<std::string, NAME>> EnumMetadata<NAME>::Canonicalizations() { \
inline std::vector<std::pair<std::string, NAME>> EnumMetadata<NAME>::Canonicalizations() { \
return {PAIR(NAME, __VA_ARGS__)}; \
} \
template <> \
constexpr u32 EnumMetadata<NAME>::Index() { \
inline u32 EnumMetadata<NAME>::Index() { \
return __COUNTER__; \
}
@ -85,7 +85,7 @@ enum class AudioEngine : u32 {
};
template <>
constexpr std::vector<std::pair<std::string, AudioEngine>>
inline std::vector<std::pair<std::string, AudioEngine>>
EnumMetadata<AudioEngine>::Canonicalizations() {
return {
{"auto", AudioEngine::Auto},
@ -96,7 +96,7 @@ EnumMetadata<AudioEngine>::Canonicalizations() {
}
template <>
constexpr u32 EnumMetadata<AudioEngine>::Index() {
inline u32 EnumMetadata<AudioEngine>::Index() {
// This is just a sufficiently large number that is more than the number of other enums declared
// here
return 100;
@ -147,7 +147,7 @@ ENUM(AntiAliasing, None, Fxaa, Smaa, MaxEnum);
ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch);
template <typename Type>
constexpr std::string CanonicalizeEnum(Type id) {
inline std::string CanonicalizeEnum(Type id) {
const auto group = EnumMetadata<Type>::Canonicalizations();
for (auto& [name, value] : group) {
if (value == id) {
@ -158,7 +158,7 @@ constexpr std::string CanonicalizeEnum(Type id) {
}
template <typename Type>
constexpr Type ToEnum(const std::string& canonicalization) {
inline Type ToEnum(const std::string& canonicalization) {
const auto group = EnumMetadata<Type>::Canonicalizations();
for (auto& [name, value] : group) {
if (name == canonicalization) {

View File

@ -190,7 +190,7 @@ public:
}
}
[[nodiscard]] std::string constexpr Canonicalize() const override final {
[[nodiscard]] std::string Canonicalize() const override final {
if constexpr (std::is_enum_v<Type>) {
return CanonicalizeEnum(this->GetValue());
} else {
@ -256,11 +256,11 @@ public:
* @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
* @param other_setting_ A second Setting to associate to this one in metadata
*/
template <typename T = BasicSetting>
explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const std::string& name,
Category category_, u32 specialization_ = Specialization::Default,
bool save_ = true, bool runtime_modifiable_ = false,
BasicSetting* other_setting_ = nullptr)
requires(!ranged)
typename std::enable_if<!ranged, T*>::type other_setting_ = nullptr)
: Setting<Type, false>{
linkage, default_val, name, category_, specialization_,
save_, runtime_modifiable_, other_setting_} {
@ -282,12 +282,12 @@ public:
* @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
* @param other_setting_ A second Setting to associate to this one in metadata
*/
template <typename T = BasicSetting>
explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const Type& min_val,
const Type& max_val, const std::string& name, Category category_,
u32 specialization_ = Specialization::Default, bool save_ = true,
bool runtime_modifiable_ = false,
BasicSetting* other_setting_ = nullptr)
requires(ranged)
typename std::enable_if<ranged, T*>::type other_setting_ = nullptr)
: Setting<Type, true>{linkage, default_val, min_val,
max_val, name, category_,
specialization_, save_, runtime_modifiable_,

View File

@ -35,7 +35,7 @@ void RomFSFactory::SetPackedUpdate(VirtualFile update_raw_file) {
update_raw = std::move(update_raw_file);
}
ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_title_id) const {
VirtualFile RomFSFactory::OpenCurrentProcess(u64 current_process_title_id) const {
if (!updatable) {
return file;
}
@ -45,12 +45,11 @@ ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_titl
return patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw);
}
ResultVal<VirtualFile> RomFSFactory::OpenPatchedRomFS(u64 title_id, ContentRecordType type) const {
VirtualFile RomFSFactory::OpenPatchedRomFS(u64 title_id, ContentRecordType type) const {
auto nca = content_provider.GetEntry(title_id, type);
if (nca == nullptr) {
// TODO: Find the right error code to use here
return ResultUnknown;
return nullptr;
}
const PatchManager patch_manager{title_id, filesystem_controller, content_provider};
@ -58,28 +57,20 @@ ResultVal<VirtualFile> RomFSFactory::OpenPatchedRomFS(u64 title_id, ContentRecor
return patch_manager.PatchRomFS(nca->GetRomFS(), nca->GetBaseIVFCOffset(), type);
}
ResultVal<VirtualFile> RomFSFactory::OpenPatchedRomFSWithProgramIndex(
u64 title_id, u8 program_index, ContentRecordType type) const {
VirtualFile RomFSFactory::OpenPatchedRomFSWithProgramIndex(u64 title_id, u8 program_index,
ContentRecordType type) const {
const auto res_title_id = GetBaseTitleIDWithProgramIndex(title_id, program_index);
return OpenPatchedRomFS(res_title_id, type);
}
ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage,
ContentRecordType type) const {
VirtualFile RomFSFactory::Open(u64 title_id, StorageId storage, ContentRecordType type) const {
const std::shared_ptr<NCA> res = GetEntry(title_id, storage, type);
if (res == nullptr) {
// TODO(DarkLordZach): Find the right error code to use here
return ResultUnknown;
return nullptr;
}
const auto romfs = res->GetRomFS();
if (romfs == nullptr) {
// TODO(DarkLordZach): Find the right error code to use here
return ResultUnknown;
}
return romfs;
return res->GetRomFS();
}
std::shared_ptr<NCA> RomFSFactory::GetEntry(u64 title_id, StorageId storage,

View File

@ -41,13 +41,11 @@ public:
~RomFSFactory();
void SetPackedUpdate(VirtualFile update_raw_file);
[[nodiscard]] ResultVal<VirtualFile> OpenCurrentProcess(u64 current_process_title_id) const;
[[nodiscard]] ResultVal<VirtualFile> OpenPatchedRomFS(u64 title_id,
ContentRecordType type) const;
[[nodiscard]] ResultVal<VirtualFile> OpenPatchedRomFSWithProgramIndex(
u64 title_id, u8 program_index, ContentRecordType type) const;
[[nodiscard]] ResultVal<VirtualFile> Open(u64 title_id, StorageId storage,
ContentRecordType type) const;
[[nodiscard]] VirtualFile OpenCurrentProcess(u64 current_process_title_id) const;
[[nodiscard]] VirtualFile OpenPatchedRomFS(u64 title_id, ContentRecordType type) const;
[[nodiscard]] VirtualFile OpenPatchedRomFSWithProgramIndex(u64 title_id, u8 program_index,
ContentRecordType type) const;
[[nodiscard]] VirtualFile Open(u64 title_id, StorageId storage, ContentRecordType type) const;
private:
[[nodiscard]] std::shared_ptr<NCA> GetEntry(u64 title_id, StorageId storage,

View File

@ -108,26 +108,16 @@ SaveDataFactory::SaveDataFactory(Core::System& system_, VirtualDir save_director
SaveDataFactory::~SaveDataFactory() = default;
ResultVal<VirtualDir> SaveDataFactory::Create(SaveDataSpaceId space,
const SaveDataAttribute& meta) const {
VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
PrintSaveDataAttributeWarnings(meta);
const auto save_directory =
GetFullPath(system, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
auto out = dir->CreateDirectoryRelative(save_directory);
// Return an error if the save data doesn't actually exist.
if (out == nullptr) {
// TODO(DarkLordZach): Find out correct error code.
return ResultUnknown;
}
return out;
return dir->CreateDirectoryRelative(save_directory);
}
ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space,
const SaveDataAttribute& meta) const {
VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
const auto save_directory =
GetFullPath(system, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
@ -138,12 +128,6 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space,
return Create(space, meta);
}
// Return an error if the save data doesn't actually exist.
if (out == nullptr) {
// TODO(Subv): Find out correct error code.
return ResultUnknown;
}
return out;
}

View File

@ -89,8 +89,8 @@ public:
explicit SaveDataFactory(Core::System& system_, VirtualDir save_directory_);
~SaveDataFactory();
ResultVal<VirtualDir> Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const;
ResultVal<VirtualDir> Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const;
VirtualDir Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const;
VirtualDir Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const;
VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;

View File

@ -23,7 +23,7 @@ SDMCFactory::SDMCFactory(VirtualDir sd_dir_, VirtualDir sd_mod_dir_)
SDMCFactory::~SDMCFactory() = default;
ResultVal<VirtualDir> SDMCFactory::Open() const {
VirtualDir SDMCFactory::Open() const {
return sd_dir;
}

View File

@ -18,7 +18,7 @@ public:
explicit SDMCFactory(VirtualDir sd_dir_, VirtualDir sd_mod_dir_);
~SDMCFactory();
ResultVal<VirtualDir> Open() const;
VirtualDir Open() const;
VirtualDir GetSDMCModificationLoadRoot(u64 title_id) const;
VirtualDir GetSDMCContentDirectory() const;

View File

@ -768,7 +768,7 @@ Result KPageTable::UnmapProcessMemory(KProcessAddress dst_addr, size_t size,
m_memory_block_slab_manager, num_allocator_blocks);
R_TRY(allocator_result);
CASCADE_CODE(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap));
R_TRY(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap));
// Apply the memory block update.
m_memory_block_manager.Update(std::addressof(allocator), dst_addr, num_pages,

View File

@ -283,159 +283,6 @@ private:
u32 description_end;
};
/**
* This is an optional value type. It holds a `Result` and, if that code is ResultSuccess, it
* also holds a result of type `T`. If the code is an error code (not ResultSuccess), then trying
* to access the inner value with operator* is undefined behavior and will assert with Unwrap().
* Users of this class must be cognizant to check the status of the ResultVal with operator bool(),
* Code(), Succeeded() or Failed() prior to accessing the inner value.
*
* An example of how it could be used:
* \code
* ResultVal<int> Frobnicate(float strength) {
* if (strength < 0.f || strength > 1.0f) {
* // Can't frobnicate too weakly or too strongly
* return Result{ErrorModule::Common, 1};
* } else {
* // Frobnicated! Give caller a cookie
* return 42;
* }
* }
* \endcode
*
* \code
* auto frob_result = Frobnicate(0.75f);
* if (frob_result) {
* // Frobbed ok
* printf("My cookie is %d\n", *frob_result);
* } else {
* printf("Guess I overdid it. :( Error code: %ux\n", frob_result.Code().raw);
* }
* \endcode
*/
template <typename T>
class ResultVal {
public:
constexpr ResultVal() : expected{} {}
constexpr ResultVal(Result code) : expected{Common::Unexpected(code)} {}
constexpr ResultVal(ResultRange range) : expected{Common::Unexpected(range)} {}
template <typename U>
constexpr ResultVal(U&& val) : expected{std::forward<U>(val)} {}
template <typename... Args>
constexpr ResultVal(Args&&... args) : expected{std::in_place, std::forward<Args>(args)...} {}
~ResultVal() = default;
constexpr ResultVal(const ResultVal&) = default;
constexpr ResultVal(ResultVal&&) = default;
ResultVal& operator=(const ResultVal&) = default;
ResultVal& operator=(ResultVal&&) = default;
[[nodiscard]] constexpr explicit operator bool() const noexcept {
return expected.has_value();
}
[[nodiscard]] constexpr Result Code() const {
return expected.has_value() ? ResultSuccess : expected.error();
}
[[nodiscard]] constexpr bool Succeeded() const {
return expected.has_value();
}
[[nodiscard]] constexpr bool Failed() const {
return !expected.has_value();
}
[[nodiscard]] constexpr T* operator->() {
return std::addressof(expected.value());
}
[[nodiscard]] constexpr const T* operator->() const {
return std::addressof(expected.value());
}
[[nodiscard]] constexpr T& operator*() & {
return *expected;
}
[[nodiscard]] constexpr const T& operator*() const& {
return *expected;
}
[[nodiscard]] constexpr T&& operator*() && {
return *expected;
}
[[nodiscard]] constexpr const T&& operator*() const&& {
return *expected;
}
[[nodiscard]] constexpr T& Unwrap() & {
ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
return expected.value();
}
[[nodiscard]] constexpr const T& Unwrap() const& {
ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
return expected.value();
}
[[nodiscard]] constexpr T&& Unwrap() && {
ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
return std::move(expected.value());
}
[[nodiscard]] constexpr const T&& Unwrap() const&& {
ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
return std::move(expected.value());
}
template <typename U>
[[nodiscard]] constexpr T ValueOr(U&& v) const& {
return expected.value_or(v);
}
template <typename U>
[[nodiscard]] constexpr T ValueOr(U&& v) && {
return expected.value_or(v);
}
private:
// TODO (Morph): Replace this with C++23 std::expected.
Common::Expected<T, Result> expected;
};
/**
* Check for the success of `source` (which must evaluate to a ResultVal). If it succeeds, unwraps
* the contained value and assigns it to `target`, which can be either an l-value expression or a
* variable declaration. If it fails the return code is returned from the current function. Thus it
* can be used to cascade errors out, achieving something akin to exception handling.
*/
#define CASCADE_RESULT(target, source) \
auto CONCAT2(check_result_L, __LINE__) = source; \
if (CONCAT2(check_result_L, __LINE__).Failed()) { \
return CONCAT2(check_result_L, __LINE__).Code(); \
} \
target = std::move(*CONCAT2(check_result_L, __LINE__))
/**
* Analogous to CASCADE_RESULT, but for a bare Result. The code will be propagated if
* non-success, or discarded otherwise.
*/
#define CASCADE_CODE(source) \
do { \
auto CONCAT2(check_result_L, __LINE__) = source; \
if (CONCAT2(check_result_L, __LINE__).IsError()) { \
return CONCAT2(check_result_L, __LINE__); \
} \
} while (false)
#define R_SUCCEEDED(res) (static_cast<Result>(res).IsSuccess())
#define R_FAILED(res) (static_cast<Result>(res).IsFailure())

View File

@ -765,15 +765,16 @@ Result Module::Interface::InitializeApplicationInfoBase() {
// TODO(ogniK): This should be changed to reflect the target process for when we have multiple
// processes emulated. As we don't actually have pid support we should assume we're just using
// our own process
const auto launch_property =
system.GetARPManager().GetLaunchProperty(system.GetApplicationProcessProgramID());
Glue::ApplicationLaunchProperty launch_property{};
const auto result = system.GetARPManager().GetLaunchProperty(
&launch_property, system.GetApplicationProcessProgramID());
if (launch_property.Failed()) {
if (result != ResultSuccess) {
LOG_ERROR(Service_ACC, "Failed to get launch property");
return Account::ResultInvalidApplication;
}
switch (launch_property->base_game_storage_id) {
switch (launch_property.base_game_storage_id) {
case FileSys::StorageId::GameCard:
application_info.application_type = ApplicationType::GameCard;
break;
@ -785,7 +786,7 @@ Result Module::Interface::InitializeApplicationInfoBase() {
break;
default:
LOG_ERROR(Service_ACC, "Invalid game storage ID! storage_id={}",
launch_property->base_game_storage_id);
launch_property.base_game_storage_id);
return Account::ResultInvalidApplication;
}

View File

@ -1578,11 +1578,13 @@ void IApplicationFunctions::EnsureSaveData(HLERequestContext& ctx) {
attribute.title_id = system.GetApplicationProcessProgramID();
attribute.user_id = user_id;
attribute.type = FileSys::SaveDataType::SaveData;
FileSys::VirtualDir save_data{};
const auto res = system.GetFileSystemController().CreateSaveData(
FileSys::SaveDataSpaceId::NandUser, attribute);
&save_data, FileSys::SaveDataSpaceId::NandUser, attribute);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(res.Code());
rb.Push(res);
rb.Push<u64>(0);
}
@ -1667,26 +1669,30 @@ void IApplicationFunctions::GetDesiredLanguage(HLERequestContext& ctx) {
auto app_man = ns_am2->GetApplicationManagerInterface();
// Get desired application language
const auto res_lang = app_man->GetApplicationDesiredLanguage(supported_languages);
if (res_lang.Failed()) {
u8 desired_language{};
const auto res_lang =
app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages);
if (res_lang != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res_lang.Code());
rb.Push(res_lang);
return;
}
// Convert to settings language code.
const auto res_code = app_man->ConvertApplicationLanguageToLanguageCode(*res_lang);
if (res_code.Failed()) {
u64 language_code{};
const auto res_code =
app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language);
if (res_code != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res_code.Code());
rb.Push(res_code);
return;
}
LOG_DEBUG(Service_AM, "got desired_language={:016X}", *res_code);
LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(*res_code);
rb.Push(language_code);
}
void IApplicationFunctions::IsGamePlayRecordingSupported(HLERequestContext& ctx) {

View File

@ -22,13 +22,13 @@ AudCtl::AudCtl(Core::System& system_) : ServiceFramework{system_, "audctl"} {
{9, nullptr, "GetAudioOutputMode"},
{10, nullptr, "SetAudioOutputMode"},
{11, nullptr, "SetForceMutePolicy"},
{12, nullptr, "GetForceMutePolicy"},
{13, nullptr, "GetOutputModeSetting"},
{12, &AudCtl::GetForceMutePolicy, "GetForceMutePolicy"},
{13, &AudCtl::GetOutputModeSetting, "GetOutputModeSetting"},
{14, nullptr, "SetOutputModeSetting"},
{15, nullptr, "SetOutputTarget"},
{16, nullptr, "SetInputTargetForceEnabled"},
{17, nullptr, "SetHeadphoneOutputLevelMode"},
{18, nullptr, "GetHeadphoneOutputLevelMode"},
{18, &AudCtl::GetHeadphoneOutputLevelMode, "GetHeadphoneOutputLevelMode"},
{19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"},
{20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"},
{21, nullptr, "GetAudioOutputTargetForPlayReport"},
@ -41,7 +41,7 @@ AudCtl::AudCtl(Core::System& system_) : ServiceFramework{system_, "audctl"} {
{28, nullptr, "GetAudioOutputChannelCountForPlayReport"},
{29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"},
{30, nullptr, "SetSpeakerAutoMuteEnabled"},
{31, nullptr, "IsSpeakerAutoMuteEnabled"},
{31, &AudCtl::IsSpeakerAutoMuteEnabled, "IsSpeakerAutoMuteEnabled"},
{32, nullptr, "GetActiveOutputTarget"},
{33, nullptr, "GetTargetDeviceInfo"},
{34, nullptr, "AcquireTargetNotification"},
@ -96,4 +96,42 @@ void AudCtl::GetTargetVolumeMax(HLERequestContext& ctx) {
rb.Push(target_max_volume);
}
void AudCtl::GetForceMutePolicy(HLERequestContext& ctx) {
LOG_WARNING(Audio, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(ForceMutePolicy::Disable);
}
void AudCtl::GetOutputModeSetting(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto value = rp.Pop<u32>();
LOG_WARNING(Audio, "(STUBBED) called, value={}", value);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(AudioOutputMode::PcmAuto);
}
void AudCtl::GetHeadphoneOutputLevelMode(HLERequestContext& ctx) {
LOG_WARNING(Audio, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(HeadphoneOutputLevelMode::Normal);
}
void AudCtl::IsSpeakerAutoMuteEnabled(HLERequestContext& ctx) {
const bool is_speaker_auto_mute_enabled = false;
LOG_WARNING(Audio, "(STUBBED) called, is_speaker_auto_mute_enabled={}",
is_speaker_auto_mute_enabled);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(is_speaker_auto_mute_enabled);
}
} // namespace Service::Audio

View File

@ -17,8 +17,30 @@ public:
~AudCtl() override;
private:
enum class AudioOutputMode {
Invalid,
Pcm1ch,
Pcm2ch,
Pcm6ch,
PcmAuto,
};
enum class ForceMutePolicy {
Disable,
SpeakerMuteOnHeadphoneUnplugged,
};
enum class HeadphoneOutputLevelMode {
Normal,
HighPower,
};
void GetTargetVolumeMin(HLERequestContext& ctx);
void GetTargetVolumeMax(HLERequestContext& ctx);
void GetForceMutePolicy(HLERequestContext& ctx);
void GetOutputModeSetting(HLERequestContext& ctx);
void GetHeadphoneOutputLevelMode(HLERequestContext& ctx);
void IsSpeakerAutoMuteEnabled(HLERequestContext& ctx);
};
} // namespace Service::Audio

View File

@ -57,8 +57,8 @@ Result VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 size
return FileSys::ERROR_PATH_NOT_FOUND;
}
const auto entry_type = GetEntryType(path);
if (entry_type.Code() == ResultSuccess) {
FileSys::EntryType entry_type{};
if (GetEntryType(&entry_type, path) == ResultSuccess) {
return FileSys::ERROR_PATH_ALREADY_EXISTS;
}
@ -210,8 +210,8 @@ Result VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path_,
return ResultUnknown;
}
ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::string& path_,
FileSys::Mode mode) const {
Result VfsDirectoryServiceWrapper::OpenFile(FileSys::VirtualFile* out_file,
const std::string& path_, FileSys::Mode mode) const {
const std::string path(Common::FS::SanitizePath(path_));
std::string_view npath = path;
while (!npath.empty() && (npath[0] == '/' || npath[0] == '\\')) {
@ -224,50 +224,68 @@ ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::
}
if (mode == FileSys::Mode::Append) {
return std::make_shared<FileSys::OffsetVfsFile>(file, 0, file->GetSize());
*out_file = std::make_shared<FileSys::OffsetVfsFile>(file, 0, file->GetSize());
} else {
*out_file = file;
}
return file;
return ResultSuccess;
}
ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const std::string& path_) {
Result VfsDirectoryServiceWrapper::OpenDirectory(FileSys::VirtualDir* out_directory,
const std::string& path_) {
std::string path(Common::FS::SanitizePath(path_));
auto dir = GetDirectoryRelativeWrapped(backing, path);
if (dir == nullptr) {
// TODO(DarkLordZach): Find a better error code for this
return FileSys::ERROR_PATH_NOT_FOUND;
}
return dir;
*out_directory = dir;
return ResultSuccess;
}
ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
const std::string& path_) const {
Result VfsDirectoryServiceWrapper::GetEntryType(FileSys::EntryType* out_entry_type,
const std::string& path_) const {
std::string path(Common::FS::SanitizePath(path_));
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
if (dir == nullptr)
return FileSys::ERROR_PATH_NOT_FOUND;
auto filename = Common::FS::GetFilename(path);
// TODO(Subv): Some games use the '/' path, find out what this means.
if (filename.empty())
return FileSys::EntryType::Directory;
if (dir->GetFile(filename) != nullptr)
return FileSys::EntryType::File;
if (dir->GetSubdirectory(filename) != nullptr)
return FileSys::EntryType::Directory;
return FileSys::ERROR_PATH_NOT_FOUND;
}
ResultVal<FileSys::FileTimeStampRaw> VfsDirectoryServiceWrapper::GetFileTimeStampRaw(
const std::string& path) const {
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
if (dir == nullptr) {
return FileSys::ERROR_PATH_NOT_FOUND;
}
if (GetEntryType(path).Failed()) {
auto filename = Common::FS::GetFilename(path);
// TODO(Subv): Some games use the '/' path, find out what this means.
if (filename.empty()) {
*out_entry_type = FileSys::EntryType::Directory;
return ResultSuccess;
}
if (dir->GetFile(filename) != nullptr) {
*out_entry_type = FileSys::EntryType::File;
return ResultSuccess;
}
if (dir->GetSubdirectory(filename) != nullptr) {
*out_entry_type = FileSys::EntryType::Directory;
return ResultSuccess;
}
return FileSys::ERROR_PATH_NOT_FOUND;
}
Result VfsDirectoryServiceWrapper::GetFileTimeStampRaw(
FileSys::FileTimeStampRaw* out_file_time_stamp_raw, const std::string& path) const {
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
if (dir == nullptr) {
return FileSys::ERROR_PATH_NOT_FOUND;
}
return dir->GetFileTimeStamp(Common::FS::GetFilename(path));
FileSys::EntryType entry_type;
if (GetEntryType(&entry_type, path) != ResultSuccess) {
return FileSys::ERROR_PATH_NOT_FOUND;
}
*out_file_time_stamp_raw = dir->GetFileTimeStamp(Common::FS::GetFilename(path));
return ResultSuccess;
}
FileSystemController::FileSystemController(Core::System& system_) : system{system_} {}
@ -310,57 +328,54 @@ void FileSystemController::SetPackedUpdate(FileSys::VirtualFile update_raw) {
romfs_factory->SetPackedUpdate(std::move(update_raw));
}
ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFSCurrentProcess() const {
FileSys::VirtualFile FileSystemController::OpenRomFSCurrentProcess() const {
LOG_TRACE(Service_FS, "Opening RomFS for current process");
if (romfs_factory == nullptr) {
// TODO(bunnei): Find a better error code for this
return ResultUnknown;
return nullptr;
}
return romfs_factory->OpenCurrentProcess(system.GetApplicationProcessProgramID());
}
ResultVal<FileSys::VirtualFile> FileSystemController::OpenPatchedRomFS(
u64 title_id, FileSys::ContentRecordType type) const {
FileSys::VirtualFile FileSystemController::OpenPatchedRomFS(u64 title_id,
FileSys::ContentRecordType type) const {
LOG_TRACE(Service_FS, "Opening patched RomFS for title_id={:016X}", title_id);
if (romfs_factory == nullptr) {
// TODO: Find a better error code for this
return ResultUnknown;
return nullptr;
}
return romfs_factory->OpenPatchedRomFS(title_id, type);
}
ResultVal<FileSys::VirtualFile> FileSystemController::OpenPatchedRomFSWithProgramIndex(
FileSys::VirtualFile FileSystemController::OpenPatchedRomFSWithProgramIndex(
u64 title_id, u8 program_index, FileSys::ContentRecordType type) const {
LOG_TRACE(Service_FS, "Opening patched RomFS for title_id={:016X}, program_index={}", title_id,
program_index);
if (romfs_factory == nullptr) {
// TODO: Find a better error code for this
return ResultUnknown;
return nullptr;
}
return romfs_factory->OpenPatchedRomFSWithProgramIndex(title_id, program_index, type);
}
ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFS(
u64 title_id, FileSys::StorageId storage_id, FileSys::ContentRecordType type) const {
FileSys::VirtualFile FileSystemController::OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
FileSys::ContentRecordType type) const {
LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}, storage_id={:02X}, type={:02X}",
title_id, storage_id, type);
if (romfs_factory == nullptr) {
// TODO(bunnei): Find a better error code for this
return ResultUnknown;
return nullptr;
}
return romfs_factory->Open(title_id, storage_id, type);
}
ResultVal<FileSys::VirtualDir> FileSystemController::CreateSaveData(
FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& save_struct) const {
Result FileSystemController::CreateSaveData(FileSys::VirtualDir* out_save_data,
FileSys::SaveDataSpaceId space,
const FileSys::SaveDataAttribute& save_struct) const {
LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}", space,
save_struct.DebugInfo());
@ -368,11 +383,18 @@ ResultVal<FileSys::VirtualDir> FileSystemController::CreateSaveData(
return FileSys::ERROR_ENTITY_NOT_FOUND;
}
return save_data_factory->Create(space, save_struct);
auto save_data = save_data_factory->Create(space, save_struct);
if (save_data == nullptr) {
return FileSys::ERROR_ENTITY_NOT_FOUND;
}
*out_save_data = save_data;
return ResultSuccess;
}
ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveData(
FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& attribute) const {
Result FileSystemController::OpenSaveData(FileSys::VirtualDir* out_save_data,
FileSys::SaveDataSpaceId space,
const FileSys::SaveDataAttribute& attribute) const {
LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}", space,
attribute.DebugInfo());
@ -380,32 +402,50 @@ ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveData(
return FileSys::ERROR_ENTITY_NOT_FOUND;
}
return save_data_factory->Open(space, attribute);
auto save_data = save_data_factory->Open(space, attribute);
if (save_data == nullptr) {
return FileSys::ERROR_ENTITY_NOT_FOUND;
}
*out_save_data = save_data;
return ResultSuccess;
}
ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveDataSpace(
FileSys::SaveDataSpaceId space) const {
Result FileSystemController::OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space,
FileSys::SaveDataSpaceId space) const {
LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", space);
if (save_data_factory == nullptr) {
return FileSys::ERROR_ENTITY_NOT_FOUND;
}
return save_data_factory->GetSaveDataSpaceDirectory(space);
auto save_data_space = save_data_factory->GetSaveDataSpaceDirectory(space);
if (save_data_space == nullptr) {
return FileSys::ERROR_ENTITY_NOT_FOUND;
}
*out_save_data_space = save_data_space;
return ResultSuccess;
}
ResultVal<FileSys::VirtualDir> FileSystemController::OpenSDMC() const {
Result FileSystemController::OpenSDMC(FileSys::VirtualDir* out_sdmc) const {
LOG_TRACE(Service_FS, "Opening SDMC");
if (sdmc_factory == nullptr) {
return FileSys::ERROR_SD_CARD_NOT_FOUND;
}
return sdmc_factory->Open();
auto sdmc = sdmc_factory->Open();
if (sdmc == nullptr) {
return FileSys::ERROR_SD_CARD_NOT_FOUND;
}
*out_sdmc = sdmc;
return ResultSuccess;
}
ResultVal<FileSys::VirtualDir> FileSystemController::OpenBISPartition(
FileSys::BisPartitionId id) const {
Result FileSystemController::OpenBISPartition(FileSys::VirtualDir* out_bis_partition,
FileSys::BisPartitionId id) const {
LOG_TRACE(Service_FS, "Opening BIS Partition with id={:08X}", id);
if (bis_factory == nullptr) {
@ -417,11 +457,12 @@ ResultVal<FileSys::VirtualDir> FileSystemController::OpenBISPartition(
return FileSys::ERROR_INVALID_ARGUMENT;
}
return part;
*out_bis_partition = part;
return ResultSuccess;
}
ResultVal<FileSys::VirtualFile> FileSystemController::OpenBISPartitionStorage(
FileSys::BisPartitionId id) const {
Result FileSystemController::OpenBISPartitionStorage(
FileSys::VirtualFile* out_bis_partition_storage, FileSys::BisPartitionId id) const {
LOG_TRACE(Service_FS, "Opening BIS Partition Storage with id={:08X}", id);
if (bis_factory == nullptr) {
@ -433,7 +474,8 @@ ResultVal<FileSys::VirtualFile> FileSystemController::OpenBISPartitionStorage(
return FileSys::ERROR_INVALID_ARGUMENT;
}
return part;
*out_bis_partition_storage = part;
return ResultSuccess;
}
u64 FileSystemController::GetFreeSpaceSize(FileSys::StorageId id) const {

View File

@ -64,21 +64,24 @@ public:
Result RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory);
void SetPackedUpdate(FileSys::VirtualFile update_raw);
ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() const;
ResultVal<FileSys::VirtualFile> OpenPatchedRomFS(u64 title_id,
FileSys::ContentRecordType type) const;
ResultVal<FileSys::VirtualFile> OpenPatchedRomFSWithProgramIndex(
u64 title_id, u8 program_index, FileSys::ContentRecordType type) const;
ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
FileSys::ContentRecordType type) const;
ResultVal<FileSys::VirtualDir> CreateSaveData(
FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& save_struct) const;
ResultVal<FileSys::VirtualDir> OpenSaveData(
FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& save_struct) const;
ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) const;
ResultVal<FileSys::VirtualDir> OpenSDMC() const;
ResultVal<FileSys::VirtualDir> OpenBISPartition(FileSys::BisPartitionId id) const;
ResultVal<FileSys::VirtualFile> OpenBISPartitionStorage(FileSys::BisPartitionId id) const;
FileSys::VirtualFile OpenRomFSCurrentProcess() const;
FileSys::VirtualFile OpenPatchedRomFS(u64 title_id, FileSys::ContentRecordType type) const;
FileSys::VirtualFile OpenPatchedRomFSWithProgramIndex(u64 title_id, u8 program_index,
FileSys::ContentRecordType type) const;
FileSys::VirtualFile OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
FileSys::ContentRecordType type) const;
Result CreateSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space,
const FileSys::SaveDataAttribute& save_struct) const;
Result OpenSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space,
const FileSys::SaveDataAttribute& save_struct) const;
Result OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space,
FileSys::SaveDataSpaceId space) const;
Result OpenSDMC(FileSys::VirtualDir* out_sdmc) const;
Result OpenBISPartition(FileSys::VirtualDir* out_bis_partition,
FileSys::BisPartitionId id) const;
Result OpenBISPartitionStorage(FileSys::VirtualFile* out_bis_partition_storage,
FileSys::BisPartitionId id) const;
u64 GetFreeSpaceSize(FileSys::StorageId id) const;
u64 GetTotalSpaceSize(FileSys::StorageId id) const;
@ -224,26 +227,28 @@ public:
* @param mode Mode to open the file with
* @return Opened file, or error code
*/
ResultVal<FileSys::VirtualFile> OpenFile(const std::string& path, FileSys::Mode mode) const;
Result OpenFile(FileSys::VirtualFile* out_file, const std::string& path,
FileSys::Mode mode) const;
/**
* Open a directory specified by its path
* @param path Path relative to the archive
* @return Opened directory, or error code
*/
ResultVal<FileSys::VirtualDir> OpenDirectory(const std::string& path);
Result OpenDirectory(FileSys::VirtualDir* out_directory, const std::string& path);
/**
* Get the type of the specified path
* @return The type of the specified path or error code
*/
ResultVal<FileSys::EntryType> GetEntryType(const std::string& path) const;
Result GetEntryType(FileSys::EntryType* out_entry_type, const std::string& path) const;
/**
* Get the timestamp of the specified path
* @return The timestamp of the specified path or error code
*/
ResultVal<FileSys::FileTimeStampRaw> GetFileTimeStampRaw(const std::string& path) const;
Result GetFileTimeStampRaw(FileSys::FileTimeStampRaw* out_time_stamp_raw,
const std::string& path) const;
private:
FileSys::VirtualDir backing;

View File

@ -419,14 +419,15 @@ public:
LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode);
auto result = backend.OpenFile(name, mode);
if (result.Failed()) {
FileSys::VirtualFile vfs_file{};
auto result = backend.OpenFile(&vfs_file, name, mode);
if (result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result.Code());
rb.Push(result);
return;
}
auto file = std::make_shared<IFile>(system, result.Unwrap());
auto file = std::make_shared<IFile>(system, vfs_file);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
@ -444,14 +445,15 @@ public:
LOG_DEBUG(Service_FS, "called. directory={}, filter={}", name, filter_flags);
auto result = backend.OpenDirectory(name);
if (result.Failed()) {
FileSys::VirtualDir vfs_dir{};
auto result = backend.OpenDirectory(&vfs_dir, name);
if (result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result.Code());
rb.Push(result);
return;
}
auto directory = std::make_shared<IDirectory>(system, result.Unwrap());
auto directory = std::make_shared<IDirectory>(system, vfs_dir);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
@ -464,16 +466,17 @@ public:
LOG_DEBUG(Service_FS, "called. file={}", name);
auto result = backend.GetEntryType(name);
if (result.Failed()) {
FileSys::EntryType vfs_entry_type{};
auto result = backend.GetEntryType(&vfs_entry_type, name);
if (result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result.Code());
rb.Push(result);
return;
}
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(static_cast<u32>(*result));
rb.Push<u32>(static_cast<u32>(vfs_entry_type));
}
void Commit(HLERequestContext& ctx) {
@ -505,16 +508,17 @@ public:
LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", name);
auto result = backend.GetFileTimeStampRaw(name);
if (result.Failed()) {
FileSys::FileTimeStampRaw vfs_timestamp{};
auto result = backend.GetFileTimeStampRaw(&vfs_timestamp, name);
if (result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result.Code());
rb.Push(result);
return;
}
IPC::ResponseBuilder rb{ctx, 10};
rb.Push(ResultSuccess);
rb.PushRaw(*result);
rb.PushRaw(vfs_timestamp);
}
private:
@ -572,14 +576,15 @@ private:
}
void FindAllSaves(FileSys::SaveDataSpaceId space) {
const auto save_root = fsc.OpenSaveDataSpace(space);
FileSys::VirtualDir save_root{};
const auto result = fsc.OpenSaveDataSpace(&save_root, space);
if (save_root.Failed() || *save_root == nullptr) {
if (result != ResultSuccess || save_root == nullptr) {
LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space);
return;
}
for (const auto& type : (*save_root)->GetSubdirectories()) {
for (const auto& type : save_root->GetSubdirectories()) {
if (type->GetName() == "save") {
for (const auto& save_id : type->GetSubdirectories()) {
for (const auto& user_id : save_id->GetSubdirectories()) {
@ -837,9 +842,11 @@ void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) {
void FSP_SRV::OpenSdCardFileSystem(HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
auto filesystem =
std::make_shared<IFileSystem>(system, fsc.OpenSDMC().Unwrap(),
SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
FileSys::VirtualDir sdmc_dir{};
fsc.OpenSDMC(&sdmc_dir);
auto filesystem = std::make_shared<IFileSystem>(
system, sdmc_dir, SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
@ -856,7 +863,8 @@ void FSP_SRV::CreateSaveDataFileSystem(HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(),
uid[1], uid[0]);
fsc.CreateSaveData(FileSys::SaveDataSpaceId::NandUser, save_struct);
FileSys::VirtualDir save_data_dir{};
fsc.CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandUser, save_struct);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@ -874,8 +882,9 @@ void FSP_SRV::OpenSaveDataFileSystem(HLERequestContext& ctx) {
LOG_INFO(Service_FS, "called.");
auto dir = fsc.OpenSaveData(parameters.space_id, parameters.attribute);
if (dir.Failed()) {
FileSys::VirtualDir dir{};
auto result = fsc.OpenSaveData(&dir, parameters.space_id, parameters.attribute);
if (result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
return;
@ -899,8 +908,8 @@ void FSP_SRV::OpenSaveDataFileSystem(HLERequestContext& ctx) {
ASSERT(false);
}
auto filesystem = std::make_shared<IFileSystem>(system, std::move(dir.Unwrap()),
SizeGetter::FromStorageId(fsc, id));
auto filesystem =
std::make_shared<IFileSystem>(system, std::move(dir), SizeGetter::FromStorageId(fsc, id));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
@ -970,7 +979,7 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(HLERequestContext& ctx) {
if (!romfs) {
auto current_romfs = fsc.OpenRomFSCurrentProcess();
if (current_romfs.Failed()) {
if (!current_romfs) {
// TODO (bunnei): Find the right error code to use here
LOG_CRITICAL(Service_FS, "no file system interface available!");
IPC::ResponseBuilder rb{ctx, 2};
@ -978,7 +987,7 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(HLERequestContext& ctx) {
return;
}
romfs = current_romfs.Unwrap();
romfs = current_romfs;
}
auto storage = std::make_shared<IStorage>(system, romfs);
@ -999,7 +1008,7 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
auto data = fsc.OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
if (data.Failed()) {
if (!data) {
const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
if (archive != nullptr) {
@ -1021,7 +1030,7 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
const FileSys::PatchManager pm{title_id, fsc, content_provider};
auto storage = std::make_shared<IStorage>(
system, pm.PatchRomFS(std::move(data.Unwrap()), 0, FileSys::ContentRecordType::Data));
system, pm.PatchRomFS(std::move(data), 0, FileSys::ContentRecordType::Data));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
@ -1051,7 +1060,7 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) {
fsc.OpenPatchedRomFSWithProgramIndex(system.GetApplicationProcessProgramID(), program_index,
FileSys::ContentRecordType::Program);
if (patched_romfs.Failed()) {
if (!patched_romfs) {
// TODO: Find the right error code to use here
LOG_ERROR(Service_FS, "could not open storage with program_index={}", program_index);
@ -1060,7 +1069,7 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) {
return;
}
auto storage = std::make_shared<IStorage>(system, std::move(patched_romfs.Unwrap()));
auto storage = std::make_shared<IStorage>(system, std::move(patched_romfs));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);

View File

@ -65,18 +65,19 @@ void ARP_R::GetApplicationLaunchProperty(HLERequestContext& ctx) {
return;
}
const auto res = manager.GetLaunchProperty(*title_id);
ApplicationLaunchProperty launch_property{};
const auto res = manager.GetLaunchProperty(&launch_property, *title_id);
if (res.Failed()) {
if (res != ResultSuccess) {
LOG_ERROR(Service_ARP, "Failed to get launch property!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res.Code());
rb.Push(res);
return;
}
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.PushRaw(*res);
rb.PushRaw(launch_property);
}
void ARP_R::GetApplicationLaunchPropertyWithApplicationId(HLERequestContext& ctx) {
@ -85,18 +86,19 @@ void ARP_R::GetApplicationLaunchPropertyWithApplicationId(HLERequestContext& ctx
LOG_DEBUG(Service_ARP, "called, title_id={:016X}", title_id);
const auto res = manager.GetLaunchProperty(title_id);
ApplicationLaunchProperty launch_property{};
const auto res = manager.GetLaunchProperty(&launch_property, title_id);
if (res.Failed()) {
if (res != ResultSuccess) {
LOG_ERROR(Service_ARP, "Failed to get launch property!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res.Code());
rb.Push(res);
return;
}
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.PushRaw(*res);
rb.PushRaw(launch_property);
}
void ARP_R::GetApplicationControlProperty(HLERequestContext& ctx) {
@ -113,16 +115,17 @@ void ARP_R::GetApplicationControlProperty(HLERequestContext& ctx) {
return;
}
const auto res = manager.GetControlProperty(*title_id);
std::vector<u8> nacp_data;
const auto res = manager.GetControlProperty(&nacp_data, *title_id);
if (res.Failed()) {
if (res != ResultSuccess) {
LOG_ERROR(Service_ARP, "Failed to get control property!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res.Code());
rb.Push(res);
return;
}
ctx.WriteBuffer(*res);
ctx.WriteBuffer(nacp_data);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@ -134,16 +137,17 @@ void ARP_R::GetApplicationControlPropertyWithApplicationId(HLERequestContext& ct
LOG_DEBUG(Service_ARP, "called, title_id={:016X}", title_id);
const auto res = manager.GetControlProperty(title_id);
std::vector<u8> nacp_data;
const auto res = manager.GetControlProperty(&nacp_data, title_id);
if (res.Failed()) {
if (res != ResultSuccess) {
LOG_ERROR(Service_ARP, "Failed to get control property!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res.Code());
rb.Push(res);
return;
}
ctx.WriteBuffer(*res);
ctx.WriteBuffer(nacp_data);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);

View File

@ -15,7 +15,8 @@ ARPManager::ARPManager() = default;
ARPManager::~ARPManager() = default;
ResultVal<ApplicationLaunchProperty> ARPManager::GetLaunchProperty(u64 title_id) const {
Result ARPManager::GetLaunchProperty(ApplicationLaunchProperty* out_launch_property,
u64 title_id) const {
if (title_id == 0) {
return Glue::ResultInvalidProcessId;
}
@ -25,10 +26,11 @@ ResultVal<ApplicationLaunchProperty> ARPManager::GetLaunchProperty(u64 title_id)
return Glue::ResultProcessIdNotRegistered;
}
return iter->second.launch;
*out_launch_property = iter->second.launch;
return ResultSuccess;
}
ResultVal<std::vector<u8>> ARPManager::GetControlProperty(u64 title_id) const {
Result ARPManager::GetControlProperty(std::vector<u8>* out_control_property, u64 title_id) const {
if (title_id == 0) {
return Glue::ResultInvalidProcessId;
}
@ -38,7 +40,8 @@ ResultVal<std::vector<u8>> ARPManager::GetControlProperty(u64 title_id) const {
return Glue::ResultProcessIdNotRegistered;
}
return iter->second.control;
*out_control_property = iter->second.control;
return ResultSuccess;
}
Result ARPManager::Register(u64 title_id, ApplicationLaunchProperty launch,

View File

@ -32,12 +32,12 @@ public:
// Returns the ApplicationLaunchProperty corresponding to the provided title ID if it was
// previously registered, otherwise ResultProcessIdNotRegistered if it was never registered or
// ResultInvalidProcessId if the title ID is 0.
ResultVal<ApplicationLaunchProperty> GetLaunchProperty(u64 title_id) const;
Result GetLaunchProperty(ApplicationLaunchProperty* out_launch_property, u64 title_id) const;
// Returns a vector of the raw bytes of NACP data (necessarily 0x4000 in size) corresponding to
// the provided title ID if it was previously registered, otherwise ResultProcessIdNotRegistered
// if it was never registered or ResultInvalidProcessId if the title ID is 0.
ResultVal<std::vector<u8>> GetControlProperty(u64 title_id) const;
Result GetControlProperty(std::vector<u8>* out_control_property, u64 title_id) const;
// Adds a new entry to the internal database with the provided parameters, returning
// ResultProcessIdNotRegistered if attempting to re-register a title ID without an intermediate

View File

@ -357,7 +357,8 @@ public:
return ResultSuccess;
}
ResultVal<VAddr> MapProcessCodeMemory(Kernel::KProcess* process, VAddr base_addr, u64 size) {
Result MapProcessCodeMemory(VAddr* out_map_location, Kernel::KProcess* process, VAddr base_addr,
u64 size) {
auto& page_table{process->GetPageTable()};
VAddr addr{};
@ -372,20 +373,21 @@ public:
R_TRY(result);
if (ValidateRegionForMap(page_table, addr, size)) {
return addr;
*out_map_location = addr;
return ResultSuccess;
}
}
return ERROR_INSUFFICIENT_ADDRESS_SPACE;
}
ResultVal<VAddr> MapNro(Kernel::KProcess* process, VAddr nro_addr, std::size_t nro_size,
VAddr bss_addr, std::size_t bss_size, std::size_t size) {
Result MapNro(VAddr* out_map_location, Kernel::KProcess* process, VAddr nro_addr,
std::size_t nro_size, VAddr bss_addr, std::size_t bss_size, std::size_t size) {
for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) {
auto& page_table{process->GetPageTable()};
VAddr addr{};
CASCADE_RESULT(addr, MapProcessCodeMemory(process, nro_addr, nro_size));
R_TRY(MapProcessCodeMemory(&addr, process, nro_addr, nro_size));
if (bss_size) {
auto block_guard = detail::ScopeExit([&] {
@ -411,7 +413,8 @@ public:
}
if (ValidateRegionForMap(page_table, addr, size)) {
return addr;
*out_map_location = addr;
return ResultSuccess;
}
}
@ -437,9 +440,9 @@ public:
CopyCode(nro_addr + nro_header.segment_headers[DATA_INDEX].memory_offset, data_start,
nro_header.segment_headers[DATA_INDEX].memory_size);
CASCADE_CODE(process->GetPageTable().SetProcessMemoryPermission(
R_TRY(process->GetPageTable().SetProcessMemoryPermission(
text_start, ro_start - text_start, Kernel::Svc::MemoryPermission::ReadExecute));
CASCADE_CODE(process->GetPageTable().SetProcessMemoryPermission(
R_TRY(process->GetPageTable().SetProcessMemoryPermission(
ro_start, data_start - ro_start, Kernel::Svc::MemoryPermission::Read));
return process->GetPageTable().SetProcessMemoryPermission(
@ -542,31 +545,32 @@ public:
}
// Map memory for the NRO
const auto map_result{MapNro(system.ApplicationProcess(), nro_address, nro_size,
bss_address, bss_size, nro_size + bss_size)};
if (map_result.Failed()) {
VAddr map_location{};
const auto map_result{MapNro(&map_location, system.ApplicationProcess(), nro_address,
nro_size, bss_address, bss_size, nro_size + bss_size)};
if (map_result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(map_result.Code());
rb.Push(map_result);
}
// Load the NRO into the mapped memory
if (const auto result{
LoadNro(system.ApplicationProcess(), header, nro_address, *map_result)};
LoadNro(system.ApplicationProcess(), header, nro_address, map_location)};
result.IsError()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(map_result.Code());
rb.Push(result);
}
// Track the loaded NRO
nro.insert_or_assign(*map_result,
NROInfo{hash, *map_result, nro_size, bss_address, bss_size,
nro.insert_or_assign(map_location,
NROInfo{hash, map_location, nro_size, bss_address, bss_size,
header.segment_headers[TEXT_INDEX].memory_size,
header.segment_headers[RO_INDEX].memory_size,
header.segment_headers[DATA_INDEX].memory_size, nro_address});
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(*map_result);
rb.Push(map_location);
}
Result UnmapNro(const NROInfo& info) {
@ -574,19 +578,19 @@ public:
auto& page_table{system.ApplicationProcess()->GetPageTable()};
if (info.bss_size != 0) {
CASCADE_CODE(page_table.UnmapCodeMemory(
R_TRY(page_table.UnmapCodeMemory(
info.nro_address + info.text_size + info.ro_size + info.data_size, info.bss_address,
info.bss_size, Kernel::KPageTable::ICacheInvalidationStrategy::InvalidateRange));
}
CASCADE_CODE(page_table.UnmapCodeMemory(
R_TRY(page_table.UnmapCodeMemory(
info.nro_address + info.text_size + info.ro_size,
info.src_addr + info.text_size + info.ro_size, info.data_size,
Kernel::KPageTable::ICacheInvalidationStrategy::InvalidateRange));
CASCADE_CODE(page_table.UnmapCodeMemory(
R_TRY(page_table.UnmapCodeMemory(
info.nro_address + info.text_size, info.src_addr + info.text_size, info.ro_size,
Kernel::KPageTable::ICacheInvalidationStrategy::InvalidateRange));
CASCADE_CODE(page_table.UnmapCodeMemory(
R_TRY(page_table.UnmapCodeMemory(
info.nro_address, info.src_addr, info.text_size,
Kernel::KPageTable::ICacheInvalidationStrategy::InvalidateRange));
return ResultSuccess;

View File

@ -101,20 +101,14 @@ private:
LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
const auto result{manager.GetDefault(source_flag)};
if (result.Failed()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result.Code());
return;
}
if (result->size() > 0) {
ctx.WriteBuffer(SerializeArray(*result));
const auto default_miis{manager.GetDefault(source_flag)};
if (default_miis.size() > 0) {
ctx.WriteBuffer(SerializeArray(default_miis));
}
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(static_cast<u32>(result->size()));
rb.Push<u32>(static_cast<u32>(default_miis.size()));
}
void Get1(HLERequestContext& ctx) {
@ -123,15 +117,10 @@ private:
LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
const auto result{manager.GetDefault(source_flag)};
if (result.Failed()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result.Code());
return;
}
const auto default_miis{manager.GetDefault(source_flag)};
std::vector<CharInfo> values;
for (const auto& element : *result) {
for (const auto& element : default_miis) {
values.emplace_back(element.info);
}
@ -139,7 +128,7 @@ private:
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(static_cast<u32>(result->size()));
rb.Push<u32>(static_cast<u32>(default_miis.size()));
}
void UpdateLatest(HLERequestContext& ctx) {
@ -149,16 +138,17 @@ private:
LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
const auto result{manager.UpdateLatest(info, source_flag)};
if (result.Failed()) {
CharInfo new_char_info{};
const auto result{manager.UpdateLatest(&new_char_info, info, source_flag)};
if (result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result.Code());
rb.Push(result);
return;
}
IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
rb.Push(ResultSuccess);
rb.PushRaw<CharInfo>(*result);
rb.PushRaw<CharInfo>(new_char_info);
}
void BuildRandom(HLERequestContext& ctx) {

View File

@ -409,8 +409,7 @@ u32 MiiManager::GetCount(SourceFlag source_flag) const {
return static_cast<u32>(count);
}
ResultVal<CharInfo> MiiManager::UpdateLatest([[maybe_unused]] const CharInfo& info,
SourceFlag source_flag) {
Result MiiManager::UpdateLatest(CharInfo* out_info, const CharInfo& info, SourceFlag source_flag) {
if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
return ERROR_CANNOT_FIND_ENTRY;
}
@ -672,7 +671,7 @@ bool MiiManager::ValidateV3Info(const Ver3StoreData& mii_v3) const {
return is_valid;
}
ResultVal<std::vector<MiiInfoElement>> MiiManager::GetDefault(SourceFlag source_flag) {
std::vector<MiiInfoElement> MiiManager::GetDefault(SourceFlag source_flag) {
std::vector<MiiInfoElement> result;
if ((source_flag & SourceFlag::Default) == SourceFlag::None) {

View File

@ -19,12 +19,12 @@ public:
bool CheckAndResetUpdateCounter(SourceFlag source_flag, u64& current_update_counter);
bool IsFullDatabase() const;
u32 GetCount(SourceFlag source_flag) const;
ResultVal<CharInfo> UpdateLatest(const CharInfo& info, SourceFlag source_flag);
Result UpdateLatest(CharInfo* out_info, const CharInfo& info, SourceFlag source_flag);
CharInfo BuildRandom(Age age, Gender gender, Race race);
CharInfo BuildDefault(std::size_t index);
CharInfo ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const;
bool ValidateV3Info(const Ver3StoreData& mii_v3) const;
ResultVal<std::vector<MiiInfoElement>> GetDefault(SourceFlag source_flag);
std::vector<MiiInfoElement> GetDefault(SourceFlag source_flag);
Result GetIndex(const CharInfo& info, u32& index);
// This is nn::mii::detail::Ver::StoreDataRaw::BuildFromStoreData

View File

@ -392,19 +392,20 @@ void IApplicationManagerInterface::GetApplicationDesiredLanguage(HLERequestConte
IPC::RequestParser rp{ctx};
const auto supported_languages = rp.Pop<u32>();
const auto res = GetApplicationDesiredLanguage(supported_languages);
if (res.Succeeded()) {
u8 desired_language{};
const auto res = GetApplicationDesiredLanguage(&desired_language, supported_languages);
if (res == ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(*res);
rb.Push<u32>(desired_language);
} else {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res.Code());
rb.Push(res);
}
}
ResultVal<u8> IApplicationManagerInterface::GetApplicationDesiredLanguage(
const u32 supported_languages) {
Result IApplicationManagerInterface::GetApplicationDesiredLanguage(u8* out_desired_language,
const u32 supported_languages) {
LOG_DEBUG(Service_NS, "called with supported_languages={:08X}", supported_languages);
// Get language code from settings
@ -430,7 +431,8 @@ ResultVal<u8> IApplicationManagerInterface::GetApplicationDesiredLanguage(
for (const auto lang : *priority_list) {
const auto supported_flag = GetSupportedLanguageFlag(lang);
if (supported_languages == 0 || (supported_languages & supported_flag) == supported_flag) {
return static_cast<u8>(lang);
*out_desired_language = static_cast<u8>(lang);
return ResultSuccess;
}
}
@ -444,19 +446,20 @@ void IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode(
IPC::RequestParser rp{ctx};
const auto application_language = rp.Pop<u8>();
const auto res = ConvertApplicationLanguageToLanguageCode(application_language);
if (res.Succeeded()) {
u64 language_code{};
const auto res = ConvertApplicationLanguageToLanguageCode(&language_code, application_language);
if (res == ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(*res);
rb.Push(language_code);
} else {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res.Code());
rb.Push(res);
}
}
ResultVal<u64> IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode(
u8 application_language) {
Result IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode(
u64* out_language_code, u8 application_language) {
const auto language_code =
ConvertToLanguageCode(static_cast<ApplicationLanguage>(application_language));
if (language_code == std::nullopt) {
@ -464,7 +467,8 @@ ResultVal<u64> IApplicationManagerInterface::ConvertApplicationLanguageToLanguag
return Service::NS::ResultApplicationLanguageNotFound;
}
return static_cast<u64>(*language_code);
*out_language_code = static_cast<u64>(*language_code);
return ResultSuccess;
}
IApplicationVersionInterface::IApplicationVersionInterface(Core::System& system_)
@ -618,12 +622,13 @@ void IReadOnlyApplicationControlDataInterface::GetApplicationControlData(HLERequ
static_assert(sizeof(RequestParameters) == 0x10, "RequestParameters has incorrect size.");
IPC::RequestParser rp{ctx};
std::vector<u8> nacp_data{};
const auto parameters{rp.PopRaw<RequestParameters>()};
const auto nacp_data{system.GetARPManager().GetControlProperty(parameters.application_id)};
const auto result = nacp_data ? ResultSuccess : ResultUnknown;
const auto result =
system.GetARPManager().GetControlProperty(&nacp_data, parameters.application_id);
if (nacp_data) {
ctx.WriteBuffer(nacp_data->data(), nacp_data->size());
if (result == ResultSuccess) {
ctx.WriteBuffer(nacp_data.data(), nacp_data.size());
}
IPC::ResponseBuilder rb{ctx, 2};

View File

@ -28,8 +28,9 @@ public:
explicit IApplicationManagerInterface(Core::System& system_);
~IApplicationManagerInterface() override;
ResultVal<u8> GetApplicationDesiredLanguage(u32 supported_languages);
ResultVal<u64> ConvertApplicationLanguageToLanguageCode(u8 application_language);
Result GetApplicationDesiredLanguage(u8* out_desired_language, u32 supported_languages);
Result ConvertApplicationLanguageToLanguageCode(u64* out_language_code,
u8 application_language);
private:
void GetApplicationControlData(HLERequestContext& ctx);

View File

@ -183,7 +183,7 @@ std::optional<u32> Nvnflinger::FindBufferQueueId(u64 display_id, u64 layer_id) {
return layer->GetBinderId();
}
ResultVal<Kernel::KReadableEvent*> Nvnflinger::FindVsyncEvent(u64 display_id) {
Result Nvnflinger::FindVsyncEvent(Kernel::KReadableEvent** out_vsync_event, u64 display_id) {
const auto lock_guard = Lock();
auto* const display = FindDisplay(display_id);
@ -191,7 +191,7 @@ ResultVal<Kernel::KReadableEvent*> Nvnflinger::FindVsyncEvent(u64 display_id) {
return VI::ResultNotFound;
}
return display->GetVSyncEvent();
return display->GetVSyncEvent(out_vsync_event);
}
VI::Display* Nvnflinger::FindDisplay(u64 display_id) {

View File

@ -82,7 +82,7 @@ public:
///
/// If an invalid display ID is provided, then VI::ResultNotFound is returned.
/// If the vsync event has already been retrieved, then VI::ResultPermissionDenied is returned.
[[nodiscard]] ResultVal<Kernel::KReadableEvent*> FindVsyncEvent(u64 display_id);
[[nodiscard]] Result FindVsyncEvent(Kernel::KReadableEvent** out_vsync_event, u64 display_id);
/// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when
/// finished.

View File

@ -8,15 +8,16 @@
namespace Service::OLSC {
class OLSC final : public ServiceFramework<OLSC> {
class IOlscServiceForApplication final : public ServiceFramework<IOlscServiceForApplication> {
public:
explicit OLSC(Core::System& system_) : ServiceFramework{system_, "olsc:u"} {
explicit IOlscServiceForApplication(Core::System& system_)
: ServiceFramework{system_, "olsc:u"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &OLSC::Initialize, "Initialize"},
{0, &IOlscServiceForApplication::Initialize, "Initialize"},
{10, nullptr, "VerifySaveDataBackupLicenseAsync"},
{13, &OLSC::GetSaveDataBackupSetting, "GetSaveDataBackupSetting"},
{14, &OLSC::SetSaveDataBackupSettingEnabled, "SetSaveDataBackupSettingEnabled"},
{13, &IOlscServiceForApplication::GetSaveDataBackupSetting, "GetSaveDataBackupSetting"},
{14, &IOlscServiceForApplication::SetSaveDataBackupSettingEnabled, "SetSaveDataBackupSettingEnabled"},
{15, nullptr, "SetCustomData"},
{16, nullptr, "DeleteSaveDataBackupSetting"},
{18, nullptr, "GetSaveDataBackupInfoCache"},
@ -72,10 +73,155 @@ private:
bool initialized{};
};
class INativeHandleHolder final : public ServiceFramework<INativeHandleHolder> {
public:
explicit INativeHandleHolder(Core::System& system_)
: ServiceFramework{system_, "INativeHandleHolder"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetNativeHandle"},
};
// clang-format on
RegisterHandlers(functions);
}
};
class ITransferTaskListController final : public ServiceFramework<ITransferTaskListController> {
public:
explicit ITransferTaskListController(Core::System& system_)
: ServiceFramework{system_, "ITransferTaskListController"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "Unknown0"},
{1, nullptr, "Unknown1"},
{2, nullptr, "Unknown2"},
{3, nullptr, "Unknown3"},
{4, nullptr, "Unknown4"},
{5, &ITransferTaskListController::GetNativeHandleHolder , "GetNativeHandleHolder"},
{6, nullptr, "Unknown6"},
{7, nullptr, "Unknown7"},
{8, nullptr, "GetRemoteStorageController"},
{9, &ITransferTaskListController::GetNativeHandleHolder, "GetNativeHandleHolder2"},
{10, nullptr, "Unknown10"},
{11, nullptr, "Unknown11"},
{12, nullptr, "Unknown12"},
{13, nullptr, "Unknown13"},
{14, nullptr, "Unknown14"},
{15, nullptr, "Unknown15"},
{16, nullptr, "Unknown16"},
{17, nullptr, "Unknown17"},
{18, nullptr, "Unknown18"},
{19, nullptr, "Unknown19"},
{20, nullptr, "Unknown20"},
{21, nullptr, "Unknown21"},
{22, nullptr, "Unknown22"},
{23, nullptr, "Unknown23"},
{24, nullptr, "Unknown24"},
{25, nullptr, "Unknown25"},
};
// clang-format on
RegisterHandlers(functions);
}
private:
void GetNativeHandleHolder(HLERequestContext& ctx) {
LOG_INFO(Service_OLSC, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<INativeHandleHolder>(system);
}
};
class IOlscServiceForSystemService final : public ServiceFramework<IOlscServiceForSystemService> {
public:
explicit IOlscServiceForSystemService(Core::System& system_)
: ServiceFramework{system_, "olsc:s"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IOlscServiceForSystemService::OpenTransferTaskListController, "OpenTransferTaskListController"},
{1, nullptr, "OpenRemoteStorageController"},
{2, nullptr, "OpenDaemonController"},
{10, nullptr, "Unknown10"},
{11, nullptr, "Unknown11"},
{12, nullptr, "Unknown12"},
{13, nullptr, "Unknown13"},
{100, nullptr, "ListLastTransferTaskErrorInfo"},
{101, nullptr, "GetLastErrorInfoCount"},
{102, nullptr, "RemoveLastErrorInfoOld"},
{103, nullptr, "GetLastErrorInfo"},
{104, nullptr, "GetLastErrorEventHolder"},
{105, nullptr, "GetLastTransferTaskErrorInfo"},
{200, nullptr, "GetDataTransferPolicyInfo"},
{201, nullptr, "RemoveDataTransferPolicyInfo"},
{202, nullptr, "UpdateDataTransferPolicyOld"},
{203, nullptr, "UpdateDataTransferPolicy"},
{204, nullptr, "CleanupDataTransferPolicyInfo"},
{205, nullptr, "RequestDataTransferPolicy"},
{300, nullptr, "GetAutoTransferSeriesInfo"},
{301, nullptr, "UpdateAutoTransferSeriesInfo"},
{400, nullptr, "CleanupSaveDataArchiveInfoType1"},
{900, nullptr, "CleanupTransferTask"},
{902, nullptr, "CleanupSeriesInfoType0"},
{903, nullptr, "CleanupSaveDataArchiveInfoType0"},
{904, nullptr, "CleanupApplicationAutoTransferSetting"},
{905, nullptr, "CleanupErrorHistory"},
{906, nullptr, "SetLastError"},
{907, nullptr, "AddSaveDataArchiveInfoType0"},
{908, nullptr, "RemoveSeriesInfoType0"},
{909, nullptr, "GetSeriesInfoType0"},
{910, nullptr, "RemoveLastErrorInfo"},
{911, nullptr, "CleanupSeriesInfoType1"},
{912, nullptr, "RemoveSeriesInfoType1"},
{913, nullptr, "GetSeriesInfoType1"},
{1000, nullptr, "UpdateIssueOld"},
{1010, nullptr, "Unknown1010"},
{1011, nullptr, "ListIssueInfoOld"},
{1012, nullptr, "GetIssueOld"},
{1013, nullptr, "GetIssue2Old"},
{1014, nullptr, "GetIssue3Old"},
{1020, nullptr, "RepairIssueOld"},
{1021, nullptr, "RepairIssueWithUserIdOld"},
{1022, nullptr, "RepairIssue2Old"},
{1023, nullptr, "RepairIssue3Old"},
{1024, nullptr, "Unknown1024"},
{1100, nullptr, "UpdateIssue"},
{1110, nullptr, "Unknown1110"},
{1111, nullptr, "ListIssueInfo"},
{1112, nullptr, "GetIssue"},
{1113, nullptr, "GetIssue2"},
{1114, nullptr, "GetIssue3"},
{1120, nullptr, "RepairIssue"},
{1121, nullptr, "RepairIssueWithUserId"},
{1122, nullptr, "RepairIssue2"},
{1123, nullptr, "RepairIssue3"},
{1124, nullptr, "Unknown1124"},
};
// clang-format on
RegisterHandlers(functions);
}
private:
void OpenTransferTaskListController(HLERequestContext& ctx) {
LOG_INFO(Service_OLSC, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ITransferTaskListController>(system);
}
};
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
server_manager->RegisterNamedService("olsc:u", std::make_shared<OLSC>(system));
server_manager->RegisterNamedService("olsc:u",
std::make_shared<IOlscServiceForApplication>(system));
server_manager->RegisterNamedService("olsc:s",
std::make_shared<IOlscServiceForSystemService>(system));
ServerManager::RunServer(std::move(server_manager));
}

View File

@ -6,6 +6,7 @@
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/pctl/pctl.h"
#include "core/hle/service/pctl/pctl_module.h"
#include "core/hle/service/server_manager.h"
@ -24,7 +25,8 @@ constexpr Result ResultNoRestrictionEnabled{ErrorModule::PCTL, 181};
class IParentalControlService final : public ServiceFramework<IParentalControlService> {
public:
explicit IParentalControlService(Core::System& system_, Capability capability_)
: ServiceFramework{system_, "IParentalControlService"}, capability{capability_} {
: ServiceFramework{system_, "IParentalControlService"}, capability{capability_},
service_context{system_, "IParentalControlService"} {
// clang-format off
static const FunctionInfo functions[] = {
{1, &IParentalControlService::Initialize, "Initialize"},
@ -33,7 +35,7 @@ public:
{1003, nullptr, "ConfirmResumeApplicationPermission"},
{1004, nullptr, "ConfirmSnsPostPermission"},
{1005, nullptr, "ConfirmSystemSettingsPermission"},
{1006, nullptr, "IsRestrictionTemporaryUnlocked"},
{1006, &IParentalControlService::IsRestrictionTemporaryUnlocked, "IsRestrictionTemporaryUnlocked"},
{1007, nullptr, "RevertRestrictionTemporaryUnlocked"},
{1008, nullptr, "EnterRestrictedSystemSettings"},
{1009, nullptr, "LeaveRestrictedSystemSettings"},
@ -47,14 +49,14 @@ public:
{1017, &IParentalControlService::EndFreeCommunication, "EndFreeCommunication"},
{1018, &IParentalControlService::IsFreeCommunicationAvailable, "IsFreeCommunicationAvailable"},
{1031, &IParentalControlService::IsRestrictionEnabled, "IsRestrictionEnabled"},
{1032, nullptr, "GetSafetyLevel"},
{1032, &IParentalControlService::GetSafetyLevel, "GetSafetyLevel"},
{1033, nullptr, "SetSafetyLevel"},
{1034, nullptr, "GetSafetyLevelSettings"},
{1035, nullptr, "GetCurrentSettings"},
{1035, &IParentalControlService::GetCurrentSettings, "GetCurrentSettings"},
{1036, nullptr, "SetCustomSafetyLevelSettings"},
{1037, nullptr, "GetDefaultRatingOrganization"},
{1038, nullptr, "SetDefaultRatingOrganization"},
{1039, nullptr, "GetFreeCommunicationApplicationListCount"},
{1039, &IParentalControlService::GetFreeCommunicationApplicationListCount, "GetFreeCommunicationApplicationListCount"},
{1042, nullptr, "AddToFreeCommunicationApplicationList"},
{1043, nullptr, "DeleteSettings"},
{1044, nullptr, "GetFreeCommunicationApplicationList"},
@ -76,7 +78,7 @@ public:
{1206, nullptr, "GetPinCodeLength"},
{1207, nullptr, "GetPinCodeChangedEvent"},
{1208, nullptr, "GetPinCode"},
{1403, nullptr, "IsPairingActive"},
{1403, &IParentalControlService::IsPairingActive, "IsPairingActive"},
{1406, nullptr, "GetSettingsLastUpdated"},
{1411, nullptr, "GetPairingAccountInfo"},
{1421, nullptr, "GetAccountNickname"},
@ -84,18 +86,18 @@ public:
{1425, nullptr, "RequestPostEvents"},
{1426, nullptr, "GetPostEventInterval"},
{1427, nullptr, "SetPostEventInterval"},
{1432, nullptr, "GetSynchronizationEvent"},
{1432, &IParentalControlService::GetSynchronizationEvent, "GetSynchronizationEvent"},
{1451, nullptr, "StartPlayTimer"},
{1452, nullptr, "StopPlayTimer"},
{1453, nullptr, "IsPlayTimerEnabled"},
{1454, nullptr, "GetPlayTimerRemainingTime"},
{1455, nullptr, "IsRestrictedByPlayTimer"},
{1456, nullptr, "GetPlayTimerSettings"},
{1457, nullptr, "GetPlayTimerEventToRequestSuspension"},
{1458, nullptr, "IsPlayTimerAlarmDisabled"},
{1456, &IParentalControlService::GetPlayTimerSettings, "GetPlayTimerSettings"},
{1457, &IParentalControlService::GetPlayTimerEventToRequestSuspension, "GetPlayTimerEventToRequestSuspension"},
{1458, &IParentalControlService::IsPlayTimerAlarmDisabled, "IsPlayTimerAlarmDisabled"},
{1471, nullptr, "NotifyWrongPinCodeInputManyTimes"},
{1472, nullptr, "CancelNetworkRequest"},
{1473, nullptr, "GetUnlinkedEvent"},
{1473, &IParentalControlService::GetUnlinkedEvent, "GetUnlinkedEvent"},
{1474, nullptr, "ClearUnlinkedEvent"},
{1601, nullptr, "DisableAllFeatures"},
{1602, nullptr, "PostEnableAllFeatures"},
@ -131,6 +133,12 @@ public:
};
// clang-format on
RegisterHandlers(functions);
synchronization_event =
service_context.CreateEvent("IParentalControlService::SynchronizationEvent");
unlinked_event = service_context.CreateEvent("IParentalControlService::UnlinkedEvent");
request_suspension_event =
service_context.CreateEvent("IParentalControlService::RequestSuspensionEvent");
}
private:
@ -228,6 +236,17 @@ private:
states.free_communication = true;
}
void IsRestrictionTemporaryUnlocked(HLERequestContext& ctx) {
const bool is_temporary_unlocked = false;
LOG_WARNING(Service_PCTL, "(STUBBED) called, is_temporary_unlocked={}",
is_temporary_unlocked);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(is_temporary_unlocked);
}
void ConfirmStereoVisionPermission(HLERequestContext& ctx) {
LOG_DEBUG(Service_PCTL, "called");
states.stereo_vision = true;
@ -268,6 +287,34 @@ private:
rb.Push(pin_code[0] != '\0');
}
void GetSafetyLevel(HLERequestContext& ctx) {
const u32 safety_level = 0;
LOG_WARNING(Service_PCTL, "(STUBBED) called, safety_level={}", safety_level);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(safety_level);
}
void GetCurrentSettings(HLERequestContext& ctx) {
LOG_INFO(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushRaw(restriction_settings);
}
void GetFreeCommunicationApplicationListCount(HLERequestContext& ctx) {
const u32 count = 4;
LOG_WARNING(Service_PCTL, "(STUBBED) called, count={}", count);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(count);
}
void ConfirmStereoVisionRestrictionConfigurable(HLERequestContext& ctx) {
LOG_DEBUG(Service_PCTL, "called");
@ -300,6 +347,61 @@ private:
}
}
void IsPairingActive(HLERequestContext& ctx) {
const bool is_pairing_active = false;
LOG_WARNING(Service_PCTL, "(STUBBED) called, is_pairing_active={}", is_pairing_active);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(is_pairing_active);
}
void GetSynchronizationEvent(HLERequestContext& ctx) {
LOG_INFO(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(synchronization_event->GetReadableEvent());
}
void GetPlayTimerSettings(HLERequestContext& ctx) {
LOG_WARNING(Service_PCTL, "(STUBBED) called");
const PlayTimerSettings timer_settings{};
IPC::ResponseBuilder rb{ctx, 15};
rb.Push(ResultSuccess);
rb.PushRaw(timer_settings);
}
void GetPlayTimerEventToRequestSuspension(HLERequestContext& ctx) {
LOG_INFO(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(request_suspension_event->GetReadableEvent());
}
void IsPlayTimerAlarmDisabled(HLERequestContext& ctx) {
const bool is_play_timer_alarm_disabled = false;
LOG_INFO(Service_PCTL, "called, is_play_timer_alarm_disabled={}",
is_play_timer_alarm_disabled);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(is_play_timer_alarm_disabled);
}
void GetUnlinkedEvent(HLERequestContext& ctx) {
LOG_INFO(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(unlinked_event->GetReadableEvent());
}
void SetStereoVisionRestriction(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto can_use = rp.Pop<bool>();
@ -364,10 +466,30 @@ private:
bool disabled{};
};
// This is nn::pctl::RestrictionSettings
struct RestrictionSettings {
u8 rating_age;
bool sns_post_restriction;
bool free_communication_restriction;
};
static_assert(sizeof(RestrictionSettings) == 0x3, "RestrictionSettings has incorrect size.");
// This is nn::pctl::PlayTimerSettings
struct PlayTimerSettings {
std::array<u32, 13> settings;
};
static_assert(sizeof(PlayTimerSettings) == 0x34, "PlayTimerSettings has incorrect size.");
States states{};
ParentalControlSettings settings{};
RestrictionSettings restriction_settings{};
std::array<char, 8> pin_code{};
Capability capability{};
Kernel::KEvent* synchronization_event;
Kernel::KEvent* unlinked_event;
Kernel::KEvent* request_suspension_event;
KernelHelpers::ServiceContext service_context;
};
void Module::Interface::CreateService(HLERequestContext& ctx) {

View File

@ -102,16 +102,17 @@ Result ServerManager::RegisterNamedService(const std::string& service_name,
m_system.ServiceManager().RegisterService(service_name, max_sessions, handler)));
// Get the registered port.
auto port = m_system.ServiceManager().GetServicePort(service_name);
ASSERT(port.Succeeded());
Kernel::KPort* port{};
ASSERT(
R_SUCCEEDED(m_system.ServiceManager().GetServicePort(std::addressof(port), service_name)));
// Open a new reference to the server port.
(*port)->GetServerPort().Open();
port->GetServerPort().Open();
// Begin tracking the server port.
{
std::scoped_lock ll{m_list_mutex};
m_ports.emplace(std::addressof((*port)->GetServerPort()), std::move(handler));
m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler));
}
// Signal the wakeup event.

View File

@ -52,8 +52,7 @@ static Result ValidateServiceName(const std::string& name) {
Result ServiceManager::RegisterService(std::string name, u32 max_sessions,
SessionRequestHandlerPtr handler) {
CASCADE_CODE(ValidateServiceName(name));
R_TRY(ValidateServiceName(name));
std::scoped_lock lk{lock};
if (registered_services.find(name) != registered_services.end()) {
@ -77,7 +76,7 @@ Result ServiceManager::RegisterService(std::string name, u32 max_sessions,
}
Result ServiceManager::UnregisterService(const std::string& name) {
CASCADE_CODE(ValidateServiceName(name));
R_TRY(ValidateServiceName(name));
std::scoped_lock lk{lock};
const auto iter = registered_services.find(name);
@ -92,8 +91,8 @@ Result ServiceManager::UnregisterService(const std::string& name) {
return ResultSuccess;
}
ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name) {
CASCADE_CODE(ValidateServiceName(name));
Result ServiceManager::GetServicePort(Kernel::KPort** out_port, const std::string& name) {
R_TRY(ValidateServiceName(name));
std::scoped_lock lk{lock};
auto it = service_ports.find(name);
@ -102,7 +101,8 @@ ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name
return Service::SM::ResultNotRegistered;
}
return it->second;
*out_port = it->second;
return ResultSuccess;
}
/**
@ -122,32 +122,34 @@ void SM::Initialize(HLERequestContext& ctx) {
}
void SM::GetService(HLERequestContext& ctx) {
auto result = GetServiceImpl(ctx);
Kernel::KClientSession* client_session{};
auto result = GetServiceImpl(&client_session, ctx);
if (ctx.GetIsDeferred()) {
// Don't overwrite the command buffer.
return;
}
if (result.Succeeded()) {
if (result == ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
rb.Push(result.Code());
rb.PushMoveObjects(result.Unwrap());
rb.Push(result);
rb.PushMoveObjects(client_session);
} else {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result.Code());
rb.Push(result);
}
}
void SM::GetServiceTipc(HLERequestContext& ctx) {
auto result = GetServiceImpl(ctx);
Kernel::KClientSession* client_session{};
auto result = GetServiceImpl(&client_session, ctx);
if (ctx.GetIsDeferred()) {
// Don't overwrite the command buffer.
return;
}
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
rb.Push(result.Code());
rb.PushMoveObjects(result.Succeeded() ? result.Unwrap() : nullptr);
rb.Push(result);
rb.PushMoveObjects(result == ResultSuccess ? client_session : nullptr);
}
static std::string PopServiceName(IPC::RequestParser& rp) {
@ -161,7 +163,7 @@ static std::string PopServiceName(IPC::RequestParser& rp) {
return result;
}
ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(HLERequestContext& ctx) {
Result SM::GetServiceImpl(Kernel::KClientSession** out_client_session, HLERequestContext& ctx) {
if (!ctx.GetManager()->GetIsInitializedForSm()) {
return Service::SM::ResultInvalidClient;
}
@ -170,18 +172,18 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(HLERequestContext& ctx) {
std::string name(PopServiceName(rp));
// Find the named port.
auto port_result = service_manager.GetServicePort(name);
if (port_result.Code() == Service::SM::ResultInvalidServiceName) {
Kernel::KPort* port{};
auto port_result = service_manager.GetServicePort(&port, name);
if (port_result == Service::SM::ResultInvalidServiceName) {
LOG_ERROR(Service_SM, "Invalid service name '{}'", name);
return Service::SM::ResultInvalidServiceName;
}
if (port_result.Failed()) {
if (port_result != ResultSuccess) {
LOG_INFO(Service_SM, "Waiting for service {} to become available", name);
ctx.SetIsDeferred();
return Service::SM::ResultNotRegistered;
}
auto& port = port_result.Unwrap();
// Create a new session.
Kernel::KClientSession* session{};
@ -192,7 +194,8 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(HLERequestContext& ctx) {
LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId());
return session;
*out_client_session = session;
return ResultSuccess;
}
void SM::RegisterService(HLERequestContext& ctx) {

View File

@ -42,7 +42,7 @@ private:
void RegisterService(HLERequestContext& ctx);
void UnregisterService(HLERequestContext& ctx);
ResultVal<Kernel::KClientSession*> GetServiceImpl(HLERequestContext& ctx);
Result GetServiceImpl(Kernel::KClientSession** out_client_session, HLERequestContext& ctx);
ServiceManager& service_manager;
Kernel::KernelCore& kernel;
@ -55,7 +55,7 @@ public:
Result RegisterService(std::string name, u32 max_sessions, SessionRequestHandlerPtr handler);
Result UnregisterService(const std::string& name);
ResultVal<Kernel::KPort*> GetServicePort(const std::string& name);
Result GetServicePort(Kernel::KPort** out_port, const std::string& name);
template <Common::DerivedFrom<SessionRequestHandler> T>
std::shared_ptr<T> GetService(const std::string& service_name) const {

View File

@ -54,7 +54,7 @@ NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, na
RegisterHandlers(functions);
}
static ResultVal<std::string> ResolveImpl(const std::string& fqdn_in) {
static std::string ResolveImpl(const std::string& fqdn_in) {
// The real implementation makes various substitutions.
// For now we just return the string as-is, which is good enough when not
// connecting to real Nintendo servers.
@ -64,13 +64,10 @@ static ResultVal<std::string> ResolveImpl(const std::string& fqdn_in) {
static Result ResolveCommon(const std::string& fqdn_in, std::array<char, 0x100>& fqdn_out) {
const auto res = ResolveImpl(fqdn_in);
if (res.Failed()) {
return res.Code();
}
if (res->size() >= fqdn_out.size()) {
if (res.size() >= fqdn_out.size()) {
return ResultOverflow;
}
std::memcpy(fqdn_out.data(), res->c_str(), res->size() + 1);
std::memcpy(fqdn_out.data(), res.c_str(), res.size() + 1);
return ResultSuccess;
}

View File

@ -30,10 +30,10 @@ void Module::Interface::GetConfig(HLERequestContext& ctx) {
// This should call svcCallSecureMonitor with the appropriate args.
// Since we do not have it implemented yet, we will use this for now.
const auto smc_result = GetConfigImpl(config_item);
const auto result_code = smc_result.Code();
u64 smc_result{};
const auto result_code = GetConfigImpl(&smc_result, config_item);
if (smc_result.Failed()) {
if (result_code != ResultSuccess) {
LOG_ERROR(Service_SPL, "called, config_item={}, result_code={}", config_item,
result_code.raw);
@ -42,11 +42,11 @@ void Module::Interface::GetConfig(HLERequestContext& ctx) {
}
LOG_DEBUG(Service_SPL, "called, config_item={}, result_code={}, smc_result={}", config_item,
result_code.raw, *smc_result);
result_code.raw, smc_result);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(result_code);
rb.Push(*smc_result);
rb.Push(smc_result);
}
void Module::Interface::ModularExponentiate(HLERequestContext& ctx) {
@ -99,7 +99,7 @@ void Module::Interface::GetBootReason(HLERequestContext& ctx) {
rb.Push(ResultSecureMonitorNotImplemented);
}
ResultVal<u64> Module::Interface::GetConfigImpl(ConfigItem config_item) const {
Result Module::Interface::GetConfigImpl(u64* out_config, ConfigItem config_item) const {
switch (config_item) {
case ConfigItem::DisableProgramVerification:
case ConfigItem::DramId:
@ -121,40 +121,50 @@ ResultVal<u64> Module::Interface::GetConfigImpl(ConfigItem config_item) const {
return ResultSecureMonitorNotImplemented;
case ConfigItem::ExosphereApiVersion:
// Get information about the current exosphere version.
return (u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MAJOR} << 56) |
(u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MINOR} << 48) |
(u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MICRO} << 40) |
(static_cast<u64>(HLE::ApiVersion::GetTargetFirmware()));
*out_config = (u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MAJOR} << 56) |
(u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MINOR} << 48) |
(u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MICRO} << 40) |
(static_cast<u64>(HLE::ApiVersion::GetTargetFirmware()));
return ResultSuccess;
case ConfigItem::ExosphereNeedsReboot:
// We are executing, so we aren't in the process of rebooting.
return u64{0};
*out_config = u64{0};
return ResultSuccess;
case ConfigItem::ExosphereNeedsShutdown:
// We are executing, so we aren't in the process of shutting down.
return u64{0};
*out_config = u64{0};
return ResultSuccess;
case ConfigItem::ExosphereGitCommitHash:
// Get information about the current exosphere git commit hash.
return u64{0};
*out_config = u64{0};
return ResultSuccess;
case ConfigItem::ExosphereHasRcmBugPatch:
// Get information about whether this unit has the RCM bug patched.
return u64{0};
*out_config = u64{0};
return ResultSuccess;
case ConfigItem::ExosphereBlankProdInfo:
// Get whether this unit should simulate a "blanked" PRODINFO.
return u64{0};
*out_config = u64{0};
return ResultSuccess;
case ConfigItem::ExosphereAllowCalWrites:
// Get whether this unit should allow writing to the calibration partition.
return u64{0};
*out_config = u64{0};
return ResultSuccess;
case ConfigItem::ExosphereEmummcType:
// Get what kind of emummc this unit has active.
return u64{0};
*out_config = u64{0};
return ResultSuccess;
case ConfigItem::ExospherePayloadAddress:
// Gets the physical address of the reboot payload buffer, if one exists.
return ResultSecureMonitorNotInitialized;
case ConfigItem::ExosphereLogConfiguration:
// Get the log configuration.
return u64{0};
*out_config = u64{0};
return ResultSuccess;
case ConfigItem::ExosphereForceEnableUsb30:
// Get whether usb 3.0 should be force-enabled.
return u64{0};
*out_config = u64{0};
return ResultSuccess;
default:
return ResultSecureMonitorInvalidArgument;
}

View File

@ -35,7 +35,7 @@ public:
std::shared_ptr<Module> module;
private:
ResultVal<u64> GetConfigImpl(ConfigItem config_item) const;
Result GetConfigImpl(u64* out_config, ConfigItem config_item) const;
std::mt19937 rng;
};

View File

@ -4,6 +4,7 @@
#include "common/string_util.h"
#include "core/core.h"
#include "core/hle/result.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
@ -141,12 +142,12 @@ private:
bool did_set_host_name = false;
bool did_handshake = false;
ResultVal<s32> SetSocketDescriptorImpl(s32 fd) {
Result SetSocketDescriptorImpl(s32* out_fd, s32 fd) {
LOG_DEBUG(Service_SSL, "called, fd={}", fd);
ASSERT(!did_handshake);
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD>("bsd:u");
ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; });
s32 ret_fd;
// Based on https://switchbrew.org/wiki/SSL_services#SetSocketDescriptor
if (do_not_close_socket) {
auto res = bsd->DuplicateSocketImpl(fd);
@ -156,9 +157,9 @@ private:
}
fd = *res;
fd_to_close = fd;
ret_fd = fd;
*out_fd = fd;
} else {
ret_fd = -1;
*out_fd = -1;
}
std::optional<std::shared_ptr<Network::SocketBase>> sock = bsd->GetSocket(fd);
if (!sock.has_value()) {
@ -167,7 +168,7 @@ private:
}
socket = std::move(*sock);
backend->SetSocket(socket);
return ret_fd;
return ResultSuccess;
}
Result SetHostNameImpl(const std::string& hostname) {
@ -247,34 +248,36 @@ private:
return ret;
}
ResultVal<std::vector<u8>> ReadImpl(size_t size) {
Result ReadImpl(std::vector<u8>* out_data, size_t size) {
ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; });
std::vector<u8> res(size);
ResultVal<size_t> actual = backend->Read(res);
if (actual.Failed()) {
return actual.Code();
size_t actual_size{};
Result res = backend->Read(&actual_size, *out_data);
if (res != ResultSuccess) {
return res;
}
res.resize(*actual);
out_data->resize(actual_size);
return res;
}
ResultVal<size_t> WriteImpl(std::span<const u8> data) {
Result WriteImpl(size_t* out_size, std::span<const u8> data) {
ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; });
return backend->Write(data);
return backend->Write(out_size, data);
}
ResultVal<s32> PendingImpl() {
Result PendingImpl(s32* out_pending) {
LOG_WARNING(Service_SSL, "(STUBBED) called.");
return 0;
*out_pending = 0;
return ResultSuccess;
}
void SetSocketDescriptor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
const ResultVal<s32> res = SetSocketDescriptorImpl(fd);
const s32 in_fd = rp.Pop<s32>();
s32 out_fd{-1};
const Result res = SetSocketDescriptorImpl(&out_fd, in_fd);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res.Code());
rb.Push<s32>(res.ValueOr(-1));
rb.Push(res);
rb.Push<s32>(out_fd);
}
void SetHostName(HLERequestContext& ctx) {
@ -313,14 +316,15 @@ private:
};
static_assert(sizeof(OutputParameters) == 0x8);
const Result res = DoHandshakeImpl();
Result res = DoHandshakeImpl();
OutputParameters out{};
if (res == ResultSuccess) {
auto certs = backend->GetServerCerts();
if (certs.Succeeded()) {
const std::vector<u8> certs_buf = SerializeServerCerts(*certs);
std::vector<std::vector<u8>> certs;
res = backend->GetServerCerts(&certs);
if (res == ResultSuccess) {
const std::vector<u8> certs_buf = SerializeServerCerts(certs);
ctx.WriteBuffer(certs_buf);
out.certs_count = static_cast<u32>(certs->size());
out.certs_count = static_cast<u32>(certs.size());
out.certs_size = static_cast<u32>(certs_buf.size());
}
}
@ -330,29 +334,32 @@ private:
}
void Read(HLERequestContext& ctx) {
const ResultVal<std::vector<u8>> res = ReadImpl(ctx.GetWriteBufferSize());
std::vector<u8> output_bytes;
const Result res = ReadImpl(&output_bytes, ctx.GetWriteBufferSize());
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res.Code());
if (res.Succeeded()) {
rb.Push(static_cast<u32>(res->size()));
ctx.WriteBuffer(*res);
rb.Push(res);
if (res == ResultSuccess) {
rb.Push(static_cast<u32>(output_bytes.size()));
ctx.WriteBuffer(output_bytes);
} else {
rb.Push(static_cast<u32>(0));
}
}
void Write(HLERequestContext& ctx) {
const ResultVal<size_t> res = WriteImpl(ctx.ReadBuffer());
size_t write_size{0};
const Result res = WriteImpl(&write_size, ctx.ReadBuffer());
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res.Code());
rb.Push(static_cast<u32>(res.ValueOr(0)));
rb.Push(res);
rb.Push(static_cast<u32>(write_size));
}
void Pending(HLERequestContext& ctx) {
const ResultVal<s32> res = PendingImpl();
s32 pending_size{0};
const Result res = PendingImpl(&pending_size);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res.Code());
rb.Push<s32>(res.ValueOr(0));
rb.Push(res);
rb.Push<s32>(pending_size);
}
void SetSessionCacheMode(HLERequestContext& ctx) {
@ -438,13 +445,14 @@ private:
void CreateConnection(HLERequestContext& ctx) {
LOG_WARNING(Service_SSL, "called");
auto backend_res = CreateSSLConnectionBackend();
std::unique_ptr<SSLConnectionBackend> backend;
const Result res = CreateSSLConnectionBackend(&backend);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(backend_res.Code());
if (backend_res.Succeeded()) {
rb.Push(res);
if (res == ResultSuccess) {
rb.PushIpcInterface<ISslConnection>(system, ssl_version, shared_data,
std::move(*backend_res));
std::move(backend));
}
}

View File

@ -35,11 +35,11 @@ public:
virtual void SetSocket(std::shared_ptr<Network::SocketBase> socket) = 0;
virtual Result SetHostName(const std::string& hostname) = 0;
virtual Result DoHandshake() = 0;
virtual ResultVal<size_t> Read(std::span<u8> data) = 0;
virtual ResultVal<size_t> Write(std::span<const u8> data) = 0;
virtual ResultVal<std::vector<std::vector<u8>>> GetServerCerts() = 0;
virtual Result Read(size_t* out_size, std::span<u8> data) = 0;
virtual Result Write(size_t* out_size, std::span<const u8> data) = 0;
virtual Result GetServerCerts(std::vector<std::vector<u8>>* out_certs) = 0;
};
ResultVal<std::unique_ptr<SSLConnectionBackend>> CreateSSLConnectionBackend();
Result CreateSSLConnectionBackend(std::unique_ptr<SSLConnectionBackend>* out_backend);
} // namespace Service::SSL

View File

@ -7,7 +7,7 @@
namespace Service::SSL {
ResultVal<std::unique_ptr<SSLConnectionBackend>> CreateSSLConnectionBackend() {
Result CreateSSLConnectionBackend(std::unique_ptr<SSLConnectionBackend>* out_backend) {
LOG_ERROR(Service_SSL,
"Can't create SSL connection because no SSL backend is available on this platform");
return ResultInternalError;

View File

@ -105,31 +105,30 @@ public:
return ResultInternalError;
}
}
return HandleReturn("SSL_do_handshake", 0, ret).Code();
return HandleReturn("SSL_do_handshake", 0, ret);
}
ResultVal<size_t> Read(std::span<u8> data) override {
size_t actual;
const int ret = SSL_read_ex(ssl, data.data(), data.size(), &actual);
return HandleReturn("SSL_read_ex", actual, ret);
Result Read(size_t* out_size, std::span<u8> data) override {
const int ret = SSL_read_ex(ssl, data.data(), data.size(), out_size);
return HandleReturn("SSL_read_ex", out_size, ret);
}
ResultVal<size_t> Write(std::span<const u8> data) override {
size_t actual;
const int ret = SSL_write_ex(ssl, data.data(), data.size(), &actual);
return HandleReturn("SSL_write_ex", actual, ret);
Result Write(size_t* out_size, std::span<const u8> data) override {
const int ret = SSL_write_ex(ssl, data.data(), data.size(), out_size);
return HandleReturn("SSL_write_ex", out_size, ret);
}
ResultVal<size_t> HandleReturn(const char* what, size_t actual, int ret) {
Result HandleReturn(const char* what, size_t* actual, int ret) {
const int ssl_err = SSL_get_error(ssl, ret);
CheckOpenSSLErrors();
switch (ssl_err) {
case SSL_ERROR_NONE:
return actual;
return ResultSuccess;
case SSL_ERROR_ZERO_RETURN:
LOG_DEBUG(Service_SSL, "{} => SSL_ERROR_ZERO_RETURN", what);
// DoHandshake special-cases this, but for Read and Write:
return size_t(0);
*actual = 0;
return ResultSuccess;
case SSL_ERROR_WANT_READ:
LOG_DEBUG(Service_SSL, "{} => SSL_ERROR_WANT_READ", what);
return ResultWouldBlock;
@ -139,20 +138,20 @@ public:
default:
if (ssl_err == SSL_ERROR_SYSCALL && got_read_eof) {
LOG_DEBUG(Service_SSL, "{} => SSL_ERROR_SYSCALL because server hung up", what);
return size_t(0);
*actual = 0;
return ResultSuccess;
}
LOG_ERROR(Service_SSL, "{} => other SSL_get_error return value {}", what, ssl_err);
return ResultInternalError;
}
}
ResultVal<std::vector<std::vector<u8>>> GetServerCerts() override {
Result GetServerCerts(std::vector<std::vector<u8>>* out_certs) override {
STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl);
if (!chain) {
LOG_ERROR(Service_SSL, "SSL_get_peer_cert_chain returned nullptr");
return ResultInternalError;
}
std::vector<std::vector<u8>> ret;
int count = sk_X509_num(chain);
ASSERT(count >= 0);
for (int i = 0; i < count; i++) {
@ -161,10 +160,10 @@ public:
unsigned char* buf = nullptr;
int len = i2d_X509(x509, &buf);
ASSERT_OR_EXECUTE(len >= 0 && buf, { continue; });
ret.emplace_back(buf, buf + len);
out_certs->emplace_back(buf, buf + len);
OPENSSL_free(buf);
}
return ret;
return ResultSuccess;
}
~SSLConnectionBackendOpenSSL() {
@ -253,13 +252,13 @@ public:
std::shared_ptr<Network::SocketBase> socket;
};
ResultVal<std::unique_ptr<SSLConnectionBackend>> CreateSSLConnectionBackend() {
Result CreateSSLConnectionBackend(std::unique_ptr<SSLConnectionBackend>* out_backend) {
auto conn = std::make_unique<SSLConnectionBackendOpenSSL>();
const Result res = conn->Init();
if (res.IsFailure()) {
return res;
}
return conn;
R_TRY(conn->Init());
*out_backend = std::move(conn);
return ResultSuccess;
}
namespace {

View File

@ -299,21 +299,22 @@ public:
return ResultSuccess;
}
ResultVal<size_t> Read(std::span<u8> data) override {
Result Read(size_t* out_size, std::span<u8> data) override {
*out_size = 0;
if (handshake_state != HandshakeState::Connected) {
LOG_ERROR(Service_SSL, "Called Read but we did not successfully handshake");
return ResultInternalError;
}
if (data.size() == 0 || got_read_eof) {
return size_t(0);
return ResultSuccess;
}
while (1) {
if (!cleartext_read_buf.empty()) {
const size_t read_size = std::min(cleartext_read_buf.size(), data.size());
std::memcpy(data.data(), cleartext_read_buf.data(), read_size);
*out_size = std::min(cleartext_read_buf.size(), data.size());
std::memcpy(data.data(), cleartext_read_buf.data(), *out_size);
cleartext_read_buf.erase(cleartext_read_buf.begin(),
cleartext_read_buf.begin() + read_size);
return read_size;
cleartext_read_buf.begin() + *out_size);
return ResultSuccess;
}
if (!ciphertext_read_buf.empty()) {
SecBuffer empty{
@ -366,7 +367,8 @@ public:
case SEC_I_CONTEXT_EXPIRED:
// Server hung up by sending close_notify.
got_read_eof = true;
return size_t(0);
*out_size = 0;
return ResultSuccess;
default:
LOG_ERROR(Service_SSL, "DecryptMessage failed: {}",
Common::NativeErrorToString(ret));
@ -379,18 +381,21 @@ public:
}
if (ciphertext_read_buf.empty()) {
got_read_eof = true;
return size_t(0);
*out_size = 0;
return ResultSuccess;
}
}
}
ResultVal<size_t> Write(std::span<const u8> data) override {
Result Write(size_t* out_size, std::span<const u8> data) override {
*out_size = 0;
if (handshake_state != HandshakeState::Connected) {
LOG_ERROR(Service_SSL, "Called Write but we did not successfully handshake");
return ResultInternalError;
}
if (data.size() == 0) {
return size_t(0);
return ResultSuccess;
}
data = data.subspan(0, std::min<size_t>(data.size(), stream_sizes.cbMaximumMessage));
if (!cleartext_write_buf.empty()) {
@ -402,7 +407,7 @@ public:
LOG_ERROR(Service_SSL, "Called Write but buffer does not match previous buffer");
return ResultInternalError;
}
return WriteAlreadyEncryptedData();
return WriteAlreadyEncryptedData(out_size);
} else {
cleartext_write_buf.assign(data.begin(), data.end());
}
@ -448,21 +453,21 @@ public:
tmp_data_buf.end());
ciphertext_write_buf.insert(ciphertext_write_buf.end(), trailer_buf.begin(),
trailer_buf.end());
return WriteAlreadyEncryptedData();
return WriteAlreadyEncryptedData(out_size);
}
ResultVal<size_t> WriteAlreadyEncryptedData() {
Result WriteAlreadyEncryptedData(size_t* out_size) {
const Result r = FlushCiphertextWriteBuf();
if (r != ResultSuccess) {
return r;
}
// write buf is empty
const size_t cleartext_bytes_written = cleartext_write_buf.size();
*out_size = cleartext_write_buf.size();
cleartext_write_buf.clear();
return cleartext_bytes_written;
return ResultSuccess;
}
ResultVal<std::vector<std::vector<u8>>> GetServerCerts() override {
Result GetServerCerts(std::vector<std::vector<u8>>* out_certs) override {
PCCERT_CONTEXT returned_cert = nullptr;
const SECURITY_STATUS ret =
QueryContextAttributes(&ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &returned_cert);
@ -473,16 +478,15 @@ public:
return ResultInternalError;
}
PCCERT_CONTEXT some_cert = nullptr;
std::vector<std::vector<u8>> certs;
while ((some_cert = CertEnumCertificatesInStore(returned_cert->hCertStore, some_cert))) {
certs.emplace_back(static_cast<u8*>(some_cert->pbCertEncoded),
static_cast<u8*>(some_cert->pbCertEncoded) +
some_cert->cbCertEncoded);
out_certs->emplace_back(static_cast<u8*>(some_cert->pbCertEncoded),
static_cast<u8*>(some_cert->pbCertEncoded) +
some_cert->cbCertEncoded);
}
std::reverse(certs.begin(),
certs.end()); // Windows returns certs in reverse order from what we want
std::reverse(out_certs->begin(),
out_certs->end()); // Windows returns certs in reverse order from what we want
CertFreeCertificateContext(returned_cert);
return certs;
return ResultSuccess;
}
~SSLConnectionBackendSchannel() {
@ -532,13 +536,13 @@ public:
size_t read_buf_fill_size = 0;
};
ResultVal<std::unique_ptr<SSLConnectionBackend>> CreateSSLConnectionBackend() {
Result CreateSSLConnectionBackend(std::unique_ptr<SSLConnectionBackend>* out_backend) {
auto conn = std::make_unique<SSLConnectionBackendSchannel>();
const Result res = conn->Init();
if (res.IsFailure()) {
return res;
}
return conn;
R_TRY(conn->Init());
*out_backend = std::move(conn);
return ResultSuccess;
}
} // namespace Service::SSL

View File

@ -103,24 +103,20 @@ public:
return HandleReturn("SSLHandshake", 0, status).Code();
}
ResultVal<size_t> Read(std::span<u8> data) override {
size_t actual;
OSStatus status = SSLRead(context, data.data(), data.size(), &actual);
;
return HandleReturn("SSLRead", actual, status);
Result Read(size_t* out_size, std::span<u8> data) override {
OSStatus status = SSLRead(context, data.data(), data.size(), out_size);
return HandleReturn("SSLRead", out_size, status);
}
ResultVal<size_t> Write(std::span<const u8> data) override {
size_t actual;
OSStatus status = SSLWrite(context, data.data(), data.size(), &actual);
;
return HandleReturn("SSLWrite", actual, status);
Result Write(size_t* out_size, std::span<const u8> data) override {
OSStatus status = SSLWrite(context, data.data(), data.size(), out_size);
return HandleReturn("SSLWrite", out_size, status);
}
ResultVal<size_t> HandleReturn(const char* what, size_t actual, OSStatus status) {
Result HandleReturn(const char* what, size_t* actual, OSStatus status) {
switch (status) {
case 0:
return actual;
return ResultSuccess;
case errSSLWouldBlock:
return ResultWouldBlock;
default: {
@ -136,22 +132,21 @@ public:
}
}
ResultVal<std::vector<std::vector<u8>>> GetServerCerts() override {
Result GetServerCerts(std::vector<std::vector<u8>>* out_certs) override {
CFReleaser<SecTrustRef> trust;
OSStatus status = SSLCopyPeerTrust(context, &trust.ptr);
if (status) {
LOG_ERROR(Service_SSL, "SSLCopyPeerTrust failed: {}", OSStatusToString(status));
return ResultInternalError;
}
std::vector<std::vector<u8>> ret;
for (CFIndex i = 0, count = SecTrustGetCertificateCount(trust); i < count; i++) {
SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, i);
CFReleaser<CFDataRef> data(SecCertificateCopyData(cert));
ASSERT_OR_EXECUTE(data, { return ResultInternalError; });
const u8* ptr = CFDataGetBytePtr(data);
ret.emplace_back(ptr, ptr + CFDataGetLength(data));
out_certs->emplace_back(ptr, ptr + CFDataGetLength(data));
}
return ret;
return ResultSuccess;
}
static OSStatus ReadCallback(SSLConnectionRef connection, void* data, size_t* dataLength) {
@ -210,13 +205,13 @@ private:
std::shared_ptr<Network::SocketBase> socket;
};
ResultVal<std::unique_ptr<SSLConnectionBackend>> CreateSSLConnectionBackend() {
Result CreateSSLConnectionBackend(std::unique_ptr<SSLConnectionBackend>* out_backend) {
auto conn = std::make_unique<SSLConnectionBackendSecureTransport>();
const Result res = conn->Init();
if (res.IsFailure()) {
return res;
}
return conn;
R_TRY(conn->Init());
*out_backend = std::move(conn);
return ResultSuccess;
}
} // namespace Service::SSL

View File

@ -58,14 +58,15 @@ const Layer& Display::GetLayer(std::size_t index) const {
return *layers.at(index);
}
ResultVal<Kernel::KReadableEvent*> Display::GetVSyncEvent() {
Result Display::GetVSyncEvent(Kernel::KReadableEvent** out_vsync_event) {
if (got_vsync_event) {
return ResultPermissionDenied;
}
got_vsync_event = true;
return GetVSyncEventUnchecked();
*out_vsync_event = GetVSyncEventUnchecked();
return ResultSuccess;
}
Kernel::KReadableEvent* Display::GetVSyncEventUnchecked() {

View File

@ -85,7 +85,7 @@ public:
* @returns The internal Vsync event if it has not yet been retrieved,
* VI::ResultPermissionDenied otherwise.
*/
[[nodiscard]] ResultVal<Kernel::KReadableEvent*> GetVSyncEvent();
[[nodiscard]] Result GetVSyncEvent(Kernel::KReadableEvent** out_vsync_event);
/// Gets the internal vsync event.
Kernel::KReadableEvent* GetVSyncEventUnchecked();

View File

@ -683,9 +683,9 @@ private:
LOG_DEBUG(Service_VI, "called. display_id={}", display_id);
const auto vsync_event = nv_flinger.FindVsyncEvent(display_id);
if (vsync_event.Failed()) {
const auto result = vsync_event.Code();
Kernel::KReadableEvent* vsync_event{};
const auto result = nv_flinger.FindVsyncEvent(&vsync_event, display_id);
if (result != ResultSuccess) {
if (result == ResultNotFound) {
LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id);
}
@ -697,7 +697,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(*vsync_event);
rb.PushCopyObjects(vsync_event);
}
void ConvertScalingMode(HLERequestContext& ctx) {
@ -705,15 +705,16 @@ private:
const auto mode = rp.PopEnum<NintendoScaleMode>();
LOG_DEBUG(Service_VI, "called mode={}", mode);
const auto converted_mode = ConvertScalingModeImpl(mode);
ConvertedScaleMode converted_mode{};
const auto result = ConvertScalingModeImpl(&converted_mode, mode);
if (converted_mode.Succeeded()) {
if (result == ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.PushEnum(*converted_mode);
rb.PushEnum(converted_mode);
} else {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(converted_mode.Code());
rb.Push(result);
}
}
@ -760,18 +761,24 @@ private:
rb.Push(alignment);
}
static ResultVal<ConvertedScaleMode> ConvertScalingModeImpl(NintendoScaleMode mode) {
static Result ConvertScalingModeImpl(ConvertedScaleMode* out_scaling_mode,
NintendoScaleMode mode) {
switch (mode) {
case NintendoScaleMode::None:
return ConvertedScaleMode::None;
*out_scaling_mode = ConvertedScaleMode::None;
return ResultSuccess;
case NintendoScaleMode::Freeze:
return ConvertedScaleMode::Freeze;
*out_scaling_mode = ConvertedScaleMode::Freeze;
return ResultSuccess;
case NintendoScaleMode::ScaleToWindow:
return ConvertedScaleMode::ScaleToWindow;
*out_scaling_mode = ConvertedScaleMode::ScaleToWindow;
return ResultSuccess;
case NintendoScaleMode::ScaleAndCrop:
return ConvertedScaleMode::ScaleAndCrop;
*out_scaling_mode = ConvertedScaleMode::ScaleAndCrop;
return ResultSuccess;
case NintendoScaleMode::PreserveAspectRatio:
return ConvertedScaleMode::PreserveAspectRatio;
*out_scaling_mode = ConvertedScaleMode::PreserveAspectRatio;
return ResultSuccess;
default:
LOG_ERROR(Service_VI, "Invalid scaling mode specified, mode={}", mode);
return ResultOperationFailed;

View File

@ -509,9 +509,9 @@ class GuestMemory {
public:
GuestMemory() = delete;
explicit GuestMemory(M& memory_, u64 addr_, std::size_t size_,
explicit GuestMemory(M& memory, u64 addr, std::size_t size,
Common::ScratchBuffer<T>* backup = nullptr)
: memory{memory_}, addr{addr_}, size{size_} {
: m_memory{memory}, m_addr{addr}, m_size{size} {
static_assert(FLAGS & GuestMemoryFlags::Read || FLAGS & GuestMemoryFlags::Write);
if constexpr (FLAGS & GuestMemoryFlags::Read) {
Read(addr, size, backup);
@ -521,89 +521,97 @@ public:
~GuestMemory() = default;
T* data() noexcept {
return data_span.data();
return m_data_span.data();
}
const T* data() const noexcept {
return data_span.data();
return m_data_span.data();
}
size_t size() const noexcept {
return m_size;
}
size_t size_bytes() const noexcept {
return this->size() * sizeof(T);
}
[[nodiscard]] T* begin() noexcept {
return data();
return this->data();
}
[[nodiscard]] const T* begin() const noexcept {
return data();
return this->data();
}
[[nodiscard]] T* end() noexcept {
return data() + size;
return this->data() + this->size();
}
[[nodiscard]] const T* end() const noexcept {
return data() + size;
return this->data() + this->size();
}
T& operator[](size_t index) noexcept {
return data_span[index];
return m_data_span[index];
}
const T& operator[](size_t index) const noexcept {
return data_span[index];
return m_data_span[index];
}
void SetAddressAndSize(u64 addr_, std::size_t size_) noexcept {
addr = addr_;
size = size_;
addr_changed = true;
void SetAddressAndSize(u64 addr, std::size_t size) noexcept {
m_addr = addr;
m_size = size;
m_addr_changed = true;
}
std::span<T> Read(u64 addr_, std::size_t size_,
std::span<T> Read(u64 addr, std::size_t size,
Common::ScratchBuffer<T>* backup = nullptr) noexcept {
addr = addr_;
size = size_;
if (size == 0) {
is_data_copy = true;
m_addr = addr;
m_size = size;
if (m_size == 0) {
m_is_data_copy = true;
return {};
}
if (TrySetSpan()) {
if (this->TrySetSpan()) {
if constexpr (FLAGS & GuestMemoryFlags::Safe) {
memory.FlushRegion(addr, size * sizeof(T));
m_memory.FlushRegion(m_addr, this->size_bytes());
}
} else {
if (backup) {
backup->resize_destructive(size);
data_span = *backup;
backup->resize_destructive(this->size());
m_data_span = *backup;
} else {
data_copy.resize(size);
data_span = std::span(data_copy);
m_data_copy.resize(this->size());
m_data_span = std::span(m_data_copy);
}
is_data_copy = true;
span_valid = true;
m_is_data_copy = true;
m_span_valid = true;
if constexpr (FLAGS & GuestMemoryFlags::Safe) {
memory.ReadBlock(addr, data_span.data(), size * sizeof(T));
m_memory.ReadBlock(m_addr, this->data(), this->size_bytes());
} else {
memory.ReadBlockUnsafe(addr, data_span.data(), size * sizeof(T));
m_memory.ReadBlockUnsafe(m_addr, this->data(), this->size_bytes());
}
}
return data_span;
return m_data_span;
}
void Write(std::span<T> write_data) noexcept {
if constexpr (FLAGS & GuestMemoryFlags::Cached) {
memory.WriteBlockCached(addr, write_data.data(), size * sizeof(T));
m_memory.WriteBlockCached(m_addr, write_data.data(), this->size_bytes());
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
memory.WriteBlock(addr, write_data.data(), size * sizeof(T));
m_memory.WriteBlock(m_addr, write_data.data(), this->size_bytes());
} else {
memory.WriteBlockUnsafe(addr, write_data.data(), size * sizeof(T));
m_memory.WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes());
}
}
bool TrySetSpan() noexcept {
if (u8* ptr = memory.GetSpan(addr, size * sizeof(T)); ptr) {
data_span = {reinterpret_cast<T*>(ptr), size};
span_valid = true;
if (u8* ptr = m_memory.GetSpan(m_addr, this->size_bytes()); ptr) {
m_data_span = {reinterpret_cast<T*>(ptr), this->size()};
m_span_valid = true;
return true;
}
return false;
@ -611,36 +619,36 @@ public:
protected:
bool IsDataCopy() const noexcept {
return is_data_copy;
return m_is_data_copy;
}
bool AddressChanged() const noexcept {
return addr_changed;
return m_addr_changed;
}
M& memory;
u64 addr;
size_t size;
std::span<T> data_span{};
std::vector<T> data_copy;
bool span_valid{false};
bool is_data_copy{false};
bool addr_changed{false};
M& m_memory;
u64 m_addr{};
size_t m_size{};
std::span<T> m_data_span{};
std::vector<T> m_data_copy{};
bool m_span_valid{false};
bool m_is_data_copy{false};
bool m_addr_changed{false};
};
template <typename M, typename T, GuestMemoryFlags FLAGS>
class GuestMemoryScoped : public GuestMemory<M, T, FLAGS> {
public:
GuestMemoryScoped() = delete;
explicit GuestMemoryScoped(M& memory_, u64 addr_, std::size_t size_,
explicit GuestMemoryScoped(M& memory, u64 addr, std::size_t size,
Common::ScratchBuffer<T>* backup = nullptr)
: GuestMemory<M, T, FLAGS>(memory_, addr_, size_, backup) {
: GuestMemory<M, T, FLAGS>(memory, addr, size, backup) {
if constexpr (!(FLAGS & GuestMemoryFlags::Read)) {
if (!this->TrySetSpan()) {
if (backup) {
this->data_span = *backup;
this->span_valid = true;
this->is_data_copy = true;
this->m_data_span = *backup;
this->m_span_valid = true;
this->m_is_data_copy = true;
}
}
}
@ -648,24 +656,21 @@ public:
~GuestMemoryScoped() {
if constexpr (FLAGS & GuestMemoryFlags::Write) {
if (this->size == 0) [[unlikely]] {
if (this->size() == 0) [[unlikely]] {
return;
}
if (this->AddressChanged() || this->IsDataCopy()) {
ASSERT(this->span_valid);
ASSERT(this->m_span_valid);
if constexpr (FLAGS & GuestMemoryFlags::Cached) {
this->memory.WriteBlockCached(this->addr, this->data_span.data(),
this->size * sizeof(T));
this->m_memory.WriteBlockCached(this->m_addr, this->data(), this->size_bytes());
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
this->memory.WriteBlock(this->addr, this->data_span.data(),
this->size * sizeof(T));
this->m_memory.WriteBlock(this->m_addr, this->data(), this->size_bytes());
} else {
this->memory.WriteBlockUnsafe(this->addr, this->data_span.data(),
this->size * sizeof(T));
this->m_memory.WriteBlockUnsafe(this->m_addr, this->data(), this->size_bytes());
}
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
this->memory.InvalidateRegion(this->addr, this->size * sizeof(T));
this->m_memory.InvalidateRegion(this->m_addr, this->size_bytes());
}
}
}

View File

@ -5,6 +5,7 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/microprofile.h"
#include "common/polyfill_ranges.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/memory.h"

View File

@ -106,6 +106,43 @@ bool IsASTCSupported() {
return true;
}
static bool HasSlowSoftwareAstc(std::string_view vendor_name, std::string_view renderer) {
// ifdef for Unix reduces string comparisons for non-Windows drivers, and Intel
#ifdef YUZU_UNIX
// Sorted vaguely by how likely a vendor is to appear
if (vendor_name == "AMD") {
// RadeonSI
return true;
}
if (vendor_name == "Intel") {
// Must be inside YUZU_UNIX ifdef as the Windows driver uses the same vendor string
// iris, crocus
const bool is_intel_dg = (renderer.find("DG") != std::string_view::npos);
return is_intel_dg;
}
if (vendor_name == "nouveau") {
return true;
}
if (vendor_name == "X.Org") {
// R600
return true;
}
#endif
if (vendor_name == "Collabora Ltd") {
// Zink
return true;
}
if (vendor_name == "Microsoft Corporation") {
// d3d12
return true;
}
if (vendor_name == "Mesa/X.org") {
// llvmpipe, softpipe, virgl
return true;
}
return false;
}
[[nodiscard]] bool IsDebugToolAttached(std::span<const std::string_view> extensions) {
const bool nsight = std::getenv("NVTX_INJECTION64_PATH") || std::getenv("NSIGHT_LAUNCHED");
return nsight || HasExtension(extensions, "GL_EXT_debug_tool") ||
@ -120,12 +157,16 @@ Device::Device(Core::Frontend::EmuWindow& emu_window) {
}
vendor_name = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
const std::string_view version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
const std::string_view renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
const std::vector extensions = GetExtensions();
const bool is_nvidia = vendor_name == "NVIDIA Corporation";
const bool is_amd = vendor_name == "ATI Technologies Inc.";
const bool is_intel = vendor_name == "Intel";
const bool has_slow_software_astc =
!is_nvidia && !is_amd && HasSlowSoftwareAstc(vendor_name, renderer);
#ifdef __unix__
constexpr bool is_linux = true;
#else
@ -152,7 +193,7 @@ Device::Device(Core::Frontend::EmuWindow& emu_window) {
has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array;
has_image_load_formatted = HasExtension(extensions, "GL_EXT_shader_image_load_formatted");
has_texture_shadow_lod = HasExtension(extensions, "GL_EXT_texture_shadow_lod");
has_astc = IsASTCSupported();
has_astc = !has_slow_software_astc && IsASTCSupported();
has_variable_aoffi = TestVariableAoffi();
has_component_indexing_bug = is_amd;
has_precise_bug = TestPreciseBug();

View File

@ -214,13 +214,17 @@ void GameList::OnTextChanged(const QString& new_text) {
const int children_count = folder->rowCount();
for (int j = 0; j < children_count; ++j) {
++children_total;
const QStandardItem* child = folder->child(j, 0);
const auto program_id = child->data(GameListItemPath::ProgramIdRole).toULongLong();
const QString file_path =
child->data(GameListItemPath::FullPathRole).toString().toLower();
const QString file_title =
child->data(GameListItemPath::TitleRole).toString().toLower();
const QString file_program_id =
child->data(GameListItemPath::ProgramIdRole).toString().toLower();
QStringLiteral("%1").arg(program_id, 16, 16, QLatin1Char{'0'});
// Only items which filename in combination with its title contains all words
// that are in the searchfield will be visible in the gamelist
@ -231,7 +235,7 @@ void GameList::OnTextChanged(const QString& new_text) {
file_path.mid(file_path.lastIndexOf(QLatin1Char{'/'}) + 1) + QLatin1Char{' '} +
file_title;
if (ContainsAllWords(file_name, edit_filter_text) ||
(file_program_id.count() == 16 && edit_filter_text.contains(file_program_id))) {
(file_program_id.count() == 16 && file_program_id.contains(edit_filter_text))) {
tree_view->setRowHidden(j, folder_index, false);
++result_count;
} else {