1
0
mirror of https://git.suyu.dev/suyu/suyu synced 2025-12-08 13:52:08 -06:00

10 Commits

Author SHA1 Message Date
Belal Ashraf
81959ea8e5 fix wrong memory permission 2024-04-09 20:25:44 +02:00
Belal Ashraf
6d20086742 missed a semicolon 2024-04-09 13:45:26 +02:00
Belal Ashraf
311cfa231b fix formatting (part 2) 2024-04-09 13:45:26 +02:00
Belal Ashraf
bd101a52a0 fix formatting (part 1) 2024-04-09 13:45:26 +02:00
Belal Ashraf
6d13a5ea2b update definition and callsites 2024-04-09 13:45:26 +02:00
Belal Ashraf
f91107da04 take in page properties by reference instead of by value 2024-04-09 13:45:26 +02:00
Belal Ashraf
3c9732c9d1 fix formatting again again 2024-04-09 13:45:26 +02:00
Belal Ashraf
5f56ba2af6 fix formatting again 2024-04-09 13:45:26 +02:00
Belal Ashraf
96db423b41 fix formatting 2024-04-09 13:45:26 +02:00
Belal Ashraf
5002fde374 Fix bug in ConvertToKMemoryPermission 2024-04-09 13:45:26 +02:00
9 changed files with 17 additions and 281 deletions

View File

@@ -6,7 +6,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
**Note**: We do not support or condone piracy in any form. In order to use suyu, you'll need keys from your real Switch system, and games which you have legally obtained and paid for. We do not intend to make money or profit from this project.
We're in need of developers. Please join our Matrix below if you want to contribute!
We're in need of developers. Please join our Discord server below if you want to contribute!
This repo is based on Yuzu EA 4176.
<hr />
@@ -25,7 +25,7 @@ It is written in C++ with portability in mind, and we're actively working on bui
</h4>
<p align="center">
<a href="https://chat.suyu.dev">Matrix</a> |
<a href="https://discord.gg/suyu">Discord</a> |
<a href="#status">Status</a> |
<a href="#development">Development</a> |
<a href="#downloads">Downloads</a> |
@@ -48,7 +48,7 @@ We currently have builds over at the [Releases](https://git.suyu.dev/suyu/suyu/r
This project is completely free and open source, and anyone can contribute to help improve suyu.
Most of the development happens on GitLab. For development discussion, please join us on [Matrix](https://chat.suyu.dev).
Most of the development happens on GitLab. For development discussion, please join us on [Discord](https://discord.gg/suyu).
If you want to contribute, please take a look at the [Contributor's Guide](https://git.suyu.dev/suyu/suyu/wiki/Contributing) and [Developer Information](https://git.suyu.dev/suyu/suyu/wiki/Developer-Information).
You can also contact any of the developers on Discord to learn more about the current state of suyu.
@@ -77,7 +77,7 @@ We have official builds [here.](https://git.suyu.dev/suyu/suyu/releases) If any
## Support
If you have any questions, don't hesitate to ask us on [Matrix](https://chat.suyu.dev). We don't bite!
If you have any questions, don't hesitate to ask us on [Discord](https://discord.gg/suyu). We don't bite!
## License

View File

@@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Modified by palfaiate on <2024/03/07>
#pragma once
#include <algorithm>

View File

@@ -175,8 +175,9 @@ constexpr KMemoryPermission ConvertToKMemoryPermission(Svc::MemoryPermission per
return static_cast<KMemoryPermission>(
(static_cast<KMemoryPermission>(perm) & KMemoryPermission::UserMask) |
KMemoryPermission::KernelRead |
((static_cast<KMemoryPermission>(perm) & KMemoryPermission::UserWrite)
<< KMemoryPermission::KernelShift) |
((static_cast<KMemoryPermission>(perm) & Svc::MemoryPermission::UserWrite)
? KMemoryPermission::KernelWrite
: KMemoryPermission::None) |
(perm == Svc::MemoryPermission::None ? KMemoryPermission::NotMapped
: KMemoryPermission::None));
}

View File

@@ -1594,7 +1594,7 @@ size_t KPageTableBase::GetAliasCodeDataSize() const {
}
Result KPageTableBase::AllocateAndMapPagesImpl(PageLinkedList* page_list, KProcessAddress address,
size_t num_pages, KMemoryPermission perm) {
size_t num_pages, KPageProperties& perm) {
ASSERT(this->IsLockedByCurrentThread());
// Create a page group to hold the pages we allocate.
@@ -1615,7 +1615,6 @@ Result KPageTableBase::AllocateAndMapPagesImpl(PageLinkedList* page_list, KProce
}
// Map the pages.
const KPageProperties properties = {perm, false, false, DisableMergeAttribute::None};
R_RETURN(this->Operate(page_list, address, num_pages, pg, properties, OperationType::MapGroup,
false));
}
@@ -2749,12 +2748,12 @@ Result KPageTableBase::MapPages(KProcessAddress* out_addr, size_t num_pages, siz
KScopedPageTableUpdater updater(this);
// Perform mapping operation.
KPageProperties properties = {perm, false, false, DisableMergeAttribute::DisableHead};
if (is_pa_valid) {
const KPageProperties properties = {perm, false, false, DisableMergeAttribute::DisableHead};
R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, phys_addr, true, properties,
OperationType::Map, false));
} else {
R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), addr, num_pages, perm));
R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), addr, num_pages, properties));
}
// Update the blocks.
@@ -2793,7 +2792,8 @@ Result KPageTableBase::MapPages(KProcessAddress address, size_t num_pages, KMemo
KScopedPageTableUpdater updater(this);
// Map the pages.
R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), address, num_pages, perm));
KPageProperties properties = {perm, false, false, DisableMergeAttribute::DisableHead};
R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), address, num_pages, properties));
// Update the blocks.
m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, state, perm,

View File

@@ -441,7 +441,7 @@ private:
Svc::MemoryState state) const;
Result AllocateAndMapPagesImpl(PageLinkedList* page_list, KProcessAddress address,
size_t num_pages, KMemoryPermission perm);
size_t num_pages, KPageProperties& perm);
Result MapPageGroupImpl(PageLinkedList* page_list, KProcessAddress address,
const KPageGroup& pg, const KPageProperties properties, bool reuse_ll);

View File

@@ -2,7 +2,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// Modified by palfaiate on <2024/03/07>
// Reverted palfaiate's changes on <2024/03/25> -Nine-Ball
#include <QApplication>
#include <QDir>
@@ -581,9 +580,6 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
remove_menu->addSeparator();
QAction* remove_shader_cache = remove_menu->addAction(tr("Remove All Pipeline Caches"));
QAction* remove_all_content = remove_menu->addAction(tr("Remove All Installed Contents"));
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* verify_integrity = context_menu.addAction(tr("Verify Integrity"));
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"));
@@ -651,12 +647,6 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
connect(remove_cache_storage, &QAction::triggered, [this, program_id, path] {
emit RemoveFileRequested(program_id, GameListRemoveTarget::CacheStorage, path);
});
connect(dump_romfs, &QAction::triggered, [this, 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(verify_integrity, &QAction::triggered,
[this, path]() { emit VerifyIntegrityRequested(path); });
connect(copy_tid, &QAction::triggered,

View File

@@ -2,7 +2,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// Modified by palfaiate on <2024/03/07>
// Reverted palfaiate's changes on <2024/03/25> -Nine-Ball
#pragma once
@@ -53,11 +52,6 @@ enum class GameListRemoveTarget {
CacheStorage,
};
enum class DumpRomFSTarget {
Normal,
SDMC,
};
enum class GameListShortcutTarget {
Desktop,
Applications,
@@ -119,7 +113,6 @@ signals:
void RemoveFileRequested(u64 program_id, GameListRemoveTarget target,
const std::string& game_path);
void RemovePlayTimeRequested(u64 program_id);
void DumpRomFSRequested(u64 program_id, const std::string& game_path, DumpRomFSTarget target);
void VerifyIntegrityRequested(const std::string& game_path);
void CopyTIDRequested(u64 program_id);
void CreateShortcut(u64 program_id, const std::string& game_path,

View File

@@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Modified by palfaiate on <2024/03/07>
#include <cinttypes>
#include <clocale>
#include <cmath>
@@ -53,18 +55,6 @@
#include "suyu/multiplayer/state.h"
#include "suyu/util/controller_navigation.h"
// These are wrappers to avoid the calls to CreateDirectory and CreateFile because of the Windows
static FileSys::VirtualDir VfsFilesystemCreateDirectoryWrapper(
const FileSys::VirtualFilesystem& vfs, const std::string& path, FileSys::OpenMode mode) {
return vfs->CreateDirectory(path, mode);
}
// Overloaded function, also removed by palafiate
static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::VirtualDir& dir,
const std::string& path) {
return dir->CreateFile(path);
}
#include <fmt/ostream.h>
#include <glad/glad.h>
@@ -1475,7 +1465,6 @@ void GMainWindow::ConnectWidgetEvents() {
connect(game_list, &GameList::RemoveFileRequested, this, &GMainWindow::OnGameListRemoveFile);
connect(game_list, &GameList::RemovePlayTimeRequested, this,
&GMainWindow::OnGameListRemovePlayTimeData);
connect(game_list, &GameList::DumpRomFSRequested, this, &GMainWindow::OnGameListDumpRomFS);
connect(game_list, &GameList::VerifyIntegrityRequested, this,
&GMainWindow::OnGameListVerifyIntegrity);
connect(game_list, &GameList::CopyTIDRequested, this, &GMainWindow::OnGameListCopyTID);
@@ -2380,68 +2369,6 @@ void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) {
QDesktopServices::openUrl(QUrl::fromLocalFile(qt_shader_cache_path));
}
static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog& dialog,
const FileSys::VirtualDir& src, const FileSys::VirtualDir& dest,
bool full) {
if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable())
return false;
if (dialog.wasCanceled())
return false;
std::vector<u8> buffer(CopyBufferSize);
auto last_timestamp = std::chrono::steady_clock::now();
const auto QtRawCopy = [&](const FileSys::VirtualFile& src_file,
const FileSys::VirtualFile& dest_file) {
if (src_file == nullptr || dest_file == nullptr) {
return false;
}
if (!dest_file->Resize(src_file->GetSize())) {
return false;
}
for (std::size_t i = 0; i < src_file->GetSize(); i += buffer.size()) {
if (dialog.wasCanceled()) {
dest_file->Resize(0);
return false;
}
using namespace std::literals::chrono_literals;
const auto new_timestamp = std::chrono::steady_clock::now();
if ((new_timestamp - last_timestamp) > 33ms) {
last_timestamp = new_timestamp;
dialog.setValue(
static_cast<int>(std::min(read_size, total_size) * 100 / total_size));
QCoreApplication::processEvents();
}
const auto read = src_file->Read(buffer.data(), buffer.size(), i);
dest_file->Write(buffer.data(), read, i);
read_size += read;
}
return true;
};
if (full) {
for (const auto& file : src->GetFiles()) {
const auto out = VfsDirectoryCreateFileWrapper(dest, file->GetName());
if (!QtRawCopy(file, out))
return false;
}
}
for (const auto& dir : src->GetSubdirectories()) {
const auto out = dest->CreateSubdirectory(dir->GetName());
if (!RomFSRawCopy(total_size, read_size, dialog, dir, out, full))
return false;
}
return true;
}
QString GMainWindow::GetGameListErrorRemoving(InstalledEntryType type) const {
switch (type) {
case InstalledEntryType::Game:
@@ -2683,121 +2610,6 @@ void GMainWindow::RemoveCacheStorage(u64 program_id) {
Common::FS::RemoveDirRecursively(path);
}
void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path,
DumpRomFSTarget target) {
const auto failed = [this] {
QMessageBox::warning(this, tr("RomFS Extraction Failed!"),
tr("There was an error copying the RomFS files or the user "
"cancelled the operation."));
};
const auto loader =
Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::OpenMode::Read));
if (loader == nullptr) {
failed();
return;
}
FileSys::VirtualFile packed_update_raw{};
loader->ReadUpdateRaw(packed_update_raw);
const auto& installed = system->GetContentProvider();
u64 title_id{};
u8 raw_type{};
if (!SelectRomFSDumpTarget(installed, program_id, &title_id, &raw_type)) {
failed();
return;
}
const auto type = static_cast<FileSys::ContentRecordType>(raw_type);
const auto base_nca = installed.GetEntry(title_id, type);
if (!base_nca) {
failed();
return;
}
const FileSys::NCA update_nca{packed_update_raw, nullptr};
if (type != FileSys::ContentRecordType::Program ||
update_nca.GetStatus() != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS ||
update_nca.GetTitleId() != FileSys::GetUpdateTitleID(title_id)) {
packed_update_raw = {};
}
const auto base_romfs = base_nca->GetRomFS();
const auto dump_dir =
target == DumpRomFSTarget::Normal
? Common::FS::GetSuyuPath(Common::FS::SuyuPath::DumpDir)
: Common::FS::GetSuyuPath(Common::FS::SuyuPath::SDMCDir) / "atmosphere" / "contents";
const auto romfs_dir = fmt::format("{:016X}/romfs", title_id);
const auto path = Common::FS::PathToUTF8String(dump_dir / romfs_dir);
const FileSys::PatchManager pm{title_id, system->GetFileSystemController(), installed};
auto romfs = pm.PatchRomFS(base_nca.get(), base_romfs, type, packed_update_raw, false);
const auto out = VfsFilesystemCreateDirectoryWrapper(vfs, path, FileSys::OpenMode::ReadWrite);
if (out == nullptr) {
failed();
vfs->DeleteDirectory(path);
return;
}
bool ok = false;
const QStringList selections{tr("Full"), tr("Skeleton")};
const auto res = QInputDialog::getItem(
this, tr("Select RomFS Dump Mode"),
tr("Please select the how you would like the RomFS dumped.<br>Full will copy all of the "
"files into the new directory while <br>skeleton will only create the directory "
"structure."),
selections, 0, false, &ok);
if (!ok) {
failed();
vfs->DeleteDirectory(path);
return;
}
const auto extracted = FileSys::ExtractRomFS(romfs);
if (extracted == nullptr) {
failed();
return;
}
const auto full = res == selections.constFirst();
// The expected required space is the size of the RomFS + 1 GiB
const auto minimum_free_space = romfs->GetSize() + 0x40000000;
if (full && Common::FS::GetFreeSpaceSize(path) < minimum_free_space) {
QMessageBox::warning(this, tr("RomFS Extraction Failed!"),
tr("There is not enough free space at %1 to extract the RomFS. Please "
"free up space or select a different dump directory at "
"Emulation > Configure > System > Filesystem > Dump Root")
.arg(QString::fromStdString(path)));
return;
}
QProgressDialog progress(tr("Extracting RomFS..."), tr("Cancel"), 0, 100, this);
progress.setWindowModality(Qt::WindowModal);
progress.setMinimumDuration(100);
progress.setAutoClose(false);
progress.setAutoReset(false);
size_t read_size = 0;
if (RomFSRawCopy(romfs->GetSize(), read_size, progress, extracted, out, full)) {
progress.close();
QMessageBox::information(this, tr("RomFS Extraction Succeeded!"),
tr("The operation completed successfully."));
QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(path)));
} else {
progress.close();
failed();
vfs->DeleteDirectory(path);
}
}
void GMainWindow::OnGameListVerifyIntegrity(const std::string& game_path) {
const auto NotImplemented = [this] {
QMessageBox::warning(this, tr("Integrity verification couldn't be performed!"),
@@ -4868,66 +4680,6 @@ void GMainWindow::SetFirmwareVersion() {
firmware_label->setToolTip(QString::fromStdString(display_title));
}
bool GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installed, u64 program_id,
u64* selected_title_id, u8* selected_content_record_type) {
using ContentInfo = std::tuple<u64, FileSys::TitleType, FileSys::ContentRecordType>;
boost::container::flat_set<ContentInfo> available_title_ids;
const auto RetrieveEntries = [&](FileSys::TitleType title_type,
FileSys::ContentRecordType record_type) {
const auto entries = installed.ListEntriesFilter(title_type, record_type);
for (const auto& entry : entries) {
if (FileSys::GetBaseTitleID(entry.title_id) == program_id &&
installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success) {
available_title_ids.insert({entry.title_id, title_type, record_type});
}
}
};
RetrieveEntries(FileSys::TitleType::Application, FileSys::ContentRecordType::Program);
RetrieveEntries(FileSys::TitleType::Application, FileSys::ContentRecordType::HtmlDocument);
RetrieveEntries(FileSys::TitleType::Application, FileSys::ContentRecordType::LegalInformation);
RetrieveEntries(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
if (available_title_ids.empty()) {
return false;
}
size_t title_index = 0;
if (available_title_ids.size() > 1) {
QStringList list;
for (auto& [title_id, title_type, record_type] : available_title_ids) {
const auto hex_title_id = QString::fromStdString(fmt::format("{:X}", title_id));
if (record_type == FileSys::ContentRecordType::Program) {
list.push_back(QStringLiteral("Program [%1]").arg(hex_title_id));
} else if (record_type == FileSys::ContentRecordType::HtmlDocument) {
list.push_back(QStringLiteral("HTML document [%1]").arg(hex_title_id));
} else if (record_type == FileSys::ContentRecordType::LegalInformation) {
list.push_back(QStringLiteral("Legal information [%1]").arg(hex_title_id));
} else {
list.push_back(
QStringLiteral("DLC %1 [%2]").arg(title_id & 0x7FF).arg(hex_title_id));
}
}
bool ok;
const auto res = QInputDialog::getItem(
this, tr("Select RomFS Dump Target"),
tr("Please select which RomFS you would like to dump."), list, 0, false, &ok);
if (!ok) {
return false;
}
title_index = list.indexOf(res);
}
const auto& [title_id, title_type, record_type] = *available_title_ids.nth(title_index);
*selected_title_id = title_id;
*selected_content_record_type = static_cast<u8>(record_type);
return true;
}
bool GMainWindow::ConfirmClose() {
if (emu_thread == nullptr ||
UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Never) {

View File

@@ -51,7 +51,6 @@ class WaitTreeWidget;
enum class GameListOpenTarget;
enum class GameListRemoveTarget;
enum class GameListShortcutTarget;
enum class DumpRomFSTarget;
enum class InstalledEntryType;
class GameListPlaceholder;
@@ -348,7 +347,6 @@ private slots:
void OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target,
const std::string& game_path);
void OnGameListRemovePlayTimeData(u64 program_id);
void OnGameListDumpRomFS(u64 program_id, const std::string& game_path, DumpRomFSTarget target);
void OnGameListVerifyIntegrity(const std::string& game_path);
void OnGameListCopyTID(u64 program_id);
void OnGameListNavigateToGamedbEntry(u64 program_id,