Compare commits

..

5 Commits

Author SHA1 Message Date
20b744ee68 Android 191 2024-01-13 01:00:47 +00:00
d62868644b Merge yuzu-emu#12652 2024-01-13 01:00:46 +00:00
bd30c1e2d9 Merge yuzu-emu#12612 2024-01-13 01:00:46 +00:00
0dc00454e5 Merge yuzu-emu#12610 2024-01-13 01:00:46 +00:00
fd9e7d6cb1 Merge yuzu-emu#12579 2024-01-13 01:00:46 +00:00
43 changed files with 367 additions and 578 deletions

View File

@ -32,6 +32,3 @@ if [ ! -z "$DIFF" ]; then
echo "$DIFF" echo "$DIFF"
exit 1 exit 1
fi fi
cd src/android
./gradlew ktlintCheck

View File

@ -8,7 +8,17 @@ variables:
DisplayVersion: $[counter(variables['DisplayPrefix'], 1)] DisplayVersion: $[counter(variables['DisplayPrefix'], 1)]
stages: stages:
- stage: format
displayName: 'format'
jobs:
- job: format
displayName: 'clang'
pool:
vmImage: ubuntu-latest
steps:
- template: ./templates/format-check.yml
- stage: build - stage: build
dependsOn: format
displayName: 'build' displayName: 'build'
jobs: jobs:
- job: build - job: build

View File

@ -13,15 +13,13 @@ jobs:
format: format:
name: 'verify format' name: 'verify format'
runs-on: ubuntu-latest runs-on: ubuntu-latest
container:
image: yuzuemu/build-environments:linux-clang-format
options: -u 1001
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
submodules: false submodules: false
- name: set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: 'Verify Formatting' - name: 'Verify Formatting'
run: bash -ex ./.ci/scripts/format/script.sh run: bash -ex ./.ci/scripts/format/script.sh
build: build:

View File

@ -1,7 +1,9 @@
| Pull Request | Commit | Title | Author | Merged? | | Pull Request | Commit | Title | Author | Merged? |
|----|----|----|----|----| |----|----|----|----|----|
| [12579](https://github.com/yuzu-emu/yuzu-android//pull/12579) | [`66ae60a9e`](https://github.com/yuzu-emu/yuzu-android//pull/12579/files) | Core: Implement Device Mapping & GPU SMMU | [FernandoS27](https://github.com/FernandoS27/) | Yes | | [12579](https://github.com/yuzu-emu/yuzu-android//pull/12579) | [`66ae60a9e`](https://github.com/yuzu-emu/yuzu-android//pull/12579/files) | Core: Implement Device Mapping & GPU SMMU | [FernandoS27](https://github.com/FernandoS27/) | Yes |
| [12644](https://github.com/yuzu-emu/yuzu-android//pull/12644) | [`2044a289f`](https://github.com/yuzu-emu/yuzu-android//pull/12644/files) | shader_recompiler: fix Offset operand usage for non-OpImage*Gather | [liamwhite](https://github.com/liamwhite/) | Yes | | [12610](https://github.com/yuzu-emu/yuzu-android//pull/12610) | [`200b371d1`](https://github.com/yuzu-emu/yuzu-android//pull/12610/files) | server_manager: respond to session close correctly | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12612](https://github.com/yuzu-emu/yuzu-android//pull/12612) | [`aae9eea53`](https://github.com/yuzu-emu/yuzu-android//pull/12612/files) | fsp-srv: use program registry for SetCurrentProcess | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12652](https://github.com/yuzu-emu/yuzu-android//pull/12652) | [`2a0d707ce`](https://github.com/yuzu-emu/yuzu-android//pull/12652/files) | shader_recompiler: emulate 8-bit and 16-bit storage writes with cas loop | [liamwhite](https://github.com/liamwhite/) | Yes |
End of merge log. You can find the original README.md below the break. End of merge log. You can find the original README.md below the break.

View File

@ -188,15 +188,8 @@ tasks.create<Delete>("ktlintReset") {
delete(File(buildDir.path + File.separator + "intermediates/ktLint")) delete(File(buildDir.path + File.separator + "intermediates/ktLint"))
} }
val showFormatHelp = {
logger.lifecycle(
"If this check fails, please try running \"gradlew ktlintFormat\" for automatic " +
"codestyle fixes"
)
}
tasks.getByPath("ktlintKotlinScriptCheck").doFirst { showFormatHelp.invoke() }
tasks.getByPath("ktlintMainSourceSetCheck").doFirst { showFormatHelp.invoke() }
tasks.getByPath("loadKtlintReporters").dependsOn("ktlintReset") tasks.getByPath("loadKtlintReporters").dependsOn("ktlintReset")
tasks.getByPath("preBuild").dependsOn("ktlintCheck")
ktlint { ktlint {
version.set("0.47.1") version.set("0.47.1")
@ -235,33 +228,71 @@ dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
} }
fun runGitCommand(command: List<String>): String { fun getGitVersion(): String {
return try { var versionName = "0.0"
ProcessBuilder(command)
try {
versionName = ProcessBuilder("git", "describe", "--always", "--long")
.directory(project.rootDir) .directory(project.rootDir)
.redirectOutput(ProcessBuilder.Redirect.PIPE) .redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectError(ProcessBuilder.Redirect.PIPE) .redirectError(ProcessBuilder.Redirect.PIPE)
.start().inputStream.bufferedReader().use { it.readText() } .start().inputStream.bufferedReader().use { it.readText() }
.trim() .trim()
} catch (e: Exception) {
logger.error("Cannot find git")
""
}
}
fun getGitVersion(): String {
val versionName = if (System.getenv("GITHUB_ACTIONS") != null) {
val gitTag = System.getenv("GIT_TAG_NAME") ?: ""
gitTag
} else {
runGitCommand(listOf("git", "describe", "--always", "--long"))
.replace(Regex("(-0)?-[^-]+$"), "") .replace(Regex("(-0)?-[^-]+$"), "")
} } catch (e: Exception) {
return versionName.ifEmpty { "0.0" } logger.error("Cannot find git, defaulting to dummy version number")
} }
fun getGitHash(): String = if (System.getenv("GITHUB_ACTIONS") != null) {
runGitCommand(listOf("git", "rev-parse", "--short", "HEAD")).ifEmpty { "dummy-hash" } val gitTag = System.getenv("GIT_TAG_NAME")
versionName = gitTag ?: versionName
}
fun getBranch(): String = return versionName
runGitCommand(listOf("git", "rev-parse", "--abbrev-ref", "HEAD")).ifEmpty { "dummy-hash" } }
fun getGitHash(): String {
try {
val processBuilder = ProcessBuilder("git", "rev-parse", "--short", "HEAD")
processBuilder.directory(project.rootDir)
val process = processBuilder.start()
val inputStream = process.inputStream
val errorStream = process.errorStream
process.waitFor()
return if (process.exitValue() == 0) {
inputStream.bufferedReader()
.use { it.readText().trim() } // return the value of gitHash
} else {
val errorMessage = errorStream.bufferedReader().use { it.readText().trim() }
logger.error("Error running git command: $errorMessage")
"dummy-hash" // return a dummy hash value in case of an error
}
} catch (e: Exception) {
logger.error("$e: Cannot find git, defaulting to dummy build hash")
return "dummy-hash" // return a dummy hash value in case of an error
}
}
fun getBranch(): String {
try {
val processBuilder = ProcessBuilder("git", "rev-parse", "--abbrev-ref", "HEAD")
processBuilder.directory(project.rootDir)
val process = processBuilder.start()
val inputStream = process.inputStream
val errorStream = process.errorStream
process.waitFor()
return if (process.exitValue() == 0) {
inputStream.bufferedReader()
.use { it.readText().trim() } // return the value of gitHash
} else {
val errorMessage = errorStream.bufferedReader().use { it.readText().trim() }
logger.error("Error running git command: $errorMessage")
"dummy-hash" // return a dummy hash value in case of an error
}
} catch (e: Exception) {
logger.error("$e: Cannot find git, defaulting to dummy build hash")
return "dummy-hash" // return a dummy hash value in case of an error
}
}

View File

@ -76,8 +76,8 @@ class AboutFragment : Fragment() {
binding.root.findNavController().navigate(R.id.action_aboutFragment_to_licensesFragment) binding.root.findNavController().navigate(R.id.action_aboutFragment_to_licensesFragment)
} }
binding.textVersionName.text = BuildConfig.VERSION_NAME binding.textBuildHash.text = BuildConfig.GIT_HASH
binding.textVersionName.setOnClickListener { binding.buttonBuildHash.setOnClickListener {
val clipBoard = val clipBoard =
requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText(getString(R.string.build), BuildConfig.GIT_HASH) val clip = ClipData.newPlainText(getString(R.string.build), BuildConfig.GIT_HASH)

View File

@ -147,7 +147,7 @@
android:layout_marginHorizontal="20dp" /> android:layout_marginHorizontal="20dp" />
<LinearLayout <LinearLayout
android:id="@+id/button_version_name" android:id="@+id/button_build_hash"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground" android:background="?attr/selectableItemBackground"
@ -164,7 +164,7 @@
android:textAlignment="viewStart" /> android:textAlignment="viewStart" />
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
android:id="@+id/text_version_name" android:id="@+id/text_build_hash"
style="@style/TextAppearance.Material3.BodyMedium" style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@ -148,7 +148,7 @@
android:layout_marginHorizontal="20dp" /> android:layout_marginHorizontal="20dp" />
<LinearLayout <LinearLayout
android:id="@+id/button_version_name" android:id="@+id/button_build_hash"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingVertical="16dp" android:paddingVertical="16dp"
@ -165,7 +165,7 @@
android:text="@string/build" /> android:text="@string/build" />
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
android:id="@+id/text_version_name" android:id="@+id/text_build_hash"
style="@style/TextAppearance.Material3.BodyMedium" style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@ -228,10 +228,10 @@
<item>R</item> <item>R</item>
<item>ZL</item> <item>ZL</item>
<item>ZR</item> <item>ZR</item>
<item>L3</item>
<item>R3</item>
<item>@string/gamepad_left_stick</item> <item>@string/gamepad_left_stick</item>
<item>@string/gamepad_right_stick</item> <item>@string/gamepad_right_stick</item>
<item>L3</item>
<item>R3</item>
<item>@string/gamepad_d_pad</item> <item>@string/gamepad_d_pad</item>
</string-array> </string-array>

View File

@ -11,8 +11,6 @@
#include "core/guest_memory.h" #include "core/guest_memory.h"
#include "core/memory.h" #include "core/memory.h"
#include "core/hle/kernel/k_process.h"
namespace AudioCore { namespace AudioCore {
using namespace std::literals; using namespace std::literals;
@ -28,7 +26,7 @@ DeviceSession::~DeviceSession() {
} }
Result DeviceSession::Initialize(std::string_view name_, SampleFormat sample_format_, Result DeviceSession::Initialize(std::string_view name_, SampleFormat sample_format_,
u16 channel_count_, size_t session_id_, Kernel::KProcess* handle_, u16 channel_count_, size_t session_id_, u32 handle_,
u64 applet_resource_user_id_, Sink::StreamType type_) { u64 applet_resource_user_id_, Sink::StreamType type_) {
if (stream) { if (stream) {
Finalize(); Finalize();
@ -39,7 +37,6 @@ Result DeviceSession::Initialize(std::string_view name_, SampleFormat sample_for
channel_count = channel_count_; channel_count = channel_count_;
session_id = session_id_; session_id = session_id_;
handle = handle_; handle = handle_;
handle->Open();
applet_resource_user_id = applet_resource_user_id_; applet_resource_user_id = applet_resource_user_id_;
if (type == Sink::StreamType::In) { if (type == Sink::StreamType::In) {
@ -58,11 +55,6 @@ void DeviceSession::Finalize() {
sink->CloseStream(stream); sink->CloseStream(stream);
stream = nullptr; stream = nullptr;
} }
if (handle) {
handle->Close();
handle = nullptr;
}
} }
void DeviceSession::Start() { void DeviceSession::Start() {
@ -100,7 +92,7 @@ void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) {
stream->AppendBuffer(new_buffer, tmp_samples); stream->AppendBuffer(new_buffer, tmp_samples);
} else { } else {
Core::Memory::CpuGuestMemory<s16, Core::Memory::GuestMemoryFlags::UnsafeRead> samples( Core::Memory::CpuGuestMemory<s16, Core::Memory::GuestMemoryFlags::UnsafeRead> samples(
handle->GetMemory(), buffer.samples, buffer.size / sizeof(s16)); system.ApplicationMemory(), buffer.samples, buffer.size / sizeof(s16));
stream->AppendBuffer(new_buffer, samples); stream->AppendBuffer(new_buffer, samples);
} }
} }
@ -109,7 +101,7 @@ void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) {
void DeviceSession::ReleaseBuffer(const AudioBuffer& buffer) const { void DeviceSession::ReleaseBuffer(const AudioBuffer& buffer) const {
if (type == Sink::StreamType::In) { if (type == Sink::StreamType::In) {
auto samples{stream->ReleaseBuffer(buffer.size / sizeof(s16))}; auto samples{stream->ReleaseBuffer(buffer.size / sizeof(s16))};
handle->GetMemory().WriteBlockUnsafe(buffer.samples, samples.data(), buffer.size); system.ApplicationMemory().WriteBlockUnsafe(buffer.samples, samples.data(), buffer.size);
} }
} }

View File

@ -20,10 +20,6 @@ struct EventType;
} // namespace Timing } // namespace Timing
} // namespace Core } // namespace Core
namespace Kernel {
class KProcess;
} // namespace Kernel
namespace AudioCore { namespace AudioCore {
namespace Sink { namespace Sink {
@ -48,13 +44,13 @@ public:
* @param sample_format - Sample format for this device's output. * @param sample_format - Sample format for this device's output.
* @param channel_count - Number of channels for this device (2 or 6). * @param channel_count - Number of channels for this device (2 or 6).
* @param session_id - This session's id. * @param session_id - This session's id.
* @param handle - Process handle for this device session. * @param handle - Handle for this device session (unused).
* @param applet_resource_user_id - Applet resource user id for this device session (unused). * @param applet_resource_user_id - Applet resource user id for this device session (unused).
* @param type - Type of this stream (Render, In, Out). * @param type - Type of this stream (Render, In, Out).
* @return Result code for this call. * @return Result code for this call.
*/ */
Result Initialize(std::string_view name, SampleFormat sample_format, u16 channel_count, Result Initialize(std::string_view name, SampleFormat sample_format, u16 channel_count,
size_t session_id, Kernel::KProcess* handle, u64 applet_resource_user_id, size_t session_id, u32 handle, u64 applet_resource_user_id,
Sink::StreamType type); Sink::StreamType type);
/** /**
@ -141,8 +137,8 @@ private:
u16 channel_count{}; u16 channel_count{};
/// Session id of this device session /// Session id of this device session
size_t session_id{}; size_t session_id{};
/// Process handle of device memory owner /// Handle of this device session
Kernel::KProcess* handle{}; u32 handle{};
/// Applet resource user id of this device session /// Applet resource user id of this device session
u64 applet_resource_user_id{}; u64 applet_resource_user_id{};
/// Total number of samples played by this device session /// Total number of samples played by this device session

View File

@ -57,7 +57,7 @@ Result System::IsConfigValid(const std::string_view device_name,
} }
Result System::Initialize(std::string device_name, const AudioInParameter& in_params, Result System::Initialize(std::string device_name, const AudioInParameter& in_params,
Kernel::KProcess* handle_, const u64 applet_resource_user_id_) { const u32 handle_, const u64 applet_resource_user_id_) {
auto result{IsConfigValid(device_name, in_params)}; auto result{IsConfigValid(device_name, in_params)};
if (result.IsError()) { if (result.IsError()) {
return result; return result;

View File

@ -19,8 +19,7 @@ class System;
namespace Kernel { namespace Kernel {
class KEvent; class KEvent;
class KProcess; }
} // namespace Kernel
namespace AudioCore::AudioIn { namespace AudioCore::AudioIn {
@ -94,12 +93,12 @@ public:
* *
* @param device_name - The name of the requested input device. * @param device_name - The name of the requested input device.
* @param in_params - Input parameters, see AudioInParameter. * @param in_params - Input parameters, see AudioInParameter.
* @param handle - Process handle. * @param handle - Unused.
* @param applet_resource_user_id - Unused. * @param applet_resource_user_id - Unused.
* @return Result code. * @return Result code.
*/ */
Result Initialize(std::string device_name, const AudioInParameter& in_params, Result Initialize(std::string device_name, const AudioInParameter& in_params, u32 handle,
Kernel::KProcess* handle, u64 applet_resource_user_id); u64 applet_resource_user_id);
/** /**
* Start this system. * Start this system.
@ -245,8 +244,8 @@ public:
private: private:
/// Core system /// Core system
Core::System& system; Core::System& system;
/// Process handle /// (Unused)
Kernel::KProcess* handle{}; u32 handle{};
/// (Unused) /// (Unused)
u64 applet_resource_user_id{}; u64 applet_resource_user_id{};
/// Buffer event, signalled when a buffer is ready /// Buffer event, signalled when a buffer is ready

View File

@ -48,8 +48,8 @@ Result System::IsConfigValid(std::string_view device_name,
return Service::Audio::ResultInvalidChannelCount; return Service::Audio::ResultInvalidChannelCount;
} }
Result System::Initialize(std::string device_name, const AudioOutParameter& in_params, Result System::Initialize(std::string device_name, const AudioOutParameter& in_params, u32 handle_,
Kernel::KProcess* handle_, u64 applet_resource_user_id_) { u64 applet_resource_user_id_) {
auto result = IsConfigValid(device_name, in_params); auto result = IsConfigValid(device_name, in_params);
if (result.IsError()) { if (result.IsError()) {
return result; return result;

View File

@ -19,8 +19,7 @@ class System;
namespace Kernel { namespace Kernel {
class KEvent; class KEvent;
class KProcess; }
} // namespace Kernel
namespace AudioCore::AudioOut { namespace AudioCore::AudioOut {
@ -85,12 +84,12 @@ public:
* *
* @param device_name - The name of the requested output device. * @param device_name - The name of the requested output device.
* @param in_params - Input parameters, see AudioOutParameter. * @param in_params - Input parameters, see AudioOutParameter.
* @param handle - Process handle. * @param handle - Unused.
* @param applet_resource_user_id - Unused. * @param applet_resource_user_id - Unused.
* @return Result code. * @return Result code.
*/ */
Result Initialize(std::string device_name, const AudioOutParameter& in_params, Result Initialize(std::string device_name, const AudioOutParameter& in_params, u32 handle,
Kernel::KProcess* handle, u64 applet_resource_user_id); u64 applet_resource_user_id);
/** /**
* Start this system. * Start this system.
@ -229,8 +228,8 @@ public:
private: private:
/// Core system /// Core system
Core::System& system; Core::System& system;
/// Process handle /// (Unused)
Kernel::KProcess* handle{}; u32 handle{};
/// (Unused) /// (Unused)
u64 applet_resource_user_id{}; u64 applet_resource_user_id{};
/// Buffer event, signalled when a buffer is ready /// Buffer event, signalled when a buffer is ready

View File

@ -2,7 +2,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/page_table.h" #include "common/page_table.h"
#include "common/scope_exit.h"
namespace Common { namespace Common {
@ -12,10 +11,29 @@ PageTable::~PageTable() noexcept = default;
bool PageTable::BeginTraversal(TraversalEntry* out_entry, TraversalContext* out_context, bool PageTable::BeginTraversal(TraversalEntry* out_entry, TraversalContext* out_context,
Common::ProcessAddress address) const { Common::ProcessAddress address) const {
out_context->next_offset = GetInteger(address); // Setup invalid defaults.
out_context->next_page = address / page_size; out_entry->phys_addr = 0;
out_entry->block_size = page_size;
out_context->next_page = 0;
return this->ContinueTraversal(out_entry, out_context); // Validate that we can read the actual entry.
const auto page = address / page_size;
if (page >= backing_addr.size()) {
return false;
}
// Validate that the entry is mapped.
const auto phys_addr = backing_addr[page];
if (phys_addr == 0) {
return false;
}
// Populate the results.
out_entry->phys_addr = phys_addr + GetInteger(address);
out_context->next_page = page + 1;
out_context->next_offset = GetInteger(address) + page_size;
return true;
} }
bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* context) const { bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* context) const {
@ -23,12 +41,6 @@ bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* c
out_entry->phys_addr = 0; out_entry->phys_addr = 0;
out_entry->block_size = page_size; out_entry->block_size = page_size;
// Regardless of whether the page was mapped, advance on exit.
SCOPE_EXIT({
context->next_page += 1;
context->next_offset += page_size;
});
// Validate that we can read the actual entry. // Validate that we can read the actual entry.
const auto page = context->next_page; const auto page = context->next_page;
if (page >= backing_addr.size()) { if (page >= backing_addr.size()) {
@ -43,6 +55,8 @@ bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* c
// Populate the results. // Populate the results.
out_entry->phys_addr = phys_addr + context->next_offset; out_entry->phys_addr = phys_addr + context->next_offset;
context->next_page = page + 1;
context->next_offset += page_size;
return true; return true;
} }

View File

@ -22,10 +22,14 @@ using NativeExecutionParameters = Kernel::KThread::NativeExecutionParameters;
constexpr size_t MaxRelativeBranch = 128_MiB; constexpr size_t MaxRelativeBranch = 128_MiB;
constexpr u32 ModuleCodeIndex = 0x24 / sizeof(u32); constexpr u32 ModuleCodeIndex = 0x24 / sizeof(u32);
Patcher::Patcher() : c(m_patch_instructions) { Patcher::Patcher() : c(m_patch_instructions) {}
// The first word of the patch section is always a branch to the first instruction of the
// module. Patcher::~Patcher() = default;
c.dw(0);
void Patcher::PatchText(const Kernel::PhysicalMemory& program_image,
const Kernel::CodeSet::Segment& code) {
// Branch to the first instruction of the module.
this->BranchToModule(0);
// Write save context helper function. // Write save context helper function.
c.l(m_save_context); c.l(m_save_context);
@ -34,25 +38,6 @@ Patcher::Patcher() : c(m_patch_instructions) {
// Write load context helper function. // Write load context helper function.
c.l(m_load_context); c.l(m_load_context);
WriteLoadContext(); WriteLoadContext();
}
Patcher::~Patcher() = default;
bool Patcher::PatchText(const Kernel::PhysicalMemory& program_image,
const Kernel::CodeSet::Segment& code) {
// If we have patched modules but cannot reach the new module, then it needs its own patcher.
const size_t image_size = program_image.size();
if (total_program_size + image_size > MaxRelativeBranch && total_program_size > 0) {
return false;
}
// Add a new module patch to our list
modules.emplace_back();
curr_patch = &modules.back();
// The first word of the patch section is always a branch to the first instruction of the
// module.
curr_patch->m_branch_to_module_relocations.push_back({0, 0});
// Retrieve text segment data. // Retrieve text segment data.
const auto text = std::span{program_image}.subspan(code.offset, code.size); const auto text = std::span{program_image}.subspan(code.offset, code.size);
@ -109,17 +94,16 @@ bool Patcher::PatchText(const Kernel::PhysicalMemory& program_image,
} }
if (auto exclusive = Exclusive{inst}; exclusive.Verify()) { if (auto exclusive = Exclusive{inst}; exclusive.Verify()) {
curr_patch->m_exclusives.push_back(i); m_exclusives.push_back(i);
} }
} }
// Determine patching mode for the final relocation step // Determine patching mode for the final relocation step
total_program_size += image_size; const size_t image_size = program_image.size();
this->mode = image_size > MaxRelativeBranch ? PatchMode::PreText : PatchMode::PostData; this->mode = image_size > MaxRelativeBranch ? PatchMode::PreText : PatchMode::PostData;
return true;
} }
bool Patcher::RelocateAndCopy(Common::ProcessAddress load_base, void Patcher::RelocateAndCopy(Common::ProcessAddress load_base,
const Kernel::CodeSet::Segment& code, const Kernel::CodeSet::Segment& code,
Kernel::PhysicalMemory& program_image, Kernel::PhysicalMemory& program_image,
EntryTrampolines* out_trampolines) { EntryTrampolines* out_trampolines) {
@ -136,7 +120,7 @@ bool Patcher::RelocateAndCopy(Common::ProcessAddress load_base,
if (mode == PatchMode::PreText) { if (mode == PatchMode::PreText) {
rc.B(rel.patch_offset - patch_size - rel.module_offset); rc.B(rel.patch_offset - patch_size - rel.module_offset);
} else { } else {
rc.B(total_program_size - rel.module_offset + rel.patch_offset); rc.B(image_size - rel.module_offset + rel.patch_offset);
} }
}; };
@ -145,7 +129,7 @@ bool Patcher::RelocateAndCopy(Common::ProcessAddress load_base,
if (mode == PatchMode::PreText) { if (mode == PatchMode::PreText) {
rc.B(patch_size - rel.patch_offset + rel.module_offset); rc.B(patch_size - rel.patch_offset + rel.module_offset);
} else { } else {
rc.B(rel.module_offset - total_program_size - rel.patch_offset); rc.B(rel.module_offset - image_size - rel.patch_offset);
} }
}; };
@ -153,7 +137,7 @@ bool Patcher::RelocateAndCopy(Common::ProcessAddress load_base,
if (mode == PatchMode::PreText) { if (mode == PatchMode::PreText) {
return GetInteger(load_base) + patch_offset; return GetInteger(load_base) + patch_offset;
} else { } else {
return GetInteger(load_base) + total_program_size + patch_offset; return GetInteger(load_base) + image_size + patch_offset;
} }
}; };
@ -166,39 +150,32 @@ bool Patcher::RelocateAndCopy(Common::ProcessAddress load_base,
}; };
// We are now ready to relocate! // We are now ready to relocate!
auto& patch = modules[m_relocate_module_index++]; for (const Relocation& rel : m_branch_to_patch_relocations) {
for (const Relocation& rel : patch.m_branch_to_patch_relocations) {
ApplyBranchToPatchRelocation(text_words.data() + rel.module_offset / sizeof(u32), rel); ApplyBranchToPatchRelocation(text_words.data() + rel.module_offset / sizeof(u32), rel);
} }
for (const Relocation& rel : patch.m_branch_to_module_relocations) { for (const Relocation& rel : m_branch_to_module_relocations) {
ApplyBranchToModuleRelocation(m_patch_instructions.data() + rel.patch_offset / sizeof(u32), ApplyBranchToModuleRelocation(m_patch_instructions.data() + rel.patch_offset / sizeof(u32),
rel); rel);
} }
// Rewrite PC constants and record post trampolines // Rewrite PC constants and record post trampolines
for (const Relocation& rel : patch.m_write_module_pc_relocations) { for (const Relocation& rel : m_write_module_pc_relocations) {
oaknut::CodeGenerator rc{m_patch_instructions.data() + rel.patch_offset / sizeof(u32)}; oaknut::CodeGenerator rc{m_patch_instructions.data() + rel.patch_offset / sizeof(u32)};
rc.dx(RebasePc(rel.module_offset)); rc.dx(RebasePc(rel.module_offset));
} }
for (const Trampoline& rel : patch.m_trampolines) { for (const Trampoline& rel : m_trampolines) {
out_trampolines->insert({RebasePc(rel.module_offset), RebasePatch(rel.patch_offset)}); out_trampolines->insert({RebasePc(rel.module_offset), RebasePatch(rel.patch_offset)});
} }
// Cortex-A57 seems to treat all exclusives as ordered, but newer processors do not. // Cortex-A57 seems to treat all exclusives as ordered, but newer processors do not.
// Convert to ordered to preserve this assumption. // Convert to ordered to preserve this assumption.
for (const ModuleTextAddress i : patch.m_exclusives) { for (const ModuleTextAddress i : m_exclusives) {
auto exclusive = Exclusive{text_words[i]}; auto exclusive = Exclusive{text_words[i]};
text_words[i] = exclusive.AsOrdered(); text_words[i] = exclusive.AsOrdered();
} }
// Remove the patched module size from the total. This is done so total_program_size // Copy to program image
// always represents the distance from the currently patched module to the patch section.
total_program_size -= image_size;
// Only copy to the program image of the last module
if (m_relocate_module_index == modules.size()) {
if (this->mode == PatchMode::PreText) { if (this->mode == PatchMode::PreText) {
ASSERT(image_size == total_program_size);
std::memcpy(program_image.data(), m_patch_instructions.data(), std::memcpy(program_image.data(), m_patch_instructions.data(),
m_patch_instructions.size() * sizeof(u32)); m_patch_instructions.size() * sizeof(u32));
} else { } else {
@ -206,10 +183,6 @@ bool Patcher::RelocateAndCopy(Common::ProcessAddress load_base,
std::memcpy(program_image.data() + image_size, m_patch_instructions.data(), std::memcpy(program_image.data() + image_size, m_patch_instructions.data(),
m_patch_instructions.size() * sizeof(u32)); m_patch_instructions.size() * sizeof(u32));
} }
return true;
}
return false;
} }
size_t Patcher::GetSectionSize() const noexcept { size_t Patcher::GetSectionSize() const noexcept {
@ -349,7 +322,7 @@ void Patcher::WriteSvcTrampoline(ModuleDestLabel module_dest, u32 svc_id) {
// Write the post-SVC trampoline address, which will jump back to the guest after restoring its // Write the post-SVC trampoline address, which will jump back to the guest after restoring its
// state. // state.
curr_patch->m_trampolines.push_back({c.offset(), module_dest}); m_trampolines.push_back({c.offset(), module_dest});
// Host called this location. Save the return address so we can // Host called this location. Save the return address so we can
// unwind the stack properly when jumping back. // unwind the stack properly when jumping back.

View File

@ -31,9 +31,9 @@ public:
explicit Patcher(); explicit Patcher();
~Patcher(); ~Patcher();
bool PatchText(const Kernel::PhysicalMemory& program_image, void PatchText(const Kernel::PhysicalMemory& program_image,
const Kernel::CodeSet::Segment& code); const Kernel::CodeSet::Segment& code);
bool RelocateAndCopy(Common::ProcessAddress load_base, const Kernel::CodeSet::Segment& code, void RelocateAndCopy(Common::ProcessAddress load_base, const Kernel::CodeSet::Segment& code,
Kernel::PhysicalMemory& program_image, EntryTrampolines* out_trampolines); Kernel::PhysicalMemory& program_image, EntryTrampolines* out_trampolines);
size_t GetSectionSize() const noexcept; size_t GetSectionSize() const noexcept;
@ -61,16 +61,16 @@ private:
private: private:
void BranchToPatch(uintptr_t module_dest) { void BranchToPatch(uintptr_t module_dest) {
curr_patch->m_branch_to_patch_relocations.push_back({c.offset(), module_dest}); m_branch_to_patch_relocations.push_back({c.offset(), module_dest});
} }
void BranchToModule(uintptr_t module_dest) { void BranchToModule(uintptr_t module_dest) {
curr_patch->m_branch_to_module_relocations.push_back({c.offset(), module_dest}); m_branch_to_module_relocations.push_back({c.offset(), module_dest});
c.dw(0); c.dw(0);
} }
void WriteModulePc(uintptr_t module_dest) { void WriteModulePc(uintptr_t module_dest) {
curr_patch->m_write_module_pc_relocations.push_back({c.offset(), module_dest}); m_write_module_pc_relocations.push_back({c.offset(), module_dest});
c.dx(0); c.dx(0);
} }
@ -84,22 +84,15 @@ private:
uintptr_t module_offset; ///< Offset in bytes from the start of the text section. uintptr_t module_offset; ///< Offset in bytes from the start of the text section.
}; };
struct ModulePatch { oaknut::VectorCodeGenerator c;
std::vector<Trampoline> m_trampolines; std::vector<Trampoline> m_trampolines;
std::vector<Relocation> m_branch_to_patch_relocations{}; std::vector<Relocation> m_branch_to_patch_relocations{};
std::vector<Relocation> m_branch_to_module_relocations{}; std::vector<Relocation> m_branch_to_module_relocations{};
std::vector<Relocation> m_write_module_pc_relocations{}; std::vector<Relocation> m_write_module_pc_relocations{};
std::vector<ModuleTextAddress> m_exclusives{}; std::vector<ModuleTextAddress> m_exclusives{};
};
oaknut::VectorCodeGenerator c;
oaknut::Label m_save_context{}; oaknut::Label m_save_context{};
oaknut::Label m_load_context{}; oaknut::Label m_load_context{};
PatchMode mode{PatchMode::None}; PatchMode mode{PatchMode::None};
size_t total_program_size{};
size_t m_relocate_module_index{};
std::vector<ModulePatch> modules;
ModulePatch* curr_patch;
}; };
} // namespace Core::NCE } // namespace Core::NCE

View File

@ -114,7 +114,7 @@ public:
} }
Kernel::KThread* GetActiveThread() override { Kernel::KThread* GetActiveThread() override {
return state->active_thread.GetPointerUnsafe(); return state->active_thread;
} }
private: private:
@ -147,14 +147,11 @@ private:
std::scoped_lock lk{connection_lock}; std::scoped_lock lk{connection_lock};
// Find the process we are going to debug.
SetDebugProcess();
// Ensure everything is stopped. // Ensure everything is stopped.
PauseEmulation(); PauseEmulation();
// Set up the new frontend. // Set up the new frontend.
frontend = std::make_unique<GDBStub>(*this, system, debug_process.GetPointerUnsafe()); frontend = std::make_unique<GDBStub>(*this, system);
// Set the new state. This will tear down any existing state. // Set the new state. This will tear down any existing state.
state = ConnectionState{ state = ConnectionState{
@ -197,20 +194,15 @@ private:
UpdateActiveThread(); UpdateActiveThread();
if (state->info.type == SignalType::Watchpoint) { if (state->info.type == SignalType::Watchpoint) {
frontend->Watchpoint(std::addressof(*state->active_thread), frontend->Watchpoint(state->active_thread, *state->info.watchpoint);
*state->info.watchpoint);
} else { } else {
frontend->Stopped(std::addressof(*state->active_thread)); frontend->Stopped(state->active_thread);
} }
break; break;
case SignalType::ShuttingDown: case SignalType::ShuttingDown:
frontend->ShuttingDown(); frontend->ShuttingDown();
// Release members.
state->active_thread.Reset(nullptr);
debug_process.Reset(nullptr);
// Wait for emulation to shut down gracefully now. // Wait for emulation to shut down gracefully now.
state->signal_pipe.close(); state->signal_pipe.close();
state->client_socket.shutdown(boost::asio::socket_base::shutdown_both); state->client_socket.shutdown(boost::asio::socket_base::shutdown_both);
@ -230,7 +222,7 @@ private:
stopped = true; stopped = true;
PauseEmulation(); PauseEmulation();
UpdateActiveThread(); UpdateActiveThread();
frontend->Stopped(state->active_thread.GetPointerUnsafe()); frontend->Stopped(state->active_thread);
break; break;
} }
case DebuggerAction::Continue: case DebuggerAction::Continue:
@ -240,7 +232,7 @@ private:
MarkResumed([&] { MarkResumed([&] {
state->active_thread->SetStepState(Kernel::StepState::StepPending); state->active_thread->SetStepState(Kernel::StepState::StepPending);
state->active_thread->Resume(Kernel::SuspendType::Debug); state->active_thread->Resume(Kernel::SuspendType::Debug);
ResumeEmulation(state->active_thread.GetPointerUnsafe()); ResumeEmulation(state->active_thread);
}); });
break; break;
case DebuggerAction::StepThreadLocked: { case DebuggerAction::StepThreadLocked: {
@ -263,7 +255,6 @@ private:
} }
void PauseEmulation() { void PauseEmulation() {
Kernel::KScopedLightLock ll{debug_process->GetListLock()};
Kernel::KScopedSchedulerLock sl{system.Kernel()}; Kernel::KScopedSchedulerLock sl{system.Kernel()};
// Put all threads to sleep on next scheduler round. // Put all threads to sleep on next scheduler round.
@ -273,9 +264,6 @@ private:
} }
void ResumeEmulation(Kernel::KThread* except = nullptr) { void ResumeEmulation(Kernel::KThread* except = nullptr) {
Kernel::KScopedLightLock ll{debug_process->GetListLock()};
Kernel::KScopedSchedulerLock sl{system.Kernel()};
// Wake up all threads. // Wake up all threads.
for (auto& thread : ThreadList()) { for (auto& thread : ThreadList()) {
if (std::addressof(thread) == except) { if (std::addressof(thread) == except) {
@ -289,16 +277,15 @@ private:
template <typename Callback> template <typename Callback>
void MarkResumed(Callback&& cb) { void MarkResumed(Callback&& cb) {
Kernel::KScopedSchedulerLock sl{system.Kernel()};
stopped = false; stopped = false;
cb(); cb();
} }
void UpdateActiveThread() { void UpdateActiveThread() {
Kernel::KScopedLightLock ll{debug_process->GetListLock()};
auto& threads{ThreadList()}; auto& threads{ThreadList()};
for (auto& thread : threads) { for (auto& thread : threads) {
if (std::addressof(thread) == state->active_thread.GetPointerUnsafe()) { if (std::addressof(thread) == state->active_thread) {
// Thread is still alive, no need to update. // Thread is still alive, no need to update.
return; return;
} }
@ -306,18 +293,12 @@ private:
state->active_thread = std::addressof(threads.front()); state->active_thread = std::addressof(threads.front());
} }
private:
void SetDebugProcess() {
debug_process = std::move(system.Kernel().GetProcessList().back());
}
Kernel::KProcess::ThreadList& ThreadList() { Kernel::KProcess::ThreadList& ThreadList() {
return debug_process->GetThreadList(); return system.ApplicationProcess()->GetThreadList();
} }
private: private:
System& system; System& system;
Kernel::KScopedAutoObject<Kernel::KProcess> debug_process;
std::unique_ptr<DebuggerFrontend> frontend; std::unique_ptr<DebuggerFrontend> frontend;
boost::asio::io_context io_context; boost::asio::io_context io_context;
@ -329,7 +310,7 @@ private:
boost::process::async_pipe signal_pipe; boost::process::async_pipe signal_pipe;
SignalInfo info; SignalInfo info;
Kernel::KScopedAutoObject<Kernel::KThread> active_thread; Kernel::KThread* active_thread;
std::array<u8, 4096> client_data; std::array<u8, 4096> client_data;
bool pipe_data; bool pipe_data;
}; };

View File

@ -108,9 +108,9 @@ static std::string EscapeXML(std::string_view data) {
return escaped; return escaped;
} }
GDBStub::GDBStub(DebuggerBackend& backend_, Core::System& system_, Kernel::KProcess* debug_process_) GDBStub::GDBStub(DebuggerBackend& backend_, Core::System& system_)
: DebuggerFrontend(backend_), system{system_}, debug_process{debug_process_} { : DebuggerFrontend(backend_), system{system_} {
if (GetProcess()->Is64Bit()) { if (system.ApplicationProcess()->Is64Bit()) {
arch = std::make_unique<GDBStubA64>(); arch = std::make_unique<GDBStubA64>();
} else { } else {
arch = std::make_unique<GDBStubA32>(); arch = std::make_unique<GDBStubA32>();
@ -276,7 +276,7 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction
const size_t size{static_cast<size_t>(strtoll(command.data() + sep, nullptr, 16))}; const size_t size{static_cast<size_t>(strtoll(command.data() + sep, nullptr, 16))};
std::vector<u8> mem(size); std::vector<u8> mem(size);
if (GetMemory().ReadBlock(addr, mem.data(), size)) { if (system.ApplicationMemory().ReadBlock(addr, mem.data(), size)) {
// Restore any bytes belonging to replaced instructions. // Restore any bytes belonging to replaced instructions.
auto it = replaced_instructions.lower_bound(addr); auto it = replaced_instructions.lower_bound(addr);
for (; it != replaced_instructions.end() && it->first < addr + size; it++) { for (; it != replaced_instructions.end() && it->first < addr + size; it++) {
@ -310,8 +310,8 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction
const auto mem_substr{std::string_view(command).substr(mem_sep)}; const auto mem_substr{std::string_view(command).substr(mem_sep)};
const auto mem{Common::HexStringToVector(mem_substr, false)}; const auto mem{Common::HexStringToVector(mem_substr, false)};
if (GetMemory().WriteBlock(addr, mem.data(), size)) { if (system.ApplicationMemory().WriteBlock(addr, mem.data(), size)) {
Core::InvalidateInstructionCacheRange(GetProcess(), addr, size); Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, size);
SendReply(GDB_STUB_REPLY_OK); SendReply(GDB_STUB_REPLY_OK);
} else { } else {
SendReply(GDB_STUB_REPLY_ERR); SendReply(GDB_STUB_REPLY_ERR);
@ -353,7 +353,7 @@ void GDBStub::HandleBreakpointInsert(std::string_view command) {
const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))}; const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))};
const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))}; const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))};
if (!GetMemory().IsValidVirtualAddressRange(addr, size)) { if (!system.ApplicationMemory().IsValidVirtualAddressRange(addr, size)) {
SendReply(GDB_STUB_REPLY_ERR); SendReply(GDB_STUB_REPLY_ERR);
return; return;
} }
@ -362,20 +362,22 @@ void GDBStub::HandleBreakpointInsert(std::string_view command) {
switch (type) { switch (type) {
case BreakpointType::Software: case BreakpointType::Software:
replaced_instructions[addr] = GetMemory().Read32(addr); replaced_instructions[addr] = system.ApplicationMemory().Read32(addr);
GetMemory().Write32(addr, arch->BreakpointInstruction()); system.ApplicationMemory().Write32(addr, arch->BreakpointInstruction());
Core::InvalidateInstructionCacheRange(GetProcess(), addr, sizeof(u32)); Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, sizeof(u32));
success = true; success = true;
break; break;
case BreakpointType::WriteWatch: case BreakpointType::WriteWatch:
success = GetProcess()->InsertWatchpoint(addr, size, Kernel::DebugWatchpointType::Write); success = system.ApplicationProcess()->InsertWatchpoint(addr, size,
Kernel::DebugWatchpointType::Write);
break; break;
case BreakpointType::ReadWatch: case BreakpointType::ReadWatch:
success = GetProcess()->InsertWatchpoint(addr, size, Kernel::DebugWatchpointType::Read); success = system.ApplicationProcess()->InsertWatchpoint(addr, size,
Kernel::DebugWatchpointType::Read);
break; break;
case BreakpointType::AccessWatch: case BreakpointType::AccessWatch:
success = success = system.ApplicationProcess()->InsertWatchpoint(
GetProcess()->InsertWatchpoint(addr, size, Kernel::DebugWatchpointType::ReadOrWrite); addr, size, Kernel::DebugWatchpointType::ReadOrWrite);
break; break;
case BreakpointType::Hardware: case BreakpointType::Hardware:
default: default:
@ -398,7 +400,7 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) {
const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))}; const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))};
const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))}; const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))};
if (!GetMemory().IsValidVirtualAddressRange(addr, size)) { if (!system.ApplicationMemory().IsValidVirtualAddressRange(addr, size)) {
SendReply(GDB_STUB_REPLY_ERR); SendReply(GDB_STUB_REPLY_ERR);
return; return;
} }
@ -409,22 +411,24 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) {
case BreakpointType::Software: { case BreakpointType::Software: {
const auto orig_insn{replaced_instructions.find(addr)}; const auto orig_insn{replaced_instructions.find(addr)};
if (orig_insn != replaced_instructions.end()) { if (orig_insn != replaced_instructions.end()) {
GetMemory().Write32(addr, orig_insn->second); system.ApplicationMemory().Write32(addr, orig_insn->second);
Core::InvalidateInstructionCacheRange(GetProcess(), addr, sizeof(u32)); Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, sizeof(u32));
replaced_instructions.erase(addr); replaced_instructions.erase(addr);
success = true; success = true;
} }
break; break;
} }
case BreakpointType::WriteWatch: case BreakpointType::WriteWatch:
success = GetProcess()->RemoveWatchpoint(addr, size, Kernel::DebugWatchpointType::Write); success = system.ApplicationProcess()->RemoveWatchpoint(addr, size,
Kernel::DebugWatchpointType::Write);
break; break;
case BreakpointType::ReadWatch: case BreakpointType::ReadWatch:
success = GetProcess()->RemoveWatchpoint(addr, size, Kernel::DebugWatchpointType::Read); success = system.ApplicationProcess()->RemoveWatchpoint(addr, size,
Kernel::DebugWatchpointType::Read);
break; break;
case BreakpointType::AccessWatch: case BreakpointType::AccessWatch:
success = success = system.ApplicationProcess()->RemoveWatchpoint(
GetProcess()->RemoveWatchpoint(addr, size, Kernel::DebugWatchpointType::ReadOrWrite); addr, size, Kernel::DebugWatchpointType::ReadOrWrite);
break; break;
case BreakpointType::Hardware: case BreakpointType::Hardware:
default: default:
@ -462,10 +466,10 @@ void GDBStub::HandleQuery(std::string_view command) {
const auto target_xml{arch->GetTargetXML()}; const auto target_xml{arch->GetTargetXML()};
SendReply(PaginateBuffer(target_xml, command.substr(30))); SendReply(PaginateBuffer(target_xml, command.substr(30)));
} else if (command.starts_with("Offsets")) { } else if (command.starts_with("Offsets")) {
const auto main_offset = Core::FindMainModuleEntrypoint(GetProcess()); const auto main_offset = Core::FindMainModuleEntrypoint(system.ApplicationProcess());
SendReply(fmt::format("TextSeg={:x}", GetInteger(main_offset))); SendReply(fmt::format("TextSeg={:x}", GetInteger(main_offset)));
} else if (command.starts_with("Xfer:libraries:read::")) { } else if (command.starts_with("Xfer:libraries:read::")) {
auto modules = Core::FindModules(GetProcess()); auto modules = Core::FindModules(system.ApplicationProcess());
std::string buffer; std::string buffer;
buffer += R"(<?xml version="1.0"?>)"; buffer += R"(<?xml version="1.0"?>)";
@ -479,7 +483,7 @@ void GDBStub::HandleQuery(std::string_view command) {
SendReply(PaginateBuffer(buffer, command.substr(21))); SendReply(PaginateBuffer(buffer, command.substr(21)));
} else if (command.starts_with("fThreadInfo")) { } else if (command.starts_with("fThreadInfo")) {
// beginning of list // beginning of list
const auto& threads = GetProcess()->GetThreadList(); const auto& threads = system.ApplicationProcess()->GetThreadList();
std::vector<std::string> thread_ids; std::vector<std::string> thread_ids;
for (const auto& thread : threads) { for (const auto& thread : threads) {
thread_ids.push_back(fmt::format("{:x}", thread.GetThreadId())); thread_ids.push_back(fmt::format("{:x}", thread.GetThreadId()));
@ -493,7 +497,7 @@ void GDBStub::HandleQuery(std::string_view command) {
buffer += R"(<?xml version="1.0"?>)"; buffer += R"(<?xml version="1.0"?>)";
buffer += "<threads>"; buffer += "<threads>";
const auto& threads = GetProcess()->GetThreadList(); const auto& threads = system.ApplicationProcess()->GetThreadList();
for (const auto& thread : threads) { for (const auto& thread : threads) {
auto thread_name{Core::GetThreadName(&thread)}; auto thread_name{Core::GetThreadName(&thread)};
if (!thread_name) { if (!thread_name) {
@ -609,7 +613,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
std::string_view command_str{reinterpret_cast<const char*>(&command[0]), command.size()}; std::string_view command_str{reinterpret_cast<const char*>(&command[0]), command.size()};
std::string reply; std::string reply;
auto* process = GetProcess(); auto* process = system.ApplicationProcess();
auto& page_table = process->GetPageTable(); auto& page_table = process->GetPageTable();
const char* commands = "Commands:\n" const char* commands = "Commands:\n"
@ -710,7 +714,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
} }
Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) { Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) {
auto& threads{GetProcess()->GetThreadList()}; auto& threads{system.ApplicationProcess()->GetThreadList()};
for (auto& thread : threads) { for (auto& thread : threads) {
if (thread.GetThreadId() == thread_id) { if (thread.GetThreadId() == thread_id) {
return std::addressof(thread); return std::addressof(thread);
@ -779,12 +783,4 @@ void GDBStub::SendStatus(char status) {
backend.WriteToClient(buf); backend.WriteToClient(buf);
} }
Kernel::KProcess* GDBStub::GetProcess() {
return debug_process;
}
Core::Memory::Memory& GDBStub::GetMemory() {
return GetProcess()->GetMemory();
}
} // namespace Core } // namespace Core

View File

@ -12,22 +12,13 @@
#include "core/debugger/debugger_interface.h" #include "core/debugger/debugger_interface.h"
#include "core/debugger/gdbstub_arch.h" #include "core/debugger/gdbstub_arch.h"
namespace Kernel {
class KProcess;
}
namespace Core::Memory {
class Memory;
}
namespace Core { namespace Core {
class System; class System;
class GDBStub : public DebuggerFrontend { class GDBStub : public DebuggerFrontend {
public: public:
explicit GDBStub(DebuggerBackend& backend, Core::System& system, explicit GDBStub(DebuggerBackend& backend, Core::System& system);
Kernel::KProcess* debug_process);
~GDBStub() override; ~GDBStub() override;
void Connected() override; void Connected() override;
@ -51,12 +42,8 @@ private:
void SendReply(std::string_view data); void SendReply(std::string_view data);
void SendStatus(char status); void SendStatus(char status);
Kernel::KProcess* GetProcess();
Core::Memory::Memory& GetMemory();
private: private:
Core::System& system; Core::System& system;
Kernel::KProcess* debug_process;
std::unique_ptr<GDBStubArch> arch; std::unique_ptr<GDBStubArch> arch;
std::vector<char> current_command; std::vector<char> current_command;
std::map<VAddr, u32> replaced_instructions; std::map<VAddr, u32> replaced_instructions;

View File

@ -28,14 +28,14 @@ Result KMemoryBlockManager::Initialize(KProcessAddress st, KProcessAddress nd,
} }
void KMemoryBlockManager::Finalize(KMemoryBlockSlabManager* slab_manager, void KMemoryBlockManager::Finalize(KMemoryBlockSlabManager* slab_manager,
BlockCallback&& block_callback) { HostUnmapCallback&& host_unmap_callback) {
// Erase every block until we have none left. // Erase every block until we have none left.
auto it = m_memory_block_tree.begin(); auto it = m_memory_block_tree.begin();
while (it != m_memory_block_tree.end()) { while (it != m_memory_block_tree.end()) {
KMemoryBlock* block = std::addressof(*it); KMemoryBlock* block = std::addressof(*it);
it = m_memory_block_tree.erase(it); it = m_memory_block_tree.erase(it);
block_callback(block->GetAddress(), block->GetSize());
slab_manager->Free(block); slab_manager->Free(block);
host_unmap_callback(block->GetAddress(), block->GetSize());
} }
ASSERT(m_memory_block_tree.empty()); ASSERT(m_memory_block_tree.empty());

View File

@ -85,11 +85,11 @@ public:
public: public:
KMemoryBlockManager(); KMemoryBlockManager();
using BlockCallback = std::function<void(Common::ProcessAddress, u64)>; using HostUnmapCallback = std::function<void(Common::ProcessAddress, u64)>;
Result Initialize(KProcessAddress st, KProcessAddress nd, Result Initialize(KProcessAddress st, KProcessAddress nd,
KMemoryBlockSlabManager* slab_manager); KMemoryBlockSlabManager* slab_manager);
void Finalize(KMemoryBlockSlabManager* slab_manager, BlockCallback&& block_callback); void Finalize(KMemoryBlockSlabManager* slab_manager, HostUnmapCallback&& host_unmap_callback);
iterator end() { iterator end() {
return m_memory_block_tree.end(); return m_memory_block_tree.end();

View File

@ -431,43 +431,15 @@ Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool
m_memory_block_slab_manager)); m_memory_block_slab_manager));
} }
Result KPageTableBase::FinalizeProcess() {
// Only process tables should be finalized.
ASSERT(!this->IsKernel());
// NOTE: Here Nintendo calls an unknown OnFinalize function.
// this->OnFinalize();
// NOTE: Here Nintendo calls a second unknown OnFinalize function.
// this->OnFinalize2();
// NOTE: Here Nintendo does a page table walk to discover heap pages to free.
// We will use the block manager finalization below to free them.
R_SUCCEED();
}
void KPageTableBase::Finalize() { void KPageTableBase::Finalize() {
this->FinalizeProcess(); auto HostUnmapCallback = [&](KProcessAddress addr, u64 size) {
if (Settings::IsFastmemEnabled()) {
auto BlockCallback = [&](KProcessAddress addr, u64 size) {
if (m_impl->fastmem_arena) {
m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size, false); m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size, false);
} }
// Get physical pages.
KPageGroup pg(m_kernel, m_block_info_manager);
this->MakePageGroup(pg, addr, size / PageSize);
// Free the pages.
pg.CloseAndReset();
}; };
// Finalize memory blocks. // Finalize memory blocks.
{ m_memory_block_manager.Finalize(m_memory_block_slab_manager, std::move(HostUnmapCallback));
KScopedLightLock lk(m_general_lock);
m_memory_block_manager.Finalize(m_memory_block_slab_manager, std::move(BlockCallback));
}
// Free any unsafe mapped memory. // Free any unsafe mapped memory.
if (m_mapped_unsafe_physical_memory) { if (m_mapped_unsafe_physical_memory) {

View File

@ -241,7 +241,6 @@ public:
KResourceLimit* resource_limit, Core::Memory::Memory& memory, KResourceLimit* resource_limit, Core::Memory::Memory& memory,
KProcessAddress aslr_space_start); KProcessAddress aslr_space_start);
Result FinalizeProcess();
void Finalize(); void Finalize();
bool IsKernel() const { bool IsKernel() const {

View File

@ -172,12 +172,6 @@ void KProcess::Finalize() {
m_resource_limit->Close(); m_resource_limit->Close();
} }
// Clear expensive resources, as the destructor is not called for guest objects.
for (auto& interface : m_arm_interfaces) {
interface.reset();
}
m_exclusive_monitor.reset();
// Perform inherited finalization. // Perform inherited finalization.
KSynchronizationObject::Finalize(); KSynchronizationObject::Finalize();
} }
@ -1239,10 +1233,10 @@ void KProcess::LoadModule(CodeSet code_set, KProcessAddress base_addr) {
ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite); ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite);
#ifdef HAS_NCE #ifdef HAS_NCE
const auto& patch = code_set.PatchSegment(); if (this->IsApplication() && Settings::IsNceEnabled()) {
if (this->IsApplication() && Settings::IsNceEnabled() && patch.size != 0) {
auto& buffer = m_kernel.System().DeviceMemory().buffer; auto& buffer = m_kernel.System().DeviceMemory().buffer;
const auto& code = code_set.CodeSegment(); const auto& code = code_set.CodeSegment();
const auto& patch = code_set.PatchSegment();
buffer.Protect(GetInteger(base_addr + code.addr), code.size, buffer.Protect(GetInteger(base_addr + code.addr), code.size,
Common::MemoryPermission::Read | Common::MemoryPermission::Execute); Common::MemoryPermission::Read | Common::MemoryPermission::Execute);
buffer.Protect(GetInteger(base_addr + patch.addr), patch.size, buffer.Protect(GetInteger(base_addr + patch.addr), patch.size,

View File

@ -112,14 +112,7 @@ struct KernelCore::Impl {
old_process->Close(); old_process->Close();
} }
{
std::scoped_lock lk{process_list_lock};
for (auto* const process : process_list) {
process->Terminate();
process->Close();
}
process_list.clear(); process_list.clear();
}
next_object_id = 0; next_object_id = 0;
next_kernel_process_id = KProcess::InitialProcessIdMin; next_kernel_process_id = KProcess::InitialProcessIdMin;
@ -777,7 +770,6 @@ struct KernelCore::Impl {
std::atomic<u64> next_thread_id{1}; std::atomic<u64> next_thread_id{1};
// Lists all processes that exist in the current session. // Lists all processes that exist in the current session.
std::mutex process_list_lock;
std::vector<KProcess*> process_list; std::vector<KProcess*> process_list;
std::atomic<KProcess*> application_process{}; std::atomic<KProcess*> application_process{};
std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context;
@ -877,19 +869,9 @@ KResourceLimit* KernelCore::GetSystemResourceLimit() {
} }
void KernelCore::AppendNewProcess(KProcess* process) { void KernelCore::AppendNewProcess(KProcess* process) {
process->Open();
std::scoped_lock lk{impl->process_list_lock};
impl->process_list.push_back(process); impl->process_list.push_back(process);
} }
void KernelCore::RemoveProcess(KProcess* process) {
std::scoped_lock lk{impl->process_list_lock};
if (std::erase(impl->process_list, process)) {
process->Close();
}
}
void KernelCore::MakeApplicationProcess(KProcess* process) { void KernelCore::MakeApplicationProcess(KProcess* process) {
impl->MakeApplicationProcess(process); impl->MakeApplicationProcess(process);
} }
@ -902,15 +884,8 @@ const KProcess* KernelCore::ApplicationProcess() const {
return impl->application_process; return impl->application_process;
} }
std::list<KScopedAutoObject<KProcess>> KernelCore::GetProcessList() { const std::vector<KProcess*>& KernelCore::GetProcessList() const {
std::list<KScopedAutoObject<KProcess>> processes; return impl->process_list;
std::scoped_lock lk{impl->process_list_lock};
for (auto* const process : impl->process_list) {
processes.emplace_back(process);
}
return processes;
} }
Kernel::GlobalSchedulerContext& KernelCore::GlobalSchedulerContext() { Kernel::GlobalSchedulerContext& KernelCore::GlobalSchedulerContext() {

View File

@ -5,7 +5,6 @@
#include <array> #include <array>
#include <functional> #include <functional>
#include <list>
#include <memory> #include <memory>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
@ -117,9 +116,8 @@ public:
/// Retrieves a shared pointer to the system resource limit instance. /// Retrieves a shared pointer to the system resource limit instance.
KResourceLimit* GetSystemResourceLimit(); KResourceLimit* GetSystemResourceLimit();
/// Adds/removes the given pointer to an internal list of active processes. /// Adds the given shared pointer to an internal list of active processes.
void AppendNewProcess(KProcess* process); void AppendNewProcess(KProcess* process);
void RemoveProcess(KProcess* process);
/// Makes the given process the new application process. /// Makes the given process the new application process.
void MakeApplicationProcess(KProcess* process); void MakeApplicationProcess(KProcess* process);
@ -131,7 +129,7 @@ public:
const KProcess* ApplicationProcess() const; const KProcess* ApplicationProcess() const;
/// Retrieves the list of processes. /// Retrieves the list of processes.
std::list<KScopedAutoObject<KProcess>> GetProcessList(); const std::vector<KProcess*>& GetProcessList() const;
/// Gets the sole instance of the global scheduler /// Gets the sole instance of the global scheduler
Kernel::GlobalSchedulerContext& GlobalSchedulerContext(); Kernel::GlobalSchedulerContext& GlobalSchedulerContext();

View File

@ -74,15 +74,13 @@ Result GetProcessList(Core::System& system, s32* out_num_processes, u64 out_proc
} }
auto& memory = GetCurrentMemory(kernel); auto& memory = GetCurrentMemory(kernel);
auto process_list = kernel.GetProcessList(); const auto& process_list = kernel.GetProcessList();
auto it = process_list.begin();
const auto num_processes = process_list.size(); const auto num_processes = process_list.size();
const auto copy_amount = const auto copy_amount =
std::min(static_cast<std::size_t>(out_process_ids_size), num_processes); std::min(static_cast<std::size_t>(out_process_ids_size), num_processes);
for (std::size_t i = 0; i < copy_amount && it != process_list.end(); ++i, ++it) { for (std::size_t i = 0; i < copy_amount; ++i) {
memory.Write64(out_process_ids, (*it)->GetProcessId()); memory.Write64(out_process_ids, process_list[i]->GetProcessId());
out_process_ids += sizeof(u64); out_process_ids += sizeof(u64);
} }

View File

@ -61,7 +61,9 @@ ProfileManager::ProfileManager() {
OpenUser(*GetUser(current)); OpenUser(*GetUser(current));
} }
ProfileManager::~ProfileManager() = default; ProfileManager::~ProfileManager() {
WriteUserSaveFile();
}
/// After a users creation it needs to be "registered" to the system. AddToProfiles handles the /// After a users creation it needs to be "registered" to the system. AddToProfiles handles the
/// internal management of the users profiles /// internal management of the users profiles
@ -111,8 +113,6 @@ Result ProfileManager::CreateNewUser(UUID uuid, const ProfileUsername& username)
return ERROR_USER_ALREADY_EXISTS; return ERROR_USER_ALREADY_EXISTS;
} }
is_save_needed = true;
return AddUser({ return AddUser({
.user_uuid = uuid, .user_uuid = uuid,
.username = username, .username = username,
@ -326,9 +326,6 @@ bool ProfileManager::RemoveUser(UUID uuid) {
profiles[*index] = ProfileInfo{}; profiles[*index] = ProfileInfo{};
std::stable_partition(profiles.begin(), profiles.end(), std::stable_partition(profiles.begin(), profiles.end(),
[](const ProfileInfo& profile) { return profile.user_uuid.IsValid(); }); [](const ProfileInfo& profile) { return profile.user_uuid.IsValid(); });
is_save_needed = true;
return true; return true;
} }
@ -343,8 +340,6 @@ bool ProfileManager::SetProfileBase(UUID uuid, const ProfileBase& profile_new) {
profile.username = profile_new.username; profile.username = profile_new.username;
profile.creation_time = profile_new.timestamp; profile.creation_time = profile_new.timestamp;
is_save_needed = true;
return true; return true;
} }
@ -353,7 +348,6 @@ bool ProfileManager::SetProfileBaseAndData(Common::UUID uuid, const ProfileBase&
const auto index = GetUserIndex(uuid); const auto index = GetUserIndex(uuid);
if (index.has_value() && SetProfileBase(uuid, profile_new)) { if (index.has_value() && SetProfileBase(uuid, profile_new)) {
profiles[*index].data = data_new; profiles[*index].data = data_new;
is_save_needed = true;
return true; return true;
} }
@ -397,10 +391,6 @@ void ProfileManager::ParseUserSaveFile() {
} }
void ProfileManager::WriteUserSaveFile() { void ProfileManager::WriteUserSaveFile() {
if (!is_save_needed) {
return;
}
ProfileDataRaw raw{}; ProfileDataRaw raw{};
for (std::size_t i = 0; i < MAX_USERS; ++i) { for (std::size_t i = 0; i < MAX_USERS; ++i) {
@ -433,10 +423,7 @@ void ProfileManager::WriteUserSaveFile() {
if (!save.IsOpen() || !save.SetSize(sizeof(ProfileDataRaw)) || !save.WriteObject(raw)) { if (!save.IsOpen() || !save.SetSize(sizeof(ProfileDataRaw)) || !save.WriteObject(raw)) {
LOG_WARNING(Service_ACC, "Failed to write save data to file... No changes to user data " LOG_WARNING(Service_ACC, "Failed to write save data to file... No changes to user data "
"made in current session will be saved."); "made in current session will be saved.");
return;
} }
is_save_needed = false;
} }
}; // namespace Service::Account }; // namespace Service::Account

View File

@ -103,7 +103,6 @@ private:
std::optional<std::size_t> AddToProfiles(const ProfileInfo& profile); std::optional<std::size_t> AddToProfiles(const ProfileInfo& profile);
bool RemoveProfileAtIndex(std::size_t index); bool RemoveProfileAtIndex(std::size_t index);
bool is_save_needed{};
std::array<ProfileInfo, MAX_USERS> profiles{}; std::array<ProfileInfo, MAX_USERS> profiles{};
std::array<ProfileInfo, MAX_USERS> stored_opened_profiles{}; std::array<ProfileInfo, MAX_USERS> stored_opened_profiles{};
std::size_t user_count{}; std::size_t user_count{};

View File

@ -18,11 +18,11 @@ using namespace AudioCore::AudioIn;
class IAudioIn final : public ServiceFramework<IAudioIn> { class IAudioIn final : public ServiceFramework<IAudioIn> {
public: public:
explicit IAudioIn(Core::System& system_, Manager& manager, size_t session_id, explicit IAudioIn(Core::System& system_, Manager& manager, size_t session_id,
const std::string& device_name, const AudioInParameter& in_params, const std::string& device_name, const AudioInParameter& in_params, u32 handle,
Kernel::KProcess* handle, u64 applet_resource_user_id) u64 applet_resource_user_id)
: ServiceFramework{system_, "IAudioIn"}, : ServiceFramework{system_, "IAudioIn"},
service_context{system_, "IAudioIn"}, event{service_context.CreateEvent("AudioInEvent")}, service_context{system_, "IAudioIn"}, event{service_context.CreateEvent("AudioInEvent")},
process{handle}, impl{std::make_shared<In>(system_, manager, event, session_id)} { impl{std::make_shared<In>(system_, manager, event, session_id)} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &IAudioIn::GetAudioInState, "GetAudioInState"}, {0, &IAudioIn::GetAudioInState, "GetAudioInState"},
@ -45,8 +45,6 @@ public:
RegisterHandlers(functions); RegisterHandlers(functions);
process->Open();
if (impl->GetSystem() if (impl->GetSystem()
.Initialize(device_name, in_params, handle, applet_resource_user_id) .Initialize(device_name, in_params, handle, applet_resource_user_id)
.IsError()) { .IsError()) {
@ -57,7 +55,6 @@ public:
~IAudioIn() override { ~IAudioIn() override {
impl->Free(); impl->Free();
service_context.CloseEvent(event); service_context.CloseEvent(event);
process->Close();
} }
[[nodiscard]] std::shared_ptr<In> GetImpl() { [[nodiscard]] std::shared_ptr<In> GetImpl() {
@ -199,7 +196,6 @@ private:
KernelHelpers::ServiceContext service_context; KernelHelpers::ServiceContext service_context;
Kernel::KEvent* event; Kernel::KEvent* event;
Kernel::KProcess* process;
std::shared_ptr<AudioCore::AudioIn::In> impl; std::shared_ptr<AudioCore::AudioIn::In> impl;
Common::ScratchBuffer<u64> released_buffer; Common::ScratchBuffer<u64> released_buffer;
}; };
@ -271,14 +267,6 @@ void AudInU::OpenAudioIn(HLERequestContext& ctx) {
auto device_name = Common::StringFromBuffer(device_name_data); auto device_name = Common::StringFromBuffer(device_name_data);
auto handle{ctx.GetCopyHandle(0)}; auto handle{ctx.GetCopyHandle(0)};
auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)};
if (process.IsNull()) {
LOG_ERROR(Service_Audio, "Failed to get process handle");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
}
std::scoped_lock l{impl->mutex}; std::scoped_lock l{impl->mutex};
auto link{impl->LinkToManager()}; auto link{impl->LinkToManager()};
if (link.IsError()) { if (link.IsError()) {
@ -299,9 +287,8 @@ void AudInU::OpenAudioIn(HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id, LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id,
impl->num_free_sessions); impl->num_free_sessions);
auto audio_in = auto audio_in = std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name,
std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params, in_params, handle, applet_resource_user_id);
process.GetPointerUnsafe(), applet_resource_user_id);
impl->sessions[new_session_id] = audio_in->GetImpl(); impl->sessions[new_session_id] = audio_in->GetImpl();
impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id; impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id;
@ -331,14 +318,6 @@ void AudInU::OpenAudioInProtocolSpecified(HLERequestContext& ctx) {
auto device_name = Common::StringFromBuffer(device_name_data); auto device_name = Common::StringFromBuffer(device_name_data);
auto handle{ctx.GetCopyHandle(0)}; auto handle{ctx.GetCopyHandle(0)};
auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)};
if (process.IsNull()) {
LOG_ERROR(Service_Audio, "Failed to get process handle");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
}
std::scoped_lock l{impl->mutex}; std::scoped_lock l{impl->mutex};
auto link{impl->LinkToManager()}; auto link{impl->LinkToManager()};
if (link.IsError()) { if (link.IsError()) {
@ -359,9 +338,8 @@ void AudInU::OpenAudioInProtocolSpecified(HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id, LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id,
impl->num_free_sessions); impl->num_free_sessions);
auto audio_in = auto audio_in = std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name,
std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params, in_params, handle, applet_resource_user_id);
process.GetPointerUnsafe(), applet_resource_user_id);
impl->sessions[new_session_id] = audio_in->GetImpl(); impl->sessions[new_session_id] = audio_in->GetImpl();
impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id; impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id;

View File

@ -26,10 +26,9 @@ class IAudioOut final : public ServiceFramework<IAudioOut> {
public: public:
explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager, explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager,
size_t session_id, const std::string& device_name, size_t session_id, const std::string& device_name,
const AudioOutParameter& in_params, Kernel::KProcess* handle, const AudioOutParameter& in_params, u32 handle, u64 applet_resource_user_id)
u64 applet_resource_user_id)
: ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"}, : ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"},
event{service_context.CreateEvent("AudioOutEvent")}, process{handle}, event{service_context.CreateEvent("AudioOutEvent")},
impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} { impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} {
// clang-format off // clang-format off
@ -51,14 +50,11 @@ public:
}; };
// clang-format on // clang-format on
RegisterHandlers(functions); RegisterHandlers(functions);
process->Open();
} }
~IAudioOut() override { ~IAudioOut() override {
impl->Free(); impl->Free();
service_context.CloseEvent(event); service_context.CloseEvent(event);
process->Close();
} }
[[nodiscard]] std::shared_ptr<AudioCore::AudioOut::Out> GetImpl() { [[nodiscard]] std::shared_ptr<AudioCore::AudioOut::Out> GetImpl() {
@ -210,7 +206,6 @@ private:
KernelHelpers::ServiceContext service_context; KernelHelpers::ServiceContext service_context;
Kernel::KEvent* event; Kernel::KEvent* event;
Kernel::KProcess* process;
std::shared_ptr<AudioCore::AudioOut::Out> impl; std::shared_ptr<AudioCore::AudioOut::Out> impl;
Common::ScratchBuffer<u64> released_buffer; Common::ScratchBuffer<u64> released_buffer;
}; };
@ -262,14 +257,6 @@ void AudOutU::OpenAudioOut(HLERequestContext& ctx) {
auto device_name = Common::StringFromBuffer(device_name_data); auto device_name = Common::StringFromBuffer(device_name_data);
auto handle{ctx.GetCopyHandle(0)}; auto handle{ctx.GetCopyHandle(0)};
auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)};
if (process.IsNull()) {
LOG_ERROR(Service_Audio, "Failed to get process handle");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
}
auto link{impl->LinkToManager()}; auto link{impl->LinkToManager()};
if (link.IsError()) { if (link.IsError()) {
LOG_ERROR(Service_Audio, "Failed to link Audio Out to Audio Manager"); LOG_ERROR(Service_Audio, "Failed to link Audio Out to Audio Manager");
@ -289,11 +276,10 @@ void AudOutU::OpenAudioOut(HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id, LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id,
impl->num_free_sessions); impl->num_free_sessions);
auto audio_out = auto audio_out = std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name,
std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name, in_params, in_params, handle, applet_resource_user_id);
process.GetPointerUnsafe(), applet_resource_user_id); result = audio_out->GetImpl()->GetSystem().Initialize(device_name, in_params, handle,
result = audio_out->GetImpl()->GetSystem().Initialize( applet_resource_user_id);
device_name, in_params, process.GetPointerUnsafe(), applet_resource_user_id);
if (result.IsError()) { if (result.IsError()) {
LOG_ERROR(Service_Audio, "Failed to initialize the AudioOut System!"); LOG_ERROR(Service_Audio, "Failed to initialize the AudioOut System!");
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};

View File

@ -15,10 +15,9 @@
namespace Service::Glue { namespace Service::Glue {
namespace { namespace {
std::optional<u64> GetTitleIDForProcessID(Core::System& system, u64 process_id) { std::optional<u64> GetTitleIDForProcessID(const Core::System& system, u64 process_id) {
auto list = system.Kernel().GetProcessList(); const auto& list = system.Kernel().GetProcessList();
const auto iter = std::find_if(list.begin(), list.end(), [&process_id](const auto& process) {
const auto iter = std::find_if(list.begin(), list.end(), [&process_id](auto& process) {
return process->GetProcessId() == process_id; return process->GetProcessId() == process_id;
}); });

View File

@ -22,10 +22,12 @@ void LoopProcess(Core::System& system) {
std::shared_ptr<HidFirmwareSettings> firmware_settings = std::shared_ptr<HidFirmwareSettings> firmware_settings =
std::make_shared<HidFirmwareSettings>(); std::make_shared<HidFirmwareSettings>();
// TODO: Remove this hack when am is emulated properly. // TODO: Remove this hack until this service is emulated properly.
const auto process_list = system.Kernel().GetProcessList();
if (!process_list.empty()) {
resource_manager->Initialize(); resource_manager->Initialize();
resource_manager->RegisterAppletResourceUserId(system.ApplicationProcess()->GetProcessId(), resource_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), true);
true); }
server_manager->RegisterNamedService( server_manager->RegisterNamedService(
"hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings)); "hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings));

View File

@ -22,26 +22,27 @@ constexpr Result ResultProcessNotFound{ErrorModule::PM, 1};
constexpr u64 NO_PROCESS_FOUND_PID{0}; constexpr u64 NO_PROCESS_FOUND_PID{0};
using ProcessList = std::list<Kernel::KScopedAutoObject<Kernel::KProcess>>; std::optional<Kernel::KProcess*> SearchProcessList(
const std::vector<Kernel::KProcess*>& process_list,
template <typename F> std::function<bool(Kernel::KProcess*)> predicate) {
Kernel::KScopedAutoObject<Kernel::KProcess> SearchProcessList(ProcessList& process_list,
F&& predicate) {
const auto iter = std::find_if(process_list.begin(), process_list.end(), predicate); const auto iter = std::find_if(process_list.begin(), process_list.end(), predicate);
if (iter == process_list.end()) { if (iter == process_list.end()) {
return nullptr; return std::nullopt;
} }
return iter->GetPointerUnsafe(); return *iter;
} }
void GetApplicationPidGeneric(HLERequestContext& ctx, ProcessList& process_list) { void GetApplicationPidGeneric(HLERequestContext& ctx,
auto process = SearchProcessList(process_list, [](auto& p) { return p->IsApplication(); }); const std::vector<Kernel::KProcess*>& process_list) {
const auto process = SearchProcessList(process_list, [](const auto& proc) {
return proc->GetProcessId() == Kernel::KProcess::ProcessIdMin;
});
IPC::ResponseBuilder rb{ctx, 4}; IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
rb.Push(process.IsNull() ? NO_PROCESS_FOUND_PID : process->GetProcessId()); rb.Push(process.has_value() ? (*process)->GetProcessId() : NO_PROCESS_FOUND_PID);
} }
} // Anonymous namespace } // Anonymous namespace
@ -79,7 +80,8 @@ private:
class DebugMonitor final : public ServiceFramework<DebugMonitor> { class DebugMonitor final : public ServiceFramework<DebugMonitor> {
public: public:
explicit DebugMonitor(Core::System& system_) : ServiceFramework{system_, "pm:dmnt"} { explicit DebugMonitor(Core::System& system_)
: ServiceFramework{system_, "pm:dmnt"}, kernel{system_.Kernel()} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, nullptr, "GetJitDebugProcessIdList"}, {0, nullptr, "GetJitDebugProcessIdList"},
@ -104,11 +106,12 @@ private:
LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id);
auto list = kernel.GetProcessList(); const auto process =
auto process = SearchProcessList( SearchProcessList(kernel.GetProcessList(), [program_id](const auto& proc) {
list, [program_id](auto& p) { return p->GetProgramId() == program_id; }); return proc->GetProgramId() == program_id;
});
if (process.IsNull()) { if (!process.has_value()) {
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultProcessNotFound); rb.Push(ResultProcessNotFound);
return; return;
@ -116,13 +119,12 @@ private:
IPC::ResponseBuilder rb{ctx, 4}; IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
rb.Push(process->GetProcessId()); rb.Push((*process)->GetProcessId());
} }
void GetApplicationProcessId(HLERequestContext& ctx) { void GetApplicationProcessId(HLERequestContext& ctx) {
LOG_DEBUG(Service_PM, "called"); LOG_DEBUG(Service_PM, "called");
auto list = kernel.GetProcessList(); GetApplicationPidGeneric(ctx, kernel.GetProcessList());
GetApplicationPidGeneric(ctx, list);
} }
void AtmosphereGetProcessInfo(HLERequestContext& ctx) { void AtmosphereGetProcessInfo(HLERequestContext& ctx) {
@ -133,10 +135,11 @@ private:
LOG_WARNING(Service_PM, "(Partial Implementation) called, pid={:016X}", pid); LOG_WARNING(Service_PM, "(Partial Implementation) called, pid={:016X}", pid);
auto list = kernel.GetProcessList(); const auto process = SearchProcessList(kernel.GetProcessList(), [pid](const auto& proc) {
auto process = SearchProcessList(list, [pid](auto& p) { return p->GetProcessId() == pid; }); return proc->GetProcessId() == pid;
});
if (process.IsNull()) { if (!process.has_value()) {
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultProcessNotFound); rb.Push(ResultProcessNotFound);
return; return;
@ -156,7 +159,7 @@ private:
OverrideStatus override_status{}; OverrideStatus override_status{};
ProgramLocation program_location{ ProgramLocation program_location{
.program_id = process->GetProgramId(), .program_id = (*process)->GetProgramId(),
.storage_id = 0, .storage_id = 0,
}; };
@ -166,11 +169,14 @@ private:
rb.PushRaw(program_location); rb.PushRaw(program_location);
rb.PushRaw(override_status); rb.PushRaw(override_status);
} }
const Kernel::KernelCore& kernel;
}; };
class Info final : public ServiceFramework<Info> { class Info final : public ServiceFramework<Info> {
public: public:
explicit Info(Core::System& system_) : ServiceFramework{system_, "pm:info"} { explicit Info(Core::System& system_, const std::vector<Kernel::KProcess*>& process_list_)
: ServiceFramework{system_, "pm:info"}, process_list{process_list_} {
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &Info::GetProgramId, "GetProgramId"}, {0, &Info::GetProgramId, "GetProgramId"},
{65000, &Info::AtmosphereGetProcessId, "AtmosphereGetProcessId"}, {65000, &Info::AtmosphereGetProcessId, "AtmosphereGetProcessId"},
@ -187,11 +193,11 @@ private:
LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id); LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id);
auto list = kernel.GetProcessList(); const auto process = SearchProcessList(process_list, [process_id](const auto& proc) {
auto process = SearchProcessList( return proc->GetProcessId() == process_id;
list, [process_id](auto& p) { return p->GetProcessId() == process_id; }); });
if (process.IsNull()) { if (!process.has_value()) {
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultProcessNotFound); rb.Push(ResultProcessNotFound);
return; return;
@ -199,7 +205,7 @@ private:
IPC::ResponseBuilder rb{ctx, 4}; IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
rb.Push(process->GetProgramId()); rb.Push((*process)->GetProgramId());
} }
void AtmosphereGetProcessId(HLERequestContext& ctx) { void AtmosphereGetProcessId(HLERequestContext& ctx) {
@ -208,11 +214,11 @@ private:
LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id);
auto list = system.Kernel().GetProcessList(); const auto process = SearchProcessList(process_list, [program_id](const auto& proc) {
auto process = SearchProcessList( return proc->GetProgramId() == program_id;
list, [program_id](auto& p) { return p->GetProgramId() == program_id; }); });
if (process.IsNull()) { if (!process.has_value()) {
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultProcessNotFound); rb.Push(ResultProcessNotFound);
return; return;
@ -220,13 +226,16 @@ private:
IPC::ResponseBuilder rb{ctx, 4}; IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
rb.Push(process->GetProcessId()); rb.Push((*process)->GetProcessId());
} }
const std::vector<Kernel::KProcess*>& process_list;
}; };
class Shell final : public ServiceFramework<Shell> { class Shell final : public ServiceFramework<Shell> {
public: public:
explicit Shell(Core::System& system_) : ServiceFramework{system_, "pm:shell"} { explicit Shell(Core::System& system_)
: ServiceFramework{system_, "pm:shell"}, kernel{system_.Kernel()} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, nullptr, "LaunchProgram"}, {0, nullptr, "LaunchProgram"},
@ -248,9 +257,10 @@ public:
private: private:
void GetApplicationProcessIdForShell(HLERequestContext& ctx) { void GetApplicationProcessIdForShell(HLERequestContext& ctx) {
LOG_DEBUG(Service_PM, "called"); LOG_DEBUG(Service_PM, "called");
auto list = kernel.GetProcessList(); GetApplicationPidGeneric(ctx, kernel.GetProcessList());
GetApplicationPidGeneric(ctx, list);
} }
const Kernel::KernelCore& kernel;
}; };
void LoopProcess(Core::System& system) { void LoopProcess(Core::System& system) {
@ -258,7 +268,8 @@ void LoopProcess(Core::System& system) {
server_manager->RegisterNamedService("pm:bm", std::make_shared<BootMode>(system)); server_manager->RegisterNamedService("pm:bm", std::make_shared<BootMode>(system));
server_manager->RegisterNamedService("pm:dmnt", std::make_shared<DebugMonitor>(system)); server_manager->RegisterNamedService("pm:dmnt", std::make_shared<DebugMonitor>(system));
server_manager->RegisterNamedService("pm:info", std::make_shared<Info>(system)); server_manager->RegisterNamedService(
"pm:info", std::make_shared<Info>(system, system.Kernel().GetProcessList()));
server_manager->RegisterNamedService("pm:shell", std::make_shared<Shell>(system)); server_manager->RegisterNamedService("pm:shell", std::make_shared<Shell>(system));
ServerManager::RunServer(std::move(server_manager)); ServerManager::RunServer(std::move(server_manager));
} }

View File

@ -19,54 +19,8 @@
#include "core/arm/nce/patcher.h" #include "core/arm/nce/patcher.h"
#endif #endif
#ifndef HAS_NCE
namespace Core::NCE {
class Patcher {};
} // namespace Core::NCE
#endif
namespace Loader { namespace Loader {
struct PatchCollection {
explicit PatchCollection(bool is_application_) : is_application{is_application_} {
module_patcher_indices.fill(-1);
patchers.emplace_back();
}
std::vector<Core::NCE::Patcher>* GetPatchers() {
if (is_application && Settings::IsNceEnabled()) {
return &patchers;
}
return nullptr;
}
size_t GetTotalPatchSize() const {
size_t total_size{};
#ifdef HAS_NCE
for (auto& patcher : patchers) {
total_size += patcher.GetSectionSize();
}
#endif
return total_size;
}
void SaveIndex(size_t module) {
module_patcher_indices[module] = static_cast<s32>(patchers.size() - 1);
}
s32 GetIndex(size_t module) const {
return module_patcher_indices[module];
}
s32 GetLastIndex() const {
return static_cast<s32>(patchers.size()) - 1;
}
bool is_application;
std::vector<Core::NCE::Patcher> patchers;
std::array<s32, 13> module_patcher_indices{};
};
AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_, AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_,
bool override_update_) bool override_update_)
: AppLoader(std::move(file_)), override_update(override_update_), is_hbl(false) { : AppLoader(std::move(file_)), override_update(override_update_), is_hbl(false) {
@ -188,7 +142,18 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
std::size_t code_size{}; std::size_t code_size{};
// Define an nce patch context for each potential module. // Define an nce patch context for each potential module.
PatchCollection patch_ctx{is_application}; #ifdef HAS_NCE
std::array<Core::NCE::Patcher, 13> module_patchers;
#endif
const auto GetPatcher = [&](size_t i) -> Core::NCE::Patcher* {
#ifdef HAS_NCE
if (is_application && Settings::IsNceEnabled()) {
return &module_patchers[i];
}
#endif
return nullptr;
};
// Use the NSO module loader to figure out the code layout // Use the NSO module loader to figure out the code layout
for (size_t i = 0; i < static_modules.size(); i++) { for (size_t i = 0; i < static_modules.size(); i++) {
@ -199,14 +164,13 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
} }
const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; const bool should_pass_arguments = std::strcmp(module, "rtld") == 0;
const auto tentative_next_load_addr = AppLoader_NSO::LoadModule( const auto tentative_next_load_addr =
process, system, *module_file, code_size, should_pass_arguments, false, {}, AppLoader_NSO::LoadModule(process, system, *module_file, code_size,
patch_ctx.GetPatchers(), patch_ctx.GetLastIndex()); should_pass_arguments, false, {}, GetPatcher(i));
if (!tentative_next_load_addr) { if (!tentative_next_load_addr) {
return {ResultStatus::ErrorLoadingNSO, {}}; return {ResultStatus::ErrorLoadingNSO, {}};
} }
patch_ctx.SaveIndex(i);
code_size = *tentative_next_load_addr; code_size = *tentative_next_load_addr;
} }
@ -220,9 +184,6 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
return 0; return 0;
}(); }();
// Add patch size to the total module size
code_size += patch_ctx.GetTotalPatchSize();
// Setup the process code layout // Setup the process code layout
if (process.LoadFromMetadata(metadata, code_size, fastmem_base, is_hbl).IsError()) { if (process.LoadFromMetadata(metadata, code_size, fastmem_base, is_hbl).IsError()) {
return {ResultStatus::ErrorUnableToParseKernelMetadata, {}}; return {ResultStatus::ErrorUnableToParseKernelMetadata, {}};
@ -243,9 +204,9 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
const VAddr load_addr{next_load_addr}; const VAddr load_addr{next_load_addr};
const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; const bool should_pass_arguments = std::strcmp(module, "rtld") == 0;
const auto tentative_next_load_addr = AppLoader_NSO::LoadModule( const auto tentative_next_load_addr =
process, system, *module_file, load_addr, should_pass_arguments, true, pm, AppLoader_NSO::LoadModule(process, system, *module_file, load_addr,
patch_ctx.GetPatchers(), patch_ctx.GetIndex(i)); should_pass_arguments, true, pm, GetPatcher(i));
if (!tentative_next_load_addr) { if (!tentative_next_load_addr) {
return {ResultStatus::ErrorLoadingNSO, {}}; return {ResultStatus::ErrorLoadingNSO, {}};
} }

View File

@ -275,12 +275,12 @@ AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::KProcess& process, Core::S
return {ResultStatus::ErrorLoadingNRO, {}}; return {ResultStatus::ErrorLoadingNRO, {}};
} }
u64 program_id{}; if (romfs != nullptr) {
ReadProgramId(program_id);
system.GetFileSystemController().RegisterProcess( system.GetFileSystemController().RegisterProcess(
process.GetProcessId(), program_id, process.GetProcessId(), {},
std::make_unique<FileSys::RomFSFactory>(*this, system.GetContentProvider(), std::make_unique<FileSys::RomFSFactory>(*this, system.GetContentProvider(),
system.GetFileSystemController())); system.GetFileSystemController()));
}
is_loaded = true; is_loaded = true;
return {ResultStatus::Success, LoadParameters{Kernel::KThread::DefaultThreadPriority, return {ResultStatus::Success, LoadParameters{Kernel::KThread::DefaultThreadPriority,

View File

@ -77,8 +77,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::
const FileSys::VfsFile& nso_file, VAddr load_base, const FileSys::VfsFile& nso_file, VAddr load_base,
bool should_pass_arguments, bool load_into_process, bool should_pass_arguments, bool load_into_process,
std::optional<FileSys::PatchManager> pm, std::optional<FileSys::PatchManager> pm,
std::vector<Core::NCE::Patcher>* patches, Core::NCE::Patcher* patch) {
s32 patch_index) {
if (nso_file.GetSize() < sizeof(NSOHeader)) { if (nso_file.GetSize() < sizeof(NSOHeader)) {
return std::nullopt; return std::nullopt;
} }
@ -95,12 +94,9 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::
// Allocate some space at the beginning if we are patching in PreText mode. // Allocate some space at the beginning if we are patching in PreText mode.
const size_t module_start = [&]() -> size_t { const size_t module_start = [&]() -> size_t {
#ifdef HAS_NCE #ifdef HAS_NCE
if (patches && load_into_process) { if (patch && patch->GetPatchMode() == Core::NCE::PatchMode::PreText) {
auto* patch = &patches->operator[](patch_index);
if (patch->GetPatchMode() == Core::NCE::PatchMode::PreText) {
return patch->GetSectionSize(); return patch->GetSectionSize();
} }
}
#endif #endif
return 0; return 0;
}(); }();
@ -164,24 +160,27 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::
#ifdef HAS_NCE #ifdef HAS_NCE
// If we are computing the process code layout and using nce backend, patch. // If we are computing the process code layout and using nce backend, patch.
const auto& code = codeset.CodeSegment(); const auto& code = codeset.CodeSegment();
auto* patch = patches ? &patches->operator[](patch_index) : nullptr; if (patch && patch->GetPatchMode() == Core::NCE::PatchMode::None) {
if (patch && !load_into_process) {
// Patch SVCs and MRS calls in the guest code // Patch SVCs and MRS calls in the guest code
while (!patch->PatchText(program_image, code)) { patch->PatchText(program_image, code);
patch = &patches->emplace_back();
} // Add patch section size to the module size.
image_size += static_cast<u32>(patch->GetSectionSize());
} else if (patch) { } else if (patch) {
// Relocate code patch and copy to the program_image. // Relocate code patch and copy to the program_image.
if (patch->RelocateAndCopy(load_base, code, program_image, &process.GetPostHandlers())) { patch->RelocateAndCopy(load_base, code, program_image, &process.GetPostHandlers());
// Update patch section. // Update patch section.
auto& patch_segment = codeset.PatchSegment(); auto& patch_segment = codeset.PatchSegment();
patch_segment.addr = patch_segment.addr =
patch->GetPatchMode() == Core::NCE::PatchMode::PreText ? 0 : image_size; patch->GetPatchMode() == Core::NCE::PatchMode::PreText ? 0 : image_size;
patch_segment.size = static_cast<u32>(patch->GetSectionSize()); patch_segment.size = static_cast<u32>(patch->GetSectionSize());
}
// Refresh image_size to take account the patch section if it was added by RelocateAndCopy // Add patch section size to the module size. In PreText mode image_size
image_size = static_cast<u32>(program_image.size()); // already contains the patch segment as part of module_start.
if (patch->GetPatchMode() == Core::NCE::PatchMode::PostData) {
image_size += patch_segment.size;
}
} }
#endif #endif

View File

@ -93,8 +93,7 @@ public:
const FileSys::VfsFile& nso_file, VAddr load_base, const FileSys::VfsFile& nso_file, VAddr load_base,
bool should_pass_arguments, bool load_into_process, bool should_pass_arguments, bool load_into_process,
std::optional<FileSys::PatchManager> pm = {}, std::optional<FileSys::PatchManager> pm = {},
std::vector<Core::NCE::Patcher>* patches = nullptr, Core::NCE::Patcher* patch = nullptr);
s32 patch_index = -1);
LoadResult Load(Kernel::KProcess& process, Core::System& system) override; LoadResult Load(Kernel::KProcess& process, Core::System& system) override;

View File

@ -12,11 +12,6 @@ namespace Shader::Backend::SPIRV {
namespace { namespace {
class ImageOperands { class ImageOperands {
public: public:
[[maybe_unused]] static constexpr bool ImageSampleOffsetAllowed = false;
[[maybe_unused]] static constexpr bool ImageGatherOffsetAllowed = true;
[[maybe_unused]] static constexpr bool ImageFetchOffsetAllowed = false;
[[maybe_unused]] static constexpr bool ImageGradientOffsetAllowed = false;
explicit ImageOperands(EmitContext& ctx, bool has_bias, bool has_lod, bool has_lod_clamp, explicit ImageOperands(EmitContext& ctx, bool has_bias, bool has_lod, bool has_lod_clamp,
Id lod, const IR::Value& offset) { Id lod, const IR::Value& offset) {
if (has_bias) { if (has_bias) {
@ -27,7 +22,7 @@ public:
const Id lod_value{has_lod_clamp ? ctx.OpCompositeExtract(ctx.F32[1], lod, 0) : lod}; const Id lod_value{has_lod_clamp ? ctx.OpCompositeExtract(ctx.F32[1], lod, 0) : lod};
Add(spv::ImageOperandsMask::Lod, lod_value); Add(spv::ImageOperandsMask::Lod, lod_value);
} }
AddOffset(ctx, offset, ImageSampleOffsetAllowed); AddOffset(ctx, offset);
if (has_lod_clamp) { if (has_lod_clamp) {
const Id lod_clamp{has_bias ? ctx.OpCompositeExtract(ctx.F32[1], lod, 1) : lod}; const Id lod_clamp{has_bias ? ctx.OpCompositeExtract(ctx.F32[1], lod, 1) : lod};
Add(spv::ImageOperandsMask::MinLod, lod_clamp); Add(spv::ImageOperandsMask::MinLod, lod_clamp);
@ -60,17 +55,20 @@ public:
Add(spv::ImageOperandsMask::ConstOffsets, offsets); Add(spv::ImageOperandsMask::ConstOffsets, offsets);
} }
explicit ImageOperands(Id lod, Id ms) { explicit ImageOperands(Id offset, Id lod, Id ms) {
if (Sirit::ValidId(lod)) { if (Sirit::ValidId(lod)) {
Add(spv::ImageOperandsMask::Lod, lod); Add(spv::ImageOperandsMask::Lod, lod);
} }
if (Sirit::ValidId(offset)) {
Add(spv::ImageOperandsMask::Offset, offset);
}
if (Sirit::ValidId(ms)) { if (Sirit::ValidId(ms)) {
Add(spv::ImageOperandsMask::Sample, ms); Add(spv::ImageOperandsMask::Sample, ms);
} }
} }
explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivatives, explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivatives,
u32 num_derivatives, const IR::Value& offset, Id lod_clamp) { u32 num_derivatives, Id offset, Id lod_clamp) {
if (!Sirit::ValidId(derivatives)) { if (!Sirit::ValidId(derivatives)) {
throw LogicError("Derivatives must be present"); throw LogicError("Derivatives must be present");
} }
@ -85,14 +83,16 @@ public:
const Id derivatives_Y{ctx.OpCompositeConstruct( const Id derivatives_Y{ctx.OpCompositeConstruct(
ctx.F32[num_derivatives], std::span{deriv_y_accum.data(), deriv_y_accum.size()})}; ctx.F32[num_derivatives], std::span{deriv_y_accum.data(), deriv_y_accum.size()})};
Add(spv::ImageOperandsMask::Grad, derivatives_X, derivatives_Y); Add(spv::ImageOperandsMask::Grad, derivatives_X, derivatives_Y);
AddOffset(ctx, offset, ImageGradientOffsetAllowed); if (Sirit::ValidId(offset)) {
Add(spv::ImageOperandsMask::Offset, offset);
}
if (has_lod_clamp) { if (has_lod_clamp) {
Add(spv::ImageOperandsMask::MinLod, lod_clamp); Add(spv::ImageOperandsMask::MinLod, lod_clamp);
} }
} }
explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivatives_1, Id derivatives_2, explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivatives_1, Id derivatives_2,
const IR::Value& offset, Id lod_clamp) { Id offset, Id lod_clamp) {
if (!Sirit::ValidId(derivatives_1) || !Sirit::ValidId(derivatives_2)) { if (!Sirit::ValidId(derivatives_1) || !Sirit::ValidId(derivatives_2)) {
throw LogicError("Derivatives must be present"); throw LogicError("Derivatives must be present");
} }
@ -111,7 +111,9 @@ public:
const Id derivatives_id2{ctx.OpCompositeConstruct( const Id derivatives_id2{ctx.OpCompositeConstruct(
ctx.F32[3], std::span{deriv_2_accum.data(), deriv_2_accum.size()})}; ctx.F32[3], std::span{deriv_2_accum.data(), deriv_2_accum.size()})};
Add(spv::ImageOperandsMask::Grad, derivatives_id1, derivatives_id2); Add(spv::ImageOperandsMask::Grad, derivatives_id1, derivatives_id2);
AddOffset(ctx, offset, ImageGradientOffsetAllowed); if (Sirit::ValidId(offset)) {
Add(spv::ImageOperandsMask::Offset, offset);
}
if (has_lod_clamp) { if (has_lod_clamp) {
Add(spv::ImageOperandsMask::MinLod, lod_clamp); Add(spv::ImageOperandsMask::MinLod, lod_clamp);
} }
@ -130,7 +132,7 @@ public:
} }
private: private:
void AddOffset(EmitContext& ctx, const IR::Value& offset, bool runtime_offset_allowed) { void AddOffset(EmitContext& ctx, const IR::Value& offset) {
if (offset.IsEmpty()) { if (offset.IsEmpty()) {
return; return;
} }
@ -163,10 +165,8 @@ private:
break; break;
} }
} }
if (runtime_offset_allowed) {
Add(spv::ImageOperandsMask::Offset, ctx.Def(offset)); Add(spv::ImageOperandsMask::Offset, ctx.Def(offset));
} }
}
void Add(spv::ImageOperandsMask new_mask, Id value) { void Add(spv::ImageOperandsMask new_mask, Id value) {
mask = static_cast<spv::ImageOperandsMask>(static_cast<unsigned>(mask) | mask = static_cast<spv::ImageOperandsMask>(static_cast<unsigned>(mask) |
@ -311,37 +311,6 @@ Id ImageGatherSubpixelOffset(EmitContext& ctx, const IR::TextureInstInfo& info,
return coords; return coords;
} }
} }
void AddOffsetToCoordinates(EmitContext& ctx, const IR::TextureInstInfo& info, Id& coords,
Id offset) {
if (!Sirit::ValidId(offset)) {
return;
}
Id result_type{};
switch (info.type) {
case TextureType::Buffer:
case TextureType::Color1D:
case TextureType::ColorArray1D: {
result_type = ctx.U32[1];
break;
}
case TextureType::Color2D:
case TextureType::Color2DRect:
case TextureType::ColorArray2D: {
result_type = ctx.U32[2];
break;
}
case TextureType::Color3D: {
result_type = ctx.U32[3];
break;
}
case TextureType::ColorCube:
case TextureType::ColorArrayCube:
return;
}
coords = ctx.OpIAdd(result_type, coords, offset);
}
} // Anonymous namespace } // Anonymous namespace
Id EmitBindlessImageSampleImplicitLod(EmitContext&) { Id EmitBindlessImageSampleImplicitLod(EmitContext&) {
@ -527,7 +496,6 @@ Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset, Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset,
Id lod, Id ms) { Id lod, Id ms) {
const auto info{inst->Flags<IR::TextureInstInfo>()}; const auto info{inst->Flags<IR::TextureInstInfo>()};
AddOffsetToCoordinates(ctx, info, coords, offset);
if (info.type == TextureType::Buffer) { if (info.type == TextureType::Buffer) {
lod = Id{}; lod = Id{};
} }
@ -535,7 +503,7 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id c
// This image is multisampled, lod must be implicit // This image is multisampled, lod must be implicit
lod = Id{}; lod = Id{};
} }
const ImageOperands operands(lod, ms); const ImageOperands operands(offset, lod, ms);
return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst, ctx.F32[4], return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst, ctx.F32[4],
TextureImage(ctx, info, index), coords, operands.MaskOptional(), operands.Span()); TextureImage(ctx, info, index), coords, operands.MaskOptional(), operands.Span());
} }
@ -580,13 +548,13 @@ Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I
} }
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
Id derivatives, const IR::Value& offset, Id lod_clamp) { Id derivatives, Id offset, Id lod_clamp) {
const auto info{inst->Flags<IR::TextureInstInfo>()}; const auto info{inst->Flags<IR::TextureInstInfo>()};
const auto operands = info.num_derivatives == 3 const auto operands =
? ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, info.num_derivatives == 3
ctx.Def(offset), {}, lod_clamp) ? ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, offset, {}, lod_clamp)
: ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, : ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, info.num_derivatives, offset,
info.num_derivatives, offset, lod_clamp); lod_clamp);
return Emit(&EmitContext::OpImageSparseSampleExplicitLod, return Emit(&EmitContext::OpImageSparseSampleExplicitLod,
&EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4], &EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4],
Texture(ctx, info, index), coords, operands.Mask(), operands.Span()); Texture(ctx, info, index), coords, operands.Mask(), operands.Span());

View File

@ -543,7 +543,7 @@ Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& i
const IR::Value& skip_mips); const IR::Value& skip_mips);
Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
Id derivatives, const IR::Value& offset, Id lod_clamp); Id derivatives, Id offset, Id lod_clamp);
Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color); void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color);
Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index); Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index);

View File

@ -205,7 +205,6 @@ void ConfigureProfileManager::AddUser() {
const auto uuid = Common::UUID::MakeRandom(); const auto uuid = Common::UUID::MakeRandom();
profile_manager.CreateNewUser(uuid, username.toStdString()); profile_manager.CreateNewUser(uuid, username.toStdString());
profile_manager.WriteUserSaveFile();
item_model->appendRow(new QStandardItem{GetIcon(uuid), FormatUserEntryText(username, uuid)}); item_model->appendRow(new QStandardItem{GetIcon(uuid), FormatUserEntryText(username, uuid)});
} }
@ -229,7 +228,6 @@ void ConfigureProfileManager::RenameUser() {
std::copy(username_std.begin(), username_std.end(), profile.username.begin()); std::copy(username_std.begin(), username_std.end(), profile.username.begin());
profile_manager.SetProfileBase(*uuid, profile); profile_manager.SetProfileBase(*uuid, profile);
profile_manager.WriteUserSaveFile();
item_model->setItem( item_model->setItem(
user, 0, user, 0,
@ -258,8 +256,6 @@ void ConfigureProfileManager::DeleteUser(const Common::UUID& uuid) {
return; return;
} }
profile_manager.WriteUserSaveFile();
item_model->removeRows(tree_view->currentIndex().row(), 1); item_model->removeRows(tree_view->currentIndex().row(), 1);
tree_view->clearSelection(); tree_view->clearSelection();