Compare commits
6 Commits
android-19
...
android-19
Author | SHA1 | Date | |
---|---|---|---|
e9d7bd2534 | |||
57c6d95eb5 | |||
b83c362cc9 | |||
0d8ce6cc50 | |||
67b104dc5a | |||
8f979a3153 |
@ -32,6 +32,3 @@ if [ ! -z "$DIFF" ]; then
|
|||||||
echo "$DIFF"
|
echo "$DIFF"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cd src/android
|
|
||||||
./gradlew ktlintCheck
|
|
||||||
|
@ -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
|
||||||
@ -33,6 +43,7 @@ stages:
|
|||||||
cache: 'true'
|
cache: 'true'
|
||||||
version: $(DisplayVersion)
|
version: $(DisplayVersion)
|
||||||
- stage: build_win
|
- stage: build_win
|
||||||
|
dependsOn: format
|
||||||
displayName: 'build-windows'
|
displayName: 'build-windows'
|
||||||
jobs:
|
jobs:
|
||||||
- job: build
|
- job: build
|
||||||
|
8
.github/workflows/verify.yml
vendored
8
.github/workflows/verify.yml
vendored
@ -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:
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
| Pull Request | Commit | Title | Author | Merged? |
|
| Pull Request | Commit | Title | Author | Merged? |
|
||||||
|----|----|----|----|----|
|
|----|----|----|----|----|
|
||||||
| [12579](https://github.com/yuzu-emu/yuzu-android//pull/12579) | [`93ef41f03`](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 |
|
| [12605](https://github.com/yuzu-emu/yuzu-android//pull/12605) | [`0683fb5a7`](https://github.com/yuzu-emu/yuzu-android//pull/12605/files) | service: hid: Create abstracted pad structure | [german77](https://github.com/german77/) | Yes |
|
||||||
| [12688](https://github.com/yuzu-emu/yuzu-android//pull/12688) | [`e9eb017aa`](https://github.com/yuzu-emu/yuzu-android//pull/12688/files) | renderer_vulkan: recreate swapchain when frame size changes | [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 |
|
||||||
|
| [12642](https://github.com/yuzu-emu/yuzu-android//pull/12642) | [`d3ba6b334`](https://github.com/yuzu-emu/yuzu-android//pull/12642/files) | android: Refactor list adapters | [t895](https://github.com/t895/) | 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.
|
||||||
|
@ -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) {
|
||||||
|
logger.error("Cannot find git, defaulting to dummy version number")
|
||||||
}
|
}
|
||||||
return versionName.ifEmpty { "0.0" }
|
|
||||||
|
if (System.getenv("GITHUB_ACTIONS") != null) {
|
||||||
|
val gitTag = System.getenv("GIT_TAG_NAME")
|
||||||
|
versionName = gitTag ?: versionName
|
||||||
|
}
|
||||||
|
|
||||||
|
return versionName
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getGitHash(): String =
|
fun getGitHash(): String {
|
||||||
runGitCommand(listOf("git", "rev-parse", "--short", "HEAD")).ifEmpty { "dummy-hash" }
|
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()
|
||||||
|
|
||||||
fun getBranch(): String =
|
return if (process.exitValue() == 0) {
|
||||||
runGitCommand(listOf("git", "rev-parse", "--abbrev-ref", "HEAD")).ifEmpty { "dummy-hash" }
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -104,7 +104,7 @@ object FileUtil {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Reference: https://stackoverflow.com/questions/42186820/documentfile-is-very-slow
|
* Reference: https://stackoverflow.com/questions/42186820/documentfile-is-very-slow
|
||||||
* This function will be faster than DocumentFile.listFiles
|
* This function will be faster than DoucmentFile.listFiles
|
||||||
* @param uri Directory uri.
|
* @param uri Directory uri.
|
||||||
* @return CheapDocument lists.
|
* @return CheapDocument lists.
|
||||||
*/
|
*/
|
||||||
|
@ -21,7 +21,7 @@ void AndroidConfig::ReloadAllValues() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AndroidConfig::SaveAllValues() {
|
void AndroidConfig::SaveAllValues() {
|
||||||
SaveValues();
|
Save();
|
||||||
SaveAndroidValues();
|
SaveAndroidValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,7 +205,7 @@ jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getIsRuntimeModifiable(JNIEn
|
|||||||
jstring jkey) {
|
jstring jkey) {
|
||||||
auto setting = getSetting<std::string>(env, jkey);
|
auto setting = getSetting<std::string>(env, jkey);
|
||||||
if (setting != nullptr) {
|
if (setting != nullptr) {
|
||||||
return setting->RuntimeModifiable();
|
return setting->RuntimeModfiable();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
<item>@string/language_dutch</item>
|
<item>@string/language_dutch</item>
|
||||||
<item>@string/language_english</item>
|
<item>@string/language_english</item>
|
||||||
<item>@string/language_french</item>
|
<item>@string/language_french</item>
|
||||||
<item>@string/language_german</item>
|
<item>@string/langauge_german</item>
|
||||||
<item>@string/language_italian</item>
|
<item>@string/language_italian</item>
|
||||||
<item>@string/language_japanese</item>
|
<item>@string/language_japanese</item>
|
||||||
<item>@string/language_korean</item>
|
<item>@string/language_korean</item>
|
||||||
@ -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>
|
||||||
|
|
||||||
|
@ -410,7 +410,7 @@
|
|||||||
<string name="language_japanese" translatable="false">日本語</string>
|
<string name="language_japanese" translatable="false">日本語</string>
|
||||||
<string name="language_english" translatable="false">English</string>
|
<string name="language_english" translatable="false">English</string>
|
||||||
<string name="language_french" translatable="false">Français</string>
|
<string name="language_french" translatable="false">Français</string>
|
||||||
<string name="language_german" translatable="false">Deutsch</string>
|
<string name="langauge_german" translatable="false">Deutsch</string>
|
||||||
<string name="language_italian" translatable="false">Italiano</string>
|
<string name="language_italian" translatable="false">Italiano</string>
|
||||||
<string name="language_spanish" translatable="false">Español</string>
|
<string name="language_spanish" translatable="false">Español</string>
|
||||||
<string name="language_chinese" translatable="false">简体中文</string>
|
<string name="language_chinese" translatable="false">简体中文</string>
|
||||||
|
@ -11,7 +11,7 @@ ADSP::ADSP(Core::System& system, Sink::Sink& sink) {
|
|||||||
opus_decoder = std::make_unique<OpusDecoder::OpusDecoder>(system);
|
opus_decoder = std::make_unique<OpusDecoder::OpusDecoder>(system);
|
||||||
opus_decoder->Send(Direction::DSP, OpusDecoder::Message::Start);
|
opus_decoder->Send(Direction::DSP, OpusDecoder::Message::Start);
|
||||||
if (opus_decoder->Receive(Direction::Host) != OpusDecoder::Message::StartOK) {
|
if (opus_decoder->Receive(Direction::Host) != OpusDecoder::Message::StartOK) {
|
||||||
LOG_ERROR(Service_Audio, "OpusDecoder failed to initialize.");
|
LOG_ERROR(Service_Audio, "OpusDeocder failed to initialize.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -41,7 +41,7 @@ void CommandGenerator::GenerateDataSourceCommand(VoiceInfo& voice_info,
|
|||||||
const VoiceState& voice_state, const s8 channel) {
|
const VoiceState& voice_state, const s8 channel) {
|
||||||
if (voice_info.mix_id == UnusedMixId) {
|
if (voice_info.mix_id == UnusedMixId) {
|
||||||
if (voice_info.splitter_id != UnusedSplitterId) {
|
if (voice_info.splitter_id != UnusedSplitterId) {
|
||||||
auto destination{splitter_context.GetDestinationData(voice_info.splitter_id, 0)};
|
auto destination{splitter_context.GetDesintationData(voice_info.splitter_id, 0)};
|
||||||
u32 dest_id{0};
|
u32 dest_id{0};
|
||||||
while (destination != nullptr) {
|
while (destination != nullptr) {
|
||||||
if (destination->IsConfigured()) {
|
if (destination->IsConfigured()) {
|
||||||
@ -55,7 +55,7 @@ void CommandGenerator::GenerateDataSourceCommand(VoiceInfo& voice_info,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
dest_id++;
|
dest_id++;
|
||||||
destination = splitter_context.GetDestinationData(voice_info.splitter_id, dest_id);
|
destination = splitter_context.GetDesintationData(voice_info.splitter_id, dest_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -234,7 +234,7 @@ void CommandGenerator::GenerateVoiceCommand(VoiceInfo& voice_info) {
|
|||||||
if (voice_info.mix_id == UnusedMixId) {
|
if (voice_info.mix_id == UnusedMixId) {
|
||||||
if (voice_info.splitter_id != UnusedSplitterId) {
|
if (voice_info.splitter_id != UnusedSplitterId) {
|
||||||
auto i{channel};
|
auto i{channel};
|
||||||
auto destination{splitter_context.GetDestinationData(voice_info.splitter_id, i)};
|
auto destination{splitter_context.GetDesintationData(voice_info.splitter_id, i)};
|
||||||
while (destination != nullptr) {
|
while (destination != nullptr) {
|
||||||
if (destination->IsConfigured()) {
|
if (destination->IsConfigured()) {
|
||||||
const auto mix_id{destination->GetMixId()};
|
const auto mix_id{destination->GetMixId()};
|
||||||
@ -249,7 +249,7 @@ void CommandGenerator::GenerateVoiceCommand(VoiceInfo& voice_info) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
i += voice_info.channel_count;
|
i += voice_info.channel_count;
|
||||||
destination = splitter_context.GetDestinationData(voice_info.splitter_id, i);
|
destination = splitter_context.GetDesintationData(voice_info.splitter_id, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -591,7 +591,7 @@ void CommandGenerator::GenerateMixCommands(MixInfo& mix_info) {
|
|||||||
if (mix_info.dst_splitter_id != UnusedSplitterId) {
|
if (mix_info.dst_splitter_id != UnusedSplitterId) {
|
||||||
s16 dest_id{0};
|
s16 dest_id{0};
|
||||||
auto destination{
|
auto destination{
|
||||||
splitter_context.GetDestinationData(mix_info.dst_splitter_id, dest_id)};
|
splitter_context.GetDesintationData(mix_info.dst_splitter_id, dest_id)};
|
||||||
while (destination != nullptr) {
|
while (destination != nullptr) {
|
||||||
if (destination->IsConfigured()) {
|
if (destination->IsConfigured()) {
|
||||||
auto splitter_mix_id{destination->GetMixId()};
|
auto splitter_mix_id{destination->GetMixId()};
|
||||||
@ -612,7 +612,7 @@ void CommandGenerator::GenerateMixCommands(MixInfo& mix_info) {
|
|||||||
}
|
}
|
||||||
dest_id++;
|
dest_id++;
|
||||||
destination =
|
destination =
|
||||||
splitter_context.GetDestinationData(mix_info.dst_splitter_id, dest_id);
|
splitter_context.GetDesintationData(mix_info.dst_splitter_id, dest_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -93,7 +93,7 @@ bool MixInfo::UpdateConnection(EdgeMatrix& edge_matrix, const InParameter& in_pa
|
|||||||
|
|
||||||
for (u32 i = 0; i < destination_count; i++) {
|
for (u32 i = 0; i < destination_count; i++) {
|
||||||
auto destination{
|
auto destination{
|
||||||
splitter_context.GetDestinationData(in_params.dest_splitter_id, i)};
|
splitter_context.GetDesintationData(in_params.dest_splitter_id, i)};
|
||||||
|
|
||||||
if (destination) {
|
if (destination) {
|
||||||
const auto destination_id{destination->GetMixId()};
|
const auto destination_id{destination->GetMixId()};
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
namespace AudioCore::Renderer {
|
namespace AudioCore::Renderer {
|
||||||
|
|
||||||
SplitterDestinationData* SplitterContext::GetDestinationData(const s32 splitter_id,
|
SplitterDestinationData* SplitterContext::GetDesintationData(const s32 splitter_id,
|
||||||
const s32 destination_id) {
|
const s32 destination_id) {
|
||||||
return splitter_infos[splitter_id].GetData(destination_id);
|
return splitter_infos[splitter_id].GetData(destination_id);
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ public:
|
|||||||
* @param destination_id - Destination index within the splitter.
|
* @param destination_id - Destination index within the splitter.
|
||||||
* @return Pointer to the found destination. May be nullptr.
|
* @return Pointer to the found destination. May be nullptr.
|
||||||
*/
|
*/
|
||||||
SplitterDestinationData* GetDestinationData(s32 splitter_id, s32 destination_id);
|
SplitterDestinationData* GetDesintationData(s32 splitter_id, s32 destination_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a splitter from the given index.
|
* Get a splitter from the given index.
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ bool BasicSetting::Save() const {
|
|||||||
return save;
|
return save;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BasicSetting::RuntimeModifiable() const {
|
bool BasicSetting::RuntimeModfiable() const {
|
||||||
return runtime_modifiable;
|
return runtime_modifiable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +186,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* @returns true if the current setting can be changed while the guest is running.
|
* @returns true if the current setting can be changed while the guest is running.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] bool RuntimeModifiable() const;
|
[[nodiscard]] bool RuntimeModfiable() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns A unique number corresponding to the setting.
|
* @returns A unique number corresponding to the setting.
|
||||||
|
@ -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,50 +150,39 @@ 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.
|
if (this->mode == PatchMode::PreText) {
|
||||||
total_program_size -= image_size;
|
std::memcpy(program_image.data(), m_patch_instructions.data(),
|
||||||
|
m_patch_instructions.size() * sizeof(u32));
|
||||||
// Only copy to the program image of the last module
|
} else {
|
||||||
if (m_relocate_module_index == modules.size()) {
|
program_image.resize(image_size + patch_size);
|
||||||
if (this->mode == PatchMode::PreText) {
|
std::memcpy(program_image.data() + image_size, m_patch_instructions.data(),
|
||||||
ASSERT(image_size == total_program_size);
|
m_patch_instructions.size() * sizeof(u32));
|
||||||
std::memcpy(program_image.data(), m_patch_instructions.data(),
|
|
||||||
m_patch_instructions.size() * sizeof(u32));
|
|
||||||
} else {
|
|
||||||
program_image.resize(image_size + patch_size);
|
|
||||||
std::memcpy(program_image.data() + image_size, m_patch_instructions.data(),
|
|
||||||
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.
|
||||||
|
@ -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 {
|
|
||||||
std::vector<Trampoline> m_trampolines;
|
|
||||||
std::vector<Relocation> m_branch_to_patch_relocations{};
|
|
||||||
std::vector<Relocation> m_branch_to_module_relocations{};
|
|
||||||
std::vector<Relocation> m_write_module_pc_relocations{};
|
|
||||||
std::vector<ModuleTextAddress> m_exclusives{};
|
|
||||||
};
|
|
||||||
|
|
||||||
oaknut::VectorCodeGenerator c;
|
oaknut::VectorCodeGenerator c;
|
||||||
|
std::vector<Trampoline> m_trampolines;
|
||||||
|
std::vector<Relocation> m_branch_to_patch_relocations{};
|
||||||
|
std::vector<Relocation> m_branch_to_module_relocations{};
|
||||||
|
std::vector<Relocation> m_write_module_pc_relocations{};
|
||||||
|
std::vector<ModuleTextAddress> m_exclusives{};
|
||||||
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
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -28,10 +28,6 @@ class Memory;
|
|||||||
template <typename DTraits>
|
template <typename DTraits>
|
||||||
struct DeviceMemoryManagerAllocator;
|
struct DeviceMemoryManagerAllocator;
|
||||||
|
|
||||||
struct Asid {
|
|
||||||
size_t id;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Traits>
|
template <typename Traits>
|
||||||
class DeviceMemoryManager {
|
class DeviceMemoryManager {
|
||||||
using DeviceInterface = typename Traits::DeviceInterface;
|
using DeviceInterface = typename Traits::DeviceInterface;
|
||||||
@ -47,14 +43,15 @@ public:
|
|||||||
void AllocateFixed(DAddr start, size_t size);
|
void AllocateFixed(DAddr start, size_t size);
|
||||||
void Free(DAddr start, size_t size);
|
void Free(DAddr start, size_t size);
|
||||||
|
|
||||||
void Map(DAddr address, VAddr virtual_address, size_t size, Asid asid, bool track = false);
|
void Map(DAddr address, VAddr virtual_address, size_t size, size_t process_id,
|
||||||
|
bool track = false);
|
||||||
|
|
||||||
void Unmap(DAddr address, size_t size);
|
void Unmap(DAddr address, size_t size);
|
||||||
|
|
||||||
void TrackContinuityImpl(DAddr address, VAddr virtual_address, size_t size, Asid asid);
|
void TrackContinuityImpl(DAddr address, VAddr virtual_address, size_t size, size_t process_id);
|
||||||
void TrackContinuity(DAddr address, VAddr virtual_address, size_t size, Asid asid) {
|
void TrackContinuity(DAddr address, VAddr virtual_address, size_t size, size_t process_id) {
|
||||||
std::scoped_lock lk(mapping_guard);
|
std::scoped_lock lk(mapping_guard);
|
||||||
TrackContinuityImpl(address, virtual_address, size, asid);
|
TrackContinuityImpl(address, virtual_address, size, process_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write / Read
|
// Write / Read
|
||||||
@ -108,8 +105,8 @@ public:
|
|||||||
void WriteBlock(DAddr address, const void* src_pointer, size_t size);
|
void WriteBlock(DAddr address, const void* src_pointer, size_t size);
|
||||||
void WriteBlockUnsafe(DAddr address, const void* src_pointer, size_t size);
|
void WriteBlockUnsafe(DAddr address, const void* src_pointer, size_t size);
|
||||||
|
|
||||||
Asid RegisterProcess(Memory::Memory* memory);
|
size_t RegisterProcess(Memory::Memory* memory);
|
||||||
void UnregisterProcess(Asid id);
|
void UnregisterProcess(size_t id);
|
||||||
|
|
||||||
void UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta);
|
void UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta);
|
||||||
|
|
||||||
@ -166,17 +163,17 @@ private:
|
|||||||
static constexpr size_t guest_max_as_bits = 39;
|
static constexpr size_t guest_max_as_bits = 39;
|
||||||
static constexpr size_t guest_as_size = 1ULL << guest_max_as_bits;
|
static constexpr size_t guest_as_size = 1ULL << guest_max_as_bits;
|
||||||
static constexpr size_t guest_mask = guest_as_size - 1ULL;
|
static constexpr size_t guest_mask = guest_as_size - 1ULL;
|
||||||
static constexpr size_t asid_start_bit = guest_max_as_bits;
|
static constexpr size_t process_id_start_bit = guest_max_as_bits;
|
||||||
|
|
||||||
std::pair<Asid, VAddr> ExtractCPUBacking(size_t page_index) {
|
std::pair<size_t, VAddr> ExtractCPUBacking(size_t page_index) {
|
||||||
auto content = cpu_backing_address[page_index];
|
auto content = cpu_backing_address[page_index];
|
||||||
const VAddr address = content & guest_mask;
|
const VAddr address = content & guest_mask;
|
||||||
const Asid asid{static_cast<size_t>(content >> asid_start_bit)};
|
const size_t process_id = static_cast<size_t>(content >> process_id_start_bit);
|
||||||
return std::make_pair(asid, address);
|
return std::make_pair(process_id, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InsertCPUBacking(size_t page_index, VAddr address, Asid asid) {
|
void InsertCPUBacking(size_t page_index, VAddr address, size_t process_id) {
|
||||||
cpu_backing_address[page_index] = address | (asid.id << asid_start_bit);
|
cpu_backing_address[page_index] = address | (process_id << process_id_start_bit);
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::VirtualBuffer<VAddr> cpu_backing_address;
|
Common::VirtualBuffer<VAddr> cpu_backing_address;
|
||||||
@ -208,4 +205,4 @@ private:
|
|||||||
std::mutex mapping_guard;
|
std::mutex mapping_guard;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
@ -215,8 +215,8 @@ void DeviceMemoryManager<Traits>::Free(DAddr start, size_t size) {
|
|||||||
|
|
||||||
template <typename Traits>
|
template <typename Traits>
|
||||||
void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size_t size,
|
void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size_t size,
|
||||||
Asid asid, bool track) {
|
size_t process_id, bool track) {
|
||||||
Core::Memory::Memory* process_memory = registered_processes[asid.id];
|
Core::Memory::Memory* process_memory = registered_processes[process_id];
|
||||||
size_t start_page_d = address >> Memory::YUZU_PAGEBITS;
|
size_t start_page_d = address >> Memory::YUZU_PAGEBITS;
|
||||||
size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS;
|
size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS;
|
||||||
std::scoped_lock lk(mapping_guard);
|
std::scoped_lock lk(mapping_guard);
|
||||||
@ -229,7 +229,7 @@ void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size
|
|||||||
}
|
}
|
||||||
auto phys_addr = static_cast<u32>(GetRawPhysicalAddr(ptr) >> Memory::YUZU_PAGEBITS) + 1U;
|
auto phys_addr = static_cast<u32>(GetRawPhysicalAddr(ptr) >> Memory::YUZU_PAGEBITS) + 1U;
|
||||||
compressed_physical_ptr[start_page_d + i] = phys_addr;
|
compressed_physical_ptr[start_page_d + i] = phys_addr;
|
||||||
InsertCPUBacking(start_page_d + i, new_vaddress, asid);
|
InsertCPUBacking(start_page_d + i, new_vaddress, process_id);
|
||||||
const u32 base_dev = compressed_device_addr[phys_addr - 1U];
|
const u32 base_dev = compressed_device_addr[phys_addr - 1U];
|
||||||
const u32 new_dev = static_cast<u32>(start_page_d + i);
|
const u32 new_dev = static_cast<u32>(start_page_d + i);
|
||||||
if (base_dev == 0) [[likely]] {
|
if (base_dev == 0) [[likely]] {
|
||||||
@ -244,7 +244,7 @@ void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size
|
|||||||
impl->multi_dev_address.Register(new_dev, start_id);
|
impl->multi_dev_address.Register(new_dev, start_id);
|
||||||
}
|
}
|
||||||
if (track) {
|
if (track) {
|
||||||
TrackContinuityImpl(address, virtual_address, size, asid);
|
TrackContinuityImpl(address, virtual_address, size, process_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,8 +277,8 @@ void DeviceMemoryManager<Traits>::Unmap(DAddr address, size_t size) {
|
|||||||
}
|
}
|
||||||
template <typename Traits>
|
template <typename Traits>
|
||||||
void DeviceMemoryManager<Traits>::TrackContinuityImpl(DAddr address, VAddr virtual_address,
|
void DeviceMemoryManager<Traits>::TrackContinuityImpl(DAddr address, VAddr virtual_address,
|
||||||
size_t size, Asid asid) {
|
size_t size, size_t process_id) {
|
||||||
Core::Memory::Memory* process_memory = registered_processes[asid.id];
|
Core::Memory::Memory* process_memory = registered_processes[process_id];
|
||||||
size_t start_page_d = address >> Memory::YUZU_PAGEBITS;
|
size_t start_page_d = address >> Memory::YUZU_PAGEBITS;
|
||||||
size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS;
|
size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS;
|
||||||
uintptr_t last_ptr = 0;
|
uintptr_t last_ptr = 0;
|
||||||
@ -488,8 +488,8 @@ void DeviceMemoryManager<Traits>::WriteBlockUnsafe(DAddr address, const void* sr
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Traits>
|
template <typename Traits>
|
||||||
Asid DeviceMemoryManager<Traits>::RegisterProcess(Memory::Memory* memory_device_inter) {
|
size_t DeviceMemoryManager<Traits>::RegisterProcess(Memory::Memory* memory_device_inter) {
|
||||||
size_t new_id{};
|
size_t new_id;
|
||||||
if (!id_pool.empty()) {
|
if (!id_pool.empty()) {
|
||||||
new_id = id_pool.front();
|
new_id = id_pool.front();
|
||||||
id_pool.pop_front();
|
id_pool.pop_front();
|
||||||
@ -498,23 +498,29 @@ Asid DeviceMemoryManager<Traits>::RegisterProcess(Memory::Memory* memory_device_
|
|||||||
registered_processes.emplace_back(memory_device_inter);
|
registered_processes.emplace_back(memory_device_inter);
|
||||||
new_id = registered_processes.size() - 1U;
|
new_id = registered_processes.size() - 1U;
|
||||||
}
|
}
|
||||||
return Asid{new_id};
|
return new_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Traits>
|
template <typename Traits>
|
||||||
void DeviceMemoryManager<Traits>::UnregisterProcess(Asid asid) {
|
void DeviceMemoryManager<Traits>::UnregisterProcess(size_t id) {
|
||||||
registered_processes[asid.id] = nullptr;
|
registered_processes[id] = nullptr;
|
||||||
id_pool.push_front(asid.id);
|
id_pool.push_front(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Traits>
|
template <typename Traits>
|
||||||
void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) {
|
void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) {
|
||||||
std::unique_lock<std::mutex> lk(counter_guard, std::defer_lock);
|
bool locked = false;
|
||||||
const auto Lock = [&] {
|
auto lock = [&] {
|
||||||
if (!lk) {
|
if (!locked) {
|
||||||
lk.lock();
|
counter_guard.lock();
|
||||||
|
locked = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
SCOPE_EXIT({
|
||||||
|
if (locked) {
|
||||||
|
counter_guard.unlock();
|
||||||
|
}
|
||||||
|
});
|
||||||
u64 uncache_begin = 0;
|
u64 uncache_begin = 0;
|
||||||
u64 cache_begin = 0;
|
u64 cache_begin = 0;
|
||||||
u64 uncache_bytes = 0;
|
u64 uncache_bytes = 0;
|
||||||
@ -524,9 +530,9 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
|
|||||||
std::atomic_thread_fence(std::memory_order_acquire);
|
std::atomic_thread_fence(std::memory_order_acquire);
|
||||||
const size_t page_end = Common::DivCeil(addr + size, Memory::YUZU_PAGESIZE);
|
const size_t page_end = Common::DivCeil(addr + size, Memory::YUZU_PAGESIZE);
|
||||||
size_t page = addr >> Memory::YUZU_PAGEBITS;
|
size_t page = addr >> Memory::YUZU_PAGEBITS;
|
||||||
auto [asid, base_vaddress] = ExtractCPUBacking(page);
|
auto [process_id, base_vaddress] = ExtractCPUBacking(page);
|
||||||
size_t vpage = base_vaddress >> Memory::YUZU_PAGEBITS;
|
size_t vpage = base_vaddress >> Memory::YUZU_PAGEBITS;
|
||||||
auto* memory_device_inter = registered_processes[asid.id];
|
auto* memory_device_inter = registered_processes[process_id];
|
||||||
for (; page != page_end; ++page) {
|
for (; page != page_end; ++page) {
|
||||||
std::atomic_uint8_t& count = cached_pages->at(page >> 3).Count(page);
|
std::atomic_uint8_t& count = cached_pages->at(page >> 3).Count(page);
|
||||||
|
|
||||||
@ -549,7 +555,7 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
|
|||||||
}
|
}
|
||||||
uncache_bytes += Memory::YUZU_PAGESIZE;
|
uncache_bytes += Memory::YUZU_PAGESIZE;
|
||||||
} else if (uncache_bytes > 0) {
|
} else if (uncache_bytes > 0) {
|
||||||
Lock();
|
lock();
|
||||||
MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
|
MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
|
||||||
uncache_bytes, false);
|
uncache_bytes, false);
|
||||||
uncache_bytes = 0;
|
uncache_bytes = 0;
|
||||||
@ -560,7 +566,7 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
|
|||||||
}
|
}
|
||||||
cache_bytes += Memory::YUZU_PAGESIZE;
|
cache_bytes += Memory::YUZU_PAGESIZE;
|
||||||
} else if (cache_bytes > 0) {
|
} else if (cache_bytes > 0) {
|
||||||
Lock();
|
lock();
|
||||||
MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes,
|
MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes,
|
||||||
true);
|
true);
|
||||||
cache_bytes = 0;
|
cache_bytes = 0;
|
||||||
@ -568,12 +574,12 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
|
|||||||
vpage++;
|
vpage++;
|
||||||
}
|
}
|
||||||
if (uncache_bytes > 0) {
|
if (uncache_bytes > 0) {
|
||||||
Lock();
|
lock();
|
||||||
MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes,
|
MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
if (cache_bytes > 0) {
|
if (cache_bytes > 0) {
|
||||||
Lock();
|
lock();
|
||||||
MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes,
|
MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes,
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
|
@ -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();
|
||||||
|
@ -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) {
|
||||||
|
@ -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 {
|
||||||
|
@ -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,
|
||||||
|
@ -112,14 +112,7 @@ struct KernelCore::Impl {
|
|||||||
old_process->Close();
|
old_process->Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
process_list.clear();
|
||||||
std::scoped_lock lk{process_list_lock};
|
|
||||||
for (auto* const process : process_list) {
|
|
||||||
process->Terminate();
|
|
||||||
process->Close();
|
|
||||||
}
|
|
||||||
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() {
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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{};
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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};
|
||||||
|
@ -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;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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.
|
||||||
resource_manager->Initialize();
|
const auto process_list = system.Kernel().GetProcessList();
|
||||||
resource_manager->RegisterAppletResourceUserId(system.ApplicationProcess()->GetProcessId(),
|
if (!process_list.empty()) {
|
||||||
true);
|
resource_manager->Initialize();
|
||||||
|
resource_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), 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));
|
||||||
|
@ -16,8 +16,9 @@
|
|||||||
|
|
||||||
namespace Service::Nvidia::NvCore {
|
namespace Service::Nvidia::NvCore {
|
||||||
|
|
||||||
Session::Session(SessionId id_, Kernel::KProcess* process_, Core::Asid asid_)
|
Session::Session(size_t id_, Kernel::KProcess* process_, size_t smmu_id_)
|
||||||
: id{id_}, process{process_}, asid{asid_}, has_preallocated_area{}, mapper{}, is_active{} {}
|
: id{id_}, process{process_}, smmu_id{smmu_id_},
|
||||||
|
has_preallocated_area{}, mapper{}, is_active{} {}
|
||||||
|
|
||||||
Session::~Session() = default;
|
Session::~Session() = default;
|
||||||
|
|
||||||
@ -40,9 +41,7 @@ Container::Container(Tegra::Host1x::Host1x& host1x_) {
|
|||||||
|
|
||||||
Container::~Container() = default;
|
Container::~Container() = default;
|
||||||
|
|
||||||
SessionId Container::OpenSession(Kernel::KProcess* process) {
|
size_t Container::OpenSession(Kernel::KProcess* process) {
|
||||||
using namespace Common::Literals;
|
|
||||||
|
|
||||||
std::scoped_lock lk(impl->session_guard);
|
std::scoped_lock lk(impl->session_guard);
|
||||||
for (auto& session : impl->sessions) {
|
for (auto& session : impl->sessions) {
|
||||||
if (!session.is_active) {
|
if (!session.is_active) {
|
||||||
@ -55,14 +54,14 @@ SessionId Container::OpenSession(Kernel::KProcess* process) {
|
|||||||
size_t new_id{};
|
size_t new_id{};
|
||||||
auto* memory_interface = &process->GetMemory();
|
auto* memory_interface = &process->GetMemory();
|
||||||
auto& smmu = impl->host1x.MemoryManager();
|
auto& smmu = impl->host1x.MemoryManager();
|
||||||
auto asid = smmu.RegisterProcess(memory_interface);
|
auto smmu_id = smmu.RegisterProcess(memory_interface);
|
||||||
if (!impl->id_pool.empty()) {
|
if (!impl->id_pool.empty()) {
|
||||||
new_id = impl->id_pool.front();
|
new_id = impl->id_pool.front();
|
||||||
impl->id_pool.pop_front();
|
impl->id_pool.pop_front();
|
||||||
impl->sessions[new_id] = Session{SessionId{new_id}, process, asid};
|
impl->sessions[new_id] = Session{new_id, process, smmu_id};
|
||||||
} else {
|
} else {
|
||||||
new_id = impl->new_ids++;
|
new_id = impl->new_ids++;
|
||||||
impl->sessions.emplace_back(SessionId{new_id}, process, asid);
|
impl->sessions.emplace_back(new_id, process, smmu_id);
|
||||||
}
|
}
|
||||||
auto& session = impl->sessions[new_id];
|
auto& session = impl->sessions[new_id];
|
||||||
session.is_active = true;
|
session.is_active = true;
|
||||||
@ -81,7 +80,7 @@ SessionId Container::OpenSession(Kernel::KProcess* process) {
|
|||||||
cur_addr));
|
cur_addr));
|
||||||
auto svc_mem_info = mem_info.GetSvcMemoryInfo();
|
auto svc_mem_info = mem_info.GetSvcMemoryInfo();
|
||||||
|
|
||||||
// Check if this memory block is heap.
|
// check if this memory block is heap
|
||||||
if (svc_mem_info.state == Kernel::Svc::MemoryState::Normal) {
|
if (svc_mem_info.state == Kernel::Svc::MemoryState::Normal) {
|
||||||
if (svc_mem_info.size > region_size) {
|
if (svc_mem_info.size > region_size) {
|
||||||
region_size = svc_mem_info.size;
|
region_size = svc_mem_info.size;
|
||||||
@ -98,21 +97,21 @@ SessionId Container::OpenSession(Kernel::KProcess* process) {
|
|||||||
cur_addr = next_address;
|
cur_addr = next_address;
|
||||||
}
|
}
|
||||||
session.has_preallocated_area = false;
|
session.has_preallocated_area = false;
|
||||||
auto start_region = region_size >= 32_MiB ? smmu.Allocate(region_size) : 0;
|
auto start_region = (region_size >> 15) >= 1024 ? smmu.Allocate(region_size) : 0;
|
||||||
if (start_region != 0) {
|
if (start_region != 0) {
|
||||||
session.mapper = std::make_unique<HeapMapper>(region_start, start_region, region_size,
|
session.mapper = std::make_unique<HeapMapper>(region_start, start_region, region_size,
|
||||||
asid, impl->host1x);
|
smmu_id, impl->host1x);
|
||||||
smmu.TrackContinuity(start_region, region_start, region_size, asid);
|
smmu.TrackContinuity(start_region, region_start, region_size, smmu_id);
|
||||||
session.has_preallocated_area = true;
|
session.has_preallocated_area = true;
|
||||||
LOG_DEBUG(Debug, "Preallocation created!");
|
LOG_CRITICAL(Debug, "Preallocation created!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return SessionId{new_id};
|
return new_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Container::CloseSession(SessionId session_id) {
|
void Container::CloseSession(size_t id) {
|
||||||
std::scoped_lock lk(impl->session_guard);
|
std::scoped_lock lk(impl->session_guard);
|
||||||
auto& session = impl->sessions[session_id.id];
|
auto& session = impl->sessions[id];
|
||||||
auto& smmu = impl->host1x.MemoryManager();
|
auto& smmu = impl->host1x.MemoryManager();
|
||||||
if (session.has_preallocated_area) {
|
if (session.has_preallocated_area) {
|
||||||
const DAddr region_start = session.mapper->GetRegionStart();
|
const DAddr region_start = session.mapper->GetRegionStart();
|
||||||
@ -122,13 +121,13 @@ void Container::CloseSession(SessionId session_id) {
|
|||||||
session.has_preallocated_area = false;
|
session.has_preallocated_area = false;
|
||||||
}
|
}
|
||||||
session.is_active = false;
|
session.is_active = false;
|
||||||
smmu.UnregisterProcess(impl->sessions[session_id.id].asid);
|
smmu.UnregisterProcess(impl->sessions[id].smmu_id);
|
||||||
impl->id_pool.emplace_front(session_id.id);
|
impl->id_pool.emplace_front(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Session* Container::GetSession(SessionId session_id) {
|
Session* Container::GetSession(size_t id) {
|
||||||
std::atomic_thread_fence(std::memory_order_acquire);
|
std::atomic_thread_fence(std::memory_order_acquire);
|
||||||
return &impl->sessions[session_id.id];
|
return &impl->sessions[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
NvMap& Container::GetNvMapFile() {
|
NvMap& Container::GetNvMapFile() {
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "core/device_memory_manager.h"
|
|
||||||
#include "core/hle/service/nvdrv/nvdata.h"
|
#include "core/hle/service/nvdrv/nvdata.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
@ -27,12 +26,8 @@ class SyncpointManager;
|
|||||||
|
|
||||||
struct ContainerImpl;
|
struct ContainerImpl;
|
||||||
|
|
||||||
struct SessionId {
|
|
||||||
size_t id;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Session {
|
struct Session {
|
||||||
Session(SessionId id_, Kernel::KProcess* process_, Core::Asid asid_);
|
Session(size_t id_, Kernel::KProcess* process_, size_t smmu_id_);
|
||||||
~Session();
|
~Session();
|
||||||
|
|
||||||
Session(const Session&) = delete;
|
Session(const Session&) = delete;
|
||||||
@ -40,9 +35,9 @@ struct Session {
|
|||||||
Session(Session&&) = default;
|
Session(Session&&) = default;
|
||||||
Session& operator=(Session&&) = default;
|
Session& operator=(Session&&) = default;
|
||||||
|
|
||||||
SessionId id;
|
size_t id;
|
||||||
Kernel::KProcess* process;
|
Kernel::KProcess* process;
|
||||||
Core::Asid asid;
|
size_t smmu_id;
|
||||||
bool has_preallocated_area{};
|
bool has_preallocated_area{};
|
||||||
std::unique_ptr<HeapMapper> mapper{};
|
std::unique_ptr<HeapMapper> mapper{};
|
||||||
bool is_active{};
|
bool is_active{};
|
||||||
@ -53,10 +48,10 @@ public:
|
|||||||
explicit Container(Tegra::Host1x::Host1x& host1x);
|
explicit Container(Tegra::Host1x::Host1x& host1x);
|
||||||
~Container();
|
~Container();
|
||||||
|
|
||||||
SessionId OpenSession(Kernel::KProcess* process);
|
size_t OpenSession(Kernel::KProcess* process);
|
||||||
void CloseSession(SessionId id);
|
void CloseSession(size_t id);
|
||||||
|
|
||||||
Session* GetSession(SessionId id);
|
Session* GetSession(size_t id);
|
||||||
|
|
||||||
NvMap& GetNvMapFile();
|
NvMap& GetNvMapFile();
|
||||||
|
|
||||||
|
@ -109,9 +109,9 @@ struct HeapMapper::HeapMapperInternal {
|
|||||||
std::mutex guard;
|
std::mutex guard;
|
||||||
};
|
};
|
||||||
|
|
||||||
HeapMapper::HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size, Core::Asid asid,
|
HeapMapper::HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size, size_t smmu_id,
|
||||||
Tegra::Host1x::Host1x& host1x)
|
Tegra::Host1x::Host1x& host1x)
|
||||||
: m_vaddress{start_vaddress}, m_daddress{start_daddress}, m_size{size}, m_asid{asid} {
|
: m_vaddress{start_vaddress}, m_daddress{start_daddress}, m_size{size}, m_smmu_id{smmu_id} {
|
||||||
m_internal = std::make_unique<HeapMapperInternal>(host1x);
|
m_internal = std::make_unique<HeapMapperInternal>(host1x);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +138,7 @@ DAddr HeapMapper::Map(VAddr start, size_t size) {
|
|||||||
const size_t offset = inter_addr - m_vaddress;
|
const size_t offset = inter_addr - m_vaddress;
|
||||||
const size_t sub_size = inter_addr_end - inter_addr;
|
const size_t sub_size = inter_addr_end - inter_addr;
|
||||||
m_internal->device_memory.Map(m_daddress + offset, m_vaddress + offset, sub_size,
|
m_internal->device_memory.Map(m_daddress + offset, m_vaddress + offset, sub_size,
|
||||||
m_asid);
|
m_smmu_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_internal->mapping_overlaps += std::make_pair(interval, 1);
|
m_internal->mapping_overlaps += std::make_pair(interval, 1);
|
||||||
@ -172,4 +172,4 @@ void HeapMapper::Unmap(VAddr start, size_t size) {
|
|||||||
m_internal->base_set.clear();
|
m_internal->base_set.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::Nvidia::NvCore
|
} // namespace Service::Nvidia::NvCore
|
@ -6,7 +6,6 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/device_memory_manager.h"
|
|
||||||
|
|
||||||
namespace Tegra::Host1x {
|
namespace Tegra::Host1x {
|
||||||
class Host1x;
|
class Host1x;
|
||||||
@ -16,7 +15,7 @@ namespace Service::Nvidia::NvCore {
|
|||||||
|
|
||||||
class HeapMapper {
|
class HeapMapper {
|
||||||
public:
|
public:
|
||||||
HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size, Core::Asid asid,
|
HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size, size_t smmu_id,
|
||||||
Tegra::Host1x::Host1x& host1x);
|
Tegra::Host1x::Host1x& host1x);
|
||||||
~HeapMapper();
|
~HeapMapper();
|
||||||
|
|
||||||
@ -42,8 +41,8 @@ private:
|
|||||||
VAddr m_vaddress;
|
VAddr m_vaddress;
|
||||||
DAddr m_daddress;
|
DAddr m_daddress;
|
||||||
size_t m_size;
|
size_t m_size;
|
||||||
Core::Asid m_asid;
|
size_t m_smmu_id;
|
||||||
std::unique_ptr<HeapMapperInternal> m_internal;
|
std::unique_ptr<HeapMapperInternal> m_internal;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::Nvidia::NvCore
|
} // namespace Service::Nvidia::NvCore
|
@ -22,8 +22,7 @@ NvMap::Handle::Handle(u64 size_, Id id_)
|
|||||||
flags.raw = 0;
|
flags.raw = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress,
|
NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress, size_t pSessionId) {
|
||||||
NvCore::SessionId pSessionId) {
|
|
||||||
std::scoped_lock lock(mutex);
|
std::scoped_lock lock(mutex);
|
||||||
// Handles cannot be allocated twice
|
// Handles cannot be allocated twice
|
||||||
if (allocated) {
|
if (allocated) {
|
||||||
@ -224,7 +223,7 @@ DAddr NvMap::PinHandle(NvMap::Handle::Id handle, bool low_area_pin) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handle_description->d_address = address;
|
handle_description->d_address = address;
|
||||||
smmu.Map(address, vaddress, map_size, session->asid, true);
|
smmu.Map(address, vaddress, map_size, session->smmu_id, true);
|
||||||
handle_description->in_heap = false;
|
handle_description->in_heap = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
#include "common/bit_field.h"
|
#include "common/bit_field.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/hle/service/nvdrv/core/container.h"
|
|
||||||
#include "core/hle/service/nvdrv/nvdata.h"
|
#include "core/hle/service/nvdrv/nvdata.h"
|
||||||
|
|
||||||
namespace Tegra {
|
namespace Tegra {
|
||||||
@ -72,7 +71,7 @@ public:
|
|||||||
u8 kind{}; //!< Used for memory compression
|
u8 kind{}; //!< Used for memory compression
|
||||||
bool allocated{}; //!< If the handle has been allocated with `Alloc`
|
bool allocated{}; //!< If the handle has been allocated with `Alloc`
|
||||||
bool in_heap{};
|
bool in_heap{};
|
||||||
NvCore::SessionId session_id{};
|
size_t session_id{};
|
||||||
|
|
||||||
DAddr d_address{}; //!< The memory location in the device's AS that this handle corresponds
|
DAddr d_address{}; //!< The memory location in the device's AS that this handle corresponds
|
||||||
//!< to, this can also be in the nvdrv tmem
|
//!< to, this can also be in the nvdrv tmem
|
||||||
@ -84,7 +83,7 @@ public:
|
|||||||
* if a 0 address is passed
|
* if a 0 address is passed
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] NvResult Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress,
|
[[nodiscard]] NvResult Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress,
|
||||||
NvCore::SessionId pSessionId);
|
size_t pSessionId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Increases the dupe counter of the handle for the given session
|
* @brief Increases the dupe counter of the handle for the given session
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/hle/service/nvdrv/core/container.h"
|
|
||||||
#include "core/hle/service/nvdrv/nvdata.h"
|
#include "core/hle/service/nvdrv/nvdata.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
@ -63,7 +62,7 @@ public:
|
|||||||
* Called once a device is opened
|
* Called once a device is opened
|
||||||
* @param fd The device fd
|
* @param fd The device fd
|
||||||
*/
|
*/
|
||||||
virtual void OnOpen(NvCore::SessionId session_id, DeviceFD fd) = 0;
|
virtual void OnOpen(size_t session_id, DeviceFD fd) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called once a device is closed
|
* Called once a device is closed
|
||||||
|
@ -35,7 +35,7 @@ NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in
|
|||||||
return NvResult::NotImplemented;
|
return NvResult::NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nvdisp_disp0::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {}
|
void nvdisp_disp0::OnOpen(size_t session_id, DeviceFD fd) {}
|
||||||
void nvdisp_disp0::OnClose(DeviceFD fd) {}
|
void nvdisp_disp0::OnClose(DeviceFD fd) {}
|
||||||
|
|
||||||
void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width,
|
void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width,
|
||||||
|
@ -32,7 +32,7 @@ public:
|
|||||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
||||||
std::span<u8> inline_output) override;
|
std::span<u8> inline_output) override;
|
||||||
|
|
||||||
void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override;
|
void OnOpen(size_t session_id, DeviceFD fd) override;
|
||||||
void OnClose(DeviceFD fd) override;
|
void OnClose(DeviceFD fd) override;
|
||||||
|
|
||||||
/// Performs a screen flip, drawing the buffer pointed to by the handle.
|
/// Performs a screen flip, drawing the buffer pointed to by the handle.
|
||||||
|
@ -86,7 +86,7 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> i
|
|||||||
return NvResult::NotImplemented;
|
return NvResult::NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nvhost_as_gpu::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {}
|
void nvhost_as_gpu::OnOpen(size_t session_id, DeviceFD fd) {}
|
||||||
void nvhost_as_gpu::OnClose(DeviceFD fd) {}
|
void nvhost_as_gpu::OnClose(DeviceFD fd) {}
|
||||||
|
|
||||||
NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) {
|
NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) {
|
||||||
|
@ -55,7 +55,7 @@ public:
|
|||||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
||||||
std::span<u8> inline_output) override;
|
std::span<u8> inline_output) override;
|
||||||
|
|
||||||
void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override;
|
void OnOpen(size_t session_id, DeviceFD fd) override;
|
||||||
void OnClose(DeviceFD fd) override;
|
void OnClose(DeviceFD fd) override;
|
||||||
|
|
||||||
Kernel::KEvent* QueryEvent(u32 event_id) override;
|
Kernel::KEvent* QueryEvent(u32 event_id) override;
|
||||||
|
@ -76,7 +76,7 @@ NvResult nvhost_ctrl::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inp
|
|||||||
return NvResult::NotImplemented;
|
return NvResult::NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nvhost_ctrl::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {}
|
void nvhost_ctrl::OnOpen(size_t session_id, DeviceFD fd) {}
|
||||||
|
|
||||||
void nvhost_ctrl::OnClose(DeviceFD fd) {}
|
void nvhost_ctrl::OnClose(DeviceFD fd) {}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ public:
|
|||||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
||||||
std::span<u8> inline_output) override;
|
std::span<u8> inline_output) override;
|
||||||
|
|
||||||
void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override;
|
void OnOpen(size_t session_id, DeviceFD fd) override;
|
||||||
void OnClose(DeviceFD fd) override;
|
void OnClose(DeviceFD fd) override;
|
||||||
|
|
||||||
Kernel::KEvent* QueryEvent(u32 event_id) override;
|
Kernel::KEvent* QueryEvent(u32 event_id) override;
|
||||||
|
@ -82,7 +82,7 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8>
|
|||||||
return NvResult::NotImplemented;
|
return NvResult::NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nvhost_ctrl_gpu::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {}
|
void nvhost_ctrl_gpu::OnOpen(size_t session_id, DeviceFD fd) {}
|
||||||
void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {}
|
void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {}
|
||||||
|
|
||||||
NvResult nvhost_ctrl_gpu::GetCharacteristics1(IoctlCharacteristics& params) {
|
NvResult nvhost_ctrl_gpu::GetCharacteristics1(IoctlCharacteristics& params) {
|
||||||
|
@ -28,7 +28,7 @@ public:
|
|||||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
||||||
std::span<u8> inline_output) override;
|
std::span<u8> inline_output) override;
|
||||||
|
|
||||||
void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override;
|
void OnOpen(size_t session_id, DeviceFD fd) override;
|
||||||
void OnClose(DeviceFD fd) override;
|
void OnClose(DeviceFD fd) override;
|
||||||
|
|
||||||
Kernel::KEvent* QueryEvent(u32 event_id) override;
|
Kernel::KEvent* QueryEvent(u32 event_id) override;
|
||||||
|
@ -120,7 +120,7 @@ NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inpu
|
|||||||
return NvResult::NotImplemented;
|
return NvResult::NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nvhost_gpu::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {}
|
void nvhost_gpu::OnOpen(size_t session_id, DeviceFD fd) {}
|
||||||
void nvhost_gpu::OnClose(DeviceFD fd) {}
|
void nvhost_gpu::OnClose(DeviceFD fd) {}
|
||||||
|
|
||||||
NvResult nvhost_gpu::SetNVMAPfd(IoctlSetNvmapFD& params) {
|
NvResult nvhost_gpu::SetNVMAPfd(IoctlSetNvmapFD& params) {
|
||||||
|
@ -47,7 +47,7 @@ public:
|
|||||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
||||||
std::span<u8> inline_output) override;
|
std::span<u8> inline_output) override;
|
||||||
|
|
||||||
void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override;
|
void OnOpen(size_t session_id, DeviceFD fd) override;
|
||||||
void OnClose(DeviceFD fd) override;
|
void OnClose(DeviceFD fd) override;
|
||||||
|
|
||||||
Kernel::KEvent* QueryEvent(u32 event_id) override;
|
Kernel::KEvent* QueryEvent(u32 event_id) override;
|
||||||
|
@ -68,7 +68,7 @@ NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in
|
|||||||
return NvResult::NotImplemented;
|
return NvResult::NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nvhost_nvdec::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {
|
void nvhost_nvdec::OnOpen(size_t session_id, DeviceFD fd) {
|
||||||
LOG_INFO(Service_NVDRV, "NVDEC video stream started");
|
LOG_INFO(Service_NVDRV, "NVDEC video stream started");
|
||||||
system.SetNVDECActive(true);
|
system.SetNVDECActive(true);
|
||||||
sessions[fd] = session_id;
|
sessions[fd] = session_id;
|
||||||
|
@ -20,7 +20,7 @@ public:
|
|||||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
||||||
std::span<u8> inline_output) override;
|
std::span<u8> inline_output) override;
|
||||||
|
|
||||||
void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override;
|
void OnOpen(size_t session_id, DeviceFD fd) override;
|
||||||
void OnClose(DeviceFD fd) override;
|
void OnClose(DeviceFD fd) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -127,7 +127,7 @@ protected:
|
|||||||
NvCore::NvMap& nvmap;
|
NvCore::NvMap& nvmap;
|
||||||
NvCore::ChannelType channel_type;
|
NvCore::ChannelType channel_type;
|
||||||
std::array<u32, MaxSyncPoints> device_syncpoints{};
|
std::array<u32, MaxSyncPoints> device_syncpoints{};
|
||||||
std::unordered_map<DeviceFD, NvCore::SessionId> sessions;
|
std::unordered_map<DeviceFD, size_t> sessions;
|
||||||
};
|
};
|
||||||
}; // namespace Devices
|
}; // namespace Devices
|
||||||
} // namespace Service::Nvidia
|
} // namespace Service::Nvidia
|
||||||
|
@ -44,7 +44,7 @@ NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in
|
|||||||
return NvResult::NotImplemented;
|
return NvResult::NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nvhost_nvjpg::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {}
|
void nvhost_nvjpg::OnOpen(size_t session_id, DeviceFD fd) {}
|
||||||
void nvhost_nvjpg::OnClose(DeviceFD fd) {}
|
void nvhost_nvjpg::OnClose(DeviceFD fd) {}
|
||||||
|
|
||||||
NvResult nvhost_nvjpg::SetNVMAPfd(IoctlSetNvmapFD& params) {
|
NvResult nvhost_nvjpg::SetNVMAPfd(IoctlSetNvmapFD& params) {
|
||||||
|
@ -22,7 +22,7 @@ public:
|
|||||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
||||||
std::span<u8> inline_output) override;
|
std::span<u8> inline_output) override;
|
||||||
|
|
||||||
void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override;
|
void OnOpen(size_t session_id, DeviceFD fd) override;
|
||||||
void OnClose(DeviceFD fd) override;
|
void OnClose(DeviceFD fd) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -68,7 +68,7 @@ NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inpu
|
|||||||
return NvResult::NotImplemented;
|
return NvResult::NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nvhost_vic::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {
|
void nvhost_vic::OnOpen(size_t session_id, DeviceFD fd) {
|
||||||
sessions[fd] = session_id;
|
sessions[fd] = session_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +78,10 @@ void nvhost_vic::OnClose(DeviceFD fd) {
|
|||||||
if (iter != host1x_file.fd_to_id.end()) {
|
if (iter != host1x_file.fd_to_id.end()) {
|
||||||
system.GPU().ClearCdmaInstance(iter->second);
|
system.GPU().ClearCdmaInstance(iter->second);
|
||||||
}
|
}
|
||||||
sessions.erase(fd);
|
auto it = sessions.find(fd);
|
||||||
|
if (it != sessions.end()) {
|
||||||
|
sessions.erase(it);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::Nvidia::Devices
|
} // namespace Service::Nvidia::Devices
|
||||||
|
@ -19,7 +19,7 @@ public:
|
|||||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
||||||
std::span<u8> inline_output) override;
|
std::span<u8> inline_output) override;
|
||||||
|
|
||||||
void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override;
|
void OnOpen(size_t session_id, DeviceFD fd) override;
|
||||||
void OnClose(DeviceFD fd) override;
|
void OnClose(DeviceFD fd) override;
|
||||||
};
|
};
|
||||||
} // namespace Service::Nvidia::Devices
|
} // namespace Service::Nvidia::Devices
|
||||||
|
@ -67,7 +67,7 @@ NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, st
|
|||||||
return NvResult::NotImplemented;
|
return NvResult::NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nvmap::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {
|
void nvmap::OnOpen(size_t session_id, DeviceFD fd) {
|
||||||
sessions[fd] = session_id;
|
sessions[fd] = session_id;
|
||||||
}
|
}
|
||||||
void nvmap::OnClose(DeviceFD fd) {
|
void nvmap::OnClose(DeviceFD fd) {
|
||||||
|
@ -33,7 +33,7 @@ public:
|
|||||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
||||||
std::span<u8> inline_output) override;
|
std::span<u8> inline_output) override;
|
||||||
|
|
||||||
void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override;
|
void OnOpen(size_t session_id, DeviceFD fd) override;
|
||||||
void OnClose(DeviceFD fd) override;
|
void OnClose(DeviceFD fd) override;
|
||||||
|
|
||||||
enum class HandleParameterType : u32_le {
|
enum class HandleParameterType : u32_le {
|
||||||
@ -115,7 +115,7 @@ private:
|
|||||||
|
|
||||||
NvCore::Container& container;
|
NvCore::Container& container;
|
||||||
NvCore::NvMap& file;
|
NvCore::NvMap& file;
|
||||||
std::unordered_map<DeviceFD, NvCore::SessionId> sessions;
|
std::unordered_map<DeviceFD, size_t> sessions;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::Nvidia::Devices
|
} // namespace Service::Nvidia::Devices
|
||||||
|
@ -52,15 +52,15 @@ void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) {
|
|||||||
return std::make_shared<NVDRV>(system, module, "nvdrv:a");
|
return std::make_shared<NVDRV>(system, module, "nvdrv:a");
|
||||||
};
|
};
|
||||||
const auto NvdrvInterfaceFactoryForSysmodules = [&, module] {
|
const auto NvdrvInterfaceFactoryForSysmodules = [&, module] {
|
||||||
return std::make_shared<NVDRV>(system, module, "nvdrv:s");
|
return std::make_shared<NVDRV>(system, module, "nvdrv:a");
|
||||||
};
|
};
|
||||||
const auto NvdrvInterfaceFactoryForTesting = [&, module] {
|
const auto NvdrvInterfaceFactory = [&, module] {
|
||||||
return std::make_shared<NVDRV>(system, module, "nvdrv:t");
|
return std::make_shared<NVDRV>(system, module, "nvdrv:t");
|
||||||
};
|
};
|
||||||
server_manager->RegisterNamedService("nvdrv", NvdrvInterfaceFactoryForApplication);
|
server_manager->RegisterNamedService("nvdrv", NvdrvInterfaceFactoryForApplication);
|
||||||
server_manager->RegisterNamedService("nvdrv:a", NvdrvInterfaceFactoryForApplets);
|
server_manager->RegisterNamedService("nvdrv:a", NvdrvInterfaceFactoryForApplets);
|
||||||
server_manager->RegisterNamedService("nvdrv:s", NvdrvInterfaceFactoryForSysmodules);
|
server_manager->RegisterNamedService("nvdrv:s", NvdrvInterfaceFactoryForSysmodules);
|
||||||
server_manager->RegisterNamedService("nvdrv:t", NvdrvInterfaceFactoryForTesting);
|
server_manager->RegisterNamedService("nvdrv:t", NvdrvInterfaceFactory);
|
||||||
server_manager->RegisterNamedService("nvmemp", std::make_shared<NVMEMP>(system));
|
server_manager->RegisterNamedService("nvmemp", std::make_shared<NVMEMP>(system));
|
||||||
nvnflinger.SetNVDrvInstance(module);
|
nvnflinger.SetNVDrvInstance(module);
|
||||||
ServerManager::RunServer(std::move(server_manager));
|
ServerManager::RunServer(std::move(server_manager));
|
||||||
@ -122,7 +122,7 @@ NvResult Module::VerifyFD(DeviceFD fd) const {
|
|||||||
return NvResult::Success;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceFD Module::Open(const std::string& device_name, NvCore::SessionId session_id) {
|
DeviceFD Module::Open(const std::string& device_name, size_t session_id) {
|
||||||
auto it = builders.find(device_name);
|
auto it = builders.find(device_name);
|
||||||
if (it == builders.end()) {
|
if (it == builders.end()) {
|
||||||
LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name);
|
LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name);
|
||||||
|
@ -77,7 +77,7 @@ public:
|
|||||||
NvResult VerifyFD(DeviceFD fd) const;
|
NvResult VerifyFD(DeviceFD fd) const;
|
||||||
|
|
||||||
/// Opens a device node and returns a file descriptor to it.
|
/// Opens a device node and returns a file descriptor to it.
|
||||||
DeviceFD Open(const std::string& device_name, NvCore::SessionId session_id);
|
DeviceFD Open(const std::string& device_name, size_t session_id);
|
||||||
|
|
||||||
/// Sends an ioctl command to the specified file descriptor.
|
/// Sends an ioctl command to the specified file descriptor.
|
||||||
NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output);
|
NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output);
|
||||||
|
@ -35,7 +35,7 @@ private:
|
|||||||
|
|
||||||
u64 pid{};
|
u64 pid{};
|
||||||
bool is_initialized{};
|
bool is_initialized{};
|
||||||
NvCore::SessionId session_id{};
|
size_t session_id{};
|
||||||
Common::ScratchBuffer<u8> output_buffer;
|
Common::ScratchBuffer<u8> output_buffer;
|
||||||
Common::ScratchBuffer<u8> inline_output_buffer;
|
Common::ScratchBuffer<u8> inline_output_buffer;
|
||||||
};
|
};
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/math_util.h"
|
#include "common/math_util.h"
|
||||||
#include "core/hle/service/nvdrv/core/container.h"
|
|
||||||
#include "core/hle/service/nvdrv/nvdata.h"
|
#include "core/hle/service/nvdrv/nvdata.h"
|
||||||
#include "core/hle/service/nvnflinger/nvnflinger.h"
|
#include "core/hle/service/nvnflinger/nvnflinger.h"
|
||||||
#include "core/hle/service/nvnflinger/ui/fence.h"
|
#include "core/hle/service/nvnflinger/ui/fence.h"
|
||||||
@ -56,7 +55,7 @@ private:
|
|||||||
u32 m_buffer_nvmap_handle = 0;
|
u32 m_buffer_nvmap_handle = 0;
|
||||||
SharedMemoryPoolLayout m_pool_layout = {};
|
SharedMemoryPoolLayout m_pool_layout = {};
|
||||||
Nvidia::DeviceFD m_nvmap_fd = {};
|
Nvidia::DeviceFD m_nvmap_fd = {};
|
||||||
Nvidia::NvCore::SessionId m_session_id = {};
|
size_t m_session_id = {};
|
||||||
std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group;
|
std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group;
|
||||||
|
|
||||||
std::mutex m_guard;
|
std::mutex m_guard;
|
||||||
|
@ -126,7 +126,7 @@ void Nvnflinger::ShutdownLayers() {
|
|||||||
|
|
||||||
void Nvnflinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
|
void Nvnflinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
|
||||||
nvdrv = std::move(instance);
|
nvdrv = std::move(instance);
|
||||||
disp_fd = nvdrv->Open("/dev/nvdisp_disp0", {});
|
disp_fd = nvdrv->Open("/dev/nvdisp_disp0", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<u64> Nvnflinger::OpenDisplay(std::string_view name) {
|
std::optional<u64> Nvnflinger::OpenDisplay(std::string_view name) {
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -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, {}};
|
||||||
}
|
}
|
||||||
|
@ -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(), {},
|
||||||
process.GetProcessId(), program_id,
|
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,
|
||||||
|
@ -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,11 +94,8 @@ 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);
|
return patch->GetSectionSize();
|
||||||
if (patch->GetPatchMode() == Core::NCE::PatchMode::PreText) {
|
|
||||||
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.
|
|
||||||
auto& patch_segment = codeset.PatchSegment();
|
|
||||||
patch_segment.addr =
|
|
||||||
patch->GetPatchMode() == Core::NCE::PatchMode::PreText ? 0 : image_size;
|
|
||||||
patch_segment.size = static_cast<u32>(patch->GetSectionSize());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh image_size to take account the patch section if it was added by RelocateAndCopy
|
// Update patch section.
|
||||||
image_size = static_cast<u32>(program_image.size());
|
auto& patch_segment = codeset.PatchSegment();
|
||||||
|
patch_segment.addr =
|
||||||
|
patch->GetPatchMode() == Core::NCE::PatchMode::PreText ? 0 : image_size;
|
||||||
|
patch_segment.size = static_cast<u32>(patch->GetSectionSize());
|
||||||
|
|
||||||
|
// Add patch section size to the module size. In PreText mode 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
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include "common/fs/fs.h"
|
#include "common/fs/fs.h"
|
||||||
#include "common/fs/path_util.h"
|
#include "common/fs/path_util.h"
|
||||||
#include "common/logging/log.h"
|
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "common/settings_common.h"
|
#include "common/settings_common.h"
|
||||||
#include "common/settings_enums.h"
|
#include "common/settings_enums.h"
|
||||||
@ -59,19 +58,6 @@ void Config::Initialize(const std::optional<std::string> config_path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Config::WriteToIni() const {
|
void Config::WriteToIni() const {
|
||||||
std::string config_type;
|
|
||||||
switch (type) {
|
|
||||||
case ConfigType::GlobalConfig:
|
|
||||||
config_type = "Global";
|
|
||||||
break;
|
|
||||||
case ConfigType::PerGameConfig:
|
|
||||||
config_type = "Game Specific";
|
|
||||||
break;
|
|
||||||
case ConfigType::InputProfile:
|
|
||||||
config_type = "Input Profile";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
LOG_INFO(Config, "Writing {} configuration to: {}", config_type, config_loc);
|
|
||||||
FILE* fp = nullptr;
|
FILE* fp = nullptr;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
fp = _wfopen(Common::UTF8ToUTF16W(config_loc).data(), L"wb");
|
fp = _wfopen(Common::UTF8ToUTF16W(config_loc).data(), L"wb");
|
||||||
@ -131,10 +117,10 @@ void Config::ReadPlayerValues(const std::size_t player_index) {
|
|||||||
player_prefix.append("player_").append(ToString(player_index)).append("_");
|
player_prefix.append("player_").append(ToString(player_index)).append("_");
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto profile_name = ReadStringSetting(std::string(player_prefix).append("profile_name"));
|
|
||||||
|
|
||||||
auto& player = Settings::values.players.GetValue()[player_index];
|
auto& player = Settings::values.players.GetValue()[player_index];
|
||||||
if (IsCustomConfig()) {
|
if (IsCustomConfig()) {
|
||||||
|
const auto profile_name =
|
||||||
|
ReadStringSetting(std::string(player_prefix).append("profile_name"));
|
||||||
if (profile_name.empty()) {
|
if (profile_name.empty()) {
|
||||||
// Use the global input config
|
// Use the global input config
|
||||||
player = Settings::values.players.GetValue(true)[player_index];
|
player = Settings::values.players.GetValue(true)[player_index];
|
||||||
@ -153,10 +139,6 @@ void Config::ReadPlayerValues(const std::size_t player_index) {
|
|||||||
player.controller_type = controller;
|
player.controller_type = controller;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (global) {
|
|
||||||
auto& player_global = Settings::values.players.GetValue(true)[player_index];
|
|
||||||
player_global.profile_name = profile_name;
|
|
||||||
}
|
|
||||||
std::string connected_key = player_prefix;
|
std::string connected_key = player_prefix;
|
||||||
player.connected = ReadBooleanSetting(connected_key.append("connected"),
|
player.connected = ReadBooleanSetting(connected_key.append("connected"),
|
||||||
std::make_optional(player_index == 0));
|
std::make_optional(player_index == 0));
|
||||||
@ -430,11 +412,6 @@ void Config::SavePlayerValues(const std::size_t player_index) {
|
|||||||
std::make_optional(static_cast<u8>(Settings::ControllerType::ProController)));
|
std::make_optional(static_cast<u8>(Settings::ControllerType::ProController)));
|
||||||
|
|
||||||
if (!player_prefix.empty() || !Settings::IsConfiguringGlobal()) {
|
if (!player_prefix.empty() || !Settings::IsConfiguringGlobal()) {
|
||||||
if (global) {
|
|
||||||
const auto& player_global = Settings::values.players.GetValue(true)[player_index];
|
|
||||||
WriteStringSetting(std::string(player_prefix).append("profile_name"),
|
|
||||||
player_global.profile_name, std::make_optional(std::string("")));
|
|
||||||
}
|
|
||||||
WriteBooleanSetting(std::string(player_prefix).append("connected"), player.connected,
|
WriteBooleanSetting(std::string(player_prefix).append("connected"), player.connected,
|
||||||
std::make_optional(player_index == 0));
|
std::make_optional(player_index == 0));
|
||||||
WriteIntegerSetting(std::string(player_prefix).append("vibration_enabled"),
|
WriteIntegerSetting(std::string(player_prefix).append("vibration_enabled"),
|
||||||
@ -491,15 +468,12 @@ void Config::SaveMotionTouchValues() {
|
|||||||
|
|
||||||
void Config::SaveValues() {
|
void Config::SaveValues() {
|
||||||
if (global) {
|
if (global) {
|
||||||
LOG_DEBUG(Config, "Saving global generic configuration values");
|
|
||||||
SaveDataStorageValues();
|
SaveDataStorageValues();
|
||||||
SaveDebuggingValues();
|
SaveDebuggingValues();
|
||||||
SaveDisabledAddOnValues();
|
SaveDisabledAddOnValues();
|
||||||
SaveNetworkValues();
|
SaveNetworkValues();
|
||||||
SaveWebServiceValues();
|
SaveWebServiceValues();
|
||||||
SaveMiscellaneousValues();
|
SaveMiscellaneousValues();
|
||||||
} else {
|
|
||||||
LOG_DEBUG(Config, "Saving only generic configuration values");
|
|
||||||
}
|
}
|
||||||
SaveControlValues();
|
SaveControlValues();
|
||||||
SaveCoreValues();
|
SaveCoreValues();
|
||||||
@ -840,6 +814,10 @@ void Config::Reload() {
|
|||||||
SaveValues();
|
SaveValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Config::Save() {
|
||||||
|
SaveValues();
|
||||||
|
}
|
||||||
|
|
||||||
void Config::ClearControlPlayerValues() const {
|
void Config::ClearControlPlayerValues() const {
|
||||||
// If key is an empty string, all keys in the current group() are removed.
|
// If key is an empty string, all keys in the current group() are removed.
|
||||||
const char* section = Settings::TranslateCategory(Settings::Category::Controls);
|
const char* section = Settings::TranslateCategory(Settings::Category::Controls);
|
||||||
|
@ -51,6 +51,7 @@ protected:
|
|||||||
[[nodiscard]] bool IsCustomConfig() const;
|
[[nodiscard]] bool IsCustomConfig() const;
|
||||||
|
|
||||||
void Reload();
|
void Reload();
|
||||||
|
void Save();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Derived config classes must implement this so they can reload all platform-specific
|
* Derived config classes must implement this so they can reload all platform-specific
|
||||||
|
@ -509,11 +509,11 @@ void EmulatedController::ReloadInput() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
turbo_button_state = 0;
|
turbo_button_state = 0;
|
||||||
is_initialized = true;
|
is_initalized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmulatedController::UnloadInput() {
|
void EmulatedController::UnloadInput() {
|
||||||
is_initialized = false;
|
is_initalized = false;
|
||||||
for (auto& button : button_devices) {
|
for (auto& button : button_devices) {
|
||||||
button.reset();
|
button.reset();
|
||||||
}
|
}
|
||||||
@ -1209,7 +1209,7 @@ void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) {
|
bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) {
|
||||||
if (!is_initialized) {
|
if (!is_initalized) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (device_index >= output_devices.size()) {
|
if (device_index >= output_devices.size()) {
|
||||||
@ -1247,7 +1247,7 @@ bool EmulatedController::IsVibrationEnabled(std::size_t device_index) {
|
|||||||
const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type);
|
const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type);
|
||||||
const auto& player = Settings::values.players.GetValue()[player_index];
|
const auto& player = Settings::values.players.GetValue()[player_index];
|
||||||
|
|
||||||
if (!is_initialized) {
|
if (!is_initalized) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1270,7 +1270,7 @@ Common::Input::DriverResult EmulatedController::SetPollingMode(
|
|||||||
EmulatedDeviceIndex device_index, Common::Input::PollingMode polling_mode) {
|
EmulatedDeviceIndex device_index, Common::Input::PollingMode polling_mode) {
|
||||||
LOG_INFO(Service_HID, "Set polling mode {}, device_index={}", polling_mode, device_index);
|
LOG_INFO(Service_HID, "Set polling mode {}, device_index={}", polling_mode, device_index);
|
||||||
|
|
||||||
if (!is_initialized) {
|
if (!is_initalized) {
|
||||||
return Common::Input::DriverResult::InvalidHandle;
|
return Common::Input::DriverResult::InvalidHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1319,7 +1319,7 @@ bool EmulatedController::SetCameraFormat(
|
|||||||
Core::IrSensor::ImageTransferProcessorFormat camera_format) {
|
Core::IrSensor::ImageTransferProcessorFormat camera_format) {
|
||||||
LOG_INFO(Service_HID, "Set camera format {}", camera_format);
|
LOG_INFO(Service_HID, "Set camera format {}", camera_format);
|
||||||
|
|
||||||
if (!is_initialized) {
|
if (!is_initalized) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1347,7 +1347,7 @@ void EmulatedController::SetRingParam(Common::ParamPackage param) {
|
|||||||
|
|
||||||
bool EmulatedController::HasNfc() const {
|
bool EmulatedController::HasNfc() const {
|
||||||
|
|
||||||
if (!is_initialized) {
|
if (!is_initalized) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1388,7 +1388,7 @@ bool EmulatedController::RemoveNfcHandle() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool EmulatedController::StartNfcPolling() {
|
bool EmulatedController::StartNfcPolling() {
|
||||||
if (!is_initialized) {
|
if (!is_initalized) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1403,7 +1403,7 @@ bool EmulatedController::StartNfcPolling() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool EmulatedController::StopNfcPolling() {
|
bool EmulatedController::StopNfcPolling() {
|
||||||
if (!is_initialized) {
|
if (!is_initalized) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1418,7 +1418,7 @@ bool EmulatedController::StopNfcPolling() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool EmulatedController::ReadAmiiboData(std::vector<u8>& data) {
|
bool EmulatedController::ReadAmiiboData(std::vector<u8>& data) {
|
||||||
if (!is_initialized) {
|
if (!is_initalized) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1434,7 +1434,7 @@ bool EmulatedController::ReadAmiiboData(std::vector<u8>& data) {
|
|||||||
|
|
||||||
bool EmulatedController::ReadMifareData(const Common::Input::MifareRequest& request,
|
bool EmulatedController::ReadMifareData(const Common::Input::MifareRequest& request,
|
||||||
Common::Input::MifareRequest& out_data) {
|
Common::Input::MifareRequest& out_data) {
|
||||||
if (!is_initialized) {
|
if (!is_initalized) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1450,7 +1450,7 @@ bool EmulatedController::ReadMifareData(const Common::Input::MifareRequest& requ
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool EmulatedController::WriteMifareData(const Common::Input::MifareRequest& request) {
|
bool EmulatedController::WriteMifareData(const Common::Input::MifareRequest& request) {
|
||||||
if (!is_initialized) {
|
if (!is_initalized) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1465,7 +1465,7 @@ bool EmulatedController::WriteMifareData(const Common::Input::MifareRequest& req
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool EmulatedController::WriteNfc(const std::vector<u8>& data) {
|
bool EmulatedController::WriteNfc(const std::vector<u8>& data) {
|
||||||
if (!is_initialized) {
|
if (!is_initalized) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1480,7 +1480,7 @@ bool EmulatedController::WriteNfc(const std::vector<u8>& data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EmulatedController::SetLedPattern() {
|
void EmulatedController::SetLedPattern() {
|
||||||
if (!is_initialized) {
|
if (!is_initalized) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1508,8 +1508,8 @@ void EmulatedController::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode mode)
|
|||||||
motion.emulated.SetGyroThreshold(motion.emulated.ThresholdLoose);
|
motion.emulated.SetGyroThreshold(motion.emulated.ThresholdLoose);
|
||||||
break;
|
break;
|
||||||
case GyroscopeZeroDriftMode::Tight:
|
case GyroscopeZeroDriftMode::Tight:
|
||||||
motion_sensitivity = motion.emulated.IsAtRestTight;
|
motion_sensitivity = motion.emulated.IsAtRestThight;
|
||||||
motion.emulated.SetGyroThreshold(motion.emulated.ThresholdTight);
|
motion.emulated.SetGyroThreshold(motion.emulated.ThresholdThight);
|
||||||
break;
|
break;
|
||||||
case GyroscopeZeroDriftMode::Standard:
|
case GyroscopeZeroDriftMode::Standard:
|
||||||
default:
|
default:
|
||||||
|
@ -559,7 +559,7 @@ private:
|
|||||||
NpadStyleTag supported_style_tag{NpadStyleSet::All};
|
NpadStyleTag supported_style_tag{NpadStyleSet::All};
|
||||||
bool is_connected{false};
|
bool is_connected{false};
|
||||||
bool is_configuring{false};
|
bool is_configuring{false};
|
||||||
bool is_initialized{false};
|
bool is_initalized{false};
|
||||||
bool system_buttons_enabled{true};
|
bool system_buttons_enabled{true};
|
||||||
f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard};
|
f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard};
|
||||||
u32 turbo_button_state{0};
|
u32 turbo_button_state{0};
|
||||||
|
@ -13,12 +13,12 @@ class MotionInput {
|
|||||||
public:
|
public:
|
||||||
static constexpr float ThresholdLoose = 0.01f;
|
static constexpr float ThresholdLoose = 0.01f;
|
||||||
static constexpr float ThresholdStandard = 0.007f;
|
static constexpr float ThresholdStandard = 0.007f;
|
||||||
static constexpr float ThresholdTight = 0.002f;
|
static constexpr float ThresholdThight = 0.002f;
|
||||||
|
|
||||||
static constexpr float IsAtRestRelaxed = 0.05f;
|
static constexpr float IsAtRestRelaxed = 0.05f;
|
||||||
static constexpr float IsAtRestLoose = 0.02f;
|
static constexpr float IsAtRestLoose = 0.02f;
|
||||||
static constexpr float IsAtRestStandard = 0.01f;
|
static constexpr float IsAtRestStandard = 0.01f;
|
||||||
static constexpr float IsAtRestTight = 0.005f;
|
static constexpr float IsAtRestThight = 0.005f;
|
||||||
|
|
||||||
static constexpr float GyroMaxValue = 5.0f;
|
static constexpr float GyroMaxValue = 5.0f;
|
||||||
static constexpr float AccelMaxValue = 7.0f;
|
static constexpr float AccelMaxValue = 7.0f;
|
||||||
|
@ -15,7 +15,7 @@ constexpr Result ResultVibrationNotInitialized{ErrorModule::HID, 121};
|
|||||||
constexpr Result ResultVibrationInvalidStyleIndex{ErrorModule::HID, 122};
|
constexpr Result ResultVibrationInvalidStyleIndex{ErrorModule::HID, 122};
|
||||||
constexpr Result ResultVibrationInvalidNpadId{ErrorModule::HID, 123};
|
constexpr Result ResultVibrationInvalidNpadId{ErrorModule::HID, 123};
|
||||||
constexpr Result ResultVibrationDeviceIndexOutOfRange{ErrorModule::HID, 124};
|
constexpr Result ResultVibrationDeviceIndexOutOfRange{ErrorModule::HID, 124};
|
||||||
constexpr Result ResultVibrationStrengthOutOfRange{ErrorModule::HID, 126};
|
constexpr Result ResultVibrationStrenghtOutOfRange{ErrorModule::HID, 126};
|
||||||
constexpr Result ResultVibrationArraySizeMismatch{ErrorModule::HID, 131};
|
constexpr Result ResultVibrationArraySizeMismatch{ErrorModule::HID, 131};
|
||||||
|
|
||||||
constexpr Result InvalidSixAxisFusionRange{ErrorModule::HID, 423};
|
constexpr Result InvalidSixAxisFusionRange{ErrorModule::HID, 423};
|
||||||
|
@ -106,8 +106,8 @@ enum class HandAnalysisMode : u32 {
|
|||||||
None,
|
None,
|
||||||
Silhouette,
|
Silhouette,
|
||||||
Image,
|
Image,
|
||||||
SilhouetteAndImage,
|
SilhoueteAndImage,
|
||||||
SilhouetteOnly,
|
SilhuetteOnly,
|
||||||
};
|
};
|
||||||
|
|
||||||
// This is nn::irsensor::IrSensorFunctionLevel
|
// This is nn::irsensor::IrSensorFunctionLevel
|
||||||
|
@ -14,7 +14,7 @@ void HidFirmwareSettings::Reload() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HidFirmwareSettings::LoadSettings(bool reload_config) {
|
void HidFirmwareSettings::LoadSettings(bool reload_config) {
|
||||||
if (is_initialized && !reload_config) {
|
if (is_initalized && !reload_config) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ void HidFirmwareSettings::LoadSettings(bool reload_config) {
|
|||||||
is_handheld_forced = true;
|
is_handheld_forced = true;
|
||||||
features_per_id_disabled = {};
|
features_per_id_disabled = {};
|
||||||
is_touch_firmware_auto_update_disabled = false;
|
is_touch_firmware_auto_update_disabled = false;
|
||||||
is_initialized = true;
|
is_initalized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HidFirmwareSettings::IsDebugPadEnabled() {
|
bool HidFirmwareSettings::IsDebugPadEnabled() {
|
||||||
|
@ -33,7 +33,7 @@ public:
|
|||||||
FeaturesPerId FeaturesDisabledPerId();
|
FeaturesPerId FeaturesDisabledPerId();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool is_initialized{};
|
bool is_initalized{};
|
||||||
|
|
||||||
// Debug settings
|
// Debug settings
|
||||||
bool is_debug_pad_enabled{};
|
bool is_debug_pad_enabled{};
|
||||||
|
@ -318,7 +318,7 @@ struct InternalFlags {
|
|||||||
BitField<1, 1, u32> is_connected;
|
BitField<1, 1, u32> is_connected;
|
||||||
BitField<2, 1, u32> is_battery_low_ovln_required;
|
BitField<2, 1, u32> is_battery_low_ovln_required;
|
||||||
BitField<3, 1, u32> is_battery_low_ovln_delay_required;
|
BitField<3, 1, u32> is_battery_low_ovln_delay_required;
|
||||||
BitField<4, 1, u32> is_sample_received;
|
BitField<4, 1, u32> is_sample_recieved;
|
||||||
BitField<5, 1, u32> is_virtual_input;
|
BitField<5, 1, u32> is_virtual_input;
|
||||||
BitField<6, 1, u32> is_wired;
|
BitField<6, 1, u32> is_wired;
|
||||||
BitField<8, 1, u32> use_center_clamp;
|
BitField<8, 1, u32> use_center_clamp;
|
||||||
|
@ -15,7 +15,7 @@ Result NpadVibration::Activate() {
|
|||||||
|
|
||||||
const f32 master_volume = 1.0f; // nn::settings::system::GetVibrationMasterVolume();
|
const f32 master_volume = 1.0f; // nn::settings::system::GetVibrationMasterVolume();
|
||||||
// if (master_volume < 0.0f || master_volume > 1.0f) {
|
// if (master_volume < 0.0f || master_volume > 1.0f) {
|
||||||
// return ResultVibrationStrengthOutOfRange;
|
// return ResultVibrationStrenghtOutOfRange;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
volume = master_volume;
|
volume = master_volume;
|
||||||
@ -30,7 +30,7 @@ Result NpadVibration::SetVibrationMasterVolume(f32 master_volume) {
|
|||||||
std::scoped_lock lock{mutex};
|
std::scoped_lock lock{mutex};
|
||||||
|
|
||||||
if (master_volume < 0.0f && master_volume > 1.0f) {
|
if (master_volume < 0.0f && master_volume > 1.0f) {
|
||||||
return ResultVibrationStrengthOutOfRange;
|
return ResultVibrationStrenghtOutOfRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
volume = master_volume;
|
volume = master_volume;
|
||||||
@ -50,7 +50,7 @@ Result NpadVibration::GetVibrationMasterVolume(f32& out_volume) const {
|
|||||||
|
|
||||||
const f32 master_volume = 1.0f; // nn::settings::system::GetVibrationMasterVolume();
|
const f32 master_volume = 1.0f; // nn::settings::system::GetVibrationMasterVolume();
|
||||||
// if (master_volume < 0.0f || master_volume > 1.0f) {
|
// if (master_volume < 0.0f || master_volume > 1.0f) {
|
||||||
// return ResultVibrationStrengthOutOfRange;
|
// return ResultVibrationStrenghtOutOfRange;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
out_volume = master_volume;
|
out_volume = master_volume;
|
||||||
@ -69,7 +69,7 @@ Result NpadVibration::EndPermitVibrationSession() {
|
|||||||
|
|
||||||
const f32 master_volume = 1.0f; // nn::settings::system::GetVibrationMasterVolume();
|
const f32 master_volume = 1.0f; // nn::settings::system::GetVibrationMasterVolume();
|
||||||
// if (master_volume < 0.0f || master_volume > 1.0f) {
|
// if (master_volume < 0.0f || master_volume > 1.0f) {
|
||||||
// return ResultVibrationStrengthOutOfRange;
|
// return ResultVibrationStrenghtOutOfRange;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
volume = master_volume;
|
volume = master_volume;
|
||||||
|
@ -249,7 +249,7 @@ Result SixAxis::EnableSixAxisSensorUnalteredPassthrough(
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto& sixaxis = GetSixaxisState(sixaxis_handle);
|
auto& sixaxis = GetSixaxisState(sixaxis_handle);
|
||||||
sixaxis.unaltered_passthrough = is_enabled;
|
sixaxis.unaltered_passtrough = is_enabled;
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,7 +262,7 @@ Result SixAxis::IsSixAxisSensorUnalteredPassthroughEnabled(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto& sixaxis = GetSixaxisState(sixaxis_handle);
|
const auto& sixaxis = GetSixaxisState(sixaxis_handle);
|
||||||
is_enabled = sixaxis.unaltered_passthrough;
|
is_enabled = sixaxis.unaltered_passtrough;
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ private:
|
|||||||
|
|
||||||
struct SixaxisParameters {
|
struct SixaxisParameters {
|
||||||
bool is_fusion_enabled{true};
|
bool is_fusion_enabled{true};
|
||||||
bool unaltered_passthrough{false};
|
bool unaltered_passtrough{false};
|
||||||
Core::HID::SixAxisSensorFusionParameters fusion{};
|
Core::HID::SixAxisSensorFusionParameters fusion{};
|
||||||
Core::HID::SixAxisSensorCalibrationParameter calibration{};
|
Core::HID::SixAxisSensorCalibrationParameter calibration{};
|
||||||
Core::HID::SixAxisSensorIcInformation ic_information{};
|
Core::HID::SixAxisSensorIcInformation ic_information{};
|
||||||
|
@ -451,11 +451,11 @@ ButtonMapping GCAdapter::GetButtonMappingForDevice(const Common::ParamPackage& p
|
|||||||
std::tuple{Settings::NativeButton::ZL, PadButton::TriggerL, PadAxes::TriggerLeft},
|
std::tuple{Settings::NativeButton::ZL, PadButton::TriggerL, PadAxes::TriggerLeft},
|
||||||
{Settings::NativeButton::ZR, PadButton::TriggerR, PadAxes::TriggerRight},
|
{Settings::NativeButton::ZR, PadButton::TriggerR, PadAxes::TriggerRight},
|
||||||
};
|
};
|
||||||
for (const auto& [switch_button, gcadapter_button, gcadapter_axis] : switch_to_gcadapter_axis) {
|
for (const auto& [switch_button, gcadapter_buton, gcadapter_axis] : switch_to_gcadapter_axis) {
|
||||||
Common::ParamPackage button_params{};
|
Common::ParamPackage button_params{};
|
||||||
button_params.Set("engine", GetEngineName());
|
button_params.Set("engine", GetEngineName());
|
||||||
button_params.Set("port", params.Get("port", 0));
|
button_params.Set("port", params.Get("port", 0));
|
||||||
button_params.Set("button", static_cast<s32>(gcadapter_button));
|
button_params.Set("button", static_cast<s32>(gcadapter_buton));
|
||||||
button_params.Set("axis", static_cast<s32>(gcadapter_axis));
|
button_params.Set("axis", static_cast<s32>(gcadapter_axis));
|
||||||
button_params.Set("threshold", 0.5f);
|
button_params.Set("threshold", 0.5f);
|
||||||
button_params.Set("range", 1.9f);
|
button_params.Set("range", 1.9f);
|
||||||
|
@ -236,9 +236,9 @@ Common::Input::DriverResult IrsProtocol::WriteRegistersStep2() {
|
|||||||
.number_of_registers = 0x8,
|
.number_of_registers = 0x8,
|
||||||
.registers =
|
.registers =
|
||||||
{
|
{
|
||||||
IrsRegister{IrRegistersAddress::LedIntensityMSB,
|
IrsRegister{IrRegistersAddress::LedIntensitiyMSB,
|
||||||
static_cast<u8>(led_intensity >> 8)},
|
static_cast<u8>(led_intensity >> 8)},
|
||||||
{IrRegistersAddress::LedIntensityLSB, static_cast<u8>(led_intensity & 0xff)},
|
{IrRegistersAddress::LedIntensitiyLSB, static_cast<u8>(led_intensity & 0xff)},
|
||||||
{IrRegistersAddress::ImageFlip, static_cast<u8>(image_flip)},
|
{IrRegistersAddress::ImageFlip, static_cast<u8>(image_flip)},
|
||||||
{IrRegistersAddress::DenoiseSmoothing, static_cast<u8>((denoise >> 16) & 0xff)},
|
{IrRegistersAddress::DenoiseSmoothing, static_cast<u8>((denoise >> 16) & 0xff)},
|
||||||
{IrRegistersAddress::DenoiseEdge, static_cast<u8>((denoise >> 8) & 0xff)},
|
{IrRegistersAddress::DenoiseEdge, static_cast<u8>((denoise >> 8) & 0xff)},
|
||||||
|
@ -282,7 +282,7 @@ enum class NFCCommand : u8 {
|
|||||||
CancelAll = 0x00,
|
CancelAll = 0x00,
|
||||||
StartPolling = 0x01,
|
StartPolling = 0x01,
|
||||||
StopPolling = 0x02,
|
StopPolling = 0x02,
|
||||||
StartWaitingReceive = 0x04,
|
StartWaitingRecieve = 0x04,
|
||||||
ReadNtag = 0x06,
|
ReadNtag = 0x06,
|
||||||
WriteNtag = 0x08,
|
WriteNtag = 0x08,
|
||||||
Mifare = 0x0F,
|
Mifare = 0x0F,
|
||||||
@ -382,8 +382,8 @@ enum class IrRegistersAddress : u16 {
|
|||||||
FinalizeConfig = 0x0700,
|
FinalizeConfig = 0x0700,
|
||||||
LedFilter = 0x0e00,
|
LedFilter = 0x0e00,
|
||||||
Leds = 0x1000,
|
Leds = 0x1000,
|
||||||
LedIntensityMSB = 0x1100,
|
LedIntensitiyMSB = 0x1100,
|
||||||
LedIntensityLSB = 0x1200,
|
LedIntensitiyLSB = 0x1200,
|
||||||
ImageFlip = 0x2d00,
|
ImageFlip = 0x2d00,
|
||||||
Resolution = 0x2e00,
|
Resolution = 0x2e00,
|
||||||
DigitalGainLSB = 0x2e01,
|
DigitalGainLSB = 0x2e01,
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user