early-access version 1814

This commit is contained in:
pineappleEA 2021-06-23 14:35:57 +02:00
parent abcdc84bad
commit 23cae6079a
52 changed files with 752 additions and 179 deletions

View file

@ -1,7 +1,7 @@
yuzu emulator early access yuzu emulator early access
============= =============
This is the source code for early-access 1805. This is the source code for early-access 1814.
## Legal Notice ## Legal Notice

View file

@ -21,6 +21,8 @@ void DetachedTasks::WaitForAllTasks() {
} }
DetachedTasks::~DetachedTasks() { DetachedTasks::~DetachedTasks() {
WaitForAllTasks();
std::unique_lock lock{mutex}; std::unique_lock lock{mutex};
ASSERT(count == 0); ASSERT(count == 0);
instance = nullptr; instance = nullptr;

View file

@ -172,7 +172,7 @@ std::string ReadStringFromFile(const std::filesystem::path& path, FileType type)
size_t WriteStringToFile(const std::filesystem::path& path, FileType type, size_t WriteStringToFile(const std::filesystem::path& path, FileType type,
std::string_view string) { std::string_view string) {
if (!IsFile(path)) { if (Exists(path) && !IsFile(path)) {
return 0; return 0;
} }
@ -183,7 +183,7 @@ size_t WriteStringToFile(const std::filesystem::path& path, FileType type,
size_t AppendStringToFile(const std::filesystem::path& path, FileType type, size_t AppendStringToFile(const std::filesystem::path& path, FileType type,
std::string_view string) { std::string_view string) {
if (!IsFile(path)) { if (Exists(path) && !IsFile(path)) {
return 0; return 0;
} }

View file

@ -49,7 +49,7 @@ void OpenFileStream(FileStream& file_stream, const Path& path, std::ios_base::op
/** /**
* Reads an entire file at path and returns a string of the contents read from the file. * Reads an entire file at path and returns a string of the contents read from the file.
* If the filesystem object at path is not a file, this function returns an empty string. * If the filesystem object at path is not a regular file, this function returns an empty string.
* *
* @param path Filesystem path * @param path Filesystem path
* @param type File type * @param type File type
@ -72,7 +72,8 @@ template <typename Path>
/** /**
* Writes a string to a file at path and returns the number of characters successfully written. * Writes a string to a file at path and returns the number of characters successfully written.
* If a file already exists at path, its contents will be erased. * If a file already exists at path, its contents will be erased.
* If the filesystem object at path is not a file, this function returns 0. * If a file does not exist at path, it creates and opens a new empty file for writing.
* If the filesystem object at path exists and is not a regular file, this function returns 0.
* *
* @param path Filesystem path * @param path Filesystem path
* @param type File type * @param type File type
@ -95,7 +96,8 @@ template <typename Path>
/** /**
* Appends a string to a file at path and returns the number of characters successfully written. * Appends a string to a file at path and returns the number of characters successfully written.
* If the filesystem object at path is not a file, this function returns 0. * If a file does not exist at path, it creates and opens a new empty file for appending.
* If the filesystem object at path exists and is not a regular file, this function returns 0.
* *
* @param path Filesystem path * @param path Filesystem path
* @param type File type * @param type File type
@ -394,11 +396,11 @@ public:
[[nodiscard]] size_t WriteString(std::span<const char> string) const; [[nodiscard]] size_t WriteString(std::span<const char> string) const;
/** /**
* Flushes any unwritten buffered data into the file. * Attempts to flush any unwritten buffered data into the file and flush the file into the disk.
* *
* @returns True if the flush was successful, false otherwise. * @returns True if the flush was successful, false otherwise.
*/ */
[[nodiscard]] bool Flush() const; bool Flush() const;
/** /**
* Resizes the file to a given size. * Resizes the file to a given size.

View file

@ -135,8 +135,9 @@ std::shared_ptr<IOFile> FileOpen(const fs::path& path, FileAccessMode mode, File
return nullptr; return nullptr;
} }
if (!IsFile(path)) { if (Exists(path) && !IsFile(path)) {
LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a file", LOG_ERROR(Common_Filesystem,
"Filesystem object at path={} exists and is not a regular file",
PathToUTF8String(path)); PathToUTF8String(path));
return nullptr; return nullptr;
} }

View file

@ -48,18 +48,18 @@ template <typename Path>
* *
* Failures occur when: * Failures occur when:
* - Input path is not valid * - Input path is not valid
* - Filesystem object at path is not a file * - Filesystem object at path is not a regular file
* - Filesystem at path is read only * - Filesystem at path is read only
* *
* @param path Filesystem path * @param path Filesystem path
* *
* @returns True if file removal succeeds or file does not exist, false otherwise. * @returns True if file removal succeeds or file does not exist, false otherwise.
*/ */
[[nodiscard]] bool RemoveFile(const std::filesystem::path& path); bool RemoveFile(const std::filesystem::path& path);
#ifdef _WIN32 #ifdef _WIN32
template <typename Path> template <typename Path>
[[nodiscard]] bool RemoveFile(const Path& path) { bool RemoveFile(const Path& path) {
if constexpr (IsChar<typename Path::value_type>) { if constexpr (IsChar<typename Path::value_type>) {
return RemoveFile(ToU8String(path)); return RemoveFile(ToU8String(path));
} else { } else {
@ -74,7 +74,7 @@ template <typename Path>
* Failures occur when: * Failures occur when:
* - One or both input path(s) is not valid * - One or both input path(s) is not valid
* - Filesystem object at old_path does not exist * - Filesystem object at old_path does not exist
* - Filesystem object at old_path is not a file * - Filesystem object at old_path is not a regular file
* - Filesystem object at new_path exists * - Filesystem object at new_path exists
* - Filesystem at either path is read only * - Filesystem at either path is read only
* *
@ -110,8 +110,8 @@ template <typename Path1, typename Path2>
* *
* Failures occur when: * Failures occur when:
* - Input path is not valid * - Input path is not valid
* - Filesystem object at path is not a file * - Filesystem object at path exists and is not a regular file
* - The file is not opened * - The file is not open
* *
* @param path Filesystem path * @param path Filesystem path
* @param mode File access mode * @param mode File access mode
@ -251,11 +251,11 @@ template <typename Path>
* *
* @returns True if directory removal succeeds or directory does not exist, false otherwise. * @returns True if directory removal succeeds or directory does not exist, false otherwise.
*/ */
[[nodiscard]] bool RemoveDir(const std::filesystem::path& path); bool RemoveDir(const std::filesystem::path& path);
#ifdef _WIN32 #ifdef _WIN32
template <typename Path> template <typename Path>
[[nodiscard]] bool RemoveDir(const Path& path) { bool RemoveDir(const Path& path) {
if constexpr (IsChar<typename Path::value_type>) { if constexpr (IsChar<typename Path::value_type>) {
return RemoveDir(ToU8String(path)); return RemoveDir(ToU8String(path));
} else { } else {
@ -276,11 +276,11 @@ template <typename Path>
* *
* @returns True if the directory and all of its contents are removed successfully, false otherwise. * @returns True if the directory and all of its contents are removed successfully, false otherwise.
*/ */
[[nodiscard]] bool RemoveDirRecursively(const std::filesystem::path& path); bool RemoveDirRecursively(const std::filesystem::path& path);
#ifdef _WIN32 #ifdef _WIN32
template <typename Path> template <typename Path>
[[nodiscard]] bool RemoveDirRecursively(const Path& path) { bool RemoveDirRecursively(const Path& path) {
if constexpr (IsChar<typename Path::value_type>) { if constexpr (IsChar<typename Path::value_type>) {
return RemoveDirRecursively(ToU8String(path)); return RemoveDirRecursively(ToU8String(path));
} else { } else {
@ -301,11 +301,11 @@ template <typename Path>
* *
* @returns True if all of the directory's contents are removed successfully, false otherwise. * @returns True if all of the directory's contents are removed successfully, false otherwise.
*/ */
[[nodiscard]] bool RemoveDirContentsRecursively(const std::filesystem::path& path); bool RemoveDirContentsRecursively(const std::filesystem::path& path);
#ifdef _WIN32 #ifdef _WIN32
template <typename Path> template <typename Path>
[[nodiscard]] bool RemoveDirContentsRecursively(const Path& path) { bool RemoveDirContentsRecursively(const Path& path) {
if constexpr (IsChar<typename Path::value_type>) { if constexpr (IsChar<typename Path::value_type>) {
return RemoveDirContentsRecursively(ToU8String(path)); return RemoveDirContentsRecursively(ToU8String(path));
} else { } else {
@ -435,11 +435,13 @@ template <typename Path>
#endif #endif
/** /**
* Returns whether a filesystem object at path is a file. * Returns whether a filesystem object at path is a regular file.
* A regular file is a file that stores text or binary data.
* It is not a directory, symlink, FIFO, socket, block device, or character device.
* *
* @param path Filesystem path * @param path Filesystem path
* *
* @returns True if a filesystem object at path is a file, false otherwise. * @returns True if a filesystem object at path is a regular file, false otherwise.
*/ */
[[nodiscard]] bool IsFile(const std::filesystem::path& path); [[nodiscard]] bool IsFile(const std::filesystem::path& path);

View file

@ -159,7 +159,7 @@ FileBackend::FileBackend(const std::filesystem::path& filename) {
// Existence checks are done within the functions themselves. // Existence checks are done within the functions themselves.
// We don't particularly care if these succeed or not. // We don't particularly care if these succeed or not.
void(FS::RemoveFile(old_filename)); FS::RemoveFile(old_filename);
void(FS::RenameFile(filename, old_filename)); void(FS::RenameFile(filename, old_filename));
file = file =
@ -186,7 +186,7 @@ void FileBackend::Write(const Entry& entry) {
bytes_written += file->WriteString(FormatLogMessage(entry).append(1, '\n')); bytes_written += file->WriteString(FormatLogMessage(entry).append(1, '\n'));
if (entry.log_level >= Level::Error) { if (entry.log_level >= Level::Error) {
void(file->Flush()); file->Flush();
} }
} }

View file

@ -139,6 +139,7 @@ add_library(core STATIC
frontend/input.h frontend/input.h
hardware_interrupt_manager.cpp hardware_interrupt_manager.cpp
hardware_interrupt_manager.h hardware_interrupt_manager.h
hle/api_version.h
hle/ipc.h hle/ipc.h
hle/ipc_helpers.h hle/ipc_helpers.h
hle/kernel/board/nintendo/nx/k_system_control.cpp hle/kernel/board/nintendo/nx/k_system_control.cpp
@ -550,6 +551,8 @@ add_library(core STATIC
hle/service/spl/module.h hle/service/spl/module.h
hle/service/spl/spl.cpp hle/service/spl/spl.cpp
hle/service/spl/spl.h hle/service/spl/spl.h
hle/service/spl/spl_results.h
hle/service/spl/spl_types.h
hle/service/ssl/ssl.cpp hle/service/ssl/ssl.cpp
hle/service/ssl/ssl.h hle/service/ssl/ssl.h
hle/service/time/clock_types.h hle/service/time/clock_types.h

View file

@ -345,8 +345,10 @@ std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(
static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type, static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type,
const Service::FileSystem::FileSystemController& fs_controller) { const Service::FileSystem::FileSystemController& fs_controller) {
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id); const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id);
if ((type != ContentRecordType::Program && type != ContentRecordType::Data) || if ((type != ContentRecordType::Program && type != ContentRecordType::Data) ||
load_dir == nullptr || load_dir->GetSize() <= 0) { ((load_dir == nullptr || load_dir->GetSize() <= 0) &&
(sdmc_load_dir == nullptr || sdmc_load_dir->GetSize() <= 0))) {
return; return;
} }
@ -356,7 +358,10 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
} }
const auto& disabled = Settings::values.disabled_addons[title_id]; const auto& disabled = Settings::values.disabled_addons[title_id];
auto patch_dirs = load_dir->GetSubdirectories(); std::vector<VirtualDir> patch_dirs = load_dir->GetSubdirectories();
if (std::find(disabled.cbegin(), disabled.cend(), "SDMC") == disabled.cend()) {
patch_dirs.push_back(sdmc_load_dir);
}
std::sort(patch_dirs.begin(), patch_dirs.end(), std::sort(patch_dirs.begin(), patch_dirs.end(),
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); }); [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
@ -524,6 +529,15 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u
} }
} }
// SDMC mod directory (RomFS LayeredFS)
const auto sdmc_mod_dir = fs_controller.GetSDMCModificationLoadRoot(title_id);
if (sdmc_mod_dir != nullptr && sdmc_mod_dir->GetSize() > 0 &&
IsDirValidAndNonEmpty(FindSubdirectoryCaseless(sdmc_mod_dir, "romfs"))) {
const auto mod_disabled =
std::find(disabled.begin(), disabled.end(), "SDMC") != disabled.end();
out.insert_or_assign(mod_disabled ? "[D] SDMC" : "SDMC", "LayeredFS");
}
// DLC // DLC
const auto dlc_entries = const auto dlc_entries =
content_provider.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data); content_provider.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data);

View file

@ -27,6 +27,14 @@ ResultVal<VirtualDir> SDMCFactory::Open() const {
return MakeResult<VirtualDir>(dir); return MakeResult<VirtualDir>(dir);
} }
VirtualDir SDMCFactory::GetSDMCModificationLoadRoot(u64 title_id) const {
// LayeredFS doesn't work on updates and title id-less homebrew
if (title_id == 0 || (title_id & 0xFFF) == 0x800) {
return nullptr;
}
return GetOrCreateDirectoryRelative(dir, fmt::format("/atmosphere/contents/{:016X}", title_id));
}
VirtualDir SDMCFactory::GetSDMCContentDirectory() const { VirtualDir SDMCFactory::GetSDMCContentDirectory() const {
return GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents"); return GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents");
} }

View file

@ -21,6 +21,7 @@ public:
ResultVal<VirtualDir> Open() const; ResultVal<VirtualDir> Open() const;
VirtualDir GetSDMCModificationLoadRoot(u64 title_id) const;
VirtualDir GetSDMCContentDirectory() const; VirtualDir GetSDMCContentDirectory() const;
RegisteredCache* GetSDMCContents() const; RegisteredCache* GetSDMCContents() const;

View file

@ -4,47 +4,29 @@
#include "core/file_sys/system_archive/system_version.h" #include "core/file_sys/system_archive/system_version.h"
#include "core/file_sys/vfs_vector.h" #include "core/file_sys/vfs_vector.h"
#include "core/hle/api_version.h"
namespace FileSys::SystemArchive { namespace FileSys::SystemArchive {
namespace SystemVersionData {
// This section should reflect the best system version to describe yuzu's HLE api.
// TODO(DarkLordZach): Update when HLE gets better.
constexpr u8 VERSION_MAJOR = 11;
constexpr u8 VERSION_MINOR = 0;
constexpr u8 VERSION_MICRO = 1;
constexpr u8 REVISION_MAJOR = 1;
constexpr u8 REVISION_MINOR = 0;
constexpr char PLATFORM_STRING[] = "NX";
constexpr char VERSION_HASH[] = "69103fcb2004dace877094c2f8c29e6113be5dbf";
constexpr char DISPLAY_VERSION[] = "11.0.1";
constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 11.0.1-1.0";
} // namespace SystemVersionData
std::string GetLongDisplayVersion() { std::string GetLongDisplayVersion() {
return SystemVersionData::DISPLAY_TITLE; return HLE::ApiVersion::DISPLAY_TITLE;
} }
VirtualDir SystemVersion() { VirtualDir SystemVersion() {
VirtualFile file = std::make_shared<VectorVfsFile>(std::vector<u8>(0x100), "file"); VirtualFile file = std::make_shared<VectorVfsFile>(std::vector<u8>(0x100), "file");
file->WriteObject(SystemVersionData::VERSION_MAJOR, 0); file->WriteObject(HLE::ApiVersion::HOS_VERSION_MAJOR, 0);
file->WriteObject(SystemVersionData::VERSION_MINOR, 1); file->WriteObject(HLE::ApiVersion::HOS_VERSION_MINOR, 1);
file->WriteObject(SystemVersionData::VERSION_MICRO, 2); file->WriteObject(HLE::ApiVersion::HOS_VERSION_MICRO, 2);
file->WriteObject(SystemVersionData::REVISION_MAJOR, 4); file->WriteObject(HLE::ApiVersion::SDK_REVISION_MAJOR, 4);
file->WriteObject(SystemVersionData::REVISION_MINOR, 5); file->WriteObject(HLE::ApiVersion::SDK_REVISION_MINOR, 5);
file->WriteArray(SystemVersionData::PLATFORM_STRING, file->WriteArray(HLE::ApiVersion::PLATFORM_STRING,
std::min<u64>(sizeof(SystemVersionData::PLATFORM_STRING), 0x20ULL), 0x8); std::min<u64>(sizeof(HLE::ApiVersion::PLATFORM_STRING), 0x20ULL), 0x8);
file->WriteArray(SystemVersionData::VERSION_HASH, file->WriteArray(HLE::ApiVersion::VERSION_HASH,
std::min<u64>(sizeof(SystemVersionData::VERSION_HASH), 0x40ULL), 0x28); std::min<u64>(sizeof(HLE::ApiVersion::VERSION_HASH), 0x40ULL), 0x28);
file->WriteArray(SystemVersionData::DISPLAY_VERSION, file->WriteArray(HLE::ApiVersion::DISPLAY_VERSION,
std::min<u64>(sizeof(SystemVersionData::DISPLAY_VERSION), 0x18ULL), 0x68); std::min<u64>(sizeof(HLE::ApiVersion::DISPLAY_VERSION), 0x18ULL), 0x68);
file->WriteArray(SystemVersionData::DISPLAY_TITLE, file->WriteArray(HLE::ApiVersion::DISPLAY_TITLE,
std::min<u64>(sizeof(SystemVersionData::DISPLAY_TITLE), 0x80ULL), 0x80); std::min<u64>(sizeof(HLE::ApiVersion::DISPLAY_TITLE), 0x80ULL), 0x80);
return std::make_shared<VectorVfsDirectory>(std::vector<VirtualFile>{file}, return std::make_shared<VectorVfsDirectory>(std::vector<VirtualFile>{file},
std::vector<VirtualDir>{}, "data"); std::vector<VirtualDir>{}, "data");
} }

View file

@ -24,17 +24,12 @@ constexpr FS::FileAccessMode ModeFlagsToFileAccessMode(Mode mode) {
case Mode::Read: case Mode::Read:
return FS::FileAccessMode::Read; return FS::FileAccessMode::Read;
case Mode::Write: case Mode::Write:
return FS::FileAccessMode::Write;
case Mode::ReadWrite: case Mode::ReadWrite:
return FS::FileAccessMode::ReadWrite;
case Mode::Append: case Mode::Append:
return FS::FileAccessMode::Append;
case Mode::ReadAppend: case Mode::ReadAppend:
return FS::FileAccessMode::ReadAppend;
case Mode::WriteAppend: case Mode::WriteAppend:
return FS::FileAccessMode::Append;
case Mode::All: case Mode::All:
return FS::FileAccessMode::ReadAppend; return FS::FileAccessMode::ReadWrite;
default: default:
return {}; return {};
} }

38
src/core/hle/api_version.h Executable file
View file

@ -0,0 +1,38 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/common_types.h"
// This file contains yuzu's HLE API version constants.
namespace HLE::ApiVersion {
// Horizon OS version constants.
constexpr u8 HOS_VERSION_MAJOR = 11;
constexpr u8 HOS_VERSION_MINOR = 0;
constexpr u8 HOS_VERSION_MICRO = 1;
// NintendoSDK version constants.
constexpr u8 SDK_REVISION_MAJOR = 1;
constexpr u8 SDK_REVISION_MINOR = 0;
constexpr char PLATFORM_STRING[] = "NX";
constexpr char VERSION_HASH[] = "69103fcb2004dace877094c2f8c29e6113be5dbf";
constexpr char DISPLAY_VERSION[] = "11.0.1";
constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 11.0.1-1.0";
// Atmosphere version constants.
constexpr u8 ATMOSPHERE_RELEASE_VERSION_MAJOR = 0;
constexpr u8 ATMOSPHERE_RELEASE_VERSION_MINOR = 19;
constexpr u8 ATMOSPHERE_RELEASE_VERSION_MICRO = 4;
constexpr u32 GetTargetFirmware() {
return u32{HOS_VERSION_MAJOR} << 24 | u32{HOS_VERSION_MINOR} << 16 |
u32{HOS_VERSION_MICRO} << 8 | 0U;
}
} // namespace HLE::ApiVersion

View file

@ -313,7 +313,7 @@ void SynchronizeInternal(AM::Applets::AppletManager& applet_manager, DirectoryGe
LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res); LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res);
if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) { if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) {
void(Common::FS::RemoveFile(zip_path)); Common::FS::RemoveFile(zip_path);
} }
HandleDownloadDisplayResult(applet_manager, res); HandleDownloadDisplayResult(applet_manager, res);
@ -445,7 +445,7 @@ std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title)
LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res); LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res);
if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) { if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) {
void(Common::FS::RemoveFile(bin_file_path)); Common::FS::RemoveFile(bin_file_path);
} }
HandleDownloadDisplayResult(applet_manager, res); HandleDownloadDisplayResult(applet_manager, res);

View file

@ -703,6 +703,16 @@ FileSys::VirtualDir FileSystemController::GetModificationLoadRoot(u64 title_id)
return bis_factory->GetModificationLoadRoot(title_id); return bis_factory->GetModificationLoadRoot(title_id);
} }
FileSys::VirtualDir FileSystemController::GetSDMCModificationLoadRoot(u64 title_id) const {
LOG_TRACE(Service_FS, "Opening SDMC mod load root for tid={:016X}", title_id);
if (sdmc_factory == nullptr) {
return nullptr;
}
return sdmc_factory->GetSDMCModificationLoadRoot(title_id);
}
FileSys::VirtualDir FileSystemController::GetModificationDumpRoot(u64 title_id) const { FileSys::VirtualDir FileSystemController::GetModificationDumpRoot(u64 title_id) const {
LOG_TRACE(Service_FS, "Opening mod dump root for tid={:016X}", title_id); LOG_TRACE(Service_FS, "Opening mod dump root for tid={:016X}", title_id);

View file

@ -115,6 +115,7 @@ public:
FileSys::VirtualDir GetContentDirectory(ContentStorageId id) const; FileSys::VirtualDir GetContentDirectory(ContentStorageId id) const;
FileSys::VirtualDir GetImageDirectory(ImageDirectoryId id) const; FileSys::VirtualDir GetImageDirectory(ImageDirectoryId id) const;
FileSys::VirtualDir GetSDMCModificationLoadRoot(u64 title_id) const;
FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) const; FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) const;
FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) const; FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) const;

View file

@ -314,6 +314,8 @@ void Controller_NPad::OnInit() {
void Controller_NPad::OnLoadInputDevices() { void Controller_NPad::OnLoadInputDevices() {
const auto& players = Settings::values.players.GetValue(); const auto& players = Settings::values.players.GetValue();
std::lock_guard lock{mutex};
for (std::size_t i = 0; i < players.size(); ++i) { for (std::size_t i = 0; i < players.size(); ++i) {
std::transform(players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, std::transform(players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_END, players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_END,
@ -348,6 +350,8 @@ void Controller_NPad::OnRelease() {
} }
void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
std::lock_guard lock{mutex};
const auto controller_idx = NPadIdToIndex(npad_id); const auto controller_idx = NPadIdToIndex(npad_id);
const auto controller_type = connected_controllers[controller_idx].type; const auto controller_type = connected_controllers[controller_idx].type;
if (!connected_controllers[controller_idx].is_connected) { if (!connected_controllers[controller_idx].is_connected) {

View file

@ -6,6 +6,8 @@
#include <array> #include <array>
#include <atomic> #include <atomic>
#include <mutex>
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/quaternion.h" #include "common/quaternion.h"
@ -563,6 +565,8 @@ private:
using MotionArray = std::array< using MotionArray = std::array<
std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>, std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>,
10>; 10>;
std::mutex mutex;
ButtonArray buttons; ButtonArray buttons;
StickArray sticks; StickArray sticks;
VibrationArray vibrations; VibrationArray vibrations;

View file

@ -9,7 +9,7 @@ namespace Service::SPL {
CSRNG::CSRNG(Core::System& system_, std::shared_ptr<Module> module_) CSRNG::CSRNG(Core::System& system_, std::shared_ptr<Module> module_)
: Interface(system_, std::move(module_), "csrng") { : Interface(system_, std::move(module_), "csrng") {
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &CSRNG::GetRandomBytes, "GetRandomBytes"}, {0, &CSRNG::GenerateRandomBytes, "GenerateRandomBytes"},
}; };
RegisterHandlers(functions); RegisterHandlers(functions);
} }

View file

@ -10,6 +10,7 @@
#include <vector> #include <vector>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/settings.h" #include "common/settings.h"
#include "core/hle/api_version.h"
#include "core/hle/ipc_helpers.h" #include "core/hle/ipc_helpers.h"
#include "core/hle/service/spl/csrng.h" #include "core/hle/service/spl/csrng.h"
#include "core/hle/service/spl/module.h" #include "core/hle/service/spl/module.h"
@ -24,7 +25,46 @@ Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> modu
Module::Interface::~Interface() = default; Module::Interface::~Interface() = default;
void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) { void Module::Interface::GetConfig(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto config_item = rp.PopEnum<ConfigItem>();
// 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();
if (smc_result.Failed()) {
LOG_ERROR(Service_SPL, "called, config_item={}, result_code={}", config_item,
result_code.raw);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result_code);
}
LOG_DEBUG(Service_SPL, "called, config_item={}, result_code={}, smc_result={}", config_item,
result_code.raw, *smc_result);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(result_code);
rb.Push(*smc_result);
}
void Module::Interface::ModularExponentiate(Kernel::HLERequestContext& ctx) {
UNIMPLEMENTED_MSG("ModularExponentiate is not implemented!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSecureMonitorNotImplemented);
}
void Module::Interface::SetConfig(Kernel::HLERequestContext& ctx) {
UNIMPLEMENTED_MSG("SetConfig is not implemented!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSecureMonitorNotImplemented);
}
void Module::Interface::GenerateRandomBytes(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_SPL, "called"); LOG_DEBUG(Service_SPL, "called");
const std::size_t size = ctx.GetWriteBufferSize(); const std::size_t size = ctx.GetWriteBufferSize();
@ -39,6 +79,88 @@ void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
} }
void Module::Interface::IsDevelopment(Kernel::HLERequestContext& ctx) {
UNIMPLEMENTED_MSG("IsDevelopment is not implemented!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSecureMonitorNotImplemented);
}
void Module::Interface::SetBootReason(Kernel::HLERequestContext& ctx) {
UNIMPLEMENTED_MSG("SetBootReason is not implemented!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSecureMonitorNotImplemented);
}
void Module::Interface::GetBootReason(Kernel::HLERequestContext& ctx) {
UNIMPLEMENTED_MSG("GetBootReason is not implemented!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSecureMonitorNotImplemented);
}
ResultVal<u64> Module::Interface::GetConfigImpl(ConfigItem config_item) const {
switch (config_item) {
case ConfigItem::DisableProgramVerification:
case ConfigItem::DramId:
case ConfigItem::SecurityEngineInterruptNumber:
case ConfigItem::FuseVersion:
case ConfigItem::HardwareType:
case ConfigItem::HardwareState:
case ConfigItem::IsRecoveryBoot:
case ConfigItem::DeviceId:
case ConfigItem::BootReason:
case ConfigItem::MemoryMode:
case ConfigItem::IsDevelopmentFunctionEnabled:
case ConfigItem::KernelConfiguration:
case ConfigItem::IsChargerHiZModeEnabled:
case ConfigItem::QuestState:
case ConfigItem::RegulatorType:
case ConfigItem::DeviceUniqueKeyGeneration:
case ConfigItem::Package2Hash:
return ResultSecureMonitorNotImplemented;
case ConfigItem::ExosphereApiVersion:
// Get information about the current exosphere version.
return MakeResult((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())));
case ConfigItem::ExosphereNeedsReboot:
// We are executing, so we aren't in the process of rebooting.
return MakeResult(u64{0});
case ConfigItem::ExosphereNeedsShutdown:
// We are executing, so we aren't in the process of shutting down.
return MakeResult(u64{0});
case ConfigItem::ExosphereGitCommitHash:
// Get information about the current exosphere git commit hash.
return MakeResult(u64{0});
case ConfigItem::ExosphereHasRcmBugPatch:
// Get information about whether this unit has the RCM bug patched.
return MakeResult(u64{0});
case ConfigItem::ExosphereBlankProdInfo:
// Get whether this unit should simulate a "blanked" PRODINFO.
return MakeResult(u64{0});
case ConfigItem::ExosphereAllowCalWrites:
// Get whether this unit should allow writing to the calibration partition.
return MakeResult(u64{0});
case ConfigItem::ExosphereEmummcType:
// Get what kind of emummc this unit has active.
return MakeResult(u64{0});
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 MakeResult(u64{0});
case ConfigItem::ExosphereForceEnableUsb30:
// Get whether usb 3.0 should be force-enabled.
return MakeResult(u64{0});
default:
return ResultSecureMonitorInvalidArgument;
}
}
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
auto module = std::make_shared<Module>(); auto module = std::make_shared<Module>();
std::make_shared<CSRNG>(system, module)->InstallAsService(service_manager); std::make_shared<CSRNG>(system, module)->InstallAsService(service_manager);

View file

@ -6,6 +6,8 @@
#include <random> #include <random>
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#include "core/hle/service/spl/spl_results.h"
#include "core/hle/service/spl/spl_types.h"
namespace Core { namespace Core {
class System; class System;
@ -21,12 +23,21 @@ public:
const char* name); const char* name);
~Interface() override; ~Interface() override;
void GetRandomBytes(Kernel::HLERequestContext& ctx); // General
void GetConfig(Kernel::HLERequestContext& ctx);
void ModularExponentiate(Kernel::HLERequestContext& ctx);
void SetConfig(Kernel::HLERequestContext& ctx);
void GenerateRandomBytes(Kernel::HLERequestContext& ctx);
void IsDevelopment(Kernel::HLERequestContext& ctx);
void SetBootReason(Kernel::HLERequestContext& ctx);
void GetBootReason(Kernel::HLERequestContext& ctx);
protected: protected:
std::shared_ptr<Module> module; std::shared_ptr<Module> module;
private: private:
ResultVal<u64> GetConfigImpl(ConfigItem config_item) const;
std::mt19937 rng; std::mt19937 rng;
}; };
}; };

View file

@ -10,13 +10,13 @@ SPL::SPL(Core::System& system_, std::shared_ptr<Module> module_)
: Interface(system_, std::move(module_), "spl:") { : Interface(system_, std::move(module_), "spl:") {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, nullptr, "GetConfig"}, {0, &SPL::GetConfig, "GetConfig"},
{1, nullptr, "ModularExponentiate"}, {1, &SPL::ModularExponentiate, "ModularExponentiate"},
{5, nullptr, "SetConfig"}, {5, &SPL::SetConfig, "SetConfig"},
{7, &SPL::GetRandomBytes, "GetRandomBytes"}, {7, &SPL::GenerateRandomBytes, "GenerateRandomBytes"},
{11, nullptr, "IsDevelopment"}, {11, &SPL::IsDevelopment, "IsDevelopment"},
{24, nullptr, "SetBootReason"}, {24, &SPL::SetBootReason, "SetBootReason"},
{25, nullptr, "GetBootReason"}, {25, &SPL::GetBootReason, "GetBootReason"},
}; };
// clang-format on // clang-format on
@ -27,22 +27,22 @@ SPL_MIG::SPL_MIG(Core::System& system_, std::shared_ptr<Module> module_)
: Interface(system_, std::move(module_), "spl:mig") { : Interface(system_, std::move(module_), "spl:mig") {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, nullptr, "GetConfig"}, {0, &SPL::GetConfig, "GetConfig"},
{1, nullptr, "ModularExponentiate"}, {1, &SPL::ModularExponentiate, "ModularExponentiate"},
{2, nullptr, "GenerateAesKek"}, {2, nullptr, "GenerateAesKek"},
{3, nullptr, "LoadAesKey"}, {3, nullptr, "LoadAesKey"},
{4, nullptr, "GenerateAesKey"}, {4, nullptr, "GenerateAesKey"},
{5, nullptr, "SetConfig"}, {5, &SPL::SetConfig, "SetConfig"},
{7, &SPL::GetRandomBytes, "GenerateRandomBytes"}, {7, &SPL::GenerateRandomBytes, "GenerateRandomBytes"},
{11, nullptr, "IsDevelopment"}, {11, &SPL::IsDevelopment, "IsDevelopment"},
{14, nullptr, "DecryptAesKey"}, {14, nullptr, "DecryptAesKey"},
{15, nullptr, "CryptAesCtr"}, {15, nullptr, "CryptAesCtr"},
{16, nullptr, "ComputeCmac"}, {16, nullptr, "ComputeCmac"},
{21, nullptr, "AllocateAesKeyslot"}, {21, nullptr, "AllocateAesKeyslot"},
{22, nullptr, "DeallocateAesKeySlot"}, {22, nullptr, "DeallocateAesKeySlot"},
{23, nullptr, "GetAesKeyslotAvailableEvent"}, {23, nullptr, "GetAesKeyslotAvailableEvent"},
{24, nullptr, "SetBootReason"}, {24, &SPL::SetBootReason, "SetBootReason"},
{25, nullptr, "GetBootReason"}, {25, &SPL::GetBootReason, "GetBootReason"},
}; };
// clang-format on // clang-format on
@ -53,16 +53,16 @@ SPL_FS::SPL_FS(Core::System& system_, std::shared_ptr<Module> module_)
: Interface(system_, std::move(module_), "spl:fs") { : Interface(system_, std::move(module_), "spl:fs") {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, nullptr, "GetConfig"}, {0, &SPL::GetConfig, "GetConfig"},
{1, nullptr, "ModularExponentiate"}, {1, &SPL::ModularExponentiate, "ModularExponentiate"},
{2, nullptr, "GenerateAesKek"}, {2, nullptr, "GenerateAesKek"},
{3, nullptr, "LoadAesKey"}, {3, nullptr, "LoadAesKey"},
{4, nullptr, "GenerateAesKey"}, {4, nullptr, "GenerateAesKey"},
{5, nullptr, "SetConfig"}, {5, &SPL::SetConfig, "SetConfig"},
{7, &SPL::GetRandomBytes, "GenerateRandomBytes"}, {7, &SPL::GenerateRandomBytes, "GenerateRandomBytes"},
{9, nullptr, "ImportLotusKey"}, {9, nullptr, "ImportLotusKey"},
{10, nullptr, "DecryptLotusMessage"}, {10, nullptr, "DecryptLotusMessage"},
{11, nullptr, "IsDevelopment"}, {11, &SPL::IsDevelopment, "IsDevelopment"},
{12, nullptr, "GenerateSpecificAesKey"}, {12, nullptr, "GenerateSpecificAesKey"},
{14, nullptr, "DecryptAesKey"}, {14, nullptr, "DecryptAesKey"},
{15, nullptr, "CryptAesCtr"}, {15, nullptr, "CryptAesCtr"},
@ -71,8 +71,8 @@ SPL_FS::SPL_FS(Core::System& system_, std::shared_ptr<Module> module_)
{21, nullptr, "AllocateAesKeyslot"}, {21, nullptr, "AllocateAesKeyslot"},
{22, nullptr, "DeallocateAesKeySlot"}, {22, nullptr, "DeallocateAesKeySlot"},
{23, nullptr, "GetAesKeyslotAvailableEvent"}, {23, nullptr, "GetAesKeyslotAvailableEvent"},
{24, nullptr, "SetBootReason"}, {24, &SPL::SetBootReason, "SetBootReason"},
{25, nullptr, "GetBootReason"}, {25, &SPL::GetBootReason, "GetBootReason"},
{31, nullptr, "GetPackage2Hash"}, {31, nullptr, "GetPackage2Hash"},
}; };
// clang-format on // clang-format on
@ -84,14 +84,14 @@ SPL_SSL::SPL_SSL(Core::System& system_, std::shared_ptr<Module> module_)
: Interface(system_, std::move(module_), "spl:ssl") { : Interface(system_, std::move(module_), "spl:ssl") {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, nullptr, "GetConfig"}, {0, &SPL::GetConfig, "GetConfig"},
{1, nullptr, "ModularExponentiate"}, {1, &SPL::ModularExponentiate, "ModularExponentiate"},
{2, nullptr, "GenerateAesKek"}, {2, nullptr, "GenerateAesKek"},
{3, nullptr, "LoadAesKey"}, {3, nullptr, "LoadAesKey"},
{4, nullptr, "GenerateAesKey"}, {4, nullptr, "GenerateAesKey"},
{5, nullptr, "SetConfig"}, {5, &SPL::SetConfig, "SetConfig"},
{7, &SPL::GetRandomBytes, "GetRandomBytes"}, {7, &SPL::GenerateRandomBytes, "GenerateRandomBytes"},
{11, nullptr, "IsDevelopment"}, {11, &SPL::IsDevelopment, "IsDevelopment"},
{13, nullptr, "DecryptDeviceUniqueData"}, {13, nullptr, "DecryptDeviceUniqueData"},
{14, nullptr, "DecryptAesKey"}, {14, nullptr, "DecryptAesKey"},
{15, nullptr, "CryptAesCtr"}, {15, nullptr, "CryptAesCtr"},
@ -99,8 +99,8 @@ SPL_SSL::SPL_SSL(Core::System& system_, std::shared_ptr<Module> module_)
{21, nullptr, "AllocateAesKeyslot"}, {21, nullptr, "AllocateAesKeyslot"},
{22, nullptr, "DeallocateAesKeySlot"}, {22, nullptr, "DeallocateAesKeySlot"},
{23, nullptr, "GetAesKeyslotAvailableEvent"}, {23, nullptr, "GetAesKeyslotAvailableEvent"},
{24, nullptr, "SetBootReason"}, {24, &SPL::SetBootReason, "SetBootReason"},
{25, nullptr, "GetBootReason"}, {25, &SPL::GetBootReason, "GetBootReason"},
{26, nullptr, "DecryptAndStoreSslClientCertKey"}, {26, nullptr, "DecryptAndStoreSslClientCertKey"},
{27, nullptr, "ModularExponentiateWithSslClientCertKey"}, {27, nullptr, "ModularExponentiateWithSslClientCertKey"},
}; };
@ -113,14 +113,14 @@ SPL_ES::SPL_ES(Core::System& system_, std::shared_ptr<Module> module_)
: Interface(system_, std::move(module_), "spl:es") { : Interface(system_, std::move(module_), "spl:es") {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, nullptr, "GetConfig"}, {0, &SPL::GetConfig, "GetConfig"},
{1, nullptr, "ModularExponentiate"}, {1, &SPL::ModularExponentiate, "ModularExponentiate"},
{2, nullptr, "GenerateAesKek"}, {2, nullptr, "GenerateAesKek"},
{3, nullptr, "LoadAesKey"}, {3, nullptr, "LoadAesKey"},
{4, nullptr, "GenerateAesKey"}, {4, nullptr, "GenerateAesKey"},
{5, nullptr, "SetConfig"}, {5, &SPL::SetConfig, "SetConfig"},
{7, &SPL::GetRandomBytes, "GenerateRandomBytes"}, {7, &SPL::GenerateRandomBytes, "GenerateRandomBytes"},
{11, nullptr, "IsDevelopment"}, {11, &SPL::IsDevelopment, "IsDevelopment"},
{13, nullptr, "DecryptDeviceUniqueData"}, {13, nullptr, "DecryptDeviceUniqueData"},
{14, nullptr, "DecryptAesKey"}, {14, nullptr, "DecryptAesKey"},
{15, nullptr, "CryptAesCtr"}, {15, nullptr, "CryptAesCtr"},
@ -131,8 +131,8 @@ SPL_ES::SPL_ES(Core::System& system_, std::shared_ptr<Module> module_)
{21, nullptr, "AllocateAesKeyslot"}, {21, nullptr, "AllocateAesKeyslot"},
{22, nullptr, "DeallocateAesKeySlot"}, {22, nullptr, "DeallocateAesKeySlot"},
{23, nullptr, "GetAesKeyslotAvailableEvent"}, {23, nullptr, "GetAesKeyslotAvailableEvent"},
{24, nullptr, "SetBootReason"}, {24, &SPL::SetBootReason, "SetBootReason"},
{25, nullptr, "GetBootReason"}, {25, &SPL::GetBootReason, "GetBootReason"},
{28, nullptr, "DecryptAndStoreDrmDeviceCertKey"}, {28, nullptr, "DecryptAndStoreDrmDeviceCertKey"},
{29, nullptr, "ModularExponentiateWithDrmDeviceCertKey"}, {29, nullptr, "ModularExponentiateWithDrmDeviceCertKey"},
{31, nullptr, "PrepareEsArchiveKey"}, {31, nullptr, "PrepareEsArchiveKey"},
@ -147,14 +147,14 @@ SPL_MANU::SPL_MANU(Core::System& system_, std::shared_ptr<Module> module_)
: Interface(system_, std::move(module_), "spl:manu") { : Interface(system_, std::move(module_), "spl:manu") {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, nullptr, "GetConfig"}, {0, &SPL::GetConfig, "GetConfig"},
{1, nullptr, "ModularExponentiate"}, {1, &SPL::ModularExponentiate, "ModularExponentiate"},
{2, nullptr, "GenerateAesKek"}, {2, nullptr, "GenerateAesKek"},
{3, nullptr, "LoadAesKey"}, {3, nullptr, "LoadAesKey"},
{4, nullptr, "GenerateAesKey"}, {4, nullptr, "GenerateAesKey"},
{5, nullptr, "SetConfig"}, {5, &SPL::SetConfig, "SetConfig"},
{7, &SPL::GetRandomBytes, "GetRandomBytes"}, {7, &SPL::GenerateRandomBytes, "GenerateRandomBytes"},
{11, nullptr, "IsDevelopment"}, {11, &SPL::IsDevelopment, "IsDevelopment"},
{13, nullptr, "DecryptDeviceUniqueData"}, {13, nullptr, "DecryptDeviceUniqueData"},
{14, nullptr, "DecryptAesKey"}, {14, nullptr, "DecryptAesKey"},
{15, nullptr, "CryptAesCtr"}, {15, nullptr, "CryptAesCtr"},
@ -162,8 +162,8 @@ SPL_MANU::SPL_MANU(Core::System& system_, std::shared_ptr<Module> module_)
{21, nullptr, "AllocateAesKeyslot"}, {21, nullptr, "AllocateAesKeyslot"},
{22, nullptr, "DeallocateAesKeySlot"}, {22, nullptr, "DeallocateAesKeySlot"},
{23, nullptr, "GetAesKeyslotAvailableEvent"}, {23, nullptr, "GetAesKeyslotAvailableEvent"},
{24, nullptr, "SetBootReason"}, {24, &SPL::SetBootReason, "SetBootReason"},
{25, nullptr, "GetBootReason"}, {25, &SPL::GetBootReason, "GetBootReason"},
{30, nullptr, "ReencryptDeviceUniqueData"}, {30, nullptr, "ReencryptDeviceUniqueData"},
}; };
// clang-format on // clang-format on

View file

@ -0,0 +1,29 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/hle/result.h"
namespace Service::SPL {
// Description 0 - 99
constexpr ResultCode ResultSecureMonitorError{ErrorModule::SPL, 0};
constexpr ResultCode ResultSecureMonitorNotImplemented{ErrorModule::SPL, 1};
constexpr ResultCode ResultSecureMonitorInvalidArgument{ErrorModule::SPL, 2};
constexpr ResultCode ResultSecureMonitorBusy{ErrorModule::SPL, 3};
constexpr ResultCode ResultSecureMonitorNoAsyncOperation{ErrorModule::SPL, 4};
constexpr ResultCode ResultSecureMonitorInvalidAsyncOperation{ErrorModule::SPL, 5};
constexpr ResultCode ResultSecureMonitorNotPermitted{ErrorModule::SPL, 6};
constexpr ResultCode ResultSecureMonitorNotInitialized{ErrorModule::SPL, 7};
constexpr ResultCode ResultInvalidSize{ErrorModule::SPL, 100};
constexpr ResultCode ResultUnknownSecureMonitorError{ErrorModule::SPL, 101};
constexpr ResultCode ResultDecryptionFailed{ErrorModule::SPL, 102};
constexpr ResultCode ResultOutOfKeySlots{ErrorModule::SPL, 104};
constexpr ResultCode ResultInvalidKeySlot{ErrorModule::SPL, 105};
constexpr ResultCode ResultBootReasonAlreadySet{ErrorModule::SPL, 106};
constexpr ResultCode ResultBootReasonNotSet{ErrorModule::SPL, 107};
constexpr ResultCode ResultInvalidArgument{ErrorModule::SPL, 108};
} // namespace Service::SPL

View file

@ -0,0 +1,230 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <span>
#include "common/bit_field.h"
#include "common/common_types.h"
namespace Service::SPL {
constexpr size_t AES_128_KEY_SIZE = 0x10;
namespace Smc {
enum class FunctionId : u32 {
SetConfig = 0xC3000401,
GetConfig = 0xC3000002,
GetResult = 0xC3000003,
GetResultData = 0xC3000404,
ModularExponentiate = 0xC3000E05,
GenerateRandomBytes = 0xC3000006,
GenerateAesKek = 0xC3000007,
LoadAesKey = 0xC3000008,
ComputeAes = 0xC3000009,
GenerateSpecificAesKey = 0xC300000A,
ComputeCmac = 0xC300040B,
ReencryptDeviceUniqueData = 0xC300D60C,
DecryptDeviceUniqueData = 0xC300100D,
ModularExponentiateWithStorageKey = 0xC300060F,
PrepareEsDeviceUniqueKey = 0xC3000610,
LoadPreparedAesKey = 0xC3000011,
PrepareCommonEsTitleKey = 0xC3000012,
// Deprecated functions.
LoadEsDeviceKey = 0xC300100C,
DecryptAndStoreGcKey = 0xC300100E,
// Atmosphere functions.
AtmosphereIramCopy = 0xF0000201,
AtmosphereReadWriteRegister = 0xF0000002,
AtmosphereGetEmummcConfig = 0xF0000404,
};
enum class CipherMode {
CbcEncrypt = 0,
CbcDecrypt = 1,
Ctr = 2,
};
enum class DeviceUniqueDataMode {
DecryptDeviceUniqueData = 0,
DecryptAndStoreGcKey = 1,
DecryptAndStoreEsDeviceKey = 2,
DecryptAndStoreSslKey = 3,
DecryptAndStoreDrmDeviceCertKey = 4,
};
enum class ModularExponentiateWithStorageKeyMode {
Gc = 0,
Ssl = 1,
DrmDeviceCert = 2,
};
enum class EsCommonKeyType {
TitleKey = 0,
ArchiveKey = 1,
};
struct AsyncOperationKey {
u64 value;
};
} // namespace Smc
enum class HardwareType {
Icosa = 0,
Copper = 1,
Hoag = 2,
Iowa = 3,
Calcio = 4,
Aula = 5,
};
enum class SocType {
Erista = 0,
Mariko = 1,
};
enum class HardwareState {
Development = 0,
Production = 1,
};
enum class MemoryArrangement {
Standard = 0,
StandardForAppletDev = 1,
StandardForSystemDev = 2,
Expanded = 3,
ExpandedForAppletDev = 4,
// Note: Dynamic is not official.
// Atmosphere uses it to maintain compatibility with firmwares prior to 6.0.0,
// which removed the explicit retrieval of memory arrangement from PM.
Dynamic = 5,
Count,
};
enum class BootReason {
Unknown = 0,
AcOk = 1,
OnKey = 2,
RtcAlarm1 = 3,
RtcAlarm2 = 4,
};
struct BootReasonValue {
union {
u32 value{};
BitField<0, 8, u32> power_intr;
BitField<8, 8, u32> rtc_intr;
BitField<16, 8, u32> nv_erc;
BitField<24, 8, u32> boot_reason;
};
};
static_assert(sizeof(BootReasonValue) == sizeof(u32), "BootReasonValue definition!");
struct AesKey {
std::array<u64, AES_128_KEY_SIZE / sizeof(u64)> data64{};
std::span<u8> AsBytes() {
return std::span{reinterpret_cast<u8*>(data64.data()), AES_128_KEY_SIZE};
}
std::span<const u8> AsBytes() const {
return std::span{reinterpret_cast<const u8*>(data64.data()), AES_128_KEY_SIZE};
}
};
static_assert(sizeof(AesKey) == AES_128_KEY_SIZE, "AesKey definition!");
struct IvCtr {
std::array<u64, AES_128_KEY_SIZE / sizeof(u64)> data64{};
std::span<u8> AsBytes() {
return std::span{reinterpret_cast<u8*>(data64.data()), AES_128_KEY_SIZE};
}
std::span<const u8> AsBytes() const {
return std::span{reinterpret_cast<const u8*>(data64.data()), AES_128_KEY_SIZE};
}
};
static_assert(sizeof(AesKey) == AES_128_KEY_SIZE, "IvCtr definition!");
struct Cmac {
std::array<u64, AES_128_KEY_SIZE / sizeof(u64)> data64{};
std::span<u8> AsBytes() {
return std::span{reinterpret_cast<u8*>(data64.data()), AES_128_KEY_SIZE};
}
std::span<const u8> AsBytes() const {
return std::span{reinterpret_cast<const u8*>(data64.data()), AES_128_KEY_SIZE};
}
};
static_assert(sizeof(AesKey) == AES_128_KEY_SIZE, "Cmac definition!");
struct AccessKey {
std::array<u64, AES_128_KEY_SIZE / sizeof(u64)> data64{};
std::span<u8> AsBytes() {
return std::span{reinterpret_cast<u8*>(data64.data()), AES_128_KEY_SIZE};
}
std::span<const u8> AsBytes() const {
return std::span{reinterpret_cast<const u8*>(data64.data()), AES_128_KEY_SIZE};
}
};
static_assert(sizeof(AesKey) == AES_128_KEY_SIZE, "AccessKey definition!");
struct KeySource {
std::array<u64, AES_128_KEY_SIZE / sizeof(u64)> data64{};
std::span<u8> AsBytes() {
return std::span{reinterpret_cast<u8*>(data64.data()), AES_128_KEY_SIZE};
}
std::span<const u8> AsBytes() const {
return std::span{reinterpret_cast<const u8*>(data64.data()), AES_128_KEY_SIZE};
}
};
static_assert(sizeof(AesKey) == AES_128_KEY_SIZE, "KeySource definition!");
enum class ConfigItem : u32 {
// Standard config items.
DisableProgramVerification = 1,
DramId = 2,
SecurityEngineInterruptNumber = 3,
FuseVersion = 4,
HardwareType = 5,
HardwareState = 6,
IsRecoveryBoot = 7,
DeviceId = 8,
BootReason = 9,
MemoryMode = 10,
IsDevelopmentFunctionEnabled = 11,
KernelConfiguration = 12,
IsChargerHiZModeEnabled = 13,
QuestState = 14,
RegulatorType = 15,
DeviceUniqueKeyGeneration = 16,
Package2Hash = 17,
// Extension config items for exosphere.
ExosphereApiVersion = 65000,
ExosphereNeedsReboot = 65001,
ExosphereNeedsShutdown = 65002,
ExosphereGitCommitHash = 65003,
ExosphereHasRcmBugPatch = 65004,
ExosphereBlankProdInfo = 65005,
ExosphereAllowCalWrites = 65006,
ExosphereEmummcType = 65007,
ExospherePayloadAddress = 65008,
ExosphereLogConfiguration = 65009,
ExosphereForceEnableUsb30 = 65010,
};
} // namespace Service::SPL

View file

@ -125,7 +125,7 @@ ResultCode TimeZoneContentManager::GetTimeZoneInfoFile(const std::string& locati
return ERROR_TIME_NOT_FOUND; return ERROR_TIME_NOT_FOUND;
} }
vfs_file = zoneinfo_dir->GetFile(location_name); vfs_file = zoneinfo_dir->GetFileRelative(location_name);
if (!vfs_file) { if (!vfs_file) {
LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"! Using default timezone.", LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"! Using default timezone.",
time_zone_binary_titleid, location_name); time_zone_binary_titleid, location_name);

View file

@ -2,25 +2,23 @@
// Licensed under GPLv2+ // Licensed under GPLv2+
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <stop_token>
#include <thread>
#include "common/settings.h" #include "common/settings.h"
#include "input_common/mouse/mouse_input.h" #include "input_common/mouse/mouse_input.h"
namespace MouseInput { namespace MouseInput {
Mouse::Mouse() { Mouse::Mouse() {
update_thread = std::thread(&Mouse::UpdateThread, this); update_thread = std::jthread([this](std::stop_token stop_token) { UpdateThread(stop_token); });
} }
Mouse::~Mouse() { Mouse::~Mouse() = default;
update_thread_running = false;
if (update_thread.joinable()) {
update_thread.join();
}
}
void Mouse::UpdateThread() { void Mouse::UpdateThread(std::stop_token stop_token) {
constexpr int update_time = 10; constexpr int update_time = 10;
while (update_thread_running) { while (!stop_token.stop_requested()) {
for (MouseInfo& info : mouse_info) { for (MouseInfo& info : mouse_info) {
const Common::Vec3f angular_direction{ const Common::Vec3f angular_direction{
-info.tilt_direction.y, -info.tilt_direction.y,

View file

@ -6,6 +6,7 @@
#include <array> #include <array>
#include <mutex> #include <mutex>
#include <stop_token>
#include <thread> #include <thread>
#include "common/common_types.h" #include "common/common_types.h"
@ -85,7 +86,7 @@ public:
[[nodiscard]] const MouseData& GetMouseState(std::size_t button) const; [[nodiscard]] const MouseData& GetMouseState(std::size_t button) const;
private: private:
void UpdateThread(); void UpdateThread(std::stop_token stop_token);
void UpdateYuzuSettings(); void UpdateYuzuSettings();
void StopPanning(); void StopPanning();
@ -105,12 +106,11 @@ private:
u16 buttons{}; u16 buttons{};
u16 toggle_buttons{}; u16 toggle_buttons{};
u16 lock_buttons{}; u16 lock_buttons{};
std::thread update_thread; std::jthread update_thread;
MouseButton last_button{MouseButton::Undefined}; MouseButton last_button{MouseButton::Undefined};
std::array<MouseInfo, 7> mouse_info; std::array<MouseInfo, 7> mouse_info;
Common::SPSCQueue<MouseStatus> mouse_queue; Common::SPSCQueue<MouseStatus> mouse_queue;
bool configuring{false}; bool configuring{false};
bool update_thread_running{true};
int mouse_panning_timout{}; int mouse_panning_timout{};
}; };
} // namespace MouseInput } // namespace MouseInput

View file

@ -4,10 +4,10 @@
#pragma once #pragma once
#include <atomic>
#include <functional> #include <functional>
#include <optional> #include <optional>
#include <span> #include <span>
#include <stop_token>
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/fermi_2d.h" #include "video_core/engines/fermi_2d.h"
#include "video_core/gpu.h" #include "video_core/gpu.h"
@ -129,7 +129,7 @@ public:
virtual void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {} virtual void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {}
/// Initialize disk cached resources for the game being emulated /// Initialize disk cached resources for the game being emulated
virtual void LoadDiskResources(u64 title_id, const std::atomic_bool& stop_loading, virtual void LoadDiskResources(u64 title_id, std::stop_token stop_loading,
const DiskResourceLoadCallback& callback) {} const DiskResourceLoadCallback& callback) {}
/// Grant access to the Guest Driver Profile for recording/obtaining info on the guest driver. /// Grant access to the Guest Driver Profile for recording/obtaining info on the guest driver.

View file

@ -42,6 +42,8 @@ public:
[[nodiscard]] virtual RasterizerInterface* ReadRasterizer() = 0; [[nodiscard]] virtual RasterizerInterface* ReadRasterizer() = 0;
[[nodiscard]] virtual std::string GetDeviceVendor() const = 0;
// Getter/setter functions: // Getter/setter functions:
// ------------------------ // ------------------------

View file

@ -202,13 +202,13 @@ Device::Device() {
LOG_ERROR(Render_OpenGL, "OpenGL 4.6 is not available"); LOG_ERROR(Render_OpenGL, "OpenGL 4.6 is not available");
throw std::runtime_error{"Insufficient version"}; throw std::runtime_error{"Insufficient version"};
} }
const std::string_view vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR)); 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 version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
const std::vector extensions = GetExtensions(); const std::vector extensions = GetExtensions();
const bool is_nvidia = vendor == "NVIDIA Corporation"; const bool is_nvidia = vendor_name == "NVIDIA Corporation";
const bool is_amd = vendor == "ATI Technologies Inc."; const bool is_amd = vendor_name == "ATI Technologies Inc.";
const bool is_intel = vendor == "Intel"; const bool is_intel = vendor_name == "Intel";
#ifdef __unix__ #ifdef __unix__
const bool is_linux = true; const bool is_linux = true;
@ -275,6 +275,56 @@ Device::Device() {
} }
} }
std::string Device::GetVendorName() const {
if (vendor_name == "NVIDIA Corporation") {
return "NVIDIA";
}
if (vendor_name == "ATI Technologies Inc.") {
return "AMD";
}
if (vendor_name == "Intel") {
// For Mesa, `Intel` is an overloaded vendor string that could mean crocus or iris.
// Simply return `INTEL` for those as well as the Windows driver.
return "INTEL";
}
if (vendor_name == "Intel Open Source Technology Center") {
return "I965";
}
if (vendor_name == "Mesa Project") {
return "I915";
}
if (vendor_name == "Mesa/X.org") {
// This vendor string is overloaded between llvmpipe, softpipe, and virgl, so just return
// MESA instead of one of those driver names.
return "MESA";
}
if (vendor_name == "AMD") {
return "RADEONSI";
}
if (vendor_name == "nouveau") {
return "NOUVEAU";
}
if (vendor_name == "X.Org") {
return "R600";
}
if (vendor_name == "Collabora Ltd") {
return "ZINK";
}
if (vendor_name == "Intel Corporation") {
return "OPENSWR";
}
if (vendor_name == "Microsoft Corporation") {
return "D3D12";
}
if (vendor_name == "NVIDIA") {
// Mesa's tegra driver reports `NVIDIA`. Only present in this list because the default
// strategy would have returned `NVIDIA` here for this driver, the same result as the
// proprietary driver.
return "TEGRA";
}
return vendor_name;
}
Device::Device(std::nullptr_t) { Device::Device(std::nullptr_t) {
max_uniform_buffers.fill(std::numeric_limits<u32>::max()); max_uniform_buffers.fill(std::numeric_limits<u32>::max());
uniform_buffer_alignment = 4; uniform_buffer_alignment = 4;

View file

@ -22,6 +22,8 @@ public:
explicit Device(); explicit Device();
explicit Device(std::nullptr_t); explicit Device(std::nullptr_t);
[[nodiscard]] std::string GetVendorName() const;
u32 GetMaxUniformBuffers(Tegra::Engines::ShaderType shader_type) const noexcept { u32 GetMaxUniformBuffers(Tegra::Engines::ShaderType shader_type) const noexcept {
return max_uniform_buffers[static_cast<std::size_t>(shader_type)]; return max_uniform_buffers[static_cast<std::size_t>(shader_type)];
} }
@ -130,6 +132,7 @@ private:
static bool TestVariableAoffi(); static bool TestVariableAoffi();
static bool TestPreciseBug(); static bool TestPreciseBug();
std::string vendor_name;
std::array<u32, Tegra::Engines::MaxShaderTypes> max_uniform_buffers{}; std::array<u32, Tegra::Engines::MaxShaderTypes> max_uniform_buffers{};
std::array<BaseBindings, Tegra::Engines::MaxShaderTypes> base_bindings{}; std::array<BaseBindings, Tegra::Engines::MaxShaderTypes> base_bindings{};
size_t uniform_buffer_alignment{}; size_t uniform_buffer_alignment{};

View file

@ -351,7 +351,7 @@ void RasterizerOpenGL::SetupShaders(bool is_indexed) {
} }
} }
void RasterizerOpenGL::LoadDiskResources(u64 title_id, const std::atomic_bool& stop_loading, void RasterizerOpenGL::LoadDiskResources(u64 title_id, std::stop_token stop_loading,
const VideoCore::DiskResourceLoadCallback& callback) { const VideoCore::DiskResourceLoadCallback& callback) {
shader_cache.LoadDiskCache(title_id, stop_loading, callback); shader_cache.LoadDiskCache(title_id, stop_loading, callback);
} }

View file

@ -96,7 +96,7 @@ public:
const Tegra::Engines::Fermi2D::Config& copy_config) override; const Tegra::Engines::Fermi2D::Config& copy_config) override;
bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr,
u32 pixel_stride) override; u32 pixel_stride) override;
void LoadDiskResources(u64 title_id, const std::atomic_bool& stop_loading, void LoadDiskResources(u64 title_id, std::stop_token stop_loading,
const VideoCore::DiskResourceLoadCallback& callback) override; const VideoCore::DiskResourceLoadCallback& callback) override;
/// Returns true when there are commands queued to the OpenGL server. /// Returns true when there are commands queued to the OpenGL server.

View file

@ -331,7 +331,7 @@ ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer_,
ShaderCacheOpenGL::~ShaderCacheOpenGL() = default; ShaderCacheOpenGL::~ShaderCacheOpenGL() = default;
void ShaderCacheOpenGL::LoadDiskCache(u64 title_id, const std::atomic_bool& stop_loading, void ShaderCacheOpenGL::LoadDiskCache(u64 title_id, std::stop_token stop_loading,
const VideoCore::DiskResourceLoadCallback& callback) { const VideoCore::DiskResourceLoadCallback& callback) {
disk_cache.BindTitleID(title_id); disk_cache.BindTitleID(title_id);
const std::optional transferable = disk_cache.LoadTransferable(); const std::optional transferable = disk_cache.LoadTransferable();
@ -372,7 +372,7 @@ void ShaderCacheOpenGL::LoadDiskCache(u64 title_id, const std::atomic_bool& stop
const auto scope = context->Acquire(); const auto scope = context->Acquire();
for (std::size_t i = begin; i < end; ++i) { for (std::size_t i = begin; i < end; ++i) {
if (stop_loading) { if (stop_loading.stop_requested()) {
return; return;
} }
const auto& entry = (*transferable)[i]; const auto& entry = (*transferable)[i];
@ -435,7 +435,7 @@ void ShaderCacheOpenGL::LoadDiskCache(u64 title_id, const std::atomic_bool& stop
precompiled_cache_altered = true; precompiled_cache_altered = true;
return; return;
} }
if (stop_loading) { if (stop_loading.stop_requested()) {
return; return;
} }

View file

@ -127,7 +127,7 @@ public:
~ShaderCacheOpenGL() override; ~ShaderCacheOpenGL() override;
/// Loads disk cache for the current game /// Loads disk cache for the current game
void LoadDiskCache(u64 title_id, const std::atomic_bool& stop_loading, void LoadDiskCache(u64 title_id, std::stop_token stop_loading,
const VideoCore::DiskResourceLoadCallback& callback); const VideoCore::DiskResourceLoadCallback& callback);
/// Gets the current specified shader stage program /// Gets the current specified shader stage program

View file

@ -70,6 +70,10 @@ public:
return &rasterizer; return &rasterizer;
} }
[[nodiscard]] std::string GetDeviceVendor() const override {
return device.GetVendorName();
}
private: private:
/// Initializes the OpenGL state and creates persistent objects. /// Initializes the OpenGL state and creates persistent objects.
void InitOpenGLObjects(); void InitOpenGLObjects();

View file

@ -47,6 +47,10 @@ public:
return &rasterizer; return &rasterizer;
} }
[[nodiscard]] std::string GetDeviceVendor() const override {
return device.GetDriverName();
}
private: private:
void Report() const; void Report() const;

View file

@ -344,6 +344,7 @@ private:
bool has_deleted_images = false; bool has_deleted_images = false;
u64 total_used_memory = 0; u64 total_used_memory = 0;
u64 minimum_memory;
u64 expected_memory; u64 expected_memory;
u64 critical_memory; u64 critical_memory;
@ -396,10 +397,12 @@ TextureCache<P>::TextureCache(Runtime& runtime_, VideoCore::RasterizerInterface&
const u64 possible_critical_memory = (device_memory * 6) / 10; const u64 possible_critical_memory = (device_memory * 6) / 10;
expected_memory = std::max(possible_expected_memory, DEFAULT_EXPECTED_MEMORY); expected_memory = std::max(possible_expected_memory, DEFAULT_EXPECTED_MEMORY);
critical_memory = std::max(possible_critical_memory, DEFAULT_CRITICAL_MEMORY); critical_memory = std::max(possible_critical_memory, DEFAULT_CRITICAL_MEMORY);
minimum_memory = 0;
} else { } else {
// on OGL we can be more conservatives as the driver takes care. // on OGL we can be more conservatives as the driver takes care.
expected_memory = DEFAULT_EXPECTED_MEMORY + Common::Size_512_MB; expected_memory = DEFAULT_EXPECTED_MEMORY + Common::Size_512_MB;
critical_memory = DEFAULT_CRITICAL_MEMORY + Common::Size_1_GB; critical_memory = DEFAULT_CRITICAL_MEMORY + Common::Size_1_GB;
minimum_memory = expected_memory;
} }
} }
@ -470,7 +473,7 @@ void TextureCache<P>::RunGarbageCollector() {
template <class P> template <class P>
void TextureCache<P>::TickFrame() { void TextureCache<P>::TickFrame() {
if (Settings::values.use_caches_gc.GetValue()) { if (Settings::values.use_caches_gc.GetValue() && total_used_memory > minimum_memory) {
RunGarbageCollector(); RunGarbageCollector();
} }
sentenced_images.Tick(); sentenced_images.Tick();

View file

@ -50,7 +50,7 @@ NsightAftermathTracker::NsightAftermathTracker() {
} }
dump_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::LogDir) / "gpucrash"; dump_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::LogDir) / "gpucrash";
void(Common::FS::RemoveDirRecursively(dump_dir)); Common::FS::RemoveDirRecursively(dump_dir);
if (!Common::FS::CreateDir(dump_dir)) { if (!Common::FS::CreateDir(dump_dir)) {
LOG_ERROR(Render_Vulkan, "Failed to create Nsight Aftermath dump directory"); LOG_ERROR(Render_Vulkan, "Failed to create Nsight Aftermath dump directory");
return; return;

View file

@ -532,6 +532,27 @@ bool Device::IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags want
return (supported_usage & wanted_usage) == wanted_usage; return (supported_usage & wanted_usage) == wanted_usage;
} }
std::string Device::GetDriverName() const {
switch (driver_id) {
case VK_DRIVER_ID_AMD_PROPRIETARY:
return "AMD";
case VK_DRIVER_ID_AMD_OPEN_SOURCE:
return "AMDVLK";
case VK_DRIVER_ID_MESA_RADV:
return "RADV";
case VK_DRIVER_ID_NVIDIA_PROPRIETARY:
return "NVIDIA";
case VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS:
return "INTEL";
case VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA:
return "ANV";
case VK_DRIVER_ID_MESA_LLVMPIPE:
return "LAVAPIPE";
default:
return vendor_name;
}
}
void Device::CheckSuitability(bool requires_swapchain) const { void Device::CheckSuitability(bool requires_swapchain) const {
std::bitset<REQUIRED_EXTENSIONS.size()> available_extensions; std::bitset<REQUIRED_EXTENSIONS.size()> available_extensions;
bool has_swapchain = false; bool has_swapchain = false;

View file

@ -45,6 +45,9 @@ public:
/// Reports a shader to Nsight Aftermath. /// Reports a shader to Nsight Aftermath.
void SaveShader(const std::vector<u32>& spirv) const; void SaveShader(const std::vector<u32>& spirv) const;
/// Returns the name of the VkDriverId reported from Vulkan.
std::string GetDriverName() const;
/// Returns the dispatch loader with direct function pointers of the device. /// Returns the dispatch loader with direct function pointers of the device.
const vk::DeviceDispatch& GetDispatchLoader() const { const vk::DeviceDispatch& GetDispatchLoader() const {
return dld; return dld;

View file

@ -51,11 +51,11 @@ void EmuThread::run() {
Common::SetCurrentThreadName(name.c_str()); Common::SetCurrentThreadName(name.c_str());
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& gpu = system.GPU();
auto stop_token = stop_source.get_token();
system.RegisterHostThread(); system.RegisterHostThread();
auto& gpu = system.GPU();
// Main process has been loaded. Make the context current to this thread and begin GPU and CPU // Main process has been loaded. Make the context current to this thread and begin GPU and CPU
// execution. // execution.
gpu.Start(); gpu.Start();
@ -65,7 +65,7 @@ void EmuThread::run() {
emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
system.Renderer().ReadRasterizer()->LoadDiskResources( system.Renderer().ReadRasterizer()->LoadDiskResources(
system.CurrentProcess()->GetTitleID(), stop_run, system.CurrentProcess()->GetTitleID(), stop_token,
[this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) { [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) {
emit LoadProgress(stage, value, total); emit LoadProgress(stage, value, total);
}); });
@ -78,7 +78,7 @@ void EmuThread::run() {
// so that the DebugModeLeft signal can be emitted before the // so that the DebugModeLeft signal can be emitted before the
// next execution step // next execution step
bool was_active = false; bool was_active = false;
while (!stop_run) { while (!stop_token.stop_requested()) {
if (running) { if (running) {
if (was_active) { if (was_active) {
emit DebugModeLeft(); emit DebugModeLeft();
@ -100,7 +100,7 @@ void EmuThread::run() {
} }
running_guard = false; running_guard = false;
if (!stop_run) { if (!stop_token.stop_requested()) {
was_active = true; was_active = true;
emit DebugModeEntered(); emit DebugModeEntered();
} }
@ -108,7 +108,7 @@ void EmuThread::run() {
UNIMPLEMENTED(); UNIMPLEMENTED();
} else { } else {
std::unique_lock lock{running_mutex}; std::unique_lock lock{running_mutex};
running_cv.wait(lock, [this] { return IsRunning() || exec_step || stop_run; }); running_cv.wait(lock, stop_token, [this] { return IsRunning() || exec_step; });
} }
} }

View file

@ -89,16 +89,16 @@ public:
* Requests for the emulation thread to stop running * Requests for the emulation thread to stop running
*/ */
void RequestStop() { void RequestStop() {
stop_run = true; stop_source.request_stop();
SetRunning(false); SetRunning(false);
} }
private: private:
bool exec_step = false; bool exec_step = false;
bool running = false; bool running = false;
std::atomic_bool stop_run{false}; std::stop_source stop_source;
std::mutex running_mutex; std::mutex running_mutex;
std::condition_variable running_cv; std::condition_variable_any running_cv;
Common::Event running_wait{}; Common::Event running_wait{};
std::atomic_bool running_guard{false}; std::atomic_bool running_guard{false};

View file

@ -47,6 +47,8 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id, const std::str
ui->setupUi(this); ui->setupUi(this);
setFocusPolicy(Qt::ClickFocus); setFocusPolicy(Qt::ClickFocus);
setWindowTitle(tr("Properties")); setWindowTitle(tr("Properties"));
// remove Help question mark button from the title bar
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
ui->addonsTab->SetTitleId(title_id); ui->addonsTab->SetTitleId(title_id);

View file

@ -6,10 +6,15 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>800</width> <width>900</width>
<height>600</height> <height>600</height>
</rect> </rect>
</property> </property>
<property name="minimumSize">
<size>
<width>900</width>
</size>
</property>
<property name="windowTitle"> <property name="windowTitle">
<string>Dialog</string> <string>Dialog</string>
</property> </property>

View file

@ -79,8 +79,8 @@ void ConfigurePerGameAddons::ApplyConfiguration() {
std::sort(disabled_addons.begin(), disabled_addons.end()); std::sort(disabled_addons.begin(), disabled_addons.end());
std::sort(current.begin(), current.end()); std::sort(current.begin(), current.end());
if (disabled_addons != current) { if (disabled_addons != current) {
void(Common::FS::RemoveFile(Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / Common::FS::RemoveFile(Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) /
"game_list" / fmt::format("{:016X}.pv.txt", title_id))); "game_list" / fmt::format("{:016X}.pv.txt", title_id));
} }
Settings::values.disabled_addons[title_id] = disabled_addons; Settings::values.disabled_addons[title_id] = disabled_addons;

View file

@ -521,7 +521,9 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
QAction* remove_custom_config = remove_menu->addAction(tr("Remove Custom Configuration")); QAction* remove_custom_config = remove_menu->addAction(tr("Remove Custom Configuration"));
remove_menu->addSeparator(); remove_menu->addSeparator();
QAction* remove_all_content = remove_menu->addAction(tr("Remove All Installed Contents")); QAction* remove_all_content = remove_menu->addAction(tr("Remove All Installed Contents"));
QAction* dump_romfs = context_menu.addAction(tr("Dump RomFS")); QMenu* dump_romfs_menu = context_menu.addMenu(tr("Dump RomFS"));
QAction* dump_romfs = dump_romfs_menu->addAction(tr("Dump RomFS"));
QAction* dump_romfs_sdmc = dump_romfs_menu->addAction(tr("Dump RomFS to SDMC"));
QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard")); QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard"));
QAction* navigate_to_gamedb_entry = context_menu.addAction(tr("Navigate to GameDB entry")); QAction* navigate_to_gamedb_entry = context_menu.addAction(tr("Navigate to GameDB entry"));
context_menu.addSeparator(); context_menu.addSeparator();
@ -570,8 +572,12 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
connect(remove_custom_config, &QAction::triggered, [this, program_id, path]() { connect(remove_custom_config, &QAction::triggered, [this, program_id, path]() {
emit RemoveFileRequested(program_id, GameListRemoveTarget::CustomConfiguration, path); emit RemoveFileRequested(program_id, GameListRemoveTarget::CustomConfiguration, path);
}); });
connect(dump_romfs, &QAction::triggered, connect(dump_romfs, &QAction::triggered, [this, program_id, path]() {
[this, program_id, path]() { emit DumpRomFSRequested(program_id, path); }); emit DumpRomFSRequested(program_id, path, DumpRomFSTarget::Normal);
});
connect(dump_romfs_sdmc, &QAction::triggered, [this, program_id, path]() {
emit DumpRomFSRequested(program_id, path, DumpRomFSTarget::SDMC);
});
connect(copy_tid, &QAction::triggered, connect(copy_tid, &QAction::triggered,
[this, program_id]() { emit CopyTIDRequested(program_id); }); [this, program_id]() { emit CopyTIDRequested(program_id); });
connect(navigate_to_gamedb_entry, &QAction::triggered, [this, program_id]() { connect(navigate_to_gamedb_entry, &QAction::triggered, [this, program_id]() {

View file

@ -45,6 +45,11 @@ enum class GameListRemoveTarget {
CustomConfiguration, CustomConfiguration,
}; };
enum class DumpRomFSTarget {
Normal,
SDMC,
};
enum class InstalledEntryType { enum class InstalledEntryType {
Game, Game,
Update, Update,
@ -92,7 +97,7 @@ signals:
void RemoveInstalledEntryRequested(u64 program_id, InstalledEntryType type); void RemoveInstalledEntryRequested(u64 program_id, InstalledEntryType type);
void RemoveFileRequested(u64 program_id, GameListRemoveTarget target, void RemoveFileRequested(u64 program_id, GameListRemoveTarget target,
const std::string& game_path); const std::string& game_path);
void DumpRomFSRequested(u64 program_id, const std::string& game_path); void DumpRomFSRequested(u64 program_id, const std::string& game_path, DumpRomFSTarget target);
void CopyTIDRequested(u64 program_id); void CopyTIDRequested(u64 program_id);
void NavigateToGamedbEntryRequested(u64 program_id, void NavigateToGamedbEntryRequested(u64 program_id,
const CompatibilityList& compatibility_list); const CompatibilityList& compatibility_list);

View file

@ -104,6 +104,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include "input_common/main.h" #include "input_common/main.h"
#include "util/overlay_dialog.h" #include "util/overlay_dialog.h"
#include "video_core/gpu.h" #include "video_core/gpu.h"
#include "video_core/renderer_base.h"
#include "video_core/shader_notify.h" #include "video_core/shader_notify.h"
#include "yuzu/about_dialog.h" #include "yuzu/about_dialog.h"
#include "yuzu/bootmanager.h" #include "yuzu/bootmanager.h"
@ -194,10 +195,10 @@ static void RemoveCachedContents() {
const auto offline_legal_information = cache_dir / "offline_web_applet_legal_information"; const auto offline_legal_information = cache_dir / "offline_web_applet_legal_information";
const auto offline_system_data = cache_dir / "offline_web_applet_system_data"; const auto offline_system_data = cache_dir / "offline_web_applet_system_data";
void(Common::FS::RemoveDirRecursively(offline_fonts)); Common::FS::RemoveDirRecursively(offline_fonts);
void(Common::FS::RemoveDirRecursively(offline_manual)); Common::FS::RemoveDirRecursively(offline_manual);
void(Common::FS::RemoveDirRecursively(offline_legal_information)); Common::FS::RemoveDirRecursively(offline_legal_information);
void(Common::FS::RemoveDirRecursively(offline_system_data)); Common::FS::RemoveDirRecursively(offline_system_data);
} }
GMainWindow::GMainWindow() GMainWindow::GMainWindow()
@ -1422,7 +1423,8 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index, S
std::filesystem::path{filename.toStdU16String()}.filename()); std::filesystem::path{filename.toStdU16String()}.filename());
} }
LOG_INFO(Frontend, "Booting game: {:016X} | {} | {}", title_id, title_name, title_version); LOG_INFO(Frontend, "Booting game: {:016X} | {} | {}", title_id, title_name, title_version);
UpdateWindowTitle(title_name, title_version); const auto gpu_vendor = system.GPU().Renderer().GetDeviceVendor();
UpdateWindowTitle(title_name, title_version, gpu_vendor);
loading_screen->Prepare(system.GetAppLoader()); loading_screen->Prepare(system.GetAppLoader());
loading_screen->show(); loading_screen->show();
@ -1743,8 +1745,8 @@ void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryT
RemoveAddOnContent(program_id, entry_type); RemoveAddOnContent(program_id, entry_type);
break; break;
} }
void(Common::FS::RemoveDirRecursively(Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / Common::FS::RemoveDirRecursively(Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) /
"game_list")); "game_list");
game_list->PopulateAsync(UISettings::values.game_dirs); game_list->PopulateAsync(UISettings::values.game_dirs);
} }
@ -1876,7 +1878,8 @@ void GMainWindow::RemoveCustomConfiguration(u64 program_id, const std::string& g
} }
} }
void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path) { void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path,
DumpRomFSTarget target) {
const auto failed = [this] { const auto failed = [this] {
QMessageBox::warning(this, tr("RomFS Extraction Failed!"), QMessageBox::warning(this, tr("RomFS Extraction Failed!"),
tr("There was an error copying the RomFS files or the user " tr("There was an error copying the RomFS files or the user "
@ -1904,7 +1907,10 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
return; return;
} }
const auto dump_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir); const auto dump_dir =
target == DumpRomFSTarget::Normal
? Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir)
: Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir) / "atmosphere" / "contents";
const auto romfs_dir = fmt::format("{:016X}/romfs", *romfs_title_id); const auto romfs_dir = fmt::format("{:016X}/romfs", *romfs_title_id);
const auto path = Common::FS::PathToUTF8String(dump_dir / romfs_dir); const auto path = Common::FS::PathToUTF8String(dump_dir / romfs_dir);
@ -2213,8 +2219,8 @@ void GMainWindow::OnMenuInstallToNAND() {
: tr("%n file(s) failed to install\n", "", failed_files.size())); : tr("%n file(s) failed to install\n", "", failed_files.size()));
QMessageBox::information(this, tr("Install Results"), install_results); QMessageBox::information(this, tr("Install Results"), install_results);
void(Common::FS::RemoveDirRecursively(Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / Common::FS::RemoveDirRecursively(Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) /
"game_list")); "game_list");
game_list->PopulateAsync(UISettings::values.game_dirs); game_list->PopulateAsync(UISettings::values.game_dirs);
ui.action_Install_File_NAND->setEnabled(true); ui.action_Install_File_NAND->setEnabled(true);
} }
@ -2846,13 +2852,13 @@ void GMainWindow::MigrateConfigFiles() {
LOG_INFO(Frontend, "Migrating config file from {} to {}", origin, destination); LOG_INFO(Frontend, "Migrating config file from {} to {}", origin, destination);
if (!Common::FS::RenameFile(origin, destination)) { if (!Common::FS::RenameFile(origin, destination)) {
// Delete the old config file if one already exists in the new location. // Delete the old config file if one already exists in the new location.
void(Common::FS::RemoveFile(origin)); Common::FS::RemoveFile(origin);
} }
} }
} }
void GMainWindow::UpdateWindowTitle(const std::string& title_name, void GMainWindow::UpdateWindowTitle(std::string_view title_name, std::string_view title_version,
const std::string& title_version) { std::string_view gpu_vendor) {
const auto branch_name = std::string(Common::g_scm_branch); const auto branch_name = std::string(Common::g_scm_branch);
const auto description = std::string(Common::g_scm_desc); const auto description = std::string(Common::g_scm_desc);
const auto build_id = std::string(Common::g_build_id); const auto build_id = std::string(Common::g_build_id);
@ -2864,7 +2870,8 @@ void GMainWindow::UpdateWindowTitle(const std::string& title_name,
if (title_name.empty()) { if (title_name.empty()) {
setWindowTitle(QString::fromStdString(window_title)); setWindowTitle(QString::fromStdString(window_title));
} else { } else {
const auto run_title = fmt::format("{} | {} | {}", window_title, title_name, title_version); const auto run_title =
fmt::format("{} | {} | {} | {}", window_title, title_name, title_version, gpu_vendor);
setWindowTitle(QString::fromStdString(run_title)); setWindowTitle(QString::fromStdString(run_title));
} }
} }
@ -3040,9 +3047,9 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
const auto keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir); const auto keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir);
void(Common::FS::RemoveFile(keys_dir / "prod.keys_autogenerated")); Common::FS::RemoveFile(keys_dir / "prod.keys_autogenerated");
void(Common::FS::RemoveFile(keys_dir / "console.keys_autogenerated")); Common::FS::RemoveFile(keys_dir / "console.keys_autogenerated");
void(Common::FS::RemoveFile(keys_dir / "title.keys_autogenerated")); Common::FS::RemoveFile(keys_dir / "title.keys_autogenerated");
} }
Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance();

View file

@ -34,6 +34,7 @@ class QProgressDialog;
class WaitTreeWidget; class WaitTreeWidget;
enum class GameListOpenTarget; enum class GameListOpenTarget;
enum class GameListRemoveTarget; enum class GameListRemoveTarget;
enum class DumpRomFSTarget;
enum class InstalledEntryType; enum class InstalledEntryType;
class GameListPlaceholder; class GameListPlaceholder;
@ -244,7 +245,7 @@ private slots:
void OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type); void OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type);
void OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target, void OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target,
const std::string& game_path); const std::string& game_path);
void OnGameListDumpRomFS(u64 program_id, const std::string& game_path); void OnGameListDumpRomFS(u64 program_id, const std::string& game_path, DumpRomFSTarget target);
void OnGameListCopyTID(u64 program_id); void OnGameListCopyTID(u64 program_id);
void OnGameListNavigateToGamedbEntry(u64 program_id, void OnGameListNavigateToGamedbEntry(u64 program_id,
const CompatibilityList& compatibility_list); const CompatibilityList& compatibility_list);
@ -287,8 +288,8 @@ private:
InstallResult InstallNSPXCI(const QString& filename); InstallResult InstallNSPXCI(const QString& filename);
InstallResult InstallNCA(const QString& filename); InstallResult InstallNCA(const QString& filename);
void MigrateConfigFiles(); void MigrateConfigFiles();
void UpdateWindowTitle(const std::string& title_name = {}, void UpdateWindowTitle(std::string_view title_name = {}, std::string_view title_version = {},
const std::string& title_version = {}); std::string_view gpu_vendor = {});
void UpdateStatusBar(); void UpdateStatusBar();
void UpdateStatusButtons(); void UpdateStatusButtons();
void UpdateUISettings(); void UpdateUISettings();

View file

@ -219,7 +219,7 @@ int main(int argc, char** argv) {
system.GPU().Start(); system.GPU().Start();
system.Renderer().ReadRasterizer()->LoadDiskResources( system.Renderer().ReadRasterizer()->LoadDiskResources(
system.CurrentProcess()->GetTitleID(), false, system.CurrentProcess()->GetTitleID(), std::stop_token{},
[](VideoCore::LoadCallbackStage, size_t value, size_t total) {}); [](VideoCore::LoadCallbackStage, size_t value, size_t total) {});
void(system.Run()); void(system.Run());