Compare commits
12 commits
Author | SHA1 | Date | |
---|---|---|---|
|
036416fde7 | ||
|
662470c415 | ||
|
5da5b518c5 | ||
|
acc5668274 | ||
|
1c5281eb0e | ||
|
b0e53d4aad | ||
|
c452cd2bf2 | ||
|
711d4f8824 | ||
|
5149b333d7 | ||
|
4e51d76fa6 | ||
|
a1d90f053a | ||
|
c7de7890b6 |
41 changed files with 694 additions and 367 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -50,6 +50,7 @@ build/
|
|||
# Android Studio
|
||||
.idea/caches
|
||||
.idea/assetWizardSettings.xml
|
||||
.idea/runConfigurations.xml
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
|
4
.gitmodules
vendored
4
.gitmodules
vendored
|
@ -21,3 +21,7 @@
|
|||
path = app/libraries/tzcode
|
||||
url = https://github.com/skyline-emu/tz
|
||||
branch = master
|
||||
[submodule "app/libraries/perfetto"]
|
||||
path = app/libraries/perfetto
|
||||
url = https://android.googlesource.com/platform/external/perfetto
|
||||
branch = releases/v12.x
|
||||
|
|
2
.idea/inspectionProfiles/Project_Default.xml
generated
2
.idea/inspectionProfiles/Project_Default.xml
generated
|
@ -171,7 +171,7 @@
|
|||
</inspection_tool>
|
||||
<inspection_tool class="CheckedExceptionClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ClangTidy" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="clangTidyChecks" value="-*,bugprone-argument-comment,bugprone-assert-side-effect,bugprone-bad-signal-to-kill-thread,bugprone-branch-clone,bugprone-copy-constructor-init,bugprone-dangling-handle,bugprone-dynamic-static-initializers,bugprone-fold-init-type,bugprone-forward-declaration-namespace,bugprone-forwarding-reference-overload,bugprone-inaccurate-erase,bugprone-incorrect-roundings,bugprone-integer-division,bugprone-lambda-function-name,bugprone-macro-parentheses,bugprone-macro-repeated-side-effects,bugprone-misplaced-operator-in-strlen-in-alloc,bugprone-misplaced-pointer-arithmetic-in-alloc,bugprone-misplaced-widening-cast,bugprone-move-forwarding-reference,bugprone-multiple-statement-macro,bugprone-no-escape,bugprone-not-null-terminated-result,bugprone-parent-virtual-call,bugprone-posix-return,bugprone-reserved-identifier,bugprone-sizeof-container,bugprone-sizeof-expression,bugprone-spuriously-wake-up-functions,bugprone-string-constructor,bugprone-string-integer-assignment,bugprone-string-literal-with-embedded-nul,bugprone-suspicious-enum-usage,bugprone-suspicious-include,bugprone-suspicious-memset-usage,bugprone-suspicious-missing-comma,bugprone-suspicious-semicolon,bugprone-suspicious-string-compare,bugprone-swapped-arguments,bugprone-terminating-continue,bugprone-throw-keyword-missing,bugprone-too-small-loop-variable,bugprone-undefined-memory-manipulation,bugprone-undelegated-constructor,bugprone-unhandled-self-assignment,bugprone-unused-raii,bugprone-unused-return-value,bugprone-use-after-move,bugprone-virtual-near-miss,cert-dcl21-cpp,cert-dcl58-cpp,cert-err34-c,cert-err58-cpp,cert-err60-cpp,cert-flp30-c,cert-msc50-cpp,cert-msc51-cpp,cert-str34-c,cppcoreguidelines-interfaces-global-init,cppcoreguidelines-narrowing-conversions,cppcoreguidelines-pro-type-static-cast-downcast,cppcoreguidelines-slicing,google-default-arguments,google-explicit-constructor,google-runtime-operator,hicpp-exception-baseclass,hicpp-multiway-paths-covered,misc-misplaced-const,misc-new-delete-overloads,misc-no-recursion,misc-non-copyable-objects,misc-throw-by-value-catch-by-reference,misc-unconventional-assign-operator,misc-uniqueptr-reset-release,modernize-avoid-bind,modernize-concat-nested-namespaces,modernize-deprecated-ios-base-aliases,modernize-loop-convert,modernize-make-shared,modernize-make-unique,modernize-pass-by-value,modernize-raw-string-literal,modernize-redundant-void-arg,modernize-replace-auto-ptr,modernize-replace-disallow-copy-and-assign-macro,modernize-replace-random-shuffle,modernize-return-braced-init-list,modernize-shrink-to-fit,modernize-unary-static-assert,modernize-use-auto,modernize-use-bool-literals,modernize-use-emplace,modernize-use-equals-default,modernize-use-equals-delete,modernize-use-nodiscard,modernize-use-noexcept,modernize-use-nullptr,modernize-use-override,modernize-use-transparent-functors,modernize-use-uncaught-exceptions,mpi-buffer-deref,mpi-type-mismatch,openmp-use-default-none,performance-faster-string-find,performance-for-range-copy,performance-implicit-conversion-in-loop,performance-inefficient-algorithm,performance-inefficient-string-concatenation,performance-inefficient-vector-operation,performance-move-const-arg,performance-move-constructor-init,performance-no-automatic-move,performance-noexcept-move-constructor,performance-trivially-destructible,performance-type-promotion-in-math-fn,performance-unnecessary-copy-initialization,performance-unnecessary-value-param,portability-simd-intrinsics,readability-avoid-const-params-in-decls,readability-const-return-type,readability-container-size-empty,readability-convert-member-functions-to-static,readability-delete-null-pointer,readability-deleted-default,readability-inconsistent-declaration-parameter-name,readability-make-member-function-const,readability-misleading-indentation,readability-misplaced-array-index,readability-non-const-parameter,readability-redundant-control-flow,readability-redundant-declaration,readability-redundant-function-ptr-dereference,readability-redundant-smartptr-get,readability-redundant-string-cstr,readability-redundant-string-init,readability-simplify-subscript-expr,readability-static-accessed-through-instance,readability-static-definition-in-anonymous-namespace,readability-string-compare,readability-uniqueptr-delete-release,readability-use-anyofallof" />
|
||||
<option name="clangTidyChecks" value="-*,bugprone-argument-comment,bugprone-assert-side-effect,bugprone-bad-signal-to-kill-thread,bugprone-branch-clone,bugprone-copy-constructor-init,bugprone-dangling-handle,bugprone-dynamic-static-initializers,bugprone-fold-init-type,bugprone-forward-declaration-namespace,bugprone-forwarding-reference-overload,bugprone-inaccurate-erase,bugprone-incorrect-roundings,bugprone-integer-division,bugprone-lambda-function-name,bugprone-macro-parentheses,bugprone-macro-repeated-side-effects,bugprone-misplaced-operator-in-strlen-in-alloc,bugprone-misplaced-pointer-arithmetic-in-alloc,bugprone-misplaced-widening-cast,bugprone-move-forwarding-reference,bugprone-multiple-statement-macro,bugprone-no-escape,bugprone-not-null-terminated-result,bugprone-parent-virtual-call,bugprone-posix-return,bugprone-reserved-identifier,bugprone-sizeof-container,bugprone-sizeof-expression,bugprone-spuriously-wake-up-functions,bugprone-string-constructor,bugprone-string-integer-assignment,bugprone-string-literal-with-embedded-nul,bugprone-suspicious-enum-usage,bugprone-suspicious-include,bugprone-suspicious-memset-usage,bugprone-suspicious-missing-comma,bugprone-suspicious-semicolon,bugprone-suspicious-string-compare,bugprone-swapped-arguments,bugprone-terminating-continue,bugprone-throw-keyword-missing,bugprone-too-small-loop-variable,bugprone-undefined-memory-manipulation,bugprone-undelegated-constructor,bugprone-unhandled-self-assignment,bugprone-unused-raii,bugprone-unused-return-value,bugprone-use-after-move,bugprone-virtual-near-miss,cert-dcl21-cpp,cert-dcl58-cpp,cert-err34-c,cert-err52-cpp,cert-err60-cpp,cert-flp30-c,cert-msc50-cpp,cert-msc51-cpp,cert-str34-c,cppcoreguidelines-interfaces-global-init,cppcoreguidelines-narrowing-conversions,cppcoreguidelines-pro-type-static-cast-downcast,cppcoreguidelines-slicing,google-default-arguments,google-explicit-constructor,google-runtime-operator,hicpp-exception-baseclass,hicpp-multiway-paths-covered,misc-misplaced-const,misc-new-delete-overloads,misc-no-recursion,misc-non-copyable-objects,misc-throw-by-value-catch-by-reference,misc-unconventional-assign-operator,misc-uniqueptr-reset-release,modernize-avoid-bind,modernize-concat-nested-namespaces,modernize-deprecated-headers,modernize-deprecated-ios-base-aliases,modernize-loop-convert,modernize-make-shared,modernize-make-unique,modernize-pass-by-value,modernize-raw-string-literal,modernize-redundant-void-arg,modernize-replace-auto-ptr,modernize-replace-disallow-copy-and-assign-macro,modernize-replace-random-shuffle,modernize-return-braced-init-list,modernize-shrink-to-fit,modernize-unary-static-assert,modernize-use-auto,modernize-use-bool-literals,modernize-use-emplace,modernize-use-equals-default,modernize-use-equals-delete,modernize-use-nodiscard,modernize-use-noexcept,modernize-use-nullptr,modernize-use-override,modernize-use-transparent-functors,modernize-use-uncaught-exceptions,mpi-buffer-deref,mpi-type-mismatch,openmp-use-default-none,performance-faster-string-find,performance-for-range-copy,performance-implicit-conversion-in-loop,performance-inefficient-algorithm,performance-inefficient-string-concatenation,performance-inefficient-vector-operation,performance-move-const-arg,performance-move-constructor-init,performance-no-automatic-move,performance-noexcept-move-constructor,performance-trivially-destructible,performance-type-promotion-in-math-fn,performance-unnecessary-copy-initialization,performance-unnecessary-value-param,portability-simd-intrinsics,readability-avoid-const-params-in-decls,readability-const-return-type,readability-container-size-empty,readability-convert-member-functions-to-static,readability-delete-null-pointer,readability-deleted-default,readability-inconsistent-declaration-parameter-name,readability-make-member-function-const,readability-misleading-indentation,readability-misplaced-array-index,readability-non-const-parameter,readability-redundant-control-flow,readability-redundant-declaration,readability-redundant-function-ptr-dereference,readability-redundant-smartptr-get,readability-redundant-string-cstr,readability-redundant-string-init,readability-simplify-subscript-expr,readability-static-accessed-through-instance,readability-static-definition-in-anonymous-namespace,readability-string-compare,readability-uniqueptr-delete-release,readability-use-anyofallof" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="ClassComplexity" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="m_limit" value="80" />
|
||||
|
|
60
.idea/runConfigurations/Main.xml
generated
Normal file
60
.idea/runConfigurations/Main.xml
generated
Normal file
|
@ -0,0 +1,60 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Main" type="AndroidRunConfigurationType" factoryName="Android App" activateToolWindowBeforeRun="false">
|
||||
<module name="skyline.app" />
|
||||
<option name="DEPLOY" value="true" />
|
||||
<option name="DEPLOY_APK_FROM_BUNDLE" value="false" />
|
||||
<option name="DEPLOY_AS_INSTANT" value="false" />
|
||||
<option name="ARTIFACT_NAME" value="" />
|
||||
<option name="PM_INSTALL_OPTIONS" value="" />
|
||||
<option name="ALL_USERS" value="false" />
|
||||
<option name="ALWAYS_INSTALL_WITH_PM" value="false" />
|
||||
<option name="DYNAMIC_FEATURES_DISABLED_LIST" value="" />
|
||||
<option name="ACTIVITY_EXTRA_FLAGS" value="" />
|
||||
<option name="MODE" value="default_activity" />
|
||||
<option name="CLEAR_LOGCAT" value="false" />
|
||||
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
|
||||
<option name="SKIP_NOOP_APK_INSTALLATIONS" value="true" />
|
||||
<option name="FORCE_STOP_RUNNING_APP" value="true" />
|
||||
<option name="TARGET_SELECTION_MODE" value="DEVICE_AND_SNAPSHOT_COMBO_BOX" />
|
||||
<option name="SELECTED_CLOUD_MATRIX_CONFIGURATION_ID" value="-1" />
|
||||
<option name="SELECTED_CLOUD_MATRIX_PROJECT_ID" value="" />
|
||||
<option name="DEBUGGER_TYPE" value="Auto" />
|
||||
<Auto>
|
||||
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||
<option name="SHOW_STATIC_VARS" value="true" />
|
||||
<option name="WORKING_DIR" value="" />
|
||||
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||
</Auto>
|
||||
<Hybrid>
|
||||
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||
<option name="SHOW_STATIC_VARS" value="true" />
|
||||
<option name="WORKING_DIR" value="" />
|
||||
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||
</Hybrid>
|
||||
<Java />
|
||||
<Native>
|
||||
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||
<option name="SHOW_STATIC_VARS" value="true" />
|
||||
<option name="WORKING_DIR" value="" />
|
||||
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||
</Native>
|
||||
<Profilers>
|
||||
<option name="ADVANCED_PROFILING_ENABLED" value="false" />
|
||||
<option name="STARTUP_PROFILING_ENABLED" value="false" />
|
||||
<option name="STARTUP_CPU_PROFILING_ENABLED" value="false" />
|
||||
<option name="STARTUP_CPU_PROFILING_CONFIGURATION_NAME" value="Sample Java Methods" />
|
||||
<option name="STARTUP_NATIVE_MEMORY_PROFILING_ENABLED" value="false" />
|
||||
<option name="NATIVE_MEMORY_SAMPLE_RATE_BYTES" value="2048" />
|
||||
</Profilers>
|
||||
<option name="DEEP_LINK" value="" />
|
||||
<option name="ACTIVITY_CLASS" value="" />
|
||||
<option name="SEARCH_ACTIVITY_IN_GLOBAL_SCOPE" value="false" />
|
||||
<option name="SKIP_ACTIVITY_VALIDATION" value="false" />
|
||||
<method v="2">
|
||||
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
|
@ -1,5 +1,5 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Setting" type="AndroidRunConfigurationType" factoryName="Android App" activateToolWindowBeforeRun="false">
|
||||
<configuration default="false" name="Settings" type="AndroidRunConfigurationType" factoryName="Android App" activateToolWindowBeforeRun="false">
|
||||
<module name="skyline.app" />
|
||||
<option name="DEPLOY" value="true" />
|
||||
<option name="DEPLOY_APK_FROM_BUNDLE" value="false" />
|
2
.idea/vcs.xml
generated
2
.idea/vcs.xml
generated
|
@ -6,7 +6,9 @@
|
|||
<mapping directory="$PROJECT_DIR$/app/libraries/frozen" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/libraries/lz4" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/libraries/oboe" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/libraries/perfetto" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/libraries/pugixml" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/libraries/tzcode" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/libraries/vkhpp" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
38
README.md
38
README.md
|
@ -1,34 +1,36 @@
|
|||
<h1 align="center">
|
||||
<img height="60%" width="60%" src="https://i.imgur.com/6PJ7Ml2.png"><br>
|
||||
<a href="https://github.com/skyline-emu/skyline" target="_blank">
|
||||
<img height="60%" width="60%" src="https://i.imgur.com/6PJ7Ml2.png"><br>
|
||||
</a>
|
||||
<a href="https://discord.gg/XnbXNQM" target="_blank">
|
||||
<img src="https://img.shields.io/discord/545842171459272705?label=Discord&logo=Discord&color=yellow">
|
||||
</a>
|
||||
<a href="LICENSE.md" target="_blank">
|
||||
<img src="https://img.shields.io/badge/License-MPL%202.0-yellow"/><br>
|
||||
<a href="https://github.com/skyline-emu/skyline/actions/workflows/ci.yml" target="_blank">
|
||||
<img src="https://github.com/skyline-emu/skyline/actions/workflows/ci.yml/badge.svg"/><br>
|
||||
</a>
|
||||
<img src="https://forthebadge.com/images/badges/built-for-android.svg"/>
|
||||
</h1>
|
||||
|
||||
<p align="center">
|
||||
<i>Skyline is an experimental emulator that runs on ARMv8 Android™ devices and emulates the functionality of a Nintendo Switch™ system. It's licensed under the MPL, refer to the <a href="https://github.com/skyline-emu/skyline/blob/master/LICENSE.md">license file</a> for more information.</i><br/><br>
|
||||
<b>Skyline</b> is an experimental emulator that runs on <b>ARMv8 Android™</b> devices and emulates the functionality of a <b>Nintendo Switch™</b> system, licensed under <a href="https://github.com/skyline-emu/skyline/blob/master/LICENSE.md"><b>Mozilla Public License 2.0</b></a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
### Contact
|
||||
You can contact the core developers of Skyline at our [Discord](https://discord.gg/XnbXNQM). If you have any questions, feel free to ask. It's also a good place to just keep up with the emulator, as most talk regarding development goes on over there.
|
||||
You can contact the core developers of Skyline at our **[Discord](https://discord.gg/XnbXNQM)**. If you have any questions, feel free to ask. It's also a good place to just keep up with the emulator, as most talk regarding development goes on over there.
|
||||
|
||||
### Credit
|
||||
[<img align="left" height="10%" width="10%" src="https://avatars1.githubusercontent.com/u/39036280?v=4"/>](https://ryujinx.org/)
|
||||
[**Ryujinx**](https://ryujinx.org/)<br>
|
||||
We've used Ryujinx throughout the project for reference, the amount of accuracy of their HLE kernel implementation is what makes them such an amazing reference. In addition, the team behind the project has been really helpful with any queries we had.
|
||||
---
|
||||
|
||||
[<img align="left" height="10%" width="10%" src="https://avatars3.githubusercontent.com/u/35075882?v=4"/>](https://yuzu-emu.org/)
|
||||
[**Team yuzu**](https://github.com/yuzu-emu/)<br>
|
||||
We have recieved a fair share of advice from the team behind [yuzu](https://yuzu-emu.org/). Just like the Ryujinx team, they've been really receptive and helpful for any queries we've had and have provided feedback on our code which was extremely useful during the early stages of the emulator.
|
||||
### Special Thanks
|
||||
A few noteworthy teams/projects who've helped us along the way are:
|
||||
* **[Ryujinx](https://ryujinx.org/):** We've used Ryujinx for reference throughout the project, the amount of accuracy of their HLE kernel implementation is what makes them such an amazing reference. The team behind the project has been really helpful with any queries we've had. **It should be noted that Skyline is not based on Ryujinx**.
|
||||
|
||||
[<img align="left" height="10%" width="10%" src="https://avatars3.githubusercontent.com/u/31827450?v=4"/>](https://switchbrew.org/)
|
||||
[**Switchbrew**](https://github.com/switchbrew/)<br>
|
||||
We've extensively used Switchbrew whether that be their [wiki](https://switchbrew.org/) with it's collosal amount of information on the Switch that has saved us countless hours of time or [libnx](https://github.com/switchbrew/libnx) which was crucial to initial development of the emulator to ensure that our implementations were correct.
|
||||
* **[Switchbrew](https://github.com/switchbrew/):** We've extensively used Switchbrew whether that be their **[wiki](https://switchbrew.org/)** with it's colossal amount of information on the Switch that has saved us countless hours of time or **[libnx](https://github.com/switchbrew/libnx)** which was crucial to initial development of the emulator to ensure that our HLE kernel and sysmodule implementations were accurate.
|
||||
|
||||
* **[Atmosphère](https://github.com/Atmosphere-NX/Atmosphere):** We've used [libmesosphere](https://github.com/Atmosphere-NX/Atmosphere/tree/master/libraries/libmesosphere) as another reference for our HLE kernel, it's faithfulness to the HOS kernel helps us a lot. This makes it invaluably important for us as a tool for writing code that can accurately emulate HOS behavior without missing any crucial parts.
|
||||
|
||||
---
|
||||
|
||||
### Disclaimer
|
||||
* Nintendo Switch is a trademark of Nintendo Co., Ltd.
|
||||
* Android is a trademark of Google LLC.
|
||||
* **Nintendo Switch** is a trademark of **Nintendo Co., Ltd**
|
||||
* **Android** is a trademark of **Google LLC**
|
||||
|
|
|
@ -17,7 +17,9 @@ if (uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE")
|
|||
endif ()
|
||||
|
||||
add_subdirectory("libraries/fmt")
|
||||
|
||||
add_subdirectory("libraries/tzcode")
|
||||
target_compile_options(tzcode PRIVATE -Wno-everything)
|
||||
|
||||
add_subdirectory("libraries/oboe")
|
||||
include_directories("libraries/oboe/include")
|
||||
|
@ -32,6 +34,11 @@ include_directories("libraries/frozen/include")
|
|||
|
||||
find_package(mbedtls REQUIRED CONFIG)
|
||||
|
||||
# Perfetto SDK
|
||||
include_directories(libraries/perfetto/sdk)
|
||||
add_library(perfetto STATIC libraries/perfetto/sdk/perfetto.cc)
|
||||
target_compile_options(perfetto PRIVATE -Wno-everything)
|
||||
|
||||
include_directories(${source_DIR}/skyline)
|
||||
|
||||
add_library(skyline SHARED
|
||||
|
@ -41,6 +48,7 @@ add_library(skyline SHARED
|
|||
${source_DIR}/skyline/common/settings.cpp
|
||||
${source_DIR}/skyline/common/signal.cpp
|
||||
${source_DIR}/skyline/common/uuid.cpp
|
||||
${source_DIR}/skyline/common/trace.cpp
|
||||
${source_DIR}/skyline/nce/guest.S
|
||||
${source_DIR}/skyline/nce.cpp
|
||||
${source_DIR}/skyline/jvm.cpp
|
||||
|
@ -180,5 +188,5 @@ add_library(skyline SHARED
|
|||
${source_DIR}/skyline/services/prepo/IPrepoService.cpp
|
||||
)
|
||||
# target_precompile_headers(skyline PRIVATE ${source_DIR}/skyline/common.h) # PCH will currently break Intellisense
|
||||
target_link_libraries(skyline vulkan android fmt lz4_static tzcode oboe mbedtls::mbedcrypto)
|
||||
target_link_libraries(skyline vulkan android perfetto fmt lz4_static tzcode oboe mbedtls::mbedcrypto)
|
||||
target_compile_options(skyline PRIVATE -Wall -Wno-unknown-attributes -Wno-c++20-extensions -Wno-c++17-extensions -Wno-c99-designator -Wno-reorder -Wno-missing-braces -Wno-unused-variable -Wno-unused-private-field)
|
||||
|
|
1
app/libraries/perfetto
Submodule
1
app/libraries/perfetto
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 3f02be823cef0f54e720c0382ffc4507f48e6e4b
|
|
@ -10,6 +10,7 @@
|
|||
#include "skyline/common.h"
|
||||
#include "skyline/common/signal.h"
|
||||
#include "skyline/common/settings.h"
|
||||
#include "skyline/common/trace.h"
|
||||
#include "skyline/loader/loader.h"
|
||||
#include "skyline/vfs/android_asset_filesystem.h"
|
||||
#include "skyline/os.h"
|
||||
|
@ -64,6 +65,12 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(
|
|||
|
||||
auto start{std::chrono::steady_clock::now()};
|
||||
|
||||
// Initialize tracing
|
||||
perfetto::TracingInitArgs args;
|
||||
args.backends |= perfetto::kSystemBackend;
|
||||
perfetto::Tracing::Initialize(args);
|
||||
perfetto::TrackEvent::Register();
|
||||
|
||||
try {
|
||||
auto os{std::make_shared<skyline::kernel::OS>(jvmManager, logger, settings, std::string(appFilesPath), GetTimeZoneName(), std::make_shared<skyline::vfs::AndroidAssetFileSystem>(AAssetManager_fromJava(env, assetManager)))};
|
||||
OsWeak = os;
|
||||
|
@ -73,24 +80,26 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(
|
|||
env->ReleaseStringUTFChars(appFilesPathJstring, appFilesPath);
|
||||
|
||||
auto romUri{env->GetStringUTFChars(romUriJstring, nullptr)};
|
||||
logger->Info("Launching ROM {}", romUri);
|
||||
logger->InfoNoPrefix("Launching ROM {}", romUri);
|
||||
env->ReleaseStringUTFChars(romUriJstring, romUri);
|
||||
|
||||
os->Execute(romFd, static_cast<skyline::loader::RomFormat>(romType));
|
||||
} catch (std::exception &e) {
|
||||
logger->Error(e.what());
|
||||
logger->Error("An exception has occurred: {}", e.what());
|
||||
} catch (const skyline::signal::SignalException &e) {
|
||||
logger->Error(e.what());
|
||||
logger->Error("An exception has occurred: {}", e.what());
|
||||
} catch (...) {
|
||||
logger->Error("An unknown exception has occurred");
|
||||
}
|
||||
|
||||
perfetto::TrackEvent::Flush();
|
||||
|
||||
InputWeak.reset();
|
||||
|
||||
logger->Info("Emulation has ended");
|
||||
logger->InfoNoPrefix("Emulation has ended");
|
||||
|
||||
auto end{std::chrono::steady_clock::now()};
|
||||
logger->Info("Done in: {} ms", (std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()));
|
||||
logger->InfoNoPrefix("Done in: {} ms", (std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()));
|
||||
|
||||
close(romFd);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ namespace skyline::audio {
|
|||
builder.setFramesPerCallback(constant::MixBufferSize);
|
||||
builder.setUsage(oboe::Usage::Game);
|
||||
builder.setCallback(this);
|
||||
builder.setSharingMode(oboe::SharingMode::Exclusive);
|
||||
builder.setPerformanceMode(oboe::PerformanceMode::LowLatency);
|
||||
|
||||
builder.openManagedStream(outputStream);
|
||||
outputStream->requestStart();
|
||||
|
|
|
@ -35,7 +35,7 @@ namespace skyline {
|
|||
void Logger::WriteHeader(const std::string &str) {
|
||||
__android_log_write(ANDROID_LOG_INFO, "emu-cpp", str.c_str());
|
||||
|
||||
std::lock_guard guard(mtx);
|
||||
std::lock_guard guard(mutex);
|
||||
logFile << "\0360\035" << str << '\n';
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ namespace skyline {
|
|||
|
||||
__android_log_write(levelAlog[static_cast<u8>(level)], logTag.c_str(), str.c_str());
|
||||
|
||||
std::lock_guard guard(mtx);
|
||||
std::lock_guard guard(mutex);
|
||||
logFile << "\0361\035" << levelCharacter[static_cast<u8>(level)] << '\035' << threadName << '\035' << str << '\n'; // We use RS (\036) and GS (\035) as our delimiters
|
||||
}
|
||||
|
||||
|
|
|
@ -145,6 +145,14 @@ namespace skyline {
|
|||
else
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief {fmt}::format but with FmtCast built into it
|
||||
*/
|
||||
template<typename S, typename... Args>
|
||||
auto Format(S formatString, Args &&... args) {
|
||||
return fmt::format(formatString, FmtCast(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -152,10 +160,6 @@ namespace skyline {
|
|||
*/
|
||||
class exception : public std::runtime_error {
|
||||
public:
|
||||
/**
|
||||
* @param formatStr The exception string to be written, with {fmt} formatting
|
||||
* @param args The arguments based on format_str
|
||||
*/
|
||||
template<typename S, typename... Args>
|
||||
exception(const S &formatStr, Args &&... args) : runtime_error(fmt::format(formatStr, util::FmtCast(args)...)) {}
|
||||
};
|
||||
|
@ -451,7 +455,7 @@ namespace skyline {
|
|||
class Logger {
|
||||
private:
|
||||
std::ofstream logFile; //!< An output stream to the log file
|
||||
std::mutex mtx; //!< A mutex to lock before logging anything
|
||||
std::mutex mutex; //!< Synchronizes all output I/O to ensure there are no races
|
||||
|
||||
public:
|
||||
enum class LogLevel {
|
||||
|
@ -487,34 +491,111 @@ namespace skyline {
|
|||
|
||||
void Write(LogLevel level, const std::string &str);
|
||||
|
||||
template<typename S, typename... Args>
|
||||
void Error(const S &formatStr, Args &&... args) {
|
||||
/**
|
||||
* @brief A wrapper around a string which captures the calling function using Clang source location builtins
|
||||
* @note A function needs to be declared for every argument template specialization as CTAD cannot work with implicit casting
|
||||
* @url https://clang.llvm.org/docs/LanguageExtensions.html#source-location-builtins
|
||||
*/
|
||||
template<typename S>
|
||||
struct FunctionString {
|
||||
S string;
|
||||
const char *function;
|
||||
|
||||
FunctionString(S string, const char *function = __builtin_FUNCTION()) : string(std::move(string)), function(function) {}
|
||||
|
||||
std::string operator*() {
|
||||
return std::string(function) + ": " + std::string(string);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
void Error(FunctionString<const char*> formatString, Args &&... args) {
|
||||
if (LogLevel::Error <= configLevel)
|
||||
Write(LogLevel::Error, fmt::format(formatStr, util::FmtCast(args)...));
|
||||
Write(LogLevel::Error, fmt::format(*formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Error(FunctionString<std::string> formatString, Args &&... args) {
|
||||
if (LogLevel::Error <= configLevel)
|
||||
Write(LogLevel::Error, fmt::format(*formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename S, typename... Args>
|
||||
void Warn(const S &formatStr, Args &&... args) {
|
||||
void ErrorNoPrefix(S formatString, Args &&... args) {
|
||||
if (LogLevel::Error <= configLevel)
|
||||
Write(LogLevel::Error, fmt::format(formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Warn(FunctionString<const char*> formatString, Args &&... args) {
|
||||
if (LogLevel::Warn <= configLevel)
|
||||
Write(LogLevel::Warn, fmt::format(formatStr, util::FmtCast(args)...));
|
||||
Write(LogLevel::Warn, fmt::format(*formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Warn(FunctionString<std::string> formatString, Args &&... args) {
|
||||
if (LogLevel::Warn <= configLevel)
|
||||
Write(LogLevel::Warn, fmt::format(*formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename S, typename... Args>
|
||||
void Info(const S &formatStr, Args &&... args) {
|
||||
void WarnNoPrefix(S formatString, Args &&... args) {
|
||||
if (LogLevel::Warn <= configLevel)
|
||||
Write(LogLevel::Warn, fmt::format(formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Info(FunctionString<const char*> formatString, Args &&... args) {
|
||||
if (LogLevel::Info <= configLevel)
|
||||
Write(LogLevel::Info, fmt::format(formatStr, util::FmtCast(args)...));
|
||||
Write(LogLevel::Info, fmt::format(*formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Info(FunctionString<std::string> formatString, Args &&... args) {
|
||||
if (LogLevel::Info <= configLevel)
|
||||
Write(LogLevel::Info, fmt::format(*formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename S, typename... Args>
|
||||
void Debug(const S &formatStr, Args &&... args) {
|
||||
void InfoNoPrefix(S formatString, Args &&... args) {
|
||||
if (LogLevel::Info <= configLevel)
|
||||
Write(LogLevel::Info, fmt::format(formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Debug(FunctionString<const char*> formatString, Args &&... args) {
|
||||
if (LogLevel::Debug <= configLevel)
|
||||
Write(LogLevel::Debug, fmt::format(formatStr, util::FmtCast(args)...));
|
||||
Write(LogLevel::Debug, fmt::format(*formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Debug(FunctionString<std::string> formatString, Args &&... args) {
|
||||
if (LogLevel::Debug <= configLevel)
|
||||
Write(LogLevel::Debug, fmt::format(*formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename S, typename... Args>
|
||||
void Verbose(const S &formatStr, Args &&... args) {
|
||||
void DebugNoPrefix(S formatString, Args &&... args) {
|
||||
if (LogLevel::Debug <= configLevel)
|
||||
Write(LogLevel::Debug, fmt::format(formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Verbose(FunctionString<const char*> formatString, Args &&... args) {
|
||||
if (LogLevel::Verbose <= configLevel)
|
||||
Write(LogLevel::Verbose, fmt::format(formatStr, util::FmtCast(args)...));
|
||||
Write(LogLevel::Verbose, fmt::format(*formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Verbose(FunctionString<std::string> formatString, Args &&... args) {
|
||||
if (LogLevel::Verbose <= configLevel)
|
||||
Write(LogLevel::Verbose, fmt::format(*formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename S, typename... Args>
|
||||
void VerboseNoPrefix(S formatString, Args &&... args) {
|
||||
if (LogLevel::Verbose <= configLevel)
|
||||
Write(LogLevel::Verbose, fmt::format(formatString, util::FmtCast(args)...));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
3
app/src/main/cpp/skyline/common/trace.cpp
Normal file
3
app/src/main/cpp/skyline/common/trace.cpp
Normal file
|
@ -0,0 +1,3 @@
|
|||
#include "trace.h"
|
||||
|
||||
PERFETTO_TRACK_EVENT_STATIC_STORAGE(); //!< Expands into a structure with static storage for all track events
|
26
app/src/main/cpp/skyline/common/trace.h
Normal file
26
app/src/main/cpp/skyline/common/trace.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <limits>
|
||||
#include <perfetto.h>
|
||||
#include <common.h>
|
||||
|
||||
#define TRACE_EVENT_FMT(category, formatString, ...) TRACE_EVENT("kernel", nullptr, [&](perfetto::EventContext ctx) { \
|
||||
ctx.event()->set_name(skyline::util::Format(formatString, __VA_ARGS__)); \
|
||||
})
|
||||
|
||||
PERFETTO_DEFINE_CATEGORIES(
|
||||
perfetto::Category("scheduler").SetDescription("Events from the HLE scheduler"),
|
||||
perfetto::Category("kernel").SetDescription("Events from parts of the HLE kernel"),
|
||||
perfetto::Category("guest").SetDescription("Events relating to guest code"),
|
||||
perfetto::Category("gpu").SetDescription("Events from the emulated GPU"),
|
||||
perfetto::Category("service").SetDescription("Events from the HLE sysmodule implementations")
|
||||
);
|
||||
|
||||
namespace skyline::trace {
|
||||
/**
|
||||
* @brief Perfetto track IDs for custom tracks, counting down from U64 max to avoid conflicts
|
||||
*/
|
||||
enum class TrackIds : u64 {
|
||||
Presentation = std::numeric_limits<u64>::max(),
|
||||
};
|
||||
}
|
|
@ -9,7 +9,11 @@ extern skyline::u16 Fps;
|
|||
extern skyline::u32 FrameTime;
|
||||
|
||||
namespace skyline::gpu {
|
||||
PresentationEngine::PresentationEngine(const DeviceState &state) : state(state), vsyncEvent(std::make_shared<kernel::type::KEvent>(state, true)), bufferEvent(std::make_shared<kernel::type::KEvent>(state, true)) {}
|
||||
PresentationEngine::PresentationEngine(const DeviceState &state) : state(state), vsyncEvent(std::make_shared<kernel::type::KEvent>(state, true)), bufferEvent(std::make_shared<kernel::type::KEvent>(state, true)), presentationTrack(static_cast<uint64_t>(trace::TrackIds::Presentation), perfetto::ProcessTrack::Current()) {
|
||||
auto desc{presentationTrack.Serialize()};
|
||||
desc.set_name("Presentation");
|
||||
perfetto::TrackEvent::SetTrackDescriptor(presentationTrack, desc);
|
||||
}
|
||||
|
||||
PresentationEngine::~PresentationEngine() {
|
||||
if (window)
|
||||
|
@ -76,6 +80,8 @@ namespace skyline::gpu {
|
|||
FrameTime = static_cast<u32>((now - frameTimestamp) / 10000); // frametime / 100 is the real ms value, this is to retain the first two decimals
|
||||
Fps = static_cast<u16>(constant::NsInSecond / (now - frameTimestamp));
|
||||
|
||||
TRACE_EVENT_INSTANT("gpu", "Present", presentationTrack, "FrameTimeNs", now - frameTimestamp, "Fps", Fps);
|
||||
|
||||
frameTimestamp = now;
|
||||
} else {
|
||||
frameTimestamp = util::GetTimeNs();
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <common/trace.h>
|
||||
#include <kernel/types/KEvent.h>
|
||||
#include "texture.h"
|
||||
|
||||
|
@ -16,6 +17,7 @@ namespace skyline::gpu {
|
|||
std::condition_variable windowConditional;
|
||||
jobject surface{}; //!< The Surface object backing the ANativeWindow
|
||||
u64 frameTimestamp{}; //!< The timestamp of the last frame being shown
|
||||
perfetto::Track presentationTrack; //!< Perfetto track used for presentation events
|
||||
|
||||
public:
|
||||
texture::Dimensions resolution{};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include <common/trace.h>
|
||||
#include <android/native_window.h>
|
||||
#include <kernel/types/KProcess.h>
|
||||
#include <unistd.h>
|
||||
|
@ -22,6 +23,7 @@ namespace skyline::gpu {
|
|||
}
|
||||
|
||||
void Texture::SynchronizeHost() {
|
||||
TRACE_EVENT("gpu", "Texture::SynchronizeHost");
|
||||
auto pointer{guest->pointer};
|
||||
auto size{format.GetSize(dimensions)};
|
||||
backing.resize(size);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <unistd.h>
|
||||
#include <common/signal.h>
|
||||
#include <common/trace.h>
|
||||
#include "types/KThread.h"
|
||||
#include "scheduler.h"
|
||||
|
||||
|
@ -13,12 +14,14 @@ namespace skyline::kernel {
|
|||
|
||||
void Scheduler::SignalHandler(int signal, siginfo *info, ucontext *ctx, void **tls) {
|
||||
if (*tls) {
|
||||
TRACE_EVENT_END("guest");
|
||||
const auto &state{*reinterpret_cast<nce::ThreadContext *>(*tls)->state};
|
||||
if (signal == PreemptionSignal)
|
||||
state.thread->isPreempted = false;
|
||||
state.scheduler->Rotate(false);
|
||||
YieldPending = false;
|
||||
state.scheduler->WaitSchedule();
|
||||
TRACE_EVENT_BEGIN("guest", "Guest");
|
||||
} else {
|
||||
YieldPending = true;
|
||||
}
|
||||
|
@ -150,6 +153,7 @@ namespace skyline::kernel {
|
|||
return !core->queue.empty() && core->queue.front() == thread;
|
||||
}};
|
||||
|
||||
TRACE_EVENT("scheduler", "WaitSchedule");
|
||||
if (loadBalance && thread->affinityMask.count() > 1) {
|
||||
std::chrono::milliseconds loadBalanceThreshold{PreemptiveTimeslice * 2}; //!< The amount of time that needs to pass unscheduled for a thread to attempt load balancing
|
||||
while (!thread->scheduleCondition.wait_for(lock, loadBalanceThreshold, wakeFunction)) {
|
||||
|
@ -177,6 +181,7 @@ namespace skyline::kernel {
|
|||
auto &thread{state.thread};
|
||||
auto *core{&cores.at(thread->coreId)};
|
||||
|
||||
TRACE_EVENT("scheduler", "TimedWaitSchedule");
|
||||
std::unique_lock lock(core->mutex);
|
||||
if (thread->scheduleCondition.wait_for(lock, timeout, [&]() {
|
||||
if (!thread->affinityMask.test(thread->coreId)) [[unlikely]] {
|
||||
|
@ -201,6 +206,7 @@ namespace skyline::kernel {
|
|||
auto &core{cores.at(thread->coreId)};
|
||||
|
||||
std::unique_lock lock(core.mutex);
|
||||
|
||||
if (core.queue.front() == thread) {
|
||||
// If this thread is at the front of the thread queue then we need to rotate the thread
|
||||
// In the case where this thread was forcefully yielded, we don't need to do this as it's done by the thread which yielded to this thread
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <os.h>
|
||||
#include <kernel/types/KProcess.h>
|
||||
#include <common/trace.h>
|
||||
#include <vfs/npdm.h>
|
||||
#include "results.h"
|
||||
#include "svc.h"
|
||||
|
@ -15,7 +16,7 @@ namespace skyline::kernel::svc {
|
|||
state.ctx->gpr.w0 = result::InvalidSize;
|
||||
state.ctx->gpr.x1 = 0;
|
||||
|
||||
state.logger->Warn("svcSetHeapSize: 'size' not divisible by 2MB: {}", size);
|
||||
state.logger->Warn("'size' not divisible by 2MB: {}", size);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -25,21 +26,21 @@ namespace skyline::kernel::svc {
|
|||
state.ctx->gpr.w0 = Result{};
|
||||
state.ctx->gpr.x1 = reinterpret_cast<u64>(heap->ptr);
|
||||
|
||||
state.logger->Debug("svcSetHeapSize: Allocated at 0x{:X} - 0x{:X} (0x{:X} bytes)", heap->ptr, heap->ptr + heap->size, heap->size);
|
||||
state.logger->Debug("Allocated at 0x{:X} - 0x{:X} (0x{:X} bytes)", heap->ptr, heap->ptr + heap->size, heap->size);
|
||||
}
|
||||
|
||||
void SetMemoryAttribute(const DeviceState &state) {
|
||||
auto pointer{reinterpret_cast<u8 *>(state.ctx->gpr.x0)};
|
||||
if (!util::PageAligned(pointer)) {
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
state.logger->Warn("svcSetMemoryAttribute: 'pointer' not page aligned: 0x{:X}", pointer);
|
||||
state.logger->Warn("'pointer' not page aligned: 0x{:X}", pointer);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t size{state.ctx->gpr.x1};
|
||||
if (!util::PageAligned(size)) {
|
||||
state.ctx->gpr.w0 = result::InvalidSize;
|
||||
state.logger->Warn("svcSetMemoryAttribute: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||
state.logger->Warn("'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -49,20 +50,20 @@ namespace skyline::kernel::svc {
|
|||
auto maskedValue{mask.value | value.value};
|
||||
if (maskedValue != mask.value || !mask.isUncached || mask.isDeviceShared || mask.isBorrowed || mask.isIpcLocked) {
|
||||
state.ctx->gpr.w0 = result::InvalidCombination;
|
||||
state.logger->Warn("svcSetMemoryAttribute: 'mask' invalid: 0x{:X}, 0x{:X}", mask.value, value.value);
|
||||
state.logger->Warn("'mask' invalid: 0x{:X}, 0x{:X}", mask.value, value.value);
|
||||
return;
|
||||
}
|
||||
|
||||
auto chunk{state.process->memory.Get(pointer)};
|
||||
if (!chunk) {
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
state.logger->Warn("svcSetMemoryAttribute: Cannot find memory region: 0x{:X}", pointer);
|
||||
state.logger->Warn("Cannot find memory region: 0x{:X}", pointer);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!chunk->state.attributeChangeAllowed) {
|
||||
state.ctx->gpr.w0 = result::InvalidState;
|
||||
state.logger->Warn("svcSetMemoryAttribute: Attribute change not allowed for chunk: 0x{:X}", pointer);
|
||||
state.logger->Warn("Attribute change not allowed for chunk: 0x{:X}", pointer);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -72,7 +73,7 @@ namespace skyline::kernel::svc {
|
|||
newChunk.attributes.isUncached = value.isUncached;
|
||||
state.process->memory.InsertChunk(newChunk);
|
||||
|
||||
state.logger->Debug("svcSetMemoryAttribute: Set CPU caching to {} at 0x{:X} - 0x{:X} (0x{:X} bytes)", !static_cast<bool>(value.isUncached), pointer, pointer + size, size);
|
||||
state.logger->Debug("Set CPU caching to {} at 0x{:X} - 0x{:X} (0x{:X} bytes)", !static_cast<bool>(value.isUncached), pointer, pointer + size, size);
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
}
|
||||
|
||||
|
@ -83,32 +84,32 @@ namespace skyline::kernel::svc {
|
|||
|
||||
if (!util::PageAligned(destination) || !util::PageAligned(source)) {
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
state.logger->Warn("svcMapMemory: Addresses not page aligned: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
|
||||
state.logger->Warn("Addresses not page aligned: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!util::PageAligned(size)) {
|
||||
state.ctx->gpr.w0 = result::InvalidSize;
|
||||
state.logger->Warn("svcMapMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||
state.logger->Warn("'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||
return;
|
||||
}
|
||||
|
||||
auto stack{state.process->memory.stack};
|
||||
if (!stack.IsInside(destination)) {
|
||||
state.ctx->gpr.w0 = result::InvalidMemoryRegion;
|
||||
state.logger->Warn("svcMapMemory: Destination not within stack region: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
|
||||
state.logger->Warn("Destination not within stack region: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
|
||||
return;
|
||||
}
|
||||
|
||||
auto chunk{state.process->memory.Get(source)};
|
||||
if (!chunk) {
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
state.logger->Warn("svcMapMemory: Source has no descriptor: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
|
||||
state.logger->Warn("Source has no descriptor: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
|
||||
return;
|
||||
}
|
||||
if (!chunk->state.mapAllowed) {
|
||||
state.ctx->gpr.w0 = result::InvalidState;
|
||||
state.logger->Warn("svcMapMemory: Source doesn't allow usage of svcMapMemory: Source: 0x{:X}, Destination: 0x{:X}, Size: 0x{:X}, MemoryState: 0x{:X}", source, destination, size, chunk->state.value);
|
||||
state.logger->Warn("Source doesn't allow usage of svcMapMemory: Source: 0x{:X}, Destination: 0x{:X}, Size: 0x{:X}, MemoryState: 0x{:X}", source, destination, size, chunk->state.value);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -120,7 +121,7 @@ namespace skyline::kernel::svc {
|
|||
throw exception("svcMapMemory: Cannot find memory object in handle table for address 0x{:X}", source);
|
||||
object->item->UpdatePermission(source, size, {false, false, false});
|
||||
|
||||
state.logger->Debug("svcMapMemory: Mapped range 0x{:X} - 0x{:X} to 0x{:X} - 0x{:X} (Size: 0x{:X} bytes)", source, source + size, destination, destination + size, size);
|
||||
state.logger->Debug("Mapped range 0x{:X} - 0x{:X} to 0x{:X} - 0x{:X} (Size: 0x{:X} bytes)", source, source + size, destination, destination + size, size);
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
}
|
||||
|
||||
|
@ -131,20 +132,20 @@ namespace skyline::kernel::svc {
|
|||
|
||||
if (!util::PageAligned(destination) || !util::PageAligned(source)) {
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
state.logger->Warn("svcUnmapMemory: Addresses not page aligned: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
|
||||
state.logger->Warn("Addresses not page aligned: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!util::PageAligned(size)) {
|
||||
state.ctx->gpr.w0 = result::InvalidSize;
|
||||
state.logger->Warn("svcUnmapMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||
state.logger->Warn("'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||
return;
|
||||
}
|
||||
|
||||
auto stack{state.process->memory.stack};
|
||||
if (!stack.IsInside(source)) {
|
||||
state.ctx->gpr.w0 = result::InvalidMemoryRegion;
|
||||
state.logger->Warn("svcUnmapMemory: Source not within stack region: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
|
||||
state.logger->Warn("Source not within stack region: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -152,13 +153,13 @@ namespace skyline::kernel::svc {
|
|||
auto destChunk{state.process->memory.Get(destination)};
|
||||
if (!sourceChunk || !destChunk) {
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
state.logger->Warn("svcUnmapMemory: Addresses have no descriptor: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
|
||||
state.logger->Warn("Addresses have no descriptor: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!destChunk->state.mapAllowed) {
|
||||
state.ctx->gpr.w0 = result::InvalidState;
|
||||
state.logger->Warn("svcUnmapMemory: Destination doesn't allow usage of svcMapMemory: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes) 0x{:X}", source, destination, size, destChunk->state.value);
|
||||
state.logger->Warn("Destination doesn't allow usage of svcMapMemory: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes) 0x{:X}", source, destination, size, destChunk->state.value);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -176,7 +177,7 @@ namespace skyline::kernel::svc {
|
|||
|
||||
state.process->CloseHandle(sourceObject->handle);
|
||||
|
||||
state.logger->Debug("svcUnmapMemory: Unmapped range 0x{:X} - 0x{:X} to 0x{:X} - 0x{:X} (Size: 0x{:X} bytes)", source, source + size, destination, destination + size, size);
|
||||
state.logger->Debug("Unmapped range 0x{:X} - 0x{:X} to 0x{:X} - 0x{:X} (Size: 0x{:X} bytes)", source, source + size, destination, destination + size, size);
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
}
|
||||
|
||||
|
@ -197,7 +198,7 @@ namespace skyline::kernel::svc {
|
|||
.ipcRefCount = 0,
|
||||
};
|
||||
|
||||
state.logger->Debug("svcQueryMemory: Address: 0x{:X}, Region Start: 0x{:X}, Size: 0x{:X}, Type: 0x{:X}, Is Uncached: {}, Permissions: {}{}{}", pointer, memInfo.address, memInfo.size, memInfo.type, static_cast<bool>(chunk->attributes.isUncached), chunk->permission.r ? 'R' : '-', chunk->permission.w ? 'W' : '-', chunk->permission.x ? 'X' : '-');
|
||||
state.logger->Debug("Address: 0x{:X}, Region Start: 0x{:X}, Size: 0x{:X}, Type: 0x{:X}, Is Uncached: {}, Permissions: {}{}{}", pointer, memInfo.address, memInfo.size, memInfo.type, static_cast<bool>(chunk->attributes.isUncached), chunk->permission.r ? 'R' : '-', chunk->permission.w ? 'W' : '-', chunk->permission.x ? 'X' : '-');
|
||||
} else {
|
||||
auto addressSpaceEnd{reinterpret_cast<u64>(state.process->memory.addressSpace.address + state.process->memory.addressSpace.size)};
|
||||
|
||||
|
@ -207,7 +208,7 @@ namespace skyline::kernel::svc {
|
|||
.type = static_cast<u32>(memory::MemoryType::Reserved),
|
||||
};
|
||||
|
||||
state.logger->Debug("svcQueryMemory: Trying to query memory outside of the application's address space: 0x{:X}", pointer);
|
||||
state.logger->Debug("Trying to query memory outside of the application's address space: 0x{:X}", pointer);
|
||||
}
|
||||
|
||||
*reinterpret_cast<memory::MemoryInfo *>(state.ctx->gpr.x0) = memInfo;
|
||||
|
@ -216,7 +217,7 @@ namespace skyline::kernel::svc {
|
|||
}
|
||||
|
||||
void ExitProcess(const DeviceState &state) {
|
||||
state.logger->Debug("svcExitProcess: Exiting process");
|
||||
state.logger->Debug("Exiting process");
|
||||
if (state.thread->id)
|
||||
state.process->Kill(false);
|
||||
std::longjmp(state.thread->originalCtx, true);
|
||||
|
@ -236,13 +237,13 @@ namespace skyline::kernel::svc {
|
|||
idealCore = (idealCore == IdealCoreUseProcessValue) ? state.process->npdm.meta.idealCore : idealCore;
|
||||
if (idealCore < 0 || idealCore >= constant::CoreCount) {
|
||||
state.ctx->gpr.w0 = result::InvalidCoreId;
|
||||
state.logger->Warn("svcCreateThread: 'idealCore' invalid: {}", idealCore);
|
||||
state.logger->Warn("'idealCore' invalid: {}", idealCore);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!state.process->npdm.threadInfo.priority.Valid(priority)) {
|
||||
state.ctx->gpr.w0 = result::InvalidPriority;
|
||||
state.logger->Warn("svcCreateThread: 'priority' invalid: {}", priority);
|
||||
state.logger->Warn("'priority' invalid: {}", priority);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -252,12 +253,12 @@ namespace skyline::kernel::svc {
|
|||
|
||||
auto thread{state.process->CreateThread(entry, entryArgument, stackTop, priority, idealCore)};
|
||||
if (thread) {
|
||||
state.logger->Debug("svcCreateThread: Created thread #{} with handle 0x{:X} (Entry Point: 0x{:X}, Argument: 0x{:X}, Stack Pointer: 0x{:X}, Priority: {}, Ideal Core: {})", thread->id, thread->handle, entry, entryArgument, stackTop, priority, idealCore);
|
||||
state.logger->Debug("Created thread #{} with handle 0x{:X} (Entry Point: 0x{:X}, Argument: 0x{:X}, Stack Pointer: 0x{:X}, Priority: {}, Ideal Core: {})", thread->id, thread->handle, entry, entryArgument, stackTop, priority, idealCore);
|
||||
|
||||
state.ctx->gpr.w1 = thread->handle;
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
} else {
|
||||
state.logger->Debug("svcCreateThread: Cannot create thread (Entry Point: 0x{:X}, Argument: 0x{:X}, Stack Pointer: 0x{:X}, Priority: {}, Ideal Core: {})", entry, entryArgument, stackTop, priority, idealCore);
|
||||
state.logger->Debug("Cannot create thread (Entry Point: 0x{:X}, Argument: 0x{:X}, Stack Pointer: 0x{:X}, Priority: {}, Ideal Core: {})", entry, entryArgument, stackTop, priority, idealCore);
|
||||
state.ctx->gpr.w1 = 0;
|
||||
state.ctx->gpr.w0 = result::OutOfResource;
|
||||
}
|
||||
|
@ -267,17 +268,17 @@ namespace skyline::kernel::svc {
|
|||
KHandle handle{state.ctx->gpr.w0};
|
||||
try {
|
||||
auto thread{state.process->GetHandle<type::KThread>(handle)};
|
||||
state.logger->Debug("svcStartThread: Starting thread #{}: 0x{:X}", thread->id, handle);
|
||||
state.logger->Debug("Starting thread #{}: 0x{:X}", thread->id, handle);
|
||||
thread->Start();
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
} catch (const std::out_of_range &) {
|
||||
state.logger->Warn("svcStartThread: 'handle' invalid: 0x{:X}", handle);
|
||||
state.logger->Warn("'handle' invalid: 0x{:X}", handle);
|
||||
state.ctx->gpr.w0 = result::InvalidHandle;
|
||||
}
|
||||
}
|
||||
|
||||
void ExitThread(const DeviceState &state) {
|
||||
state.logger->Debug("svcExitThread: Exiting current thread");
|
||||
state.logger->Debug("Exiting current thread");
|
||||
std::longjmp(state.thread->originalCtx, true);
|
||||
}
|
||||
|
||||
|
@ -288,7 +289,8 @@ namespace skyline::kernel::svc {
|
|||
|
||||
i64 in{static_cast<i64>(state.ctx->gpr.x0)};
|
||||
if (in > 0) {
|
||||
state.logger->Debug("svcSleepThread: Sleeping for {}ns", in);
|
||||
state.logger->Debug("Sleeping for {}ns", in);
|
||||
TRACE_EVENT("kernel", "SleepThread", "duration", in);
|
||||
|
||||
struct timespec spec{
|
||||
.tv_sec = static_cast<time_t>(in / 1000000000),
|
||||
|
@ -299,22 +301,30 @@ namespace skyline::kernel::svc {
|
|||
nanosleep(&spec, nullptr);
|
||||
} else {
|
||||
switch (in) {
|
||||
case yieldWithCoreMigration:
|
||||
state.logger->Debug("svcSleepThread: Waking any appropriate parked threads and yielding");
|
||||
case yieldWithCoreMigration: {
|
||||
state.logger->Debug("Waking any appropriate parked threads and yielding");
|
||||
TRACE_EVENT("kernel", "YieldWithCoreMigration");
|
||||
state.scheduler->WakeParkedThread();
|
||||
[[fallthrough]];
|
||||
case yieldWithoutCoreMigration:
|
||||
if (in == yieldWithoutCoreMigration)
|
||||
state.logger->Debug("svcSleepThread: Cooperative yield");
|
||||
state.scheduler->Rotate();
|
||||
state.scheduler->WaitSchedule();
|
||||
break;
|
||||
}
|
||||
|
||||
case yieldToAnyThread:
|
||||
state.logger->Debug("svcSleepThread: Parking current thread");
|
||||
case yieldWithoutCoreMigration: {
|
||||
state.logger->Debug("Cooperative yield");
|
||||
TRACE_EVENT("kernel", "YieldWithoutCoreMigration");
|
||||
state.scheduler->Rotate();
|
||||
state.scheduler->WaitSchedule();
|
||||
break;
|
||||
}
|
||||
|
||||
case yieldToAnyThread: {
|
||||
state.logger->Debug("Parking current thread");
|
||||
TRACE_EVENT("kernel", "YieldToAnyThread");
|
||||
state.scheduler->ParkThread();
|
||||
state.scheduler->WaitSchedule(false);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
|
@ -327,12 +337,12 @@ namespace skyline::kernel::svc {
|
|||
try {
|
||||
auto thread{state.process->GetHandle<type::KThread>(handle)};
|
||||
u8 priority{thread->priority};
|
||||
state.logger->Debug("svcGetThreadPriority: Retrieving thread #{}'s priority: {}", thread->id, priority);
|
||||
state.logger->Debug("Retrieving thread #{}'s priority: {}", thread->id, priority);
|
||||
|
||||
state.ctx->gpr.w1 = priority;
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
} catch (const std::out_of_range &) {
|
||||
state.logger->Warn("svcGetThreadPriority: 'handle' invalid: 0x{:X}", handle);
|
||||
state.logger->Warn("'handle' invalid: 0x{:X}", handle);
|
||||
state.ctx->gpr.w0 = result::InvalidHandle;
|
||||
}
|
||||
}
|
||||
|
@ -341,13 +351,13 @@ namespace skyline::kernel::svc {
|
|||
KHandle handle{state.ctx->gpr.w0};
|
||||
u8 priority{static_cast<u8>(state.ctx->gpr.w1)};
|
||||
if (!state.process->npdm.threadInfo.priority.Valid(priority)) {
|
||||
state.logger->Warn("svcSetThreadPriority: 'priority' invalid: 0x{:X}", priority);
|
||||
state.logger->Warn("'priority' invalid: 0x{:X}", priority);
|
||||
state.ctx->gpr.w0 = result::InvalidPriority;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
auto thread{state.process->GetHandle<type::KThread>(handle)};
|
||||
state.logger->Debug("svcSetThreadPriority: Setting thread #{}'s priority to {}", thread->id, priority);
|
||||
state.logger->Debug("Setting thread #{}'s priority to {}", thread->id, priority);
|
||||
if (thread->priority != priority) {
|
||||
thread->basePriority = priority;
|
||||
u8 newPriority{};
|
||||
|
@ -362,7 +372,7 @@ namespace skyline::kernel::svc {
|
|||
}
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
} catch (const std::out_of_range &) {
|
||||
state.logger->Warn("svcSetThreadPriority: 'handle' invalid: 0x{:X}", handle);
|
||||
state.logger->Warn("'handle' invalid: 0x{:X}", handle);
|
||||
state.ctx->gpr.w0 = result::InvalidHandle;
|
||||
}
|
||||
}
|
||||
|
@ -373,13 +383,13 @@ namespace skyline::kernel::svc {
|
|||
auto thread{state.process->GetHandle<type::KThread>(handle)};
|
||||
auto idealCore{thread->idealCore};
|
||||
auto affinityMask{thread->affinityMask};
|
||||
state.logger->Debug("svcGetThreadCoreMask: Getting thread #{}'s Ideal Core ({}) + Affinity Mask ({})", thread->id, idealCore, affinityMask);
|
||||
state.logger->Debug("Getting thread #{}'s Ideal Core ({}) + Affinity Mask ({})", thread->id, idealCore, affinityMask);
|
||||
|
||||
state.ctx->gpr.x2 = affinityMask.to_ullong();
|
||||
state.ctx->gpr.w1 = idealCore;
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
} catch (const std::out_of_range &) {
|
||||
state.logger->Warn("svcGetThreadCoreMask: 'handle' invalid: 0x{:X}", handle);
|
||||
state.logger->Warn("'handle' invalid: 0x{:X}", handle);
|
||||
state.ctx->gpr.w0 = result::InvalidHandle;
|
||||
}
|
||||
}
|
||||
|
@ -402,25 +412,25 @@ namespace skyline::kernel::svc {
|
|||
|
||||
auto processMask{state.process->npdm.threadInfo.coreMask};
|
||||
if ((processMask | affinityMask) != processMask) {
|
||||
state.logger->Warn("svcSetThreadCoreMask: 'affinityMask' invalid: {} (Process Mask: {})", affinityMask, processMask);
|
||||
state.logger->Warn("'affinityMask' invalid: {} (Process Mask: {})", affinityMask, processMask);
|
||||
state.ctx->gpr.w0 = result::InvalidCoreId;
|
||||
return;
|
||||
}
|
||||
|
||||
if (affinityMask.none() || !affinityMask.test(idealCore)) {
|
||||
state.logger->Warn("svcSetThreadCoreMask: 'affinityMask' invalid: {} (Ideal Core: {})", affinityMask, idealCore);
|
||||
state.logger->Warn("'affinityMask' invalid: {} (Ideal Core: {})", affinityMask, idealCore);
|
||||
state.ctx->gpr.w0 = result::InvalidCombination;
|
||||
return;
|
||||
}
|
||||
|
||||
state.logger->Debug("svcSetThreadCoreMask: Setting thread #{}'s Ideal Core ({}) + Affinity Mask ({})", thread->id, idealCore, affinityMask);
|
||||
state.logger->Debug("Setting thread #{}'s Ideal Core ({}) + Affinity Mask ({})", thread->id, idealCore, affinityMask);
|
||||
|
||||
std::lock_guard guard(thread->coreMigrationMutex);
|
||||
thread->idealCore = idealCore;
|
||||
thread->affinityMask = affinityMask;
|
||||
|
||||
if (!affinityMask.test(thread->coreId) && thread->coreId != constant::ParkedCoreId) {
|
||||
state.logger->Debug("svcSetThreadCoreMask: Migrating thread #{} to Ideal Core C{} -> C{}", thread->id, thread->coreId, idealCore);
|
||||
state.logger->Debug("Migrating thread #{} to Ideal Core C{} -> C{}", thread->id, thread->coreId, idealCore);
|
||||
|
||||
if (thread == state.thread) {
|
||||
state.scheduler->RemoveThread();
|
||||
|
@ -436,7 +446,7 @@ namespace skyline::kernel::svc {
|
|||
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
} catch (const std::out_of_range &) {
|
||||
state.logger->Warn("svcSetThreadCoreMask: 'handle' invalid: 0x{:X}", handle);
|
||||
state.logger->Warn("'handle' invalid: 0x{:X}", handle);
|
||||
state.ctx->gpr.w0 = result::InvalidHandle;
|
||||
}
|
||||
}
|
||||
|
@ -444,18 +454,19 @@ namespace skyline::kernel::svc {
|
|||
void GetCurrentProcessorNumber(const DeviceState &state) {
|
||||
std::lock_guard guard(state.thread->coreMigrationMutex);
|
||||
auto coreId{state.thread->coreId};
|
||||
state.logger->Debug("svcGetCurrentProcessorNumber: C{}", coreId);
|
||||
state.logger->Debug("C{}", coreId);
|
||||
state.ctx->gpr.w0 = coreId;
|
||||
}
|
||||
|
||||
void ClearEvent(const DeviceState &state) {
|
||||
KHandle handle{state.ctx->gpr.w0};
|
||||
TRACE_EVENT_FMT("kernel", "ClearEvent 0x{:X}", handle);
|
||||
try {
|
||||
std::static_pointer_cast<type::KEvent>(state.process->GetHandle(handle))->ResetSignal();
|
||||
state.logger->Debug("svcClearEvent: Clearing 0x{:X}", handle);
|
||||
state.logger->Debug("Clearing 0x{:X}", handle);
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
} catch (const std::out_of_range &) {
|
||||
state.logger->Warn("svcClearEvent: 'handle' invalid: 0x{:X}", handle);
|
||||
state.logger->Warn("'handle' invalid: 0x{:X}", handle);
|
||||
state.ctx->gpr.w0 = result::InvalidHandle;
|
||||
return;
|
||||
}
|
||||
|
@ -468,31 +479,31 @@ namespace skyline::kernel::svc {
|
|||
|
||||
if (!util::PageAligned(pointer)) {
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
state.logger->Warn("svcMapSharedMemory: 'pointer' not page aligned: 0x{:X}", pointer);
|
||||
state.logger->Warn("'pointer' not page aligned: 0x{:X}", pointer);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t size{state.ctx->gpr.x2};
|
||||
if (!util::PageAligned(size)) {
|
||||
state.ctx->gpr.w0 = result::InvalidSize;
|
||||
state.logger->Warn("svcMapSharedMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||
state.logger->Warn("'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||
return;
|
||||
}
|
||||
|
||||
memory::Permission permission(state.ctx->gpr.w3);
|
||||
if ((permission.w && !permission.r) || (permission.x && !permission.r)) {
|
||||
state.logger->Warn("svcMapSharedMemory: 'permission' invalid: {}{}{}", permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-');
|
||||
state.logger->Warn("'permission' invalid: {}{}{}", permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-');
|
||||
state.ctx->gpr.w0 = result::InvalidNewMemoryPermission;
|
||||
return;
|
||||
}
|
||||
|
||||
state.logger->Debug("svcMapSharedMemory: Mapping shared memory at 0x{:X} - 0x{:X} (0x{:X} bytes) ({}{}{})", pointer, pointer + size, size, permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-');
|
||||
state.logger->Debug("Mapping shared memory at 0x{:X} - 0x{:X} (0x{:X} bytes) ({}{}{})", pointer, pointer + size, size, permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-');
|
||||
|
||||
object->Map(pointer, size, permission);
|
||||
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
} catch (const std::out_of_range &) {
|
||||
state.logger->Warn("svcMapSharedMemory: 'handle' invalid: 0x{:X}", static_cast<u32>(state.ctx->gpr.w0));
|
||||
state.logger->Warn("'handle' invalid: 0x{:X}", static_cast<u32>(state.ctx->gpr.w0));
|
||||
state.ctx->gpr.w0 = result::InvalidHandle;
|
||||
}
|
||||
}
|
||||
|
@ -501,26 +512,26 @@ namespace skyline::kernel::svc {
|
|||
auto pointer{reinterpret_cast<u8 *>(state.ctx->gpr.x1)};
|
||||
if (!util::PageAligned(pointer)) {
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
state.logger->Warn("svcCreateTransferMemory: 'pointer' not page aligned: 0x{:X}", pointer);
|
||||
state.logger->Warn("'pointer' not page aligned: 0x{:X}", pointer);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t size{state.ctx->gpr.x2};
|
||||
if (!util::PageAligned(size)) {
|
||||
state.ctx->gpr.w0 = result::InvalidSize;
|
||||
state.logger->Warn("svcCreateTransferMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||
state.logger->Warn("'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||
return;
|
||||
}
|
||||
|
||||
memory::Permission permission(state.ctx->gpr.w3);
|
||||
if ((permission.w && !permission.r) || (permission.x && !permission.r)) {
|
||||
state.logger->Warn("svcCreateTransferMemory: 'permission' invalid: {}{}{}", permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-');
|
||||
state.logger->Warn("'permission' invalid: {}{}{}", permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-');
|
||||
state.ctx->gpr.w0 = result::InvalidNewMemoryPermission;
|
||||
return;
|
||||
}
|
||||
|
||||
auto tmem{state.process->NewHandle<type::KTransferMemory>(pointer, size, permission)};
|
||||
state.logger->Debug("svcCreateTransferMemory: Creating transfer memory at 0x{:X} - 0x{:X} (0x{:X} bytes) ({}{}{})", pointer, pointer + size, size, permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-');
|
||||
state.logger->Debug("Creating transfer memory at 0x{:X} - 0x{:X} (0x{:X} bytes) ({}{}{})", pointer, pointer + size, size, permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-');
|
||||
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
state.ctx->gpr.w1 = tmem.handle;
|
||||
|
@ -530,16 +541,17 @@ namespace skyline::kernel::svc {
|
|||
KHandle handle{static_cast<KHandle>(state.ctx->gpr.w0)};
|
||||
try {
|
||||
state.process->CloseHandle(handle);
|
||||
state.logger->Debug("svcCloseHandle: Closing 0x{:X}", handle);
|
||||
state.logger->Debug("Closing 0x{:X}", handle);
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
} catch (const std::out_of_range &) {
|
||||
state.logger->Warn("svcCloseHandle: 'handle' invalid: 0x{:X}", handle);
|
||||
state.logger->Warn("'handle' invalid: 0x{:X}", handle);
|
||||
state.ctx->gpr.w0 = result::InvalidHandle;
|
||||
}
|
||||
}
|
||||
|
||||
void ResetSignal(const DeviceState &state) {
|
||||
KHandle handle{state.ctx->gpr.w0};
|
||||
TRACE_EVENT_FMT("kernel", "ResetSignal 0x{:X}", handle);
|
||||
try {
|
||||
auto object{state.process->GetHandle(handle)};
|
||||
switch (object->objectType) {
|
||||
|
@ -549,16 +561,16 @@ namespace skyline::kernel::svc {
|
|||
break;
|
||||
|
||||
default: {
|
||||
state.logger->Warn("svcResetSignal: 'handle' type invalid: 0x{:X} ({})", handle, object->objectType);
|
||||
state.logger->Warn("'handle' type invalid: 0x{:X} ({})", handle, object->objectType);
|
||||
state.ctx->gpr.w0 = result::InvalidHandle;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
state.logger->Debug("svcResetSignal: Resetting 0x{:X}", handle);
|
||||
state.logger->Debug("Resetting 0x{:X}", handle);
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
} catch (const std::out_of_range &) {
|
||||
state.logger->Warn("svcResetSignal: 'handle' invalid: 0x{:X}", handle);
|
||||
state.logger->Warn("'handle' invalid: 0x{:X}", handle);
|
||||
state.ctx->gpr.w0 = result::InvalidHandle;
|
||||
return;
|
||||
}
|
||||
|
@ -588,7 +600,7 @@ namespace skyline::kernel::svc {
|
|||
break;
|
||||
|
||||
default: {
|
||||
state.logger->Debug("svcWaitSynchronization: An invalid handle was supplied: 0x{:X}", handle);
|
||||
state.logger->Debug("An invalid handle was supplied: 0x{:X}", handle);
|
||||
state.ctx->gpr.w0 = result::InvalidHandle;
|
||||
return;
|
||||
}
|
||||
|
@ -597,12 +609,14 @@ namespace skyline::kernel::svc {
|
|||
|
||||
i64 timeout{static_cast<i64>(state.ctx->gpr.x3)};
|
||||
if (waitHandles.size() == 1) {
|
||||
state.logger->Debug("svcWaitSynchronization: Waiting on 0x{:X} for {}ns", waitHandles[0], timeout);
|
||||
state.logger->Debug("Waiting on 0x{:X} for {}ns", waitHandles[0], timeout);
|
||||
TRACE_EVENT_FMT("kernel", "WaitSynchronization 0x{:X}", waitHandles[0]);
|
||||
} else if (Logger::LogLevel::Debug <= state.logger->configLevel) {
|
||||
std::string handleString;
|
||||
for (const auto &handle : waitHandles)
|
||||
handleString += fmt::format("* 0x{:X}\n", handle);
|
||||
state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: {}ns", handleString, timeout);
|
||||
state.logger->Debug("Waiting on handles:\n{}Timeout: {}ns", handleString, timeout);
|
||||
TRACE_EVENT("kernel", "WaitSynchronizationMultiple");
|
||||
}
|
||||
|
||||
std::unique_lock lock(type::KSyncObject::syncObjectMutex);
|
||||
|
@ -615,7 +629,7 @@ namespace skyline::kernel::svc {
|
|||
u32 index{};
|
||||
for (const auto &object : objectTable) {
|
||||
if (object->signalled) {
|
||||
state.logger->Debug("svcWaitSynchronization: Signalled 0x{:X}", waitHandles[index]);
|
||||
state.logger->Debug("Signalled 0x{:X}", waitHandles[index]);
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
state.ctx->gpr.w1 = index;
|
||||
return;
|
||||
|
@ -624,7 +638,7 @@ namespace skyline::kernel::svc {
|
|||
}
|
||||
|
||||
if (timeout == 0) {
|
||||
state.logger->Debug("svcWaitSynchronization: No handle is currently signalled");
|
||||
state.logger->Debug("No handle is currently signalled");
|
||||
state.ctx->gpr.w0 = result::TimedOut;
|
||||
return;
|
||||
}
|
||||
|
@ -663,15 +677,15 @@ namespace skyline::kernel::svc {
|
|||
}
|
||||
|
||||
if (wakeObject) {
|
||||
state.logger->Debug("svcWaitSynchronization: Signalled 0x{:X}", waitHandles[wakeIndex]);
|
||||
state.logger->Debug("Signalled 0x{:X}", waitHandles[wakeIndex]);
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
state.ctx->gpr.w1 = wakeIndex;
|
||||
} else if (state.thread->cancelSync) {
|
||||
state.thread->cancelSync = false;
|
||||
state.logger->Debug("svcWaitSynchronization: Wait has been cancelled");
|
||||
state.logger->Debug("Wait has been cancelled");
|
||||
state.ctx->gpr.w0 = result::Cancelled;
|
||||
} else {
|
||||
state.logger->Debug("svcWaitSynchronization: Wait has timed out");
|
||||
state.logger->Debug("Wait has timed out");
|
||||
state.ctx->gpr.w0 = result::TimedOut;
|
||||
lock.unlock();
|
||||
state.scheduler->InsertThread(state.thread);
|
||||
|
@ -690,7 +704,7 @@ namespace skyline::kernel::svc {
|
|||
}
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
} catch (const std::out_of_range &) {
|
||||
state.logger->Warn("svcCancelSynchronization: 'handle' invalid: 0x{:X}", static_cast<u32>(state.ctx->gpr.w0));
|
||||
state.logger->Warn("'handle' invalid: 0x{:X}", static_cast<u32>(state.ctx->gpr.w0));
|
||||
state.ctx->gpr.w0 = result::InvalidHandle;
|
||||
}
|
||||
}
|
||||
|
@ -698,22 +712,23 @@ namespace skyline::kernel::svc {
|
|||
void ArbitrateLock(const DeviceState &state) {
|
||||
auto mutex{reinterpret_cast<u32 *>(state.ctx->gpr.x1)};
|
||||
if (!util::WordAligned(mutex)) {
|
||||
state.logger->Warn("svcArbitrateLock: 'mutex' not word aligned: 0x{:X}", mutex);
|
||||
state.logger->Warn("'mutex' not word aligned: 0x{:X}", mutex);
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
return;
|
||||
}
|
||||
|
||||
state.logger->Debug("svcArbitrateLock: Locking 0x{:X}", mutex);
|
||||
state.logger->Debug("Locking 0x{:X}", mutex);
|
||||
TRACE_EVENT_FMT("kernel", "MutexLock 0x{:X}", mutex);
|
||||
|
||||
KHandle ownerHandle{state.ctx->gpr.w0};
|
||||
KHandle requesterHandle{state.ctx->gpr.w2};
|
||||
auto result{state.process->MutexLock(mutex, ownerHandle, requesterHandle)};
|
||||
if (result == Result{})
|
||||
state.logger->Debug("svcArbitrateLock: Locked 0x{:X}", mutex);
|
||||
state.logger->Debug("Locked 0x{:X}", mutex);
|
||||
else if (result == result::InvalidCurrentMemory)
|
||||
result = Result{}; // If the mutex value isn't expected then it's still successful
|
||||
else if (result == result::InvalidHandle)
|
||||
state.logger->Warn("svcArbitrateLock: 'ownerHandle' invalid: 0x{:X} (0x{:X})", ownerHandle, mutex);
|
||||
state.logger->Warn("'ownerHandle' invalid: 0x{:X} (0x{:X})", ownerHandle, mutex);
|
||||
|
||||
state.ctx->gpr.w0 = result;
|
||||
}
|
||||
|
@ -721,14 +736,16 @@ namespace skyline::kernel::svc {
|
|||
void ArbitrateUnlock(const DeviceState &state) {
|
||||
auto mutex{reinterpret_cast<u32 *>(state.ctx->gpr.x0)};
|
||||
if (!util::WordAligned(mutex)) {
|
||||
state.logger->Warn("svcArbitrateUnlock: 'mutex' not word aligned: 0x{:X}", mutex);
|
||||
state.logger->Warn("'mutex' not word aligned: 0x{:X}", mutex);
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
return;
|
||||
}
|
||||
|
||||
state.logger->Debug("svcArbitrateUnlock: Unlocking 0x{:X}", mutex);
|
||||
TRACE_EVENT_FMT("kernel", "MutexUnlock 0x{:X}", mutex);
|
||||
|
||||
state.logger->Debug("Unlocking 0x{:X}", mutex);
|
||||
state.process->MutexUnlock(mutex);
|
||||
state.logger->Debug("svcArbitrateUnlock: Unlocked 0x{:X}", mutex);
|
||||
state.logger->Debug("Unlocked 0x{:X}", mutex);
|
||||
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
}
|
||||
|
@ -736,7 +753,7 @@ namespace skyline::kernel::svc {
|
|||
void WaitProcessWideKeyAtomic(const DeviceState &state) {
|
||||
auto mutex{reinterpret_cast<u32 *>(state.ctx->gpr.x0)};
|
||||
if (!util::WordAligned(mutex)) {
|
||||
state.logger->Warn("svcWaitProcessWideKeyAtomic: 'mutex' not word aligned: 0x{:X}", mutex);
|
||||
state.logger->Warn("'mutex' not word aligned: 0x{:X}", mutex);
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
return;
|
||||
}
|
||||
|
@ -745,13 +762,13 @@ namespace skyline::kernel::svc {
|
|||
KHandle requesterHandle{state.ctx->gpr.w2};
|
||||
|
||||
i64 timeout{static_cast<i64>(state.ctx->gpr.x3)};
|
||||
state.logger->Debug("svcWaitProcessWideKeyAtomic: Waiting on 0x{:X} with 0x{:X} for {}ns", conditional, mutex, timeout);
|
||||
state.logger->Debug("Waiting on 0x{:X} with 0x{:X} for {}ns", conditional, mutex, timeout);
|
||||
|
||||
auto result{state.process->ConditionalVariableWait(conditional, mutex, requesterHandle, timeout)};
|
||||
if (result == Result{})
|
||||
state.logger->Debug("svcWaitProcessWideKeyAtomic: Waited for 0x{:X} and reacquired 0x{:X}", conditional, mutex);
|
||||
state.logger->Debug("Waited for 0x{:X} and reacquired 0x{:X}", conditional, mutex);
|
||||
else if (result == result::TimedOut)
|
||||
state.logger->Debug("svcWaitProcessWideKeyAtomic: Wait on 0x{:X} has timed out after {}ns", conditional, timeout);
|
||||
state.logger->Debug("Wait on 0x{:X} has timed out after {}ns", conditional, timeout);
|
||||
state.ctx->gpr.w0 = result;
|
||||
}
|
||||
|
||||
|
@ -759,7 +776,7 @@ namespace skyline::kernel::svc {
|
|||
auto conditional{reinterpret_cast<u32 *>(state.ctx->gpr.x0)};
|
||||
i32 count{static_cast<i32>(state.ctx->gpr.w1)};
|
||||
|
||||
state.logger->Debug("svcSignalProcessWideKey: Signalling 0x{:X} for {} waiters", conditional, count);
|
||||
state.logger->Debug("Signalling 0x{:X} for {} waiters", conditional, count);
|
||||
state.process->ConditionalVariableSignal(conditional, count);
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
}
|
||||
|
@ -785,12 +802,12 @@ namespace skyline::kernel::svc {
|
|||
if (port.compare("sm:") >= 0) {
|
||||
handle = state.process->NewHandle<type::KSession>(std::static_pointer_cast<service::BaseService>(state.os->serviceManager.smUserInterface)).handle;
|
||||
} else {
|
||||
state.logger->Warn("svcConnectToNamedPort: Connecting to invalid port: '{}'", port);
|
||||
state.logger->Warn("Connecting to invalid port: '{}'", port);
|
||||
state.ctx->gpr.w0 = result::NotFound;
|
||||
return;
|
||||
}
|
||||
|
||||
state.logger->Debug("svcConnectToNamedPort: Connecting to port '{}' at 0x{:X}", port, handle);
|
||||
state.logger->Debug("Connecting to port '{}' at 0x{:X}", port, handle);
|
||||
|
||||
state.ctx->gpr.w1 = handle;
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
|
@ -806,7 +823,7 @@ namespace skyline::kernel::svc {
|
|||
KHandle handle{state.ctx->gpr.w1};
|
||||
size_t tid{state.process->GetHandle<type::KThread>(handle)->id};
|
||||
|
||||
state.logger->Debug("svcGetThreadId: Handle: 0x{:X}, TID: {}", handle, tid);
|
||||
state.logger->Debug("Handle: 0x{:X}, TID: {}", handle, tid);
|
||||
|
||||
state.ctx->gpr.x1 = tid;
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
|
@ -815,9 +832,9 @@ namespace skyline::kernel::svc {
|
|||
void Break(const DeviceState &state) {
|
||||
auto reason{state.ctx->gpr.x0};
|
||||
if (reason & (1ULL << 31)) {
|
||||
state.logger->Debug("svcBreak: Debugger is being engaged ({})", reason);
|
||||
state.logger->Debug("Debugger is being engaged ({})", reason);
|
||||
} else {
|
||||
state.logger->Error("svcBreak: Exit Stack Trace ({}){}", reason, state.loader->GetStackTrace());
|
||||
state.logger->Error("Exit Stack Trace ({}){}", reason, state.loader->GetStackTrace());
|
||||
if (state.thread->id)
|
||||
state.process->Kill(false);
|
||||
std::longjmp(state.thread->originalCtx, true);
|
||||
|
@ -825,12 +842,12 @@ namespace skyline::kernel::svc {
|
|||
}
|
||||
|
||||
void OutputDebugString(const DeviceState &state) {
|
||||
auto string{span(reinterpret_cast<u8 *>(state.ctx->gpr.x0), state.ctx->gpr.x1).as_string()};
|
||||
auto string{span(reinterpret_cast<char *>(state.ctx->gpr.x0), state.ctx->gpr.x1).as_string()};
|
||||
|
||||
if (string.back() == '\n')
|
||||
string.remove_suffix(1);
|
||||
|
||||
state.logger->Info("svcOutputDebugString: {}", string);
|
||||
state.logger->Info("{}", string);
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
}
|
||||
|
||||
|
@ -957,12 +974,12 @@ namespace skyline::kernel::svc {
|
|||
break;
|
||||
|
||||
default:
|
||||
state.logger->Warn("svcGetInfo: Unimplemented case ID0: {}, ID1: {}", static_cast<u32>(info), id1);
|
||||
state.logger->Warn("Unimplemented case ID0: {}, ID1: {}", static_cast<u32>(info), id1);
|
||||
state.ctx->gpr.w0 = result::InvalidEnumValue;
|
||||
return;
|
||||
}
|
||||
|
||||
state.logger->Debug("svcGetInfo: ID0: {}, ID1: {}, Out: 0x{:X}", static_cast<u32>(info), id1, out);
|
||||
state.logger->Debug("ID0: {}, ID1: {}, Out: 0x{:X}", static_cast<u32>(info), id1, out);
|
||||
|
||||
state.ctx->gpr.x1 = out;
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
|
@ -1017,7 +1034,7 @@ namespace skyline::kernel::svc {
|
|||
if (memory) {
|
||||
auto item{static_pointer_cast<type::KPrivateMemory>(memory->item)};
|
||||
auto initialSize{item->size};
|
||||
if (item->memState == memory::states::Heap) {
|
||||
if (item->memoryState == memory::states::Heap) {
|
||||
if (item->ptr >= pointer) {
|
||||
if (item->size <= size) {
|
||||
item->Resize(0);
|
||||
|
@ -1044,7 +1061,7 @@ namespace skyline::kernel::svc {
|
|||
void WaitForAddress(const DeviceState &state) {
|
||||
auto address{reinterpret_cast<u32 *>(state.ctx->gpr.x0)};
|
||||
if (!util::WordAligned(address)) [[unlikely]] {
|
||||
state.logger->Warn("svcWaitForAddress: 'address' not word aligned: 0x{:X}", address);
|
||||
state.logger->Warn("'address' not word aligned: 0x{:X}", address);
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
return;
|
||||
}
|
||||
|
@ -1060,14 +1077,14 @@ namespace skyline::kernel::svc {
|
|||
Result result;
|
||||
switch (arbitrationType) {
|
||||
case ArbitrationType::WaitIfLessThan:
|
||||
state.logger->Debug("svcWaitForAddress: Waiting on 0x{:X} if less than {} for {}ns", address, value, timeout);
|
||||
state.logger->Debug("Waiting on 0x{:X} if less than {} for {}ns", address, value, timeout);
|
||||
result = state.process->WaitForAddress(address, value, timeout, [](u32 *address, u32 value) {
|
||||
return *address < value;
|
||||
});
|
||||
break;
|
||||
|
||||
case ArbitrationType::DecrementAndWaitIfLessThan:
|
||||
state.logger->Debug("svcWaitForAddress: Waiting on and decrementing 0x{:X} if less than {} for {}ns", address, value, timeout);
|
||||
state.logger->Debug("Waiting on and decrementing 0x{:X} if less than {} for {}ns", address, value, timeout);
|
||||
result = state.process->WaitForAddress(address, value, timeout, [](u32 *address, u32 value) {
|
||||
u32 userValue{__atomic_load_n(address, __ATOMIC_SEQ_CST)};
|
||||
do {
|
||||
|
@ -1079,7 +1096,7 @@ namespace skyline::kernel::svc {
|
|||
break;
|
||||
|
||||
case ArbitrationType::WaitIfEqual:
|
||||
state.logger->Debug("svcWaitForAddress: Waiting on 0x{:X} if equal to {} for {}ns", address, value, timeout);
|
||||
state.logger->Debug("Waiting on 0x{:X} if equal to {} for {}ns", address, value, timeout);
|
||||
result = state.process->WaitForAddress(address, value, timeout, [](u32 *address, u32 value) {
|
||||
return *address == value;
|
||||
});
|
||||
|
@ -1087,18 +1104,18 @@ namespace skyline::kernel::svc {
|
|||
|
||||
default:
|
||||
[[unlikely]]
|
||||
state.logger->Error("svcWaitForAddress: 'arbitrationType' invalid: {}", arbitrationType);
|
||||
state.logger->Error("'arbitrationType' invalid: {}", arbitrationType);
|
||||
state.ctx->gpr.w0 = result::InvalidEnumValue;
|
||||
return;
|
||||
}
|
||||
|
||||
if (result == Result{})
|
||||
[[likely]]
|
||||
state.logger->Debug("svcWaitForAddress: Waited on 0x{:X} successfully", address);
|
||||
state.logger->Debug("Waited on 0x{:X} successfully", address);
|
||||
else if (result == result::TimedOut)
|
||||
state.logger->Debug("svcWaitForAddress: Wait on 0x{:X} has timed out after {}ns", address, timeout);
|
||||
state.logger->Debug("Wait on 0x{:X} has timed out after {}ns", address, timeout);
|
||||
else if (result == result::InvalidState)
|
||||
state.logger->Debug("svcWaitForAddress: The value at 0x{:X} did not satisfy the arbitration condition", address);
|
||||
state.logger->Debug("The value at 0x{:X} did not satisfy the arbitration condition", address);
|
||||
|
||||
state.ctx->gpr.w0 = result;
|
||||
}
|
||||
|
@ -1106,7 +1123,7 @@ namespace skyline::kernel::svc {
|
|||
void SignalToAddress(const DeviceState &state) {
|
||||
auto address{reinterpret_cast<u32 *>(state.ctx->gpr.x0)};
|
||||
if (!util::WordAligned(address)) [[unlikely]] {
|
||||
state.logger->Warn("svcWaitForAddress: 'address' not word aligned: 0x{:X}", address);
|
||||
state.logger->Warn("'address' not word aligned: 0x{:X}", address);
|
||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||
return;
|
||||
}
|
||||
|
@ -1122,19 +1139,19 @@ namespace skyline::kernel::svc {
|
|||
Result result;
|
||||
switch (signalType) {
|
||||
case SignalType::Signal:
|
||||
state.logger->Debug("svcSignalToAddress: Signalling 0x{:X} for {} waiters", address, count);
|
||||
state.logger->Debug("Signalling 0x{:X} for {} waiters", address, count);
|
||||
result = state.process->SignalToAddress(address, value, count);
|
||||
break;
|
||||
|
||||
case SignalType::SignalAndIncrementIfEqual:
|
||||
state.logger->Debug("svcSignalToAddress: Signalling 0x{:X} and incrementing if equal to {} for {} waiters", address, value, count);
|
||||
state.logger->Debug("Signalling 0x{:X} and incrementing if equal to {} for {} waiters", address, value, count);
|
||||
result = state.process->SignalToAddress(address, value, count, [](u32 *address, u32 value, u32) {
|
||||
return __atomic_compare_exchange_n(address, &value, value + 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
|
||||
});
|
||||
break;
|
||||
|
||||
case SignalType::SignalAndModifyBasedOnWaitingThreadCountIfEqual:
|
||||
state.logger->Debug("svcSignalToAddress: Signalling 0x{:X} and setting to waiting thread count if equal to {} for {} waiters", address, value, count);
|
||||
state.logger->Debug("Signalling 0x{:X} and setting to waiting thread count if equal to {} for {} waiters", address, value, count);
|
||||
result = state.process->SignalToAddress(address, value, count, [](u32 *address, u32 value, u32 waiterCount) {
|
||||
return __atomic_compare_exchange_n(address, &value, waiterCount, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
|
||||
});
|
||||
|
@ -1142,16 +1159,16 @@ namespace skyline::kernel::svc {
|
|||
|
||||
default:
|
||||
[[unlikely]]
|
||||
state.logger->Error("svcSignalToAddress: 'signalType' invalid: {}", signalType);
|
||||
state.logger->Error("'signalType' invalid: {}", signalType);
|
||||
state.ctx->gpr.w0 = result::InvalidEnumValue;
|
||||
return;
|
||||
}
|
||||
|
||||
if (result == Result{})
|
||||
[[likely]]
|
||||
state.logger->Debug("svcSignalToAddress: Signalled 0x{:X} for {} successfully", address, count);
|
||||
state.logger->Debug("Signalled 0x{:X} for {} successfully", address, count);
|
||||
else if (result == result::InvalidState)
|
||||
state.logger->Debug("svcSignalToAddress: The value at 0x{:X} did not satisfy the mutation condition", address);
|
||||
state.logger->Debug("The value at 0x{:X} did not satisfy the mutation condition", address);
|
||||
|
||||
state.ctx->gpr.w0 = result;
|
||||
}
|
||||
|
|
|
@ -229,136 +229,157 @@ namespace skyline::kernel::svc {
|
|||
void SignalToAddress(const DeviceState &state);
|
||||
|
||||
/**
|
||||
* @brief The SVC Table maps all SVCs to their corresponding functions
|
||||
* @brief A per-SVC descriptor with it's name and a function pointer
|
||||
* @note The descriptor is nullable, the validity of the descriptor can be checked with the boolean operator
|
||||
*/
|
||||
static std::array<void (*)(const DeviceState &), 0x80> SvcTable{
|
||||
nullptr, // 0x00 (Does not exist)
|
||||
SetHeapSize, // 0x01
|
||||
nullptr, // 0x02
|
||||
SetMemoryAttribute, // 0x03
|
||||
MapMemory, // 0x04
|
||||
UnmapMemory, // 0x05
|
||||
QueryMemory, // 0x06
|
||||
ExitProcess, // 0x07
|
||||
CreateThread, // 0x08
|
||||
StartThread, // 0x09
|
||||
ExitThread, // 0x0A
|
||||
SleepThread, // 0x0B
|
||||
GetThreadPriority, // 0x0C
|
||||
SetThreadPriority, // 0x0D
|
||||
GetThreadCoreMask, // 0x0E
|
||||
SetThreadCoreMask, // 0x0F
|
||||
GetCurrentProcessorNumber, // 0x10
|
||||
nullptr, // 0x11
|
||||
ClearEvent, // 0x12
|
||||
MapSharedMemory, // 0x13
|
||||
nullptr, // 0x14
|
||||
CreateTransferMemory, // 0x15
|
||||
CloseHandle, // 0x16
|
||||
ResetSignal, // 0x17
|
||||
WaitSynchronization, // 0x18
|
||||
CancelSynchronization, // 0x19
|
||||
ArbitrateLock, // 0x1A
|
||||
ArbitrateUnlock, // 0x1B
|
||||
WaitProcessWideKeyAtomic, // 0x1C
|
||||
SignalProcessWideKey, // 0x1D
|
||||
GetSystemTick, // 0x1E
|
||||
ConnectToNamedPort, // 0x1F
|
||||
nullptr, // 0x20
|
||||
SendSyncRequest, // 0x21
|
||||
nullptr, // 0x22
|
||||
nullptr, // 0x23
|
||||
nullptr, // 0x24
|
||||
GetThreadId, // 0x25
|
||||
Break, // 0x26
|
||||
OutputDebugString, // 0x27
|
||||
nullptr, // 0x28
|
||||
GetInfo, // 0x29
|
||||
nullptr, // 0x2A
|
||||
nullptr, // 0x2B
|
||||
MapPhysicalMemory, // 0x2C
|
||||
UnmapPhysicalMemory, // 0x2D
|
||||
nullptr, // 0x2E
|
||||
nullptr, // 0x2F
|
||||
nullptr, // 0x30
|
||||
nullptr, // 0x31
|
||||
nullptr, // 0x32
|
||||
nullptr, // 0x33
|
||||
WaitForAddress, // 0x34
|
||||
SignalToAddress, // 0x35
|
||||
nullptr, // 0x36
|
||||
nullptr, // 0x37
|
||||
nullptr, // 0x38
|
||||
nullptr, // 0x39
|
||||
nullptr, // 0x3A
|
||||
nullptr, // 0x3B
|
||||
nullptr, // 0x3C
|
||||
nullptr, // 0x3D
|
||||
nullptr, // 0x3E
|
||||
nullptr, // 0x3F
|
||||
nullptr, // 0x40
|
||||
nullptr, // 0x41
|
||||
nullptr, // 0x42
|
||||
nullptr, // 0x43
|
||||
nullptr, // 0x44
|
||||
nullptr, // 0x45
|
||||
nullptr, // 0x46
|
||||
nullptr, // 0x47
|
||||
nullptr, // 0x48
|
||||
nullptr, // 0x49
|
||||
nullptr, // 0x4A
|
||||
nullptr, // 0x4B
|
||||
nullptr, // 0x4C
|
||||
nullptr, // 0x4D
|
||||
nullptr, // 0x4E
|
||||
nullptr, // 0x4F
|
||||
nullptr, // 0x50
|
||||
nullptr, // 0x51
|
||||
nullptr, // 0x52
|
||||
nullptr, // 0x53
|
||||
nullptr, // 0x54
|
||||
nullptr, // 0x55
|
||||
nullptr, // 0x56
|
||||
nullptr, // 0x57
|
||||
nullptr, // 0x58
|
||||
nullptr, // 0x59
|
||||
nullptr, // 0x5A
|
||||
nullptr, // 0x5B
|
||||
nullptr, // 0x5C
|
||||
nullptr, // 0x5D
|
||||
nullptr, // 0x5E
|
||||
nullptr, // 0x5F
|
||||
nullptr, // 0x60
|
||||
nullptr, // 0x61
|
||||
nullptr, // 0x62
|
||||
nullptr, // 0x63
|
||||
nullptr, // 0x64
|
||||
nullptr, // 0x65
|
||||
nullptr, // 0x66
|
||||
nullptr, // 0x67
|
||||
nullptr, // 0x68
|
||||
nullptr, // 0x69
|
||||
nullptr, // 0x6A
|
||||
nullptr, // 0x6B
|
||||
nullptr, // 0x6C
|
||||
nullptr, // 0x6D
|
||||
nullptr, // 0x6E
|
||||
nullptr, // 0x6F
|
||||
nullptr, // 0x70
|
||||
nullptr, // 0x71
|
||||
nullptr, // 0x72
|
||||
nullptr, // 0x73
|
||||
nullptr, // 0x74
|
||||
nullptr, // 0x75
|
||||
nullptr, // 0x76
|
||||
nullptr, // 0x77
|
||||
nullptr, // 0x78
|
||||
nullptr, // 0x79
|
||||
nullptr, // 0x7A
|
||||
nullptr, // 0x7B
|
||||
nullptr, // 0x7C
|
||||
nullptr, // 0x7D
|
||||
nullptr, // 0x7E
|
||||
nullptr // 0x7F
|
||||
struct SvcDescriptor {
|
||||
void (*function)(const DeviceState &); //!< A function pointer to a HLE implementation of the SVC
|
||||
const char* name; //!< A pointer to a static string of the SVC name, the underlying data should not be mutated
|
||||
|
||||
operator bool() {
|
||||
return function;
|
||||
}
|
||||
};
|
||||
|
||||
#define SVC_NONE SvcDescriptor{} //!< A macro with a placeholder value for the SVC not being implemented or not existing
|
||||
#define SVC_STRINGIFY(name) #name
|
||||
#define SVC_ENTRY(function) SvcDescriptor{function, SVC_STRINGIFY(Svc ## function)} //!< A macro which automatically stringifies the function name as the name to prevent pointless duplication
|
||||
|
||||
/**
|
||||
* @brief The SVC table maps all SVCs to their corresponding functions
|
||||
*/
|
||||
static constexpr std::array<SvcDescriptor, 0x80> SvcTable{
|
||||
SVC_NONE, // 0x00 (Does not exist)
|
||||
SVC_ENTRY(SetHeapSize), // 0x01
|
||||
SVC_NONE, // 0x02
|
||||
SVC_ENTRY(SetMemoryAttribute), // 0x03
|
||||
SVC_ENTRY(MapMemory), // 0x04
|
||||
SVC_ENTRY(UnmapMemory), // 0x05
|
||||
SVC_ENTRY(QueryMemory), // 0x06
|
||||
SVC_ENTRY(ExitProcess), // 0x07
|
||||
SVC_ENTRY(CreateThread), // 0x08
|
||||
SVC_ENTRY(StartThread), // 0x09
|
||||
SVC_ENTRY(ExitThread), // 0x0A
|
||||
SVC_ENTRY(SleepThread), // 0x0B
|
||||
SVC_ENTRY(GetThreadPriority), // 0x0C
|
||||
SVC_ENTRY(SetThreadPriority), // 0x0D
|
||||
SVC_ENTRY(GetThreadCoreMask), // 0x0E
|
||||
SVC_ENTRY(SetThreadCoreMask), // 0x0F
|
||||
SVC_ENTRY(GetCurrentProcessorNumber), // 0x10
|
||||
SVC_NONE, // 0x11
|
||||
SVC_ENTRY(ClearEvent), // 0x12
|
||||
SVC_ENTRY(MapSharedMemory), // 0x13
|
||||
SVC_NONE, // 0x14
|
||||
SVC_ENTRY(CreateTransferMemory), // 0x15
|
||||
SVC_ENTRY(CloseHandle), // 0x16
|
||||
SVC_ENTRY(ResetSignal), // 0x17
|
||||
SVC_ENTRY(WaitSynchronization), // 0x18
|
||||
SVC_ENTRY(CancelSynchronization), // 0x19
|
||||
SVC_ENTRY(ArbitrateLock), // 0x1A
|
||||
SVC_ENTRY(ArbitrateUnlock), // 0x1B
|
||||
SVC_ENTRY(WaitProcessWideKeyAtomic), // 0x1C
|
||||
SVC_ENTRY(SignalProcessWideKey), // 0x1D
|
||||
SVC_ENTRY(GetSystemTick), // 0x1E
|
||||
SVC_ENTRY(ConnectToNamedPort), // 0x1F
|
||||
SVC_NONE, // 0x20
|
||||
SVC_ENTRY(SendSyncRequest), // 0x21
|
||||
SVC_NONE, // 0x22
|
||||
SVC_NONE, // 0x23
|
||||
SVC_NONE, // 0x24
|
||||
SVC_ENTRY(GetThreadId), // 0x25
|
||||
SVC_ENTRY(Break), // 0x26
|
||||
SVC_ENTRY(OutputDebugString), // 0x27
|
||||
SVC_NONE, // 0x28
|
||||
SVC_ENTRY(GetInfo), // 0x29
|
||||
SVC_NONE, // 0x2A
|
||||
SVC_NONE, // 0x2B
|
||||
SVC_ENTRY(MapPhysicalMemory), // 0x2C
|
||||
SVC_ENTRY(UnmapPhysicalMemory), // 0x2D
|
||||
SVC_NONE, // 0x2E
|
||||
SVC_NONE, // 0x2F
|
||||
SVC_NONE, // 0x30
|
||||
SVC_NONE, // 0x31
|
||||
SVC_NONE, // 0x32
|
||||
SVC_NONE, // 0x33
|
||||
SVC_ENTRY(WaitForAddress), // 0x34
|
||||
SVC_ENTRY(SignalToAddress), // 0x35
|
||||
SVC_NONE, // 0x36
|
||||
SVC_NONE, // 0x37
|
||||
SVC_NONE, // 0x38
|
||||
SVC_NONE, // 0x39
|
||||
SVC_NONE, // 0x3A
|
||||
SVC_NONE, // 0x3B
|
||||
SVC_NONE, // 0x3C
|
||||
SVC_NONE, // 0x3D
|
||||
SVC_NONE, // 0x3E
|
||||
SVC_NONE, // 0x3F
|
||||
SVC_NONE, // 0x40
|
||||
SVC_NONE, // 0x41
|
||||
SVC_NONE, // 0x42
|
||||
SVC_NONE, // 0x43
|
||||
SVC_NONE, // 0x44
|
||||
SVC_NONE, // 0x45
|
||||
SVC_NONE, // 0x46
|
||||
SVC_NONE, // 0x47
|
||||
SVC_NONE, // 0x48
|
||||
SVC_NONE, // 0x49
|
||||
SVC_NONE, // 0x4A
|
||||
SVC_NONE, // 0x4B
|
||||
SVC_NONE, // 0x4C
|
||||
SVC_NONE, // 0x4D
|
||||
SVC_NONE, // 0x4E
|
||||
SVC_NONE, // 0x4F
|
||||
SVC_NONE, // 0x50
|
||||
SVC_NONE, // 0x51
|
||||
SVC_NONE, // 0x52
|
||||
SVC_NONE, // 0x53
|
||||
SVC_NONE, // 0x54
|
||||
SVC_NONE, // 0x55
|
||||
SVC_NONE, // 0x56
|
||||
SVC_NONE, // 0x57
|
||||
SVC_NONE, // 0x58
|
||||
SVC_NONE, // 0x59
|
||||
SVC_NONE, // 0x5A
|
||||
SVC_NONE, // 0x5B
|
||||
SVC_NONE, // 0x5C
|
||||
SVC_NONE, // 0x5D
|
||||
SVC_NONE, // 0x5E
|
||||
SVC_NONE, // 0x5F
|
||||
SVC_NONE, // 0x60
|
||||
SVC_NONE, // 0x61
|
||||
SVC_NONE, // 0x62
|
||||
SVC_NONE, // 0x63
|
||||
SVC_NONE, // 0x64
|
||||
SVC_NONE, // 0x65
|
||||
SVC_NONE, // 0x66
|
||||
SVC_NONE, // 0x67
|
||||
SVC_NONE, // 0x68
|
||||
SVC_NONE, // 0x69
|
||||
SVC_NONE, // 0x6A
|
||||
SVC_NONE, // 0x6B
|
||||
SVC_NONE, // 0x6C
|
||||
SVC_NONE, // 0x6D
|
||||
SVC_NONE, // 0x6E
|
||||
SVC_NONE, // 0x6F
|
||||
SVC_NONE, // 0x70
|
||||
SVC_NONE, // 0x71
|
||||
SVC_NONE, // 0x72
|
||||
SVC_NONE, // 0x73
|
||||
SVC_NONE, // 0x74
|
||||
SVC_NONE, // 0x75
|
||||
SVC_NONE, // 0x76
|
||||
SVC_NONE, // 0x77
|
||||
SVC_NONE, // 0x78
|
||||
SVC_NONE, // 0x79
|
||||
SVC_NONE, // 0x7A
|
||||
SVC_NONE, // 0x7B
|
||||
SVC_NONE, // 0x7C
|
||||
SVC_NONE, // 0x7D
|
||||
SVC_NONE, // 0x7E
|
||||
SVC_NONE // 0x7F
|
||||
};
|
||||
|
||||
#undef SVC_NONE
|
||||
#undef SVC_STRINGIFY
|
||||
#undef SVC_ENTRY
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include "KProcess.h"
|
||||
|
||||
namespace skyline::kernel::type {
|
||||
KPrivateMemory::KPrivateMemory(const DeviceState &state, u8 *ptr, size_t size, memory::Permission permission, memory::MemoryState memState) : ptr(ptr), size(size), permission(permission), memState(memState), KMemory(state, KType::KPrivateMemory) {
|
||||
KPrivateMemory::KPrivateMemory(const DeviceState &state, u8 *ptr, size_t size, memory::Permission permission, memory::MemoryState memState) : ptr(ptr), size(size), permission(permission), memoryState(memState), KMemory(state, KType::KPrivateMemory) {
|
||||
if (!state.process->memory.base.IsInside(ptr) || !state.process->memory.base.IsInside(ptr + size))
|
||||
throw exception("KPrivateMemory allocation isn't inside guest address space: 0x{:X} - 0x{:X}", ptr, ptr + size);
|
||||
if (!util::PageAligned(ptr) || !util::PageAligned(size))
|
||||
|
@ -40,7 +40,7 @@ namespace skyline::kernel::type {
|
|||
.ptr = ptr + size,
|
||||
.size = nSize - size,
|
||||
.permission = permission,
|
||||
.state = memState,
|
||||
.state = memoryState,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -60,22 +60,22 @@ namespace skyline::kernel::type {
|
|||
throw exception("An occurred while remapping private memory: {}", strerror(errno));
|
||||
}
|
||||
|
||||
void KPrivateMemory::UpdatePermission(u8 *ptr, size_t size, memory::Permission permission) {
|
||||
ptr = std::clamp(ptr, this->ptr, this->ptr + this->size);
|
||||
size = std::min(size, static_cast<size_t>((this->ptr + this->size) - ptr));
|
||||
void KPrivateMemory::UpdatePermission(u8 *pPtr, size_t pSize, memory::Permission pPermission) {
|
||||
pPtr = std::clamp(pPtr, ptr, ptr + size);
|
||||
pSize = std::min(pSize, static_cast<size_t>((ptr + size) - pPtr));
|
||||
|
||||
if (ptr && !util::PageAligned(ptr))
|
||||
throw exception("KPrivateMemory permission updated with a non-page-aligned address: 0x{:X}", ptr);
|
||||
if (pPtr && !util::PageAligned(pPtr))
|
||||
throw exception("KPrivateMemory permission updated with a non-page-aligned address: 0x{:X}", pPtr);
|
||||
|
||||
// If a static code region has been mapped as writable it needs to be changed to mutable
|
||||
if (memState == memory::states::CodeStatic && permission.w)
|
||||
memState = memory::states::CodeMutable;
|
||||
if (memoryState == memory::states::CodeStatic && pPermission.w)
|
||||
memoryState = memory::states::CodeMutable;
|
||||
|
||||
state.process->memory.InsertChunk(ChunkDescriptor{
|
||||
.ptr = ptr,
|
||||
.size = size,
|
||||
.permission = permission,
|
||||
.state = memState,
|
||||
.ptr = pPtr,
|
||||
.size = pSize,
|
||||
.permission = pPermission,
|
||||
.state = memoryState,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -8,13 +8,14 @@
|
|||
namespace skyline::kernel::type {
|
||||
/**
|
||||
* @brief KPrivateMemory is used to map memory local to the guest process
|
||||
* @note This does not reflect a kernel object in Horizon OS, it is an abstraction which makes things simpler to manage in Skyline instead
|
||||
*/
|
||||
class KPrivateMemory : public KMemory {
|
||||
public:
|
||||
u8 *ptr{};
|
||||
size_t size{};
|
||||
memory::Permission permission;
|
||||
memory::MemoryState memState;
|
||||
memory::MemoryState memoryState;
|
||||
|
||||
/**
|
||||
* @param permission The permissions for the allocated memory (As reported to the application, host memory permissions aren't reflected by this)
|
||||
|
@ -22,10 +23,14 @@ namespace skyline::kernel::type {
|
|||
*/
|
||||
KPrivateMemory(const DeviceState &state, u8 *ptr, size_t size, memory::Permission permission, memory::MemoryState memState);
|
||||
|
||||
/**
|
||||
* @note There is no check regarding if any expansions will cause the memory mapping to leak into other mappings
|
||||
* @note Any extensions will have the same permissions and memory state as the initial mapping as opposed to extending the end
|
||||
*/
|
||||
void Resize(size_t size);
|
||||
|
||||
/**
|
||||
* @note Only contents of any overlapping regions will be retained
|
||||
* @note This does not copy over anything, only contents of any overlapping regions will be retained
|
||||
*/
|
||||
void Remap(u8 *ptr, size_t size);
|
||||
|
||||
|
@ -33,7 +38,7 @@ namespace skyline::kernel::type {
|
|||
return span(ptr, size);
|
||||
}
|
||||
|
||||
void UpdatePermission(u8 *ptr, size_t size, memory::Permission permission) override;
|
||||
void UpdatePermission(u8 *pPtr, size_t pSize, memory::Permission pPermission) override;
|
||||
|
||||
/**
|
||||
* @brief The destructor of private memory, it deallocates the memory
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
#include <nce.h>
|
||||
#include <os.h>
|
||||
#include <common/trace.h>
|
||||
#include <kernel/results.h>
|
||||
|
||||
#include "KProcess.h"
|
||||
|
||||
namespace skyline::kernel::type {
|
||||
|
@ -104,6 +104,8 @@ namespace skyline::kernel::type {
|
|||
constexpr u32 HandleWaitersBit{1UL << 30}; //!< A bit which denotes if a mutex psuedo-handle has waiters or not
|
||||
|
||||
Result KProcess::MutexLock(u32 *mutex, KHandle ownerHandle, KHandle tag) {
|
||||
TRACE_EVENT_FMT("kernel", "MutexLock 0x{:X}", mutex);
|
||||
|
||||
std::shared_ptr<KThread> owner;
|
||||
try {
|
||||
owner = GetHandle<KThread>(ownerHandle);
|
||||
|
@ -142,6 +144,8 @@ namespace skyline::kernel::type {
|
|||
}
|
||||
|
||||
void KProcess::MutexUnlock(u32 *mutex) {
|
||||
TRACE_EVENT_FMT("kernel", "MutexUnlock 0x{:X}", mutex);
|
||||
|
||||
std::lock_guard lock(state.thread->waiterMutex);
|
||||
auto &waiters{state.thread->waiters};
|
||||
auto nextOwnerIt{std::find_if(waiters.begin(), waiters.end(), [mutex](const std::shared_ptr<KThread> &thread) { return thread->waitKey == mutex; })};
|
||||
|
@ -203,6 +207,8 @@ namespace skyline::kernel::type {
|
|||
}
|
||||
|
||||
Result KProcess::ConditionalVariableWait(u32 *key, u32 *mutex, KHandle tag, i64 timeout) {
|
||||
TRACE_EVENT_FMT("kernel", "ConditionalVariableWait 0x{:X} (0x{:X})", key, mutex);
|
||||
|
||||
{
|
||||
std::lock_guard lock(syncWaiterMutex);
|
||||
auto queue{syncWaiters.equal_range(key)};
|
||||
|
@ -242,6 +248,8 @@ namespace skyline::kernel::type {
|
|||
}
|
||||
|
||||
void KProcess::ConditionalVariableSignal(u32 *key, i32 amount) {
|
||||
TRACE_EVENT_FMT("kernel", "ConditionalVariableSignal 0x{:X}", key);
|
||||
|
||||
std::lock_guard lock(syncWaiterMutex);
|
||||
auto queue{syncWaiters.equal_range(key)};
|
||||
|
||||
|
@ -254,6 +262,8 @@ namespace skyline::kernel::type {
|
|||
}
|
||||
|
||||
Result KProcess::WaitForAddress(u32 *address, u32 value, i64 timeout, bool (*arbitrationFunction)(u32 *, u32)) {
|
||||
TRACE_EVENT_FMT("kernel", "WaitForAddress 0x{:X}", address);
|
||||
|
||||
{
|
||||
std::lock_guard lock(syncWaiterMutex);
|
||||
if (!arbitrationFunction(address, value)) [[unlikely]]
|
||||
|
@ -287,6 +297,8 @@ namespace skyline::kernel::type {
|
|||
}
|
||||
|
||||
Result KProcess::SignalToAddress(u32 *address, u32 value, i32 amount, bool(*mutateFunction)(u32 *address, u32 value, u32 waiterCount)) {
|
||||
TRACE_EVENT_FMT("kernel", "SignalToAddress 0x{:X}", address);
|
||||
|
||||
std::lock_guard lock(syncWaiterMutex);
|
||||
auto queue{syncWaiters.equal_range(address)};
|
||||
|
||||
|
|
|
@ -8,14 +8,15 @@
|
|||
#include "KProcess.h"
|
||||
|
||||
namespace skyline::kernel::type {
|
||||
KSharedMemory::KSharedMemory(const DeviceState &state, size_t size, memory::MemoryState memState, KType type) : initialState(memState), KMemory(state, type) {
|
||||
KSharedMemory::KSharedMemory(const DeviceState &state, size_t size, memory::MemoryState memState, KType type) : memoryState(memState), KMemory(state, type) {
|
||||
fd = ASharedMemory_create("KSharedMemory", size);
|
||||
if (fd < 0)
|
||||
throw exception("An error occurred while creating shared memory: {}", fd);
|
||||
|
||||
kernel.ptr = reinterpret_cast<u8 *>(mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, fd, 0));
|
||||
if (kernel.ptr == MAP_FAILED)
|
||||
throw exception("An occurred while mapping shared memory: {}", strerror(errno));
|
||||
[[unlikely]]
|
||||
throw exception("An occurred while mapping shared memory: {}", strerror(errno));
|
||||
|
||||
kernel.size = size;
|
||||
}
|
||||
|
@ -28,14 +29,15 @@ namespace skyline::kernel::type {
|
|||
|
||||
guest.ptr = reinterpret_cast<u8 *>(mmap(ptr, size, permission.Get(), MAP_SHARED | (ptr ? MAP_FIXED : 0), fd, 0));
|
||||
if (guest.ptr == MAP_FAILED)
|
||||
throw exception("An error occurred while mapping shared memory in guest");
|
||||
[[unlikely]]
|
||||
throw exception("An error occurred while mapping shared memory in guest: {}", strerror(errno));
|
||||
guest.size = size;
|
||||
|
||||
state.process->memory.InsertChunk(ChunkDescriptor{
|
||||
.ptr = guest.ptr,
|
||||
.size = size,
|
||||
.permission = permission,
|
||||
.state = initialState,
|
||||
.state = memoryState,
|
||||
});
|
||||
|
||||
return guest.ptr;
|
||||
|
@ -47,15 +49,15 @@ namespace skyline::kernel::type {
|
|||
|
||||
if (guest.Valid()) {
|
||||
mprotect(ptr, size, permission.Get());
|
||||
|
||||
if (guest.ptr == MAP_FAILED)
|
||||
throw exception("An error occurred while updating shared memory's permissions in guest");
|
||||
[[unlikely]]
|
||||
throw exception("An error occurred while updating shared memory's permissions in guest: {}", strerror(errno));
|
||||
|
||||
state.process->memory.InsertChunk(ChunkDescriptor{
|
||||
.ptr = ptr,
|
||||
.size = size,
|
||||
.permission = permission,
|
||||
.state = initialState,
|
||||
.state = memoryState,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -65,7 +67,7 @@ namespace skyline::kernel::type {
|
|||
munmap(kernel.ptr, kernel.size);
|
||||
|
||||
if (state.process && guest.Valid()) {
|
||||
mmap(guest.ptr, guest.size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
mmap(guest.ptr, guest.size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); // As this is the destructor, we cannot throw on this failing
|
||||
state.process->memory.InsertChunk(ChunkDescriptor{
|
||||
.ptr = guest.ptr,
|
||||
.size = guest.size,
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
|
||||
namespace skyline::kernel::type {
|
||||
/**
|
||||
* @brief KSharedMemory is used to retain two mappings of the same underlying memory, allowing persistence of the memory
|
||||
* @brief KSharedMemory is used to retain two mappings of the same underlying memory, allowing sharing memory between two processes
|
||||
*/
|
||||
class KSharedMemory : public KMemory {
|
||||
private:
|
||||
int fd; //!< A file descriptor to the underlying shared memory
|
||||
memory::MemoryState initialState;
|
||||
memory::MemoryState memoryState; //!< The state of the memory as supplied initially, this is retained for any mappings
|
||||
|
||||
public:
|
||||
struct MapInfo {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <cxxabi.h>
|
||||
#include <unistd.h>
|
||||
#include <common/signal.h>
|
||||
#include <common/trace.h>
|
||||
#include <nce.h>
|
||||
#include <os.h>
|
||||
#include "KProcess.h"
|
||||
|
@ -82,6 +83,8 @@ namespace skyline::kernel::type {
|
|||
state.scheduler->WaitSchedule();
|
||||
}
|
||||
|
||||
TRACE_EVENT_BEGIN("guest", "Guest");
|
||||
|
||||
asm volatile(
|
||||
"MRS X0, TPIDR_EL0\n\t"
|
||||
"MSR TPIDR_EL0, %x0\n\t" // Set TLS to ThreadContext
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace skyline::kernel::type {
|
||||
/**
|
||||
* @brief KTransferMemory is used to transfer memory from one application to another on HOS, we emulate this abstraction using KSharedMemory as it's functionally indistinguishable for the guest and allows access from the kernel regardless of if it's mapped on the guest
|
||||
* @brief KTransferMemory is used to transfer memory from one application to another on HOS, we emulate this abstraction using KSharedMemory as it's essentially the same with the main difference being that KSharedMemory is allocated by the kernel while KTransferMemory is created from memory that's been allocated by the guest beforehand
|
||||
*/
|
||||
class KTransferMemory : public KSharedMemory {
|
||||
public:
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
#include <cxxabi.h>
|
||||
#include <unistd.h>
|
||||
#include "common/signal.h"
|
||||
#include "common/trace.h"
|
||||
#include "os.h"
|
||||
#include "gpu.h"
|
||||
#include "jvm.h"
|
||||
#include "kernel/types/KProcess.h"
|
||||
#include "kernel/svc.h"
|
||||
|
@ -14,15 +14,17 @@
|
|||
#include "nce.h"
|
||||
|
||||
namespace skyline::nce {
|
||||
void NCE::SvcHandler(u16 svc, ThreadContext *ctx) {
|
||||
void NCE::SvcHandler(u16 svcId, ThreadContext *ctx) {
|
||||
TRACE_EVENT_END("guest");
|
||||
|
||||
const auto &state{*ctx->state};
|
||||
auto svc{kernel::svc::SvcTable[svcId]};
|
||||
try {
|
||||
auto function{kernel::svc::SvcTable[svc]};
|
||||
if (function) [[likely]] {
|
||||
state.logger->Debug("SVC called 0x{:X}", svc);
|
||||
(*function)(state);
|
||||
if (svc) [[likely]] {
|
||||
TRACE_EVENT("kernel", perfetto::StaticString{svc.name});
|
||||
(svc.function)(state);
|
||||
} else [[unlikely]] {
|
||||
throw exception("Unimplemented SVC 0x{:X}", svc);
|
||||
throw exception("Unimplemented SVC 0x{:X}", svcId);
|
||||
}
|
||||
|
||||
while (kernel::Scheduler::YieldPending) [[unlikely]] {
|
||||
|
@ -32,7 +34,7 @@ namespace skyline::nce {
|
|||
}
|
||||
} catch (const signal::SignalException &e) {
|
||||
if (e.signal != SIGINT) {
|
||||
state.logger->Error("{} (SVC: 0x{:X})\nStack Trace:{}", e.what(), svc, state.loader->GetStackTrace(e.frames));
|
||||
state.logger->ErrorNoPrefix("{} (SVC: 0x{:X})\nStack Trace:{}", e.what(), svc.name, state.loader->GetStackTrace(e.frames));
|
||||
if (state.thread->id) {
|
||||
signal::BlockSignal({SIGINT});
|
||||
state.process->Kill(false);
|
||||
|
@ -41,7 +43,11 @@ namespace skyline::nce {
|
|||
abi::__cxa_end_catch(); // We call this prior to the longjmp to cause the exception object to be destroyed
|
||||
std::longjmp(state.thread->originalCtx, true);
|
||||
} catch (const std::exception &e) {
|
||||
state.logger->Error("{} (SVC: 0x{:X})\nStack Trace:{}", e.what(), svc, state.loader->GetStackTrace());
|
||||
if (svc)
|
||||
state.logger->ErrorNoPrefix("{} (SVC: {})\nStack Trace:{}", e.what(), svc.name, state.loader->GetStackTrace());
|
||||
else
|
||||
state.logger->ErrorNoPrefix("{} (SVC: 0x{:X})\nStack Trace:{}", e.what(), svcId, state.loader->GetStackTrace());
|
||||
|
||||
if (state.thread->id) {
|
||||
signal::BlockSignal({SIGINT});
|
||||
state.process->Kill(false);
|
||||
|
@ -49,6 +55,8 @@ namespace skyline::nce {
|
|||
abi::__cxa_end_catch();
|
||||
std::longjmp(state.thread->originalCtx, true);
|
||||
}
|
||||
|
||||
TRACE_EVENT_BEGIN("guest", "Guest");
|
||||
}
|
||||
|
||||
void NCE::SignalHandler(int signal, siginfo *info, ucontext *ctx, void **tls) {
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace skyline::nce {
|
|||
private:
|
||||
const DeviceState &state;
|
||||
|
||||
static void SvcHandler(u16 svc, ThreadContext *ctx);
|
||||
static void SvcHandler(u16 svcId, ThreadContext *ctx);
|
||||
|
||||
public:
|
||||
static void SignalHandler(int signal, siginfo *info, ucontext *ctx, void **tls);
|
||||
|
|
|
@ -20,9 +20,6 @@ namespace skyline::service::am {
|
|||
*/
|
||||
Result GetApplicationFunctions(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
//#undef SFUNC_BASE
|
||||
//#define SFUNC_BASE(id, Class, BaseClass, Function) std::pair<u32, std::pair<std::function<Result(Class*, type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &)>, std::string_view>>{id, {&CallBaseFunction<Class, BaseClass, BaseClass::Function>, #Function}}
|
||||
|
||||
SERVICE_DECL(
|
||||
SFUNC_BASE(0x0, IApplicationProxy, BaseProxy, GetCommonStateGetter),
|
||||
SFUNC_BASE(0x1, IApplicationProxy, BaseProxy, GetSelfController),
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace skyline::service::audio {
|
|||
Result IAudioRendererManager::OpenAudioRenderer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
IAudioRenderer::AudioRendererParameters params{request.Pop<IAudioRenderer::AudioRendererParameters>()};
|
||||
|
||||
state.logger->Debug("IAudioRendererManager: Opening a rev {} IAudioRenderer with sample rate: {}, voice count: {}, effect count: {}", IAudioRenderer::ExtractVersionFromRevision(params.revision), params.sampleRate, params.voiceCount, params.effectCount);
|
||||
state.logger->Debug("Opening a rev {} IAudioRenderer with sample rate: {}, voice count: {}, effect count: {}", IAudioRenderer::ExtractVersionFromRevision(params.revision), params.sampleRate, params.voiceCount, params.effectCount);
|
||||
|
||||
manager.RegisterService(std::make_shared<IAudioRenderer::IAudioRenderer>(state, manager, params), session, response);
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include <cxxabi.h>
|
||||
#include <common/trace.h>
|
||||
#include "base_service.h"
|
||||
|
||||
namespace skyline::service {
|
||||
|
@ -19,18 +20,19 @@ namespace skyline::service {
|
|||
}
|
||||
|
||||
Result service::BaseService::HandleRequest(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
std::pair<std::function<Result(type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &)>, std::string_view> function;
|
||||
ServiceFunctionDescriptor function;
|
||||
try {
|
||||
function = GetServiceFunction(request.payload->value);
|
||||
state.logger->Debug("Service: {} @ {}", function.second, GetName());
|
||||
state.logger->DebugNoPrefix("Service: {}", function.name);
|
||||
} catch (const std::out_of_range &) {
|
||||
state.logger->Warn("Cannot find function in service '{0}': 0x{1:X} ({1})", GetName(), static_cast<u32>(request.payload->value));
|
||||
return {};
|
||||
}
|
||||
TRACE_EVENT("service", perfetto::StaticString{function.name});
|
||||
try {
|
||||
return function.first(session, request, response);
|
||||
return function(session, request, response);
|
||||
} catch (const std::exception &e) {
|
||||
throw exception("{} (Service: {} @ {})", e.what(), function.second, GetName());
|
||||
throw exception("{} (Service: {})", e.what(), function.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,14 +5,25 @@
|
|||
|
||||
#include <kernel/ipc.h>
|
||||
|
||||
#define SFUNC(id, Class, Function) std::pair<u32, std::pair<std::function<Result(Class*, type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &)>, std::string_view>>{id, {&Class::Function, #Function}}
|
||||
#define SFUNC_BASE(id, Class, BaseClass, Function) std::pair<u32, std::pair<std::function<Result(Class*, type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &)>, std::string_view>>{id, {&CallBaseFunction<Class, BaseClass, decltype(&BaseClass::Function), &BaseClass::Function>, #Function}}
|
||||
#define SERVICE_STRINGIFY(string) #string
|
||||
#define SFUNC(id, Class, Function) std::pair<u32, std::pair<Result(Class::*)(type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &), const char*>>{id, {&Class::Function, SERVICE_STRINGIFY(Class::Function)}}
|
||||
#define SFUNC_BASE(id, Class, BaseClass, Function) std::pair<u32, std::pair<Result(Class::*)(type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &), const char*>>{id, {&Class::CallBaseFunction<BaseClass, decltype(&BaseClass::Function), &BaseClass::Function>, SERVICE_STRINGIFY(Class::Function)}}
|
||||
#define SERVICE_DECL_AUTO(name, value) decltype(value) name = value
|
||||
#define SERVICE_DECL(...) \
|
||||
SERVICE_DECL_AUTO(functions, frz::make_unordered_map({__VA_ARGS__})); \
|
||||
std::pair<std::function<Result(type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &)>, std::string_view> GetServiceFunction(u32 id) override { \
|
||||
auto& function{functions.at(id)}; \
|
||||
return std::make_pair(std::bind(function.first, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), function.second); \
|
||||
#define SERVICE_DECL(...) \
|
||||
private: \
|
||||
template<typename BaseClass, typename BaseFunctionType, BaseFunctionType BaseFunction> \
|
||||
Result CallBaseFunction(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { \
|
||||
return (static_cast<BaseClass *>(this)->*BaseFunction)(session, request, response); \
|
||||
} \
|
||||
SERVICE_DECL_AUTO(functions, frz::make_unordered_map({__VA_ARGS__})); \
|
||||
protected: \
|
||||
ServiceFunctionDescriptor GetServiceFunction(u32 id) override { \
|
||||
auto& function{functions.at(id)}; \
|
||||
return ServiceFunctionDescriptor{ \
|
||||
reinterpret_cast<DerivedService*>(this), \
|
||||
reinterpret_cast<decltype(ServiceFunctionDescriptor::function)>(function.first), \
|
||||
function.second \
|
||||
}; \
|
||||
}
|
||||
#define SRVREG(class, ...) std::make_shared<class>(state, manager, ##__VA_ARGS__)
|
||||
|
||||
|
@ -37,10 +48,20 @@ namespace skyline::service {
|
|||
const DeviceState &state;
|
||||
ServiceManager &manager;
|
||||
|
||||
template<typename Class, typename BaseClass, typename BaseFunctionType, BaseFunctionType BaseFunction>
|
||||
static constexpr Result CallBaseFunction(Class *clazz, type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
return (static_cast<BaseClass *>(clazz)->*BaseFunction)(session, request, response);
|
||||
}
|
||||
class DerivedService; //!< A placeholder derived class which is used for class function semantics
|
||||
|
||||
/**
|
||||
* @brief A per-function descriptor for HLE service functions
|
||||
*/
|
||||
struct ServiceFunctionDescriptor {
|
||||
DerivedService *clazz; //!< A pointer to the class that this was derived from, it's used as the 'this' pointer for the function
|
||||
Result (DerivedService::*function)(type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &); //!< A function pointer to a HLE implementation of the service function
|
||||
const char *name; //!< A pointer to a static string in the format "Class::Function" for the specific service class/function
|
||||
|
||||
constexpr Result operator()(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
return (clazz->*function)(session, request, response);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
BaseService(const DeviceState &state, ServiceManager &manager) : state(state), manager(manager) {}
|
||||
|
@ -50,12 +71,12 @@ namespace skyline::service {
|
|||
*/
|
||||
virtual ~BaseService() = default;
|
||||
|
||||
virtual std::pair<std::function<Result(type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &)>, std::string_view> GetServiceFunction(u32 id) {
|
||||
virtual ServiceFunctionDescriptor GetServiceFunction(u32 id) {
|
||||
throw std::out_of_range("GetServiceFunction not implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The name of the class
|
||||
* @return A string with the name of the service class
|
||||
* @note The lifetime of the returned string is tied to that of the class
|
||||
*/
|
||||
const std::string &GetName();
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace skyline::service::hosbinder {
|
|||
out.Push<u32>(0);
|
||||
out.Push(queue.at(slot)->gbpBuffer);
|
||||
|
||||
state.logger->Debug("RequestBuffer: Slot: {}", slot, sizeof(GbpBuffer));
|
||||
state.logger->Debug("Slot: {}", slot, sizeof(GbpBuffer));
|
||||
}
|
||||
|
||||
void GraphicBufferProducer::DequeueBuffer(Parcel &in, Parcel &out) {
|
||||
|
@ -46,7 +46,7 @@ namespace skyline::service::hosbinder {
|
|||
out.Push(*slot);
|
||||
out.Push(std::array<u32, 13>{1, 0x24}); // Unknown
|
||||
|
||||
state.logger->Debug("DequeueBuffer: Width: {}, Height: {}, Format: {}, Usage: {}, Slot: {}", width, height, format, usage, *slot);
|
||||
state.logger->Debug("Width: {}, Height: {}, Format: {}, Usage: {}, Slot: {}", width, height, format, usage, *slot);
|
||||
}
|
||||
|
||||
void GraphicBufferProducer::QueueBuffer(Parcel &in, Parcel &out) {
|
||||
|
@ -81,7 +81,7 @@ namespace skyline::service::hosbinder {
|
|||
};
|
||||
out.Push(output);
|
||||
|
||||
state.logger->Debug("QueueBuffer: Timestamp: {}, Auto Timestamp: {}, Crop: [T: {}, B: {}, L: {}, R: {}], Scaling Mode: {}, Transform: {}, Sticky Transform: {}, Swap Interval: {}, Slot: {}", data.timestamp, data.autoTimestamp, data.crop.top, data.crop.bottom, data.crop.left, data.crop.right, data.scalingMode, data.transform, data.stickyTransform, data.swapInterval, data.slot);
|
||||
state.logger->Debug("Timestamp: {}, Auto Timestamp: {}, Crop: [T: {}, B: {}, L: {}, R: {}], Scaling Mode: {}, Transform: {}, Sticky Transform: {}, Swap Interval: {}, Slot: {}", data.timestamp, data.autoTimestamp, data.crop.top, data.crop.bottom, data.crop.left, data.crop.right, data.scalingMode, data.transform, data.stickyTransform, data.swapInterval, data.slot);
|
||||
}
|
||||
|
||||
void GraphicBufferProducer::CancelBuffer(Parcel &in) {
|
||||
|
@ -90,7 +90,7 @@ namespace skyline::service::hosbinder {
|
|||
|
||||
queue.at(slot)->status = BufferStatus::Free;
|
||||
|
||||
state.logger->Debug("CancelBuffer: Slot: {}", slot);
|
||||
state.logger->Debug("Slot: {}", slot);
|
||||
}
|
||||
|
||||
void GraphicBufferProducer::Connect(Parcel &out) {
|
||||
|
@ -152,7 +152,7 @@ namespace skyline::service::hosbinder {
|
|||
queue[data.slot] = std::make_shared<Buffer>(gbpBuffer, texture->InitializeTexture());
|
||||
state.gpu->presentation.bufferEvent->Signal();
|
||||
|
||||
state.logger->Debug("SetPreallocatedBuffer: Slot: {}, Magic: 0x{:X}, Width: {}, Height: {}, Stride: {}, Format: {}, Usage: {}, Index: {}, ID: {}, Handle: {}, Offset: 0x{:X}, Block Height: {}, Size: 0x{:X}", data.slot, gbpBuffer.magic, gbpBuffer.width, gbpBuffer.height, gbpBuffer.stride, gbpBuffer.format, gbpBuffer.usage, gbpBuffer.index, gbpBuffer.nvmapId, gbpBuffer.nvmapHandle, gbpBuffer.offset, (1U << gbpBuffer.blockHeightLog2), gbpBuffer.size);
|
||||
state.logger->Debug("Slot: {}, Magic: 0x{:X}, Width: {}, Height: {}, Stride: {}, Format: {}, Usage: {}, Index: {}, ID: {}, Handle: {}, Offset: 0x{:X}, Block Height: {}, Size: 0x{:X}", data.slot, gbpBuffer.magic, gbpBuffer.width, gbpBuffer.height, gbpBuffer.stride, gbpBuffer.format, gbpBuffer.usage, gbpBuffer.index, gbpBuffer.nvmapId, gbpBuffer.nvmapHandle, gbpBuffer.offset, (1U << gbpBuffer.blockHeightLog2), gbpBuffer.size);
|
||||
}
|
||||
|
||||
void GraphicBufferProducer::OnTransact(TransactionCode code, Parcel &in, Parcel &out) {
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace skyline::service::hosbinder {
|
|||
// If this was not done then we would need to maintain an array of GraphicBufferProducer objects for each layer and send the request for it specifically
|
||||
// There would also need to be an external compositor which composites all the graphics buffers submitted to every GraphicBufferProducer
|
||||
|
||||
state.logger->Debug("TransactParcel: Layer ID: {}, Code: {}", layerId, code);
|
||||
state.logger->Debug("Layer ID: {}, Code: {}", layerId, code);
|
||||
producer->OnTransact(code, in, out);
|
||||
|
||||
out.WriteParcel(request.outputBuf.at(0));
|
||||
|
|
|
@ -76,7 +76,7 @@ namespace skyline::service::nvdrv {
|
|||
if (event != nullptr) {
|
||||
auto handle{state.process->InsertItem<type::KEvent>(event)};
|
||||
|
||||
state.logger->Debug("QueryEvent: FD: {}, Event ID: {}, Handle: 0x{:X}", fd, eventId, handle);
|
||||
state.logger->Debug("FD: {}, Event ID: {}, Handle: 0x{:X}", fd, eventId, handle);
|
||||
response.copyHandles.push_back(handle);
|
||||
|
||||
response.Push(device::NvStatus::Success);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include <cxxabi.h>
|
||||
#include <common/trace.h>
|
||||
#include "nvdevice.h"
|
||||
|
||||
namespace skyline::service::nvdrv::device {
|
||||
|
@ -30,18 +31,19 @@ namespace skyline::service::nvdrv::device {
|
|||
}
|
||||
}()};
|
||||
|
||||
std::pair<std::function<NvStatus(IoctlType, span<u8>, span<u8>)>, std::string_view> function;
|
||||
NvDeviceFunctionDescriptor function;
|
||||
try {
|
||||
function = GetIoctlFunction(cmd);
|
||||
state.logger->Debug("{}: {} @ {}", typeString, GetName(), function.second);
|
||||
state.logger->DebugNoPrefix("{}: {}", typeString, function.name);
|
||||
} catch (std::out_of_range &) {
|
||||
state.logger->Warn("Cannot find IOCTL for device '{}': 0x{:X}", GetName(), cmd);
|
||||
return NvStatus::NotImplemented;
|
||||
}
|
||||
TRACE_EVENT("service", perfetto::StaticString{function.name});
|
||||
try {
|
||||
return function.first(type, buffer, inlineBuffer);
|
||||
return function(type, buffer, inlineBuffer);
|
||||
} catch (const std::exception &e) {
|
||||
throw exception("{} ({} @ {}: {})", e.what(), typeString, GetName(), function.second);
|
||||
throw exception("{} ({}: {})", e.what(), typeString, function.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,13 +6,18 @@
|
|||
#include <kernel/ipc.h>
|
||||
#include <kernel/types/KEvent.h>
|
||||
|
||||
#define NVFUNC(id, Class, Function) std::pair<u32, std::pair<std::function<NvStatus(Class*, IoctlType, span<u8>, span<u8>)>, std::string_view>>{id, {&Class::Function, #Function}}
|
||||
#define NV_STRINGIFY(string) #string
|
||||
#define NVFUNC(id, Class, Function) std::pair<u32, std::pair<NvStatus(Class::*)(IoctlType, span<u8>, span<u8>), const char*>>{id, {&Class::Function, NV_STRINGIFY(Class::Function)}}
|
||||
#define NVDEVICE_DECL_AUTO(name, value) decltype(value) name = value
|
||||
#define NVDEVICE_DECL(...) \
|
||||
NVDEVICE_DECL_AUTO(functions, frz::make_unordered_map({__VA_ARGS__})); \
|
||||
std::pair<std::function<NvStatus(IoctlType, span<u8>, span<u8>)>, std::string_view> GetIoctlFunction(u32 id) override { \
|
||||
auto& function{functions.at(id)}; \
|
||||
return std::make_pair(std::bind(function.first, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), function.second); \
|
||||
#define NVDEVICE_DECL(...) \
|
||||
NVDEVICE_DECL_AUTO(functions, frz::make_unordered_map({__VA_ARGS__})); \
|
||||
NvDeviceFunctionDescriptor GetIoctlFunction(u32 id) override { \
|
||||
auto& function{functions.at(id)}; \
|
||||
return NvDeviceFunctionDescriptor{ \
|
||||
reinterpret_cast<DerivedDevice*>(this), \
|
||||
reinterpret_cast<decltype(NvDeviceFunctionDescriptor::function)>(function.first), \
|
||||
function.second \
|
||||
}; \
|
||||
}
|
||||
|
||||
namespace skyline::service::nvdrv::device {
|
||||
|
@ -67,12 +72,27 @@ namespace skyline::service::nvdrv::device {
|
|||
protected:
|
||||
const DeviceState &state;
|
||||
|
||||
class DerivedDevice; //!< A placeholder derived class which is used for class function semantics
|
||||
|
||||
/**
|
||||
* @brief A per-function descriptor for NvDevice functions
|
||||
*/
|
||||
struct NvDeviceFunctionDescriptor {
|
||||
DerivedDevice *clazz; //!< A pointer to the class that this was derived from, it's used as the 'this' pointer for the function
|
||||
NvStatus (DerivedDevice::*function)(IoctlType, span<u8>, span<u8>); //!< A function pointer to the implementation of the function
|
||||
const char *name; //!< A pointer to a static string in the format "Class::Function" for the specific device class/function
|
||||
|
||||
constexpr NvStatus operator()(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
|
||||
return (clazz->*function)(type, buffer, inlineBuffer);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
NvDevice(const DeviceState &state) : state(state) {}
|
||||
|
||||
virtual ~NvDevice() = default;
|
||||
|
||||
virtual std::pair<std::function<NvStatus(IoctlType, span<u8>, span<u8>)>, std::string_view> GetIoctlFunction(u32 id) = 0;
|
||||
virtual NvDeviceFunctionDescriptor GetIoctlFunction(u32 id) = 0;
|
||||
|
||||
/**
|
||||
* @return The name of the class
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include <kernel/types/KProcess.h>
|
||||
#include <common/trace.h>
|
||||
#include "sm/IUserInterface.h"
|
||||
#include "settings/ISettingsServer.h"
|
||||
#include "settings/ISystemSettingsServer.h"
|
||||
|
@ -146,6 +147,7 @@ namespace skyline::service {
|
|||
}
|
||||
|
||||
void ServiceManager::SyncRequestHandler(KHandle handle) {
|
||||
TRACE_EVENT("kernel", "ServiceManager::SyncRequestHandler");
|
||||
auto session{state.process->GetHandle<type::KSession>(handle)};
|
||||
state.logger->Verbose("----IPC Start----");
|
||||
state.logger->Verbose("Handle is 0x{:X}", handle);
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace skyline::service::sm {
|
|||
manager.NewService(name, session, response);
|
||||
return {};
|
||||
} catch (std::out_of_range &) {
|
||||
std::string_view stringName(reinterpret_cast<char *>(&name), sizeof(u64));
|
||||
std::string_view stringName(span(reinterpret_cast<char *>(&name), sizeof(u64)).as_string(true));
|
||||
state.logger->Warn("Service has not been implemented: \"{}\"", stringName);
|
||||
return result::InvalidServiceName;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue