Compare commits
3 Commits
android-13
...
android-13
Author | SHA1 | Date | |
---|---|---|---|
ca25d1cb9e | |||
5ca8629bb2 | |||
c3e377a701 |
@ -3,4 +3,4 @@
|
|||||||
|
|
||||||
[codespell]
|
[codespell]
|
||||||
skip = ./.git,./build,./dist,./Doxyfile,./externals,./LICENSES,./src/android/app/src/main/res
|
skip = ./.git,./build,./dist,./Doxyfile,./externals,./LICENSES,./src/android/app/src/main/res
|
||||||
ignore-words-list = aci,allright,ba,canonicalizations,deques,froms,hda,inout,lod,masia,nam,nax,nce,nd,optin,pullrequests,pullrequest,te,transfered,unstall,uscaled,vas,zink
|
ignore-words-list = aci,allright,ba,canonicalizations,deques,froms,hda,inout,lod,masia,nam,nax,nd,optin,pullrequests,pullrequest,te,transfered,unstall,uscaled,vas,zink
|
||||||
|
9
.gitmodules
vendored
9
.gitmodules
vendored
@ -4,9 +4,6 @@
|
|||||||
[submodule "enet"]
|
[submodule "enet"]
|
||||||
path = externals/enet
|
path = externals/enet
|
||||||
url = https://github.com/lsalzman/enet.git
|
url = https://github.com/lsalzman/enet.git
|
||||||
[submodule "inih"]
|
|
||||||
path = externals/inih/inih
|
|
||||||
url = https://github.com/benhoyt/inih.git
|
|
||||||
[submodule "cubeb"]
|
[submodule "cubeb"]
|
||||||
path = externals/cubeb
|
path = externals/cubeb
|
||||||
url = https://github.com/mozilla/cubeb.git
|
url = https://github.com/mozilla/cubeb.git
|
||||||
@ -61,6 +58,6 @@
|
|||||||
[submodule "breakpad"]
|
[submodule "breakpad"]
|
||||||
path = externals/breakpad
|
path = externals/breakpad
|
||||||
url = https://github.com/yuzu-emu/breakpad.git
|
url = https://github.com/yuzu-emu/breakpad.git
|
||||||
[submodule "oaknut"]
|
[submodule "simpleini"]
|
||||||
path = externals/oaknut
|
path = externals/simpleini
|
||||||
url = https://github.com/merryhime/oaknut
|
url = https://github.com/brofield/simpleini.git
|
||||||
|
@ -285,7 +285,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
|
|||||||
find_package(Boost 1.79.0 REQUIRED context)
|
find_package(Boost 1.79.0 REQUIRED context)
|
||||||
find_package(enet 1.3 MODULE)
|
find_package(enet 1.3 MODULE)
|
||||||
find_package(fmt 9 REQUIRED)
|
find_package(fmt 9 REQUIRED)
|
||||||
find_package(inih 52 MODULE COMPONENTS INIReader)
|
|
||||||
find_package(LLVM 17.0.2 MODULE COMPONENTS Demangle)
|
find_package(LLVM 17.0.2 MODULE COMPONENTS Demangle)
|
||||||
find_package(lz4 REQUIRED)
|
find_package(lz4 REQUIRED)
|
||||||
find_package(nlohmann_json 3.8 REQUIRED)
|
find_package(nlohmann_json 3.8 REQUIRED)
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: 2022 Alexandre Bouvier <contact@amb.tf>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
find_package(PkgConfig QUIET)
|
|
||||||
pkg_search_module(INIH QUIET IMPORTED_TARGET inih)
|
|
||||||
if (INIReader IN_LIST inih_FIND_COMPONENTS)
|
|
||||||
pkg_search_module(INIREADER QUIET IMPORTED_TARGET INIReader)
|
|
||||||
if (INIREADER_FOUND)
|
|
||||||
set(inih_INIReader_FOUND TRUE)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include(FindPackageHandleStandardArgs)
|
|
||||||
find_package_handle_standard_args(inih
|
|
||||||
REQUIRED_VARS INIH_LINK_LIBRARIES
|
|
||||||
VERSION_VAR INIH_VERSION
|
|
||||||
HANDLE_COMPONENTS
|
|
||||||
)
|
|
||||||
|
|
||||||
if (inih_FOUND AND NOT TARGET inih::inih)
|
|
||||||
add_library(inih::inih ALIAS PkgConfig::INIH)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (inih_FOUND AND inih_INIReader_FOUND AND NOT TARGET inih::INIReader)
|
|
||||||
add_library(inih::INIReader ALIAS PkgConfig::INIREADER)
|
|
||||||
endif()
|
|
@ -1,7 +1,7 @@
|
|||||||
| Pull Request | Commit | Title | Author | Merged? |
|
| Pull Request | Commit | Title | Author | Merged? |
|
||||||
|----|----|----|----|----|
|
|----|----|----|----|----|
|
||||||
| [11535](https://github.com/yuzu-emu/yuzu//pull/11535) | [`50bcfa5fb`](https://github.com/yuzu-emu/yuzu//pull/11535/files) | renderer_vulkan: Introduce separate cmd buffer for uploads | [GPUCode](https://github.com/GPUCode/) | Yes |
|
| [11535](https://github.com/yuzu-emu/yuzu//pull/11535) | [`50bcfa5fb`](https://github.com/yuzu-emu/yuzu//pull/11535/files) | renderer_vulkan: Introduce separate cmd buffer for uploads | [GPUCode](https://github.com/GPUCode/) | Yes |
|
||||||
| [12074](https://github.com/yuzu-emu/yuzu//pull/12074) | [`20b671baa`](https://github.com/yuzu-emu/yuzu//pull/12074/files) | Implement Native Code Execution (NCE) | [GPUCode](https://github.com/GPUCode/) | Yes |
|
| [11889](https://github.com/yuzu-emu/yuzu//pull/11889) | [`a249b3018`](https://github.com/yuzu-emu/yuzu//pull/11889/files) | configuration: Unify config handling across frontends | [t895](https://github.com/t895/) | Yes |
|
||||||
|
|
||||||
|
|
||||||
End of merge log. You can find the original README.md below the break.
|
End of merge log. You can find the original README.md below the break.
|
||||||
|
5
dist/languages/.tx/config
vendored
5
dist/languages/.tx/config
vendored
@ -6,8 +6,3 @@ file_filter = <lang>.ts
|
|||||||
source_file = en.ts
|
source_file = en.ts
|
||||||
source_lang = en
|
source_lang = en
|
||||||
type = QT
|
type = QT
|
||||||
|
|
||||||
[o:yuzu-emulator:p:yuzu:r:yuzu-android]
|
|
||||||
file_filter = ../../src/android/app/src/main/res/values-<lang>/strings.xml
|
|
||||||
source_file = ../../src/android/app/src/main/res/values/strings.xml
|
|
||||||
type = ANDROID
|
|
||||||
|
12
externals/CMakeLists.txt
vendored
12
externals/CMakeLists.txt
vendored
@ -20,10 +20,6 @@ if ((ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) AND NOT TARGET xbyak::xbyak)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Dynarmic
|
# Dynarmic
|
||||||
if (ARCHITECTURE_arm64 AND NOT TARGET merry::oaknut)
|
|
||||||
add_subdirectory(oaknut)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) AND NOT TARGET dynarmic::dynarmic)
|
if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) AND NOT TARGET dynarmic::dynarmic)
|
||||||
set(DYNARMIC_IGNORE_ASSERTS ON)
|
set(DYNARMIC_IGNORE_ASSERTS ON)
|
||||||
add_subdirectory(dynarmic)
|
add_subdirectory(dynarmic)
|
||||||
@ -38,11 +34,6 @@ endif()
|
|||||||
# Glad
|
# Glad
|
||||||
add_subdirectory(glad)
|
add_subdirectory(glad)
|
||||||
|
|
||||||
# inih
|
|
||||||
if (NOT TARGET inih::INIReader)
|
|
||||||
add_subdirectory(inih)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# mbedtls
|
# mbedtls
|
||||||
add_subdirectory(mbedtls)
|
add_subdirectory(mbedtls)
|
||||||
target_include_directories(mbedtls PUBLIC ./mbedtls/include)
|
target_include_directories(mbedtls PUBLIC ./mbedtls/include)
|
||||||
@ -299,3 +290,6 @@ if (YUZU_CRASH_DUMPS AND NOT TARGET libbreakpad_client)
|
|||||||
target_link_libraries(dump_syms PRIVATE libbreakpad_client ZLIB::ZLIB)
|
target_link_libraries(dump_syms PRIVATE libbreakpad_client ZLIB::ZLIB)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# SimpleIni
|
||||||
|
add_subdirectory(simpleini)
|
||||||
|
13
externals/inih/CMakeLists.txt
vendored
13
externals/inih/CMakeLists.txt
vendored
@ -1,13 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: 2014 Gui Andrade <admin@archshift.com>
|
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
add_library(inih
|
|
||||||
inih/ini.c
|
|
||||||
inih/ini.h
|
|
||||||
inih/cpp/INIReader.cpp
|
|
||||||
inih/cpp/INIReader.h
|
|
||||||
)
|
|
||||||
|
|
||||||
create_target_directory_groups(inih)
|
|
||||||
target_include_directories(inih INTERFACE inih/cpp)
|
|
||||||
add_library(inih::INIReader ALIAS inih)
|
|
1
externals/inih/inih
vendored
1
externals/inih/inih
vendored
Submodule externals/inih/inih deleted from 9cecf0643d
1
externals/oaknut
vendored
1
externals/oaknut
vendored
Submodule externals/oaknut deleted from 316d8869e8
1
externals/simpleini
vendored
Submodule
1
externals/simpleini
vendored
Submodule
Submodule externals/simpleini added at 382ddbb4b9
@ -187,6 +187,7 @@ add_subdirectory(audio_core)
|
|||||||
add_subdirectory(video_core)
|
add_subdirectory(video_core)
|
||||||
add_subdirectory(network)
|
add_subdirectory(network)
|
||||||
add_subdirectory(input_common)
|
add_subdirectory(input_common)
|
||||||
|
add_subdirectory(frontend_common)
|
||||||
add_subdirectory(shader_recompiler)
|
add_subdirectory(shader_recompiler)
|
||||||
|
|
||||||
if (YUZU_ROOM)
|
if (YUZU_ROOM)
|
||||||
|
@ -219,7 +219,6 @@ dependencies {
|
|||||||
implementation("io.coil-kt:coil:2.2.2")
|
implementation("io.coil-kt:coil:2.2.2")
|
||||||
implementation("androidx.core:core-splashscreen:1.0.1")
|
implementation("androidx.core:core-splashscreen:1.0.1")
|
||||||
implementation("androidx.window:window:1.2.0-beta03")
|
implementation("androidx.window:window:1.2.0-beta03")
|
||||||
implementation("org.ini4j:ini4j:0.5.4")
|
|
||||||
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
||||||
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
|
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
|
||||||
implementation("androidx.navigation:navigation-fragment-ktx:2.7.4")
|
implementation("androidx.navigation:navigation-fragment-ktx:2.7.4")
|
||||||
|
@ -230,8 +230,6 @@ object NativeLibrary {
|
|||||||
*/
|
*/
|
||||||
external fun onTouchReleased(finger_id: Int)
|
external fun onTouchReleased(finger_id: Int)
|
||||||
|
|
||||||
external fun reloadSettings()
|
|
||||||
|
|
||||||
external fun initGameIni(gameID: String?)
|
external fun initGameIni(gameID: String?)
|
||||||
|
|
||||||
external fun setAppDirectory(directory: String)
|
external fun setAppDirectory(directory: String)
|
||||||
@ -301,11 +299,6 @@ object NativeLibrary {
|
|||||||
*/
|
*/
|
||||||
external fun getPerfStats(): DoubleArray
|
external fun getPerfStats(): DoubleArray
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current CPU backend.
|
|
||||||
*/
|
|
||||||
external fun getCpuBackend(): String
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies the core emulation that the orientation has changed.
|
* Notifies the core emulation that the orientation has changed.
|
||||||
*/
|
*/
|
||||||
|
@ -10,7 +10,6 @@ enum class IntSetting(
|
|||||||
override val category: Settings.Category,
|
override val category: Settings.Category,
|
||||||
override val androidDefault: Int? = null
|
override val androidDefault: Int? = null
|
||||||
) : AbstractIntSetting {
|
) : AbstractIntSetting {
|
||||||
CPU_BACKEND("cpu_backend", Settings.Category.Cpu),
|
|
||||||
CPU_ACCURACY("cpu_accuracy", Settings.Category.Cpu),
|
CPU_ACCURACY("cpu_accuracy", Settings.Category.Cpu),
|
||||||
REGION_INDEX("region_index", Settings.Category.System),
|
REGION_INDEX("region_index", Settings.Category.System),
|
||||||
LANGUAGE_INDEX("language_index", Settings.Category.System),
|
LANGUAGE_INDEX("language_index", Settings.Category.System),
|
||||||
|
@ -7,7 +7,7 @@ import android.text.TextUtils
|
|||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.YuzuApplication
|
import org.yuzu.yuzu_emu.YuzuApplication
|
||||||
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||||
|
|
||||||
object Settings {
|
object Settings {
|
||||||
private val context get() = YuzuApplication.appContext
|
private val context get() = YuzuApplication.appContext
|
||||||
@ -19,7 +19,7 @@ object Settings {
|
|||||||
context.getString(R.string.ini_saved),
|
context.getString(R.string.ini_saved),
|
||||||
Toast.LENGTH_SHORT
|
Toast.LENGTH_SHORT
|
||||||
).show()
|
).show()
|
||||||
SettingsFile.saveFile(SettingsFile.FILE_NAME_CONFIG)
|
NativeConfig.saveSettings()
|
||||||
} else {
|
} else {
|
||||||
// TODO: Save custom game settings
|
// TODO: Save custom game settings
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
|
@ -73,19 +73,10 @@ abstract class SettingsItem(
|
|||||||
R.string.frame_limit_slider,
|
R.string.frame_limit_slider,
|
||||||
R.string.frame_limit_slider_description,
|
R.string.frame_limit_slider_description,
|
||||||
1,
|
1,
|
||||||
400,
|
200,
|
||||||
"%"
|
"%"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
put(
|
|
||||||
SingleChoiceSetting(
|
|
||||||
IntSetting.CPU_BACKEND,
|
|
||||||
R.string.cpu_backend,
|
|
||||||
0,
|
|
||||||
R.array.cpuBackendNames,
|
|
||||||
R.array.cpuBackendValues
|
|
||||||
)
|
|
||||||
)
|
|
||||||
put(
|
put(
|
||||||
SingleChoiceSetting(
|
SingleChoiceSetting(
|
||||||
IntSetting.CPU_ACCURACY,
|
IntSetting.CPU_ACCURACY,
|
||||||
|
@ -21,7 +21,6 @@ import androidx.navigation.navArgs
|
|||||||
import com.google.android.material.color.MaterialColors
|
import com.google.android.material.color.MaterialColors
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.yuzu.yuzu_emu.NativeLibrary
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.databinding.ActivitySettingsBinding
|
import org.yuzu.yuzu_emu.databinding.ActivitySettingsBinding
|
||||||
@ -165,11 +164,12 @@ class SettingsActivity : AppCompatActivity() {
|
|||||||
settingsViewModel.shouldSave = false
|
settingsViewModel.shouldSave = false
|
||||||
|
|
||||||
// Delete settings file because the user may have changed values that do not exist in the UI
|
// Delete settings file because the user may have changed values that do not exist in the UI
|
||||||
|
NativeConfig.unloadConfig()
|
||||||
val settingsFile = SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_CONFIG)
|
val settingsFile = SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_CONFIG)
|
||||||
if (!settingsFile.delete()) {
|
if (!settingsFile.delete()) {
|
||||||
throw IOException("Failed to delete $settingsFile")
|
throw IOException("Failed to delete $settingsFile")
|
||||||
}
|
}
|
||||||
NativeLibrary.reloadSettings()
|
NativeConfig.initializeConfig()
|
||||||
|
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
|
@ -269,7 +269,6 @@ class SettingsFragmentPresenter(
|
|||||||
add(BooleanSetting.RENDERER_DEBUG.key)
|
add(BooleanSetting.RENDERER_DEBUG.key)
|
||||||
|
|
||||||
add(HeaderSetting(R.string.cpu))
|
add(HeaderSetting(R.string.cpu))
|
||||||
add(IntSetting.CPU_BACKEND.key)
|
|
||||||
add(IntSetting.CPU_ACCURACY.key)
|
add(IntSetting.CPU_ACCURACY.key)
|
||||||
add(BooleanSetting.CPU_DEBUG_MODE.key)
|
add(BooleanSetting.CPU_DEBUG_MODE.key)
|
||||||
add(SettingsItem.FASTMEM_COMBINED)
|
add(SettingsItem.FASTMEM_COMBINED)
|
||||||
|
@ -3,15 +3,8 @@
|
|||||||
|
|
||||||
package org.yuzu.yuzu_emu.features.settings.utils
|
package org.yuzu.yuzu_emu.features.settings.utils
|
||||||
|
|
||||||
import android.widget.Toast
|
|
||||||
import java.io.*
|
import java.io.*
|
||||||
import org.ini4j.Wini
|
|
||||||
import org.yuzu.yuzu_emu.R
|
|
||||||
import org.yuzu.yuzu_emu.YuzuApplication
|
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.*
|
|
||||||
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
||||||
import org.yuzu.yuzu_emu.utils.Log
|
|
||||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains static methods for interacting with .ini files in which settings are stored.
|
* Contains static methods for interacting with .ini files in which settings are stored.
|
||||||
@ -19,41 +12,6 @@ import org.yuzu.yuzu_emu.utils.NativeConfig
|
|||||||
object SettingsFile {
|
object SettingsFile {
|
||||||
const val FILE_NAME_CONFIG = "config"
|
const val FILE_NAME_CONFIG = "config"
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves a Settings HashMap to a given .ini file on disk. If unsuccessful, outputs an error
|
|
||||||
* telling why it failed.
|
|
||||||
*
|
|
||||||
* @param fileName The target filename without a path or extension.
|
|
||||||
*/
|
|
||||||
fun saveFile(fileName: String) {
|
|
||||||
val ini = getSettingsFile(fileName)
|
|
||||||
try {
|
|
||||||
val wini = Wini(ini)
|
|
||||||
for (specificCategory in Settings.Category.values()) {
|
|
||||||
val categoryHeader = NativeConfig.getConfigHeader(specificCategory.ordinal)
|
|
||||||
for (setting in Settings.settingsList) {
|
|
||||||
if (setting.key!!.isEmpty()) continue
|
|
||||||
|
|
||||||
val settingCategoryHeader =
|
|
||||||
NativeConfig.getConfigHeader(setting.category.ordinal)
|
|
||||||
val iniSetting: String? = wini.get(categoryHeader, setting.key)
|
|
||||||
if (iniSetting != null || settingCategoryHeader == categoryHeader) {
|
|
||||||
wini.put(settingCategoryHeader, setting.key, setting.valueAsString)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
wini.store()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.message)
|
|
||||||
val context = YuzuApplication.appContext
|
|
||||||
Toast.makeText(
|
|
||||||
context,
|
|
||||||
context.getString(R.string.error_saving, fileName, e.message),
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getSettingsFile(fileName: String): File =
|
fun getSettingsFile(fileName: String): File =
|
||||||
File(DirectoryInitialization.userDirectory + "/config/" + fileName + ".ini")
|
File(DirectoryInitialization.userDirectory + "/config/" + fileName + ".ini")
|
||||||
}
|
}
|
||||||
|
@ -414,10 +414,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
perfStatsUpdater = {
|
perfStatsUpdater = {
|
||||||
if (emulationViewModel.emulationStarted.value) {
|
if (emulationViewModel.emulationStarted.value) {
|
||||||
val perfStats = NativeLibrary.getPerfStats()
|
val perfStats = NativeLibrary.getPerfStats()
|
||||||
val cpuBackend = NativeLibrary.getCpuBackend()
|
|
||||||
if (_binding != null) {
|
if (_binding != null) {
|
||||||
binding.showFpsText.text =
|
binding.showFpsText.text = String.format("FPS: %.1f", perfStats[FPS])
|
||||||
String.format("FPS: %.1f\n%s", perfStats[FPS], cpuBackend)
|
|
||||||
}
|
}
|
||||||
perfStatsUpdateHandler.postDelayed(perfStatsUpdater!!, 800)
|
perfStatsUpdateHandler.postDelayed(perfStatsUpdater!!, 800)
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,6 @@ import org.yuzu.yuzu_emu.databinding.FragmentInstallablesBinding
|
|||||||
import org.yuzu.yuzu_emu.model.HomeViewModel
|
import org.yuzu.yuzu_emu.model.HomeViewModel
|
||||||
import org.yuzu.yuzu_emu.model.Installable
|
import org.yuzu.yuzu_emu.model.Installable
|
||||||
import org.yuzu.yuzu_emu.ui.main.MainActivity
|
import org.yuzu.yuzu_emu.ui.main.MainActivity
|
||||||
import java.time.LocalDateTime
|
|
||||||
import java.time.format.DateTimeFormatter
|
|
||||||
|
|
||||||
class InstallableFragment : Fragment() {
|
class InstallableFragment : Fragment() {
|
||||||
private var _binding: FragmentInstallablesBinding? = null
|
private var _binding: FragmentInstallablesBinding? = null
|
||||||
@ -80,15 +78,7 @@ class InstallableFragment : Fragment() {
|
|||||||
R.string.manage_save_data,
|
R.string.manage_save_data,
|
||||||
R.string.import_export_saves_description,
|
R.string.import_export_saves_description,
|
||||||
install = { mainActivity.importSaves.launch(arrayOf("application/zip")) },
|
install = { mainActivity.importSaves.launch(arrayOf("application/zip")) },
|
||||||
export = {
|
export = { mainActivity.exportSave() }
|
||||||
mainActivity.exportSaves.launch(
|
|
||||||
"yuzu saves - ${
|
|
||||||
LocalDateTime.now().format(
|
|
||||||
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
|
|
||||||
)
|
|
||||||
}.zip"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Installable(
|
Installable(
|
||||||
|
@ -18,8 +18,8 @@ class Game(
|
|||||||
val version: String = "",
|
val version: String = "",
|
||||||
val isHomebrew: Boolean = false
|
val isHomebrew: Boolean = false
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
val keyAddedToLibraryTime get() = "${path}_AddedToLibraryTime"
|
val keyAddedToLibraryTime get() = "${programId}_AddedToLibraryTime"
|
||||||
val keyLastPlayedTime get() = "${path}_LastPlayed"
|
val keyLastPlayedTime get() = "${programId}_LastPlayed"
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is Game) {
|
if (other !is Game) {
|
||||||
|
@ -6,6 +6,7 @@ package org.yuzu.yuzu_emu.ui.main
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.provider.DocumentsContract
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup.MarginLayoutParams
|
import android.view.ViewGroup.MarginLayoutParams
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
@ -19,6 +20,7 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
|||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import androidx.documentfile.provider.DocumentFile
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
@ -39,6 +41,7 @@ import org.yuzu.yuzu_emu.NativeLibrary
|
|||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
||||||
import org.yuzu.yuzu_emu.databinding.ActivityMainBinding
|
import org.yuzu.yuzu_emu.databinding.ActivityMainBinding
|
||||||
|
import org.yuzu.yuzu_emu.features.DocumentProvider
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
||||||
import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment
|
import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment
|
||||||
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
|
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
|
||||||
@ -50,6 +53,9 @@ import org.yuzu.yuzu_emu.model.TaskViewModel
|
|||||||
import org.yuzu.yuzu_emu.utils.*
|
import org.yuzu.yuzu_emu.utils.*
|
||||||
import java.io.BufferedInputStream
|
import java.io.BufferedInputStream
|
||||||
import java.io.BufferedOutputStream
|
import java.io.BufferedOutputStream
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
import java.util.zip.ZipInputStream
|
import java.util.zip.ZipInputStream
|
||||||
|
|
||||||
@ -67,6 +73,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
|||||||
|
|
||||||
// Get first subfolder in saves folder (should be the user folder)
|
// Get first subfolder in saves folder (should be the user folder)
|
||||||
val savesFolderRoot get() = File(savesFolder).listFiles()?.firstOrNull()?.canonicalPath ?: ""
|
val savesFolderRoot get() = File(savesFolder).listFiles()?.firstOrNull()?.canonicalPath ?: ""
|
||||||
|
private var lastZipCreated: File? = null
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
val splashScreen = installSplashScreen()
|
val splashScreen = installSplashScreen()
|
||||||
@ -625,6 +632,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clear existing user data
|
// Clear existing user data
|
||||||
|
NativeConfig.unloadConfig()
|
||||||
File(DirectoryInitialization.userDirectory!!).deleteRecursively()
|
File(DirectoryInitialization.userDirectory!!).deleteRecursively()
|
||||||
|
|
||||||
// Copy archive to internal storage
|
// Copy archive to internal storage
|
||||||
@ -643,37 +651,82 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
|||||||
|
|
||||||
// Reinitialize relevant data
|
// Reinitialize relevant data
|
||||||
NativeLibrary.initializeSystem(true)
|
NativeLibrary.initializeSystem(true)
|
||||||
|
NativeConfig.initializeConfig()
|
||||||
gamesViewModel.reloadGames(false)
|
gamesViewModel.reloadGames(false)
|
||||||
|
|
||||||
return@newInstance getString(R.string.user_data_import_success)
|
return@newInstance getString(R.string.user_data_import_success)
|
||||||
}.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG)
|
}.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zips the save files located in the given folder path and creates a new zip file with the current date and time.
|
||||||
|
* @return true if the zip file is successfully created, false otherwise.
|
||||||
|
*/
|
||||||
|
private fun zipSave(): Boolean {
|
||||||
|
try {
|
||||||
|
val tempFolder = File(getPublicFilesDir().canonicalPath, "temp")
|
||||||
|
tempFolder.mkdirs()
|
||||||
|
val saveFolder = File(savesFolderRoot)
|
||||||
|
val outputZipFile = File(
|
||||||
|
tempFolder,
|
||||||
|
"yuzu saves - ${
|
||||||
|
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
|
||||||
|
}.zip"
|
||||||
|
)
|
||||||
|
outputZipFile.createNewFile()
|
||||||
|
val result = FileUtil.zipFromInternalStorage(
|
||||||
|
saveFolder,
|
||||||
|
savesFolderRoot,
|
||||||
|
BufferedOutputStream(FileOutputStream(outputZipFile))
|
||||||
|
)
|
||||||
|
if (result == TaskState.Failed) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
lastZipCreated = outputZipFile
|
||||||
|
} catch (e: Exception) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exports the save file located in the given folder path by creating a zip file and sharing it via intent.
|
* Exports the save file located in the given folder path by creating a zip file and sharing it via intent.
|
||||||
*/
|
*/
|
||||||
val exportSaves = registerForActivityResult(
|
fun exportSave() {
|
||||||
ActivityResultContracts.CreateDocument("application/zip")
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
) { result ->
|
val wasZipCreated = zipSave()
|
||||||
if (result == null) {
|
val lastZipFile = lastZipCreated
|
||||||
return@registerForActivityResult
|
if (!wasZipCreated || lastZipFile == null) {
|
||||||
}
|
withContext(Dispatchers.Main) {
|
||||||
|
Toast.makeText(
|
||||||
IndeterminateProgressDialogFragment.newInstance(
|
this@MainActivity,
|
||||||
this,
|
getString(R.string.export_save_failed),
|
||||||
R.string.save_files_exporting,
|
Toast.LENGTH_LONG
|
||||||
false
|
).show()
|
||||||
) {
|
}
|
||||||
val zipResult = FileUtil.zipFromInternalStorage(
|
return@launch
|
||||||
File(savesFolderRoot),
|
|
||||||
savesFolderRoot,
|
|
||||||
BufferedOutputStream(contentResolver.openOutputStream(result))
|
|
||||||
)
|
|
||||||
return@newInstance when (zipResult) {
|
|
||||||
TaskState.Completed -> getString(R.string.export_success)
|
|
||||||
TaskState.Cancelled, TaskState.Failed -> getString(R.string.export_failed)
|
|
||||||
}
|
}
|
||||||
}.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG)
|
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
val file = DocumentFile.fromSingleUri(
|
||||||
|
this@MainActivity,
|
||||||
|
DocumentsContract.buildDocumentUri(
|
||||||
|
DocumentProvider.AUTHORITY,
|
||||||
|
"${DocumentProvider.ROOT_ID}/temp/${lastZipFile.name}"
|
||||||
|
)
|
||||||
|
)!!
|
||||||
|
val intent = Intent(Intent.ACTION_SEND)
|
||||||
|
.setDataAndType(file.uri, "application/zip")
|
||||||
|
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
|
.putExtra(Intent.EXTRA_STREAM, file.uri)
|
||||||
|
startForResultExportSave.launch(
|
||||||
|
Intent.createChooser(
|
||||||
|
intent,
|
||||||
|
getString(R.string.share_save_file)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val startForResultExportSave =
|
private val startForResultExportSave =
|
||||||
|
@ -16,6 +16,7 @@ object DirectoryInitialization {
|
|||||||
if (!areDirectoriesReady) {
|
if (!areDirectoriesReady) {
|
||||||
initializeInternalStorage()
|
initializeInternalStorage()
|
||||||
NativeLibrary.initializeSystem(false)
|
NativeLibrary.initializeSystem(false)
|
||||||
|
NativeConfig.initializeConfig()
|
||||||
areDirectoriesReady = true
|
areDirectoriesReady = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,30 @@
|
|||||||
package org.yuzu.yuzu_emu.utils
|
package org.yuzu.yuzu_emu.utils
|
||||||
|
|
||||||
object NativeConfig {
|
object NativeConfig {
|
||||||
|
/**
|
||||||
|
* Creates a Config object and opens the emulation config.
|
||||||
|
*/
|
||||||
|
@Synchronized
|
||||||
|
external fun initializeConfig()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys the stored config object. This automatically saves the existing config.
|
||||||
|
*/
|
||||||
|
@Synchronized
|
||||||
|
external fun unloadConfig()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads values saved to the config file and saves them.
|
||||||
|
*/
|
||||||
|
@Synchronized
|
||||||
|
external fun reloadSettings()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves settings values in memory to disk.
|
||||||
|
*/
|
||||||
|
@Synchronized
|
||||||
|
external fun saveSettings()
|
||||||
|
|
||||||
external fun getBoolean(key: String, getDefault: Boolean): Boolean
|
external fun getBoolean(key: String, getDefault: Boolean): Boolean
|
||||||
external fun setBoolean(key: String, value: Boolean)
|
external fun setBoolean(key: String, value: Boolean)
|
||||||
|
|
||||||
|
@ -6,9 +6,6 @@ add_library(yuzu-android SHARED
|
|||||||
android_common/android_common.h
|
android_common/android_common.h
|
||||||
applets/software_keyboard.cpp
|
applets/software_keyboard.cpp
|
||||||
applets/software_keyboard.h
|
applets/software_keyboard.h
|
||||||
config.cpp
|
|
||||||
config.h
|
|
||||||
default_ini.h
|
|
||||||
emu_window/emu_window.cpp
|
emu_window/emu_window.cpp
|
||||||
emu_window/emu_window.h
|
emu_window/emu_window.h
|
||||||
id_cache.cpp
|
id_cache.cpp
|
||||||
@ -16,15 +13,17 @@ add_library(yuzu-android SHARED
|
|||||||
native.cpp
|
native.cpp
|
||||||
native.h
|
native.h
|
||||||
native_config.cpp
|
native_config.cpp
|
||||||
uisettings.cpp
|
android_settings.cpp
|
||||||
game_metadata.cpp
|
game_metadata.cpp
|
||||||
native_log.cpp
|
native_log.cpp
|
||||||
|
android_config.cpp
|
||||||
|
android_config.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR})
|
set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR})
|
||||||
|
|
||||||
target_link_libraries(yuzu-android PRIVATE audio_core common core input_common)
|
target_link_libraries(yuzu-android PRIVATE audio_core common core input_common frontend_common)
|
||||||
target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad inih jnigraphics log)
|
target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad jnigraphics log)
|
||||||
if (ARCHITECTURE_arm64)
|
if (ARCHITECTURE_arm64)
|
||||||
target_link_libraries(yuzu-android PRIVATE adrenotools)
|
target_link_libraries(yuzu-android PRIVATE adrenotools)
|
||||||
endif()
|
endif()
|
||||||
|
70
src/android/app/src/main/jni/android_config.cpp
Normal file
70
src/android/app/src/main/jni/android_config.cpp
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "android_config.h"
|
||||||
|
#include "android_settings.h"
|
||||||
|
#include "common/settings_setting.h"
|
||||||
|
|
||||||
|
AndroidConfig::AndroidConfig(const std::string& config_name, ConfigType config_type)
|
||||||
|
: Config(config_type) {
|
||||||
|
Initialize(config_name);
|
||||||
|
if (config_type != ConfigType::InputProfile) {
|
||||||
|
ReadAndroidValues();
|
||||||
|
SaveAndroidValues();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AndroidConfig::~AndroidConfig() {
|
||||||
|
if (global) {
|
||||||
|
AndroidConfig::SaveAllValues();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidConfig::ReloadAllValues() {
|
||||||
|
Reload();
|
||||||
|
ReadAndroidValues();
|
||||||
|
SaveAndroidValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidConfig::SaveAllValues() {
|
||||||
|
Save();
|
||||||
|
SaveAndroidValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidConfig::ReadAndroidValues() {
|
||||||
|
if (global) {
|
||||||
|
ReadAndroidUIValues();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidConfig::ReadAndroidUIValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Android));
|
||||||
|
|
||||||
|
ReadCategory(Settings::Category::Android);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidConfig::SaveAndroidValues() {
|
||||||
|
if (global) {
|
||||||
|
SaveAndroidUIValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteToIni();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidConfig::SaveAndroidUIValues() {
|
||||||
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Android));
|
||||||
|
|
||||||
|
WriteCategory(Settings::Category::Android);
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Settings::BasicSetting*>& AndroidConfig::FindRelevantList(Settings::Category category) {
|
||||||
|
auto& map = Settings::values.linkage.by_category;
|
||||||
|
if (map.contains(category)) {
|
||||||
|
return Settings::values.linkage.by_category[category];
|
||||||
|
}
|
||||||
|
return AndroidSettings::values.linkage.by_category[category];
|
||||||
|
}
|
41
src/android/app/src/main/jni/android_config.h
Normal file
41
src/android/app/src/main/jni/android_config.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "frontend_common/config.h"
|
||||||
|
|
||||||
|
class AndroidConfig final : public Config {
|
||||||
|
public:
|
||||||
|
explicit AndroidConfig(const std::string& config_name = "config",
|
||||||
|
ConfigType config_type = ConfigType::GlobalConfig);
|
||||||
|
~AndroidConfig() override;
|
||||||
|
|
||||||
|
void ReloadAllValues() override;
|
||||||
|
void SaveAllValues() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void ReadAndroidValues();
|
||||||
|
void ReadAndroidUIValues();
|
||||||
|
void ReadHidbusValues() override {}
|
||||||
|
void ReadDebugControlValues() override {}
|
||||||
|
void ReadPathValues() override {}
|
||||||
|
void ReadShortcutValues() override {}
|
||||||
|
void ReadUIValues() override {}
|
||||||
|
void ReadUIGamelistValues() override {}
|
||||||
|
void ReadUILayoutValues() override {}
|
||||||
|
void ReadMultiplayerValues() override {}
|
||||||
|
|
||||||
|
void SaveAndroidValues();
|
||||||
|
void SaveAndroidUIValues();
|
||||||
|
void SaveHidbusValues() override {}
|
||||||
|
void SaveDebugControlValues() override {}
|
||||||
|
void SavePathValues() override {}
|
||||||
|
void SaveShortcutValues() override {}
|
||||||
|
void SaveUIValues() override {}
|
||||||
|
void SaveUIGamelistValues() override {}
|
||||||
|
void SaveUILayoutValues() override {}
|
||||||
|
void SaveMultiplayerValues() override {}
|
||||||
|
|
||||||
|
std::vector<Settings::BasicSetting*>& FindRelevantList(Settings::Category category) override;
|
||||||
|
};
|
@ -1,7 +1,7 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "uisettings.h"
|
#include "android_settings.h"
|
||||||
|
|
||||||
namespace AndroidSettings {
|
namespace AndroidSettings {
|
||||||
|
|
@ -13,7 +13,7 @@ struct Values {
|
|||||||
Settings::Linkage linkage;
|
Settings::Linkage linkage;
|
||||||
|
|
||||||
// Android
|
// Android
|
||||||
Settings::Setting<bool> picture_in_picture{linkage, false, "picture_in_picture",
|
Settings::Setting<bool> picture_in_picture{linkage, true, "picture_in_picture",
|
||||||
Settings::Category::Android};
|
Settings::Category::Android};
|
||||||
Settings::Setting<s32> screen_layout{linkage,
|
Settings::Setting<s32> screen_layout{linkage,
|
||||||
5,
|
5,
|
@ -1,331 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <optional>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include <INIReader.h>
|
|
||||||
#include "common/fs/file.h"
|
|
||||||
#include "common/fs/fs.h"
|
|
||||||
#include "common/fs/path_util.h"
|
|
||||||
#include "common/logging/log.h"
|
|
||||||
#include "common/settings.h"
|
|
||||||
#include "common/settings_enums.h"
|
|
||||||
#include "core/hle/service/acc/profile_manager.h"
|
|
||||||
#include "input_common/main.h"
|
|
||||||
#include "jni/config.h"
|
|
||||||
#include "jni/default_ini.h"
|
|
||||||
#include "uisettings.h"
|
|
||||||
|
|
||||||
namespace FS = Common::FS;
|
|
||||||
|
|
||||||
Config::Config(const std::string& config_name, ConfigType config_type)
|
|
||||||
: type(config_type), global{config_type == ConfigType::GlobalConfig} {
|
|
||||||
Initialize(config_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
Config::~Config() = default;
|
|
||||||
|
|
||||||
bool Config::LoadINI(const std::string& default_contents, bool retry) {
|
|
||||||
void(FS::CreateParentDir(config_loc));
|
|
||||||
config = std::make_unique<INIReader>(FS::PathToUTF8String(config_loc));
|
|
||||||
const auto config_loc_str = FS::PathToUTF8String(config_loc);
|
|
||||||
if (config->ParseError() < 0) {
|
|
||||||
if (retry) {
|
|
||||||
LOG_WARNING(Config, "Failed to load {}. Creating file from defaults...",
|
|
||||||
config_loc_str);
|
|
||||||
|
|
||||||
void(FS::CreateParentDir(config_loc));
|
|
||||||
void(FS::WriteStringToFile(config_loc, FS::FileType::TextFile, default_contents));
|
|
||||||
|
|
||||||
config = std::make_unique<INIReader>(config_loc_str);
|
|
||||||
|
|
||||||
return LoadINI(default_contents, false);
|
|
||||||
}
|
|
||||||
LOG_ERROR(Config, "Failed.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
LOG_INFO(Config, "Successfully loaded {}", config_loc_str);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
void Config::ReadSetting(const std::string& group, Settings::Setting<std::string>& setting) {
|
|
||||||
std::string setting_value = config->Get(group, setting.GetLabel(), setting.GetDefault());
|
|
||||||
if (setting_value.empty()) {
|
|
||||||
setting_value = setting.GetDefault();
|
|
||||||
}
|
|
||||||
setting = std::move(setting_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
void Config::ReadSetting(const std::string& group, Settings::Setting<bool>& setting) {
|
|
||||||
setting = config->GetBoolean(group, setting.GetLabel(), setting.GetDefault());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Type, bool ranged>
|
|
||||||
void Config::ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting) {
|
|
||||||
setting = static_cast<Type>(
|
|
||||||
config->GetInteger(group, setting.GetLabel(), static_cast<long>(setting.GetDefault())));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Config::ReadValues() {
|
|
||||||
ReadSetting("ControlsGeneral", Settings::values.mouse_enabled);
|
|
||||||
ReadSetting("ControlsGeneral", Settings::values.touch_device);
|
|
||||||
ReadSetting("ControlsGeneral", Settings::values.keyboard_enabled);
|
|
||||||
ReadSetting("ControlsGeneral", Settings::values.debug_pad_enabled);
|
|
||||||
ReadSetting("ControlsGeneral", Settings::values.vibration_enabled);
|
|
||||||
ReadSetting("ControlsGeneral", Settings::values.enable_accurate_vibrations);
|
|
||||||
ReadSetting("ControlsGeneral", Settings::values.motion_enabled);
|
|
||||||
Settings::values.touchscreen.enabled =
|
|
||||||
config->GetBoolean("ControlsGeneral", "touch_enabled", true);
|
|
||||||
Settings::values.touchscreen.rotation_angle =
|
|
||||||
config->GetInteger("ControlsGeneral", "touch_angle", 0);
|
|
||||||
Settings::values.touchscreen.diameter_x =
|
|
||||||
config->GetInteger("ControlsGeneral", "touch_diameter_x", 15);
|
|
||||||
Settings::values.touchscreen.diameter_y =
|
|
||||||
config->GetInteger("ControlsGeneral", "touch_diameter_y", 15);
|
|
||||||
|
|
||||||
int num_touch_from_button_maps =
|
|
||||||
config->GetInteger("ControlsGeneral", "touch_from_button_map", 0);
|
|
||||||
if (num_touch_from_button_maps > 0) {
|
|
||||||
for (int i = 0; i < num_touch_from_button_maps; ++i) {
|
|
||||||
Settings::TouchFromButtonMap map;
|
|
||||||
map.name = config->Get("ControlsGeneral",
|
|
||||||
std::string("touch_from_button_maps_") + std::to_string(i) +
|
|
||||||
std::string("_name"),
|
|
||||||
"default");
|
|
||||||
const int num_touch_maps = config->GetInteger(
|
|
||||||
"ControlsGeneral",
|
|
||||||
std::string("touch_from_button_maps_") + std::to_string(i) + std::string("_count"),
|
|
||||||
0);
|
|
||||||
map.buttons.reserve(num_touch_maps);
|
|
||||||
|
|
||||||
for (int j = 0; j < num_touch_maps; ++j) {
|
|
||||||
std::string touch_mapping =
|
|
||||||
config->Get("ControlsGeneral",
|
|
||||||
std::string("touch_from_button_maps_") + std::to_string(i) +
|
|
||||||
std::string("_bind_") + std::to_string(j),
|
|
||||||
"");
|
|
||||||
map.buttons.emplace_back(std::move(touch_mapping));
|
|
||||||
}
|
|
||||||
|
|
||||||
Settings::values.touch_from_button_maps.emplace_back(std::move(map));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Settings::values.touch_from_button_maps.emplace_back(
|
|
||||||
Settings::TouchFromButtonMap{"default", {}});
|
|
||||||
num_touch_from_button_maps = 1;
|
|
||||||
}
|
|
||||||
Settings::values.touch_from_button_map_index = std::clamp(
|
|
||||||
Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
|
|
||||||
|
|
||||||
ReadSetting("ControlsGeneral", Settings::values.udp_input_servers);
|
|
||||||
|
|
||||||
// Data Storage
|
|
||||||
ReadSetting("Data Storage", Settings::values.use_virtual_sd);
|
|
||||||
FS::SetYuzuPath(FS::YuzuPath::NANDDir,
|
|
||||||
config->Get("Data Storage", "nand_directory",
|
|
||||||
FS::GetYuzuPathString(FS::YuzuPath::NANDDir)));
|
|
||||||
FS::SetYuzuPath(FS::YuzuPath::SDMCDir,
|
|
||||||
config->Get("Data Storage", "sdmc_directory",
|
|
||||||
FS::GetYuzuPathString(FS::YuzuPath::SDMCDir)));
|
|
||||||
FS::SetYuzuPath(FS::YuzuPath::LoadDir,
|
|
||||||
config->Get("Data Storage", "load_directory",
|
|
||||||
FS::GetYuzuPathString(FS::YuzuPath::LoadDir)));
|
|
||||||
FS::SetYuzuPath(FS::YuzuPath::DumpDir,
|
|
||||||
config->Get("Data Storage", "dump_directory",
|
|
||||||
FS::GetYuzuPathString(FS::YuzuPath::DumpDir)));
|
|
||||||
ReadSetting("Data Storage", Settings::values.gamecard_inserted);
|
|
||||||
ReadSetting("Data Storage", Settings::values.gamecard_current_game);
|
|
||||||
ReadSetting("Data Storage", Settings::values.gamecard_path);
|
|
||||||
|
|
||||||
// System
|
|
||||||
ReadSetting("System", Settings::values.current_user);
|
|
||||||
Settings::values.current_user = std::clamp<int>(Settings::values.current_user.GetValue(), 0,
|
|
||||||
Service::Account::MAX_USERS - 1);
|
|
||||||
|
|
||||||
// Disable docked mode by default on Android
|
|
||||||
Settings::values.use_docked_mode.SetValue(config->GetBoolean("System", "use_docked_mode", false)
|
|
||||||
? Settings::ConsoleMode::Docked
|
|
||||||
: Settings::ConsoleMode::Handheld);
|
|
||||||
|
|
||||||
const auto rng_seed_enabled = config->GetBoolean("System", "rng_seed_enabled", false);
|
|
||||||
if (rng_seed_enabled) {
|
|
||||||
Settings::values.rng_seed.SetValue(config->GetInteger("System", "rng_seed", 0));
|
|
||||||
} else {
|
|
||||||
Settings::values.rng_seed.SetValue(0);
|
|
||||||
}
|
|
||||||
Settings::values.rng_seed_enabled.SetValue(rng_seed_enabled);
|
|
||||||
|
|
||||||
const auto custom_rtc_enabled = config->GetBoolean("System", "custom_rtc_enabled", false);
|
|
||||||
if (custom_rtc_enabled) {
|
|
||||||
Settings::values.custom_rtc = config->GetInteger("System", "custom_rtc", 0);
|
|
||||||
} else {
|
|
||||||
Settings::values.custom_rtc = 0;
|
|
||||||
}
|
|
||||||
Settings::values.custom_rtc_enabled = custom_rtc_enabled;
|
|
||||||
|
|
||||||
ReadSetting("System", Settings::values.language_index);
|
|
||||||
ReadSetting("System", Settings::values.region_index);
|
|
||||||
ReadSetting("System", Settings::values.time_zone_index);
|
|
||||||
ReadSetting("System", Settings::values.sound_index);
|
|
||||||
|
|
||||||
// Core
|
|
||||||
ReadSetting("Core", Settings::values.use_multi_core);
|
|
||||||
ReadSetting("Core", Settings::values.memory_layout_mode);
|
|
||||||
|
|
||||||
// Cpu
|
|
||||||
ReadSetting("Cpu", Settings::values.cpu_backend);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpu_accuracy);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpu_debug_mode);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_page_tables);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_block_linking);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_return_stack_buffer);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_fast_dispatcher);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_context_elimination);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_const_prop);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_misc_ir);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_reduce_misalign_checks);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_fastmem);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_fastmem_exclusives);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_recompile_exclusives);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_ignore_memory_aborts);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_unfuse_fma);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_reduce_fp_error);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_ignore_standard_fpcr);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_inaccurate_nan);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_fastmem_check);
|
|
||||||
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_ignore_global_monitor);
|
|
||||||
|
|
||||||
// Renderer
|
|
||||||
ReadSetting("Renderer", Settings::values.renderer_backend);
|
|
||||||
ReadSetting("Renderer", Settings::values.renderer_debug);
|
|
||||||
ReadSetting("Renderer", Settings::values.renderer_shader_feedback);
|
|
||||||
ReadSetting("Renderer", Settings::values.enable_nsight_aftermath);
|
|
||||||
ReadSetting("Renderer", Settings::values.disable_shader_loop_safety_checks);
|
|
||||||
ReadSetting("Renderer", Settings::values.vulkan_device);
|
|
||||||
|
|
||||||
ReadSetting("Renderer", Settings::values.resolution_setup);
|
|
||||||
ReadSetting("Renderer", Settings::values.scaling_filter);
|
|
||||||
ReadSetting("Renderer", Settings::values.fsr_sharpening_slider);
|
|
||||||
ReadSetting("Renderer", Settings::values.anti_aliasing);
|
|
||||||
ReadSetting("Renderer", Settings::values.fullscreen_mode);
|
|
||||||
ReadSetting("Renderer", Settings::values.aspect_ratio);
|
|
||||||
ReadSetting("Renderer", Settings::values.max_anisotropy);
|
|
||||||
ReadSetting("Renderer", Settings::values.use_speed_limit);
|
|
||||||
ReadSetting("Renderer", Settings::values.speed_limit);
|
|
||||||
ReadSetting("Renderer", Settings::values.use_disk_shader_cache);
|
|
||||||
ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation);
|
|
||||||
ReadSetting("Renderer", Settings::values.vsync_mode);
|
|
||||||
ReadSetting("Renderer", Settings::values.shader_backend);
|
|
||||||
ReadSetting("Renderer", Settings::values.use_asynchronous_shaders);
|
|
||||||
ReadSetting("Renderer", Settings::values.nvdec_emulation);
|
|
||||||
ReadSetting("Renderer", Settings::values.use_fast_gpu_time);
|
|
||||||
ReadSetting("Renderer", Settings::values.use_vulkan_driver_pipeline_cache);
|
|
||||||
|
|
||||||
ReadSetting("Renderer", Settings::values.bg_red);
|
|
||||||
ReadSetting("Renderer", Settings::values.bg_green);
|
|
||||||
ReadSetting("Renderer", Settings::values.bg_blue);
|
|
||||||
|
|
||||||
// Use GPU accuracy normal by default on Android
|
|
||||||
Settings::values.gpu_accuracy = static_cast<Settings::GpuAccuracy>(config->GetInteger(
|
|
||||||
"Renderer", "gpu_accuracy", static_cast<u32>(Settings::GpuAccuracy::Normal)));
|
|
||||||
|
|
||||||
// Use GPU default anisotropic filtering on Android
|
|
||||||
Settings::values.max_anisotropy =
|
|
||||||
static_cast<Settings::AnisotropyMode>(config->GetInteger("Renderer", "max_anisotropy", 1));
|
|
||||||
|
|
||||||
// Disable ASTC compute by default on Android
|
|
||||||
Settings::values.accelerate_astc.SetValue(
|
|
||||||
config->GetBoolean("Renderer", "accelerate_astc", false) ? Settings::AstcDecodeMode::Gpu
|
|
||||||
: Settings::AstcDecodeMode::Cpu);
|
|
||||||
|
|
||||||
// Enable asynchronous presentation by default on Android
|
|
||||||
Settings::values.async_presentation =
|
|
||||||
config->GetBoolean("Renderer", "async_presentation", true);
|
|
||||||
|
|
||||||
// Disable force_max_clock by default on Android
|
|
||||||
Settings::values.renderer_force_max_clock =
|
|
||||||
config->GetBoolean("Renderer", "force_max_clock", false);
|
|
||||||
|
|
||||||
// Disable use_reactive_flushing by default on Android
|
|
||||||
Settings::values.use_reactive_flushing =
|
|
||||||
config->GetBoolean("Renderer", "use_reactive_flushing", false);
|
|
||||||
|
|
||||||
// Audio
|
|
||||||
ReadSetting("Audio", Settings::values.sink_id);
|
|
||||||
ReadSetting("Audio", Settings::values.audio_output_device_id);
|
|
||||||
ReadSetting("Audio", Settings::values.volume);
|
|
||||||
|
|
||||||
// Miscellaneous
|
|
||||||
// log_filter has a different default here than from common
|
|
||||||
Settings::values.log_filter = "*:Info";
|
|
||||||
ReadSetting("Miscellaneous", Settings::values.use_dev_keys);
|
|
||||||
|
|
||||||
// Debugging
|
|
||||||
Settings::values.record_frame_times =
|
|
||||||
config->GetBoolean("Debugging", "record_frame_times", false);
|
|
||||||
ReadSetting("Debugging", Settings::values.dump_exefs);
|
|
||||||
ReadSetting("Debugging", Settings::values.dump_nso);
|
|
||||||
ReadSetting("Debugging", Settings::values.enable_fs_access_log);
|
|
||||||
ReadSetting("Debugging", Settings::values.reporting_services);
|
|
||||||
ReadSetting("Debugging", Settings::values.quest_flag);
|
|
||||||
ReadSetting("Debugging", Settings::values.use_debug_asserts);
|
|
||||||
ReadSetting("Debugging", Settings::values.use_auto_stub);
|
|
||||||
ReadSetting("Debugging", Settings::values.disable_macro_jit);
|
|
||||||
ReadSetting("Debugging", Settings::values.disable_macro_hle);
|
|
||||||
ReadSetting("Debugging", Settings::values.use_gdbstub);
|
|
||||||
ReadSetting("Debugging", Settings::values.gdbstub_port);
|
|
||||||
|
|
||||||
const auto title_list = config->Get("AddOns", "title_ids", "");
|
|
||||||
std::stringstream ss(title_list);
|
|
||||||
std::string line;
|
|
||||||
while (std::getline(ss, line, '|')) {
|
|
||||||
const auto title_id = std::strtoul(line.c_str(), nullptr, 16);
|
|
||||||
const auto disabled_list = config->Get("AddOns", "disabled_" + line, "");
|
|
||||||
|
|
||||||
std::stringstream inner_ss(disabled_list);
|
|
||||||
std::string inner_line;
|
|
||||||
std::vector<std::string> out;
|
|
||||||
while (std::getline(inner_ss, inner_line, '|')) {
|
|
||||||
out.push_back(inner_line);
|
|
||||||
}
|
|
||||||
|
|
||||||
Settings::values.disabled_addons.insert_or_assign(title_id, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Web Service
|
|
||||||
ReadSetting("WebService", Settings::values.enable_telemetry);
|
|
||||||
ReadSetting("WebService", Settings::values.web_api_url);
|
|
||||||
ReadSetting("WebService", Settings::values.yuzu_username);
|
|
||||||
ReadSetting("WebService", Settings::values.yuzu_token);
|
|
||||||
|
|
||||||
// Network
|
|
||||||
ReadSetting("Network", Settings::values.network_interface);
|
|
||||||
|
|
||||||
// Android
|
|
||||||
ReadSetting("Android", AndroidSettings::values.picture_in_picture);
|
|
||||||
ReadSetting("Android", AndroidSettings::values.screen_layout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Config::Initialize(const std::string& config_name) {
|
|
||||||
const auto fs_config_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir);
|
|
||||||
const auto config_file = fmt::format("{}.ini", config_name);
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case ConfigType::GlobalConfig:
|
|
||||||
config_loc = FS::PathToUTF8String(fs_config_loc / config_file);
|
|
||||||
break;
|
|
||||||
case ConfigType::PerGameConfig:
|
|
||||||
config_loc = FS::PathToUTF8String(fs_config_loc / "custom" / FS::ToU8String(config_file));
|
|
||||||
break;
|
|
||||||
case ConfigType::InputProfile:
|
|
||||||
config_loc = FS::PathToUTF8String(fs_config_loc / "input" / config_file);
|
|
||||||
LoadINI(DefaultINI::android_config_file);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
LoadINI(DefaultINI::android_config_file);
|
|
||||||
ReadValues();
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <filesystem>
|
|
||||||
#include <memory>
|
|
||||||
#include <optional>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "common/settings.h"
|
|
||||||
|
|
||||||
class INIReader;
|
|
||||||
|
|
||||||
class Config {
|
|
||||||
bool LoadINI(const std::string& default_contents = "", bool retry = true);
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum class ConfigType {
|
|
||||||
GlobalConfig,
|
|
||||||
PerGameConfig,
|
|
||||||
InputProfile,
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit Config(const std::string& config_name = "config",
|
|
||||||
ConfigType config_type = ConfigType::GlobalConfig);
|
|
||||||
~Config();
|
|
||||||
|
|
||||||
void Initialize(const std::string& config_name);
|
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* Applies a value read from the config to a Setting.
|
|
||||||
*
|
|
||||||
* @param group The name of the INI group
|
|
||||||
* @param setting The yuzu setting to modify
|
|
||||||
*/
|
|
||||||
template <typename Type, bool ranged>
|
|
||||||
void ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting);
|
|
||||||
|
|
||||||
void ReadValues();
|
|
||||||
|
|
||||||
const ConfigType type;
|
|
||||||
std::unique_ptr<INIReader> config;
|
|
||||||
std::string config_loc;
|
|
||||||
const bool global;
|
|
||||||
};
|
|
@ -1,515 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace DefaultINI {
|
|
||||||
|
|
||||||
const char* android_config_file = R"(
|
|
||||||
|
|
||||||
[ControlsP0]
|
|
||||||
# The input devices and parameters for each Switch native input
|
|
||||||
# The config section determines the player number where the config will be applied on. For example "ControlsP0", "ControlsP1", ...
|
|
||||||
# It should be in the format of "engine:[engine_name],[param1]:[value1],[param2]:[value2]..."
|
|
||||||
# Escape characters $0 (for ':'), $1 (for ',') and $2 (for '$') can be used in values
|
|
||||||
|
|
||||||
# Indicates if this player should be connected at boot
|
|
||||||
connected=
|
|
||||||
|
|
||||||
# for button input, the following devices are available:
|
|
||||||
# - "keyboard" (default) for keyboard input. Required parameters:
|
|
||||||
# - "code": the code of the key to bind
|
|
||||||
# - "sdl" for joystick input using SDL. Required parameters:
|
|
||||||
# - "guid": SDL identification GUID of the joystick
|
|
||||||
# - "port": the index of the joystick to bind
|
|
||||||
# - "button"(optional): the index of the button to bind
|
|
||||||
# - "hat"(optional): the index of the hat to bind as direction buttons
|
|
||||||
# - "axis"(optional): the index of the axis to bind
|
|
||||||
# - "direction"(only used for hat): the direction name of the hat to bind. Can be "up", "down", "left" or "right"
|
|
||||||
# - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is
|
|
||||||
# triggered if the axis value crosses
|
|
||||||
# - "direction"(only used for axis): "+" means the button is triggered when the axis value
|
|
||||||
# is greater than the threshold; "-" means the button is triggered when the axis value
|
|
||||||
# is smaller than the threshold
|
|
||||||
button_a=
|
|
||||||
button_b=
|
|
||||||
button_x=
|
|
||||||
button_y=
|
|
||||||
button_lstick=
|
|
||||||
button_rstick=
|
|
||||||
button_l=
|
|
||||||
button_r=
|
|
||||||
button_zl=
|
|
||||||
button_zr=
|
|
||||||
button_plus=
|
|
||||||
button_minus=
|
|
||||||
button_dleft=
|
|
||||||
button_dup=
|
|
||||||
button_dright=
|
|
||||||
button_ddown=
|
|
||||||
button_lstick_left=
|
|
||||||
button_lstick_up=
|
|
||||||
button_lstick_right=
|
|
||||||
button_lstick_down=
|
|
||||||
button_sl=
|
|
||||||
button_sr=
|
|
||||||
button_home=
|
|
||||||
button_screenshot=
|
|
||||||
|
|
||||||
# for analog input, the following devices are available:
|
|
||||||
# - "analog_from_button" (default) for emulating analog input from direction buttons. Required parameters:
|
|
||||||
# - "up", "down", "left", "right": sub-devices for each direction.
|
|
||||||
# Should be in the format as a button input devices using escape characters, for example, "engine$0keyboard$1code$00"
|
|
||||||
# - "modifier": sub-devices as a modifier.
|
|
||||||
# - "modifier_scale": a float number representing the applied modifier scale to the analog input.
|
|
||||||
# Must be in range of 0.0-1.0. Defaults to 0.5
|
|
||||||
# - "sdl" for joystick input using SDL. Required parameters:
|
|
||||||
# - "guid": SDL identification GUID of the joystick
|
|
||||||
# - "port": the index of the joystick to bind
|
|
||||||
# - "axis_x": the index of the axis to bind as x-axis (default to 0)
|
|
||||||
# - "axis_y": the index of the axis to bind as y-axis (default to 1)
|
|
||||||
lstick=
|
|
||||||
rstick=
|
|
||||||
|
|
||||||
# for motion input, the following devices are available:
|
|
||||||
# - "keyboard" (default) for emulating random motion input from buttons. Required parameters:
|
|
||||||
# - "code": the code of the key to bind
|
|
||||||
# - "sdl" for motion input using SDL. Required parameters:
|
|
||||||
# - "guid": SDL identification GUID of the joystick
|
|
||||||
# - "port": the index of the joystick to bind
|
|
||||||
# - "motion": the index of the motion sensor to bind
|
|
||||||
# - "cemuhookudp" for motion input using Cemu Hook protocol. Required parameters:
|
|
||||||
# - "guid": the IP address of the cemu hook server encoded to a hex string. for example 192.168.0.1 = "c0a80001"
|
|
||||||
# - "port": the port of the cemu hook server
|
|
||||||
# - "pad": the index of the joystick
|
|
||||||
# - "motion": the index of the motion sensor of the joystick to bind
|
|
||||||
motionleft=
|
|
||||||
motionright=
|
|
||||||
|
|
||||||
[ControlsGeneral]
|
|
||||||
# To use the debug_pad, prepend `debug_pad_` before each button setting above.
|
|
||||||
# i.e. debug_pad_button_a=
|
|
||||||
|
|
||||||
# Enable debug pad inputs to the guest
|
|
||||||
# 0 (default): Disabled, 1: Enabled
|
|
||||||
debug_pad_enabled =
|
|
||||||
|
|
||||||
# Whether to enable or disable vibration
|
|
||||||
# 0: Disabled, 1 (default): Enabled
|
|
||||||
vibration_enabled=
|
|
||||||
|
|
||||||
# Whether to enable or disable accurate vibrations
|
|
||||||
# 0 (default): Disabled, 1: Enabled
|
|
||||||
enable_accurate_vibrations=
|
|
||||||
|
|
||||||
# Enables controller motion inputs
|
|
||||||
# 0: Disabled, 1 (default): Enabled
|
|
||||||
motion_enabled =
|
|
||||||
|
|
||||||
# Defines the udp device's touch screen coordinate system for cemuhookudp devices
|
|
||||||
# - "min_x", "min_y", "max_x", "max_y"
|
|
||||||
touch_device=
|
|
||||||
|
|
||||||
# for mapping buttons to touch inputs.
|
|
||||||
#touch_from_button_map=1
|
|
||||||
#touch_from_button_maps_0_name=default
|
|
||||||
#touch_from_button_maps_0_count=2
|
|
||||||
#touch_from_button_maps_0_bind_0=foo
|
|
||||||
#touch_from_button_maps_0_bind_1=bar
|
|
||||||
# etc.
|
|
||||||
|
|
||||||
# List of Cemuhook UDP servers, delimited by ','.
|
|
||||||
# Default: 127.0.0.1:26760
|
|
||||||
# Example: 127.0.0.1:26760,123.4.5.67:26761
|
|
||||||
udp_input_servers =
|
|
||||||
|
|
||||||
# Enable controlling an axis via a mouse input.
|
|
||||||
# 0 (default): Off, 1: On
|
|
||||||
mouse_panning =
|
|
||||||
|
|
||||||
# Set mouse sensitivity.
|
|
||||||
# Default: 1.0
|
|
||||||
mouse_panning_sensitivity =
|
|
||||||
|
|
||||||
# Emulate an analog control stick from keyboard inputs.
|
|
||||||
# 0 (default): Disabled, 1: Enabled
|
|
||||||
emulate_analog_keyboard =
|
|
||||||
|
|
||||||
# Enable mouse inputs to the guest
|
|
||||||
# 0 (default): Disabled, 1: Enabled
|
|
||||||
mouse_enabled =
|
|
||||||
|
|
||||||
# Enable keyboard inputs to the guest
|
|
||||||
# 0 (default): Disabled, 1: Enabled
|
|
||||||
keyboard_enabled =
|
|
||||||
|
|
||||||
[Core]
|
|
||||||
# Whether to use multi-core for CPU emulation
|
|
||||||
# 0: Disabled, 1 (default): Enabled
|
|
||||||
use_multi_core =
|
|
||||||
|
|
||||||
# Enable unsafe extended guest system memory layout (8GB DRAM)
|
|
||||||
# 0 (default): Disabled, 1: Enabled
|
|
||||||
use_unsafe_extended_memory_layout =
|
|
||||||
|
|
||||||
[Cpu]
|
|
||||||
Selects the preferred CPU backend for executing ARM instructions
|
|
||||||
# 0 (default): Dynarmic, 1: NCE
|
|
||||||
cpu_backend =
|
|
||||||
|
|
||||||
# Adjusts various optimizations.
|
|
||||||
# Auto-select mode enables choice unsafe optimizations.
|
|
||||||
# Accurate enables only safe optimizations.
|
|
||||||
# Unsafe allows any unsafe optimizations.
|
|
||||||
# 0 (default): Auto-select, 1: Accurate, 2: Enable unsafe optimizations
|
|
||||||
cpu_accuracy =
|
|
||||||
|
|
||||||
# Allow disabling safe optimizations.
|
|
||||||
# 0 (default): Disabled, 1: Enabled
|
|
||||||
cpu_debug_mode =
|
|
||||||
|
|
||||||
# Enable inline page tables optimization (faster guest memory access)
|
|
||||||
# 0: Disabled, 1 (default): Enabled
|
|
||||||
cpuopt_page_tables =
|
|
||||||
|
|
||||||
# Enable block linking CPU optimization (reduce block dispatcher use during predictable jumps)
|
|
||||||
# 0: Disabled, 1 (default): Enabled
|
|
||||||
cpuopt_block_linking =
|
|
||||||
|
|
||||||
# Enable return stack buffer CPU optimization (reduce block dispatcher use during predictable returns)
|
|
||||||
# 0: Disabled, 1 (default): Enabled
|
|
||||||
cpuopt_return_stack_buffer =
|
|
||||||
|
|
||||||
# Enable fast dispatcher CPU optimization (use a two-tiered dispatcher architecture)
|
|
||||||
# 0: Disabled, 1 (default): Enabled
|
|
||||||
cpuopt_fast_dispatcher =
|
|
||||||
|
|
||||||
# Enable context elimination CPU Optimization (reduce host memory use for guest context)
|
|
||||||
# 0: Disabled, 1 (default): Enabled
|
|
||||||
cpuopt_context_elimination =
|
|
||||||
|
|
||||||
# Enable constant propagation CPU optimization (basic IR optimization)
|
|
||||||
# 0: Disabled, 1 (default): Enabled
|
|
||||||
cpuopt_const_prop =
|
|
||||||
|
|
||||||
# Enable miscellaneous CPU optimizations (basic IR optimization)
|
|
||||||
# 0: Disabled, 1 (default): Enabled
|
|
||||||
cpuopt_misc_ir =
|
|
||||||
|
|
||||||
# Enable reduction of memory misalignment checks (reduce memory fallbacks for misaligned access)
|
|
||||||
# 0: Disabled, 1 (default): Enabled
|
|
||||||
cpuopt_reduce_misalign_checks =
|
|
||||||
|
|
||||||
# Enable Host MMU Emulation (faster guest memory access)
|
|
||||||
# 0: Disabled, 1 (default): Enabled
|
|
||||||
cpuopt_fastmem =
|
|
||||||
|
|
||||||
# Enable Host MMU Emulation for exclusive memory instructions (faster guest memory access)
|
|
||||||
# 0: Disabled, 1 (default): Enabled
|
|
||||||
cpuopt_fastmem_exclusives =
|
|
||||||
|
|
||||||
# Enable fallback on failure of fastmem of exclusive memory instructions (faster guest memory access)
|
|
||||||
# 0: Disabled, 1 (default): Enabled
|
|
||||||
cpuopt_recompile_exclusives =
|
|
||||||
|
|
||||||
# Enable optimization to ignore invalid memory accesses (faster guest memory access)
|
|
||||||
# 0: Disabled, 1 (default): Enabled
|
|
||||||
cpuopt_ignore_memory_aborts =
|
|
||||||
|
|
||||||
# Enable unfuse FMA (improve performance on CPUs without FMA)
|
|
||||||
# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
|
|
||||||
# 0: Disabled, 1 (default): Enabled
|
|
||||||
cpuopt_unsafe_unfuse_fma =
|
|
||||||
|
|
||||||
# Enable faster FRSQRTE and FRECPE
|
|
||||||
# Only enabled if cpu_accuracy is set to Unsafe.
|
|
||||||
# 0: Disabled, 1 (default): Enabled
|
|
||||||
cpuopt_unsafe_reduce_fp_error =
|
|
||||||
|
|
||||||
# Enable faster ASIMD instructions (32 bits only)
|
|
||||||
# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
|
|
||||||
# 0: Disabled, 1 (default): Enabled
|
|
||||||
cpuopt_unsafe_ignore_standard_fpcr =
|
|
||||||
|
|
||||||
# Enable inaccurate NaN handling
|
|
||||||
# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
|
|
||||||
# 0: Disabled, 1 (default): Enabled
|
|
||||||
cpuopt_unsafe_inaccurate_nan =
|
|
||||||
|
|
||||||
# Disable address space checks (64 bits only)
|
|
||||||
# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
|
|
||||||
# 0: Disabled, 1 (default): Enabled
|
|
||||||
cpuopt_unsafe_fastmem_check =
|
|
||||||
|
|
||||||
# Enable faster exclusive instructions
|
|
||||||
# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
|
|
||||||
# 0: Disabled, 1 (default): Enabled
|
|
||||||
cpuopt_unsafe_ignore_global_monitor =
|
|
||||||
|
|
||||||
[Renderer]
|
|
||||||
# Which backend API to use.
|
|
||||||
# 0: OpenGL (unsupported), 1 (default): Vulkan, 2: Null
|
|
||||||
backend =
|
|
||||||
|
|
||||||
# Whether to enable asynchronous presentation (Vulkan only)
|
|
||||||
# 0: Off, 1 (default): On
|
|
||||||
async_presentation =
|
|
||||||
|
|
||||||
# Forces the GPU to run at the maximum possible clocks (thermal constraints will still be applied).
|
|
||||||
# 0 (default): Disabled, 1: Enabled
|
|
||||||
force_max_clock =
|
|
||||||
|
|
||||||
# Enable graphics API debugging mode.
|
|
||||||
# 0 (default): Disabled, 1: Enabled
|
|
||||||
debug =
|
|
||||||
|
|
||||||
# Enable shader feedback.
|
|
||||||
# 0 (default): Disabled, 1: Enabled
|
|
||||||
renderer_shader_feedback =
|
|
||||||
|
|
||||||
# Enable Nsight Aftermath crash dumps
|
|
||||||
# 0 (default): Disabled, 1: Enabled
|
|
||||||
nsight_aftermath =
|
|
||||||
|
|
||||||
# Disable shader loop safety checks, executing the shader without loop logic changes
|
|
||||||
# 0 (default): Disabled, 1: Enabled
|
|
||||||
disable_shader_loop_safety_checks =
|
|
||||||
|
|
||||||
# Which Vulkan physical device to use (defaults to 0)
|
|
||||||
vulkan_device =
|
|
||||||
|
|
||||||
# 0: 0.5x (360p/540p) [EXPERIMENTAL]
|
|
||||||
# 1: 0.75x (540p/810p) [EXPERIMENTAL]
|
|
||||||
# 2 (default): 1x (720p/1080p)
|
|
||||||
# 3: 2x (1440p/2160p)
|
|
||||||
# 4: 3x (2160p/3240p)
|
|
||||||
# 5: 4x (2880p/4320p)
|
|
||||||
# 6: 5x (3600p/5400p)
|
|
||||||
# 7: 6x (4320p/6480p)
|
|
||||||
resolution_setup =
|
|
||||||
|
|
||||||
# Pixel filter to use when up- or down-sampling rendered frames.
|
|
||||||
# 0: Nearest Neighbor
|
|
||||||
# 1 (default): Bilinear
|
|
||||||
# 2: Bicubic
|
|
||||||
# 3: Gaussian
|
|
||||||
# 4: ScaleForce
|
|
||||||
# 5: AMD FidelityFX™️ Super Resolution [Vulkan Only]
|
|
||||||
scaling_filter =
|
|
||||||
|
|
||||||
# Anti-Aliasing (AA)
|
|
||||||
# 0 (default): None, 1: FXAA
|
|
||||||
anti_aliasing =
|
|
||||||
|
|
||||||
# Whether to use fullscreen or borderless window mode
|
|
||||||
# 0 (Windows default): Borderless window, 1 (All other default): Exclusive fullscreen
|
|
||||||
fullscreen_mode =
|
|
||||||
|
|
||||||
# Aspect ratio
|
|
||||||
# 0: Default (16:9), 1: Force 4:3, 2: Force 21:9, 3: Force 16:10, 4: Stretch to Window
|
|
||||||
aspect_ratio =
|
|
||||||
|
|
||||||
# Anisotropic filtering
|
|
||||||
# 0: Default, 1: 2x, 2: 4x, 3: 8x, 4: 16x
|
|
||||||
max_anisotropy =
|
|
||||||
|
|
||||||
# Whether to enable VSync or not.
|
|
||||||
# OpenGL: Values other than 0 enable VSync
|
|
||||||
# Vulkan: FIFO is selected if the requested mode is not supported by the driver.
|
|
||||||
# FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate.
|
|
||||||
# FIFO Relaxed is similar to FIFO but allows tearing as it recovers from a slow down.
|
|
||||||
# Mailbox can have lower latency than FIFO and does not tear but may drop frames.
|
|
||||||
# Immediate (no synchronization) just presents whatever is available and can exhibit tearing.
|
|
||||||
# 0: Immediate (Off), 1 (Default): Mailbox (On), 2: FIFO, 3: FIFO Relaxed
|
|
||||||
use_vsync =
|
|
||||||
|
|
||||||
# Selects the OpenGL shader backend. NV_gpu_program5 is required for GLASM. If NV_gpu_program5 is
|
|
||||||
# not available and GLASM is selected, GLSL will be used.
|
|
||||||
# 0: GLSL, 1 (default): GLASM, 2: SPIR-V
|
|
||||||
shader_backend =
|
|
||||||
|
|
||||||
# Whether to allow asynchronous shader building.
|
|
||||||
# 0 (default): Off, 1: On
|
|
||||||
use_asynchronous_shaders =
|
|
||||||
|
|
||||||
# Uses reactive flushing instead of predictive flushing. Allowing a more accurate syncing of memory.
|
|
||||||
# 0 (default): Off, 1: On
|
|
||||||
use_reactive_flushing =
|
|
||||||
|
|
||||||
# NVDEC emulation.
|
|
||||||
# 0: Disabled, 1: CPU Decoding, 2 (default): GPU Decoding
|
|
||||||
nvdec_emulation =
|
|
||||||
|
|
||||||
# Accelerate ASTC texture decoding.
|
|
||||||
# 0 (default): Off, 1: On
|
|
||||||
accelerate_astc =
|
|
||||||
|
|
||||||
# Turns on the speed limiter, which will limit the emulation speed to the desired speed limit value
|
|
||||||
# 0: Off, 1: On (default)
|
|
||||||
use_speed_limit =
|
|
||||||
|
|
||||||
# Limits the speed of the game to run no faster than this value as a percentage of target speed
|
|
||||||
# 1 - 9999: Speed limit as a percentage of target game speed. 100 (default)
|
|
||||||
speed_limit =
|
|
||||||
|
|
||||||
# Whether to use disk based shader cache
|
|
||||||
# 0: Off, 1 (default): On
|
|
||||||
use_disk_shader_cache =
|
|
||||||
|
|
||||||
# Which gpu accuracy level to use
|
|
||||||
# 0 (default): Normal, 1: High, 2: Extreme (Very slow)
|
|
||||||
gpu_accuracy =
|
|
||||||
|
|
||||||
# Whether to use asynchronous GPU emulation
|
|
||||||
# 0 : Off (slow), 1 (default): On (fast)
|
|
||||||
use_asynchronous_gpu_emulation =
|
|
||||||
|
|
||||||
# Inform the guest that GPU operations completed more quickly than they did.
|
|
||||||
# 0: Off, 1 (default): On
|
|
||||||
use_fast_gpu_time =
|
|
||||||
|
|
||||||
# Force unmodified buffers to be flushed, which can cost performance.
|
|
||||||
# 0: Off (default), 1: On
|
|
||||||
use_pessimistic_flushes =
|
|
||||||
|
|
||||||
# Whether to use garbage collection or not for GPU caches.
|
|
||||||
# 0 (default): Off, 1: On
|
|
||||||
use_caches_gc =
|
|
||||||
|
|
||||||
# The clear color for the renderer. What shows up on the sides of the bottom screen.
|
|
||||||
# Must be in range of 0-255. Defaults to 0 for all.
|
|
||||||
bg_red =
|
|
||||||
bg_blue =
|
|
||||||
bg_green =
|
|
||||||
|
|
||||||
[Audio]
|
|
||||||
# Which audio output engine to use.
|
|
||||||
# auto (default): Auto-select
|
|
||||||
# cubeb: Cubeb audio engine (if available)
|
|
||||||
# sdl2: SDL2 audio engine (if available)
|
|
||||||
# null: No audio output
|
|
||||||
output_engine =
|
|
||||||
|
|
||||||
# Which audio device to use.
|
|
||||||
# auto (default): Auto-select
|
|
||||||
output_device =
|
|
||||||
|
|
||||||
# Output volume.
|
|
||||||
# 100 (default): 100%, 0; mute
|
|
||||||
volume =
|
|
||||||
|
|
||||||
[Data Storage]
|
|
||||||
# Whether to create a virtual SD card.
|
|
||||||
# 1: Yes, 0 (default): No
|
|
||||||
use_virtual_sd =
|
|
||||||
|
|
||||||
# Whether or not to enable gamecard emulation
|
|
||||||
# 1: Yes, 0 (default): No
|
|
||||||
gamecard_inserted =
|
|
||||||
|
|
||||||
# Whether or not the gamecard should be emulated as the current game
|
|
||||||
# If 'gamecard_inserted' is 0 this setting is irrelevant
|
|
||||||
# 1: Yes, 0 (default): No
|
|
||||||
gamecard_current_game =
|
|
||||||
|
|
||||||
# Path to an XCI file to use as the gamecard
|
|
||||||
# If 'gamecard_inserted' is 0 this setting is irrelevant
|
|
||||||
# If 'gamecard_current_game' is 1 this setting is irrelevant
|
|
||||||
gamecard_path =
|
|
||||||
|
|
||||||
[System]
|
|
||||||
# Whether the system is docked
|
|
||||||
# 1 (default): Yes, 0: No
|
|
||||||
use_docked_mode =
|
|
||||||
|
|
||||||
# Sets the seed for the RNG generator built into the switch
|
|
||||||
# rng_seed will be ignored and randomly generated if rng_seed_enabled is false
|
|
||||||
rng_seed_enabled =
|
|
||||||
rng_seed =
|
|
||||||
|
|
||||||
# Sets the current time (in seconds since 12:00 AM Jan 1, 1970) that will be used by the time service
|
|
||||||
# This will auto-increment, with the time set being the time the game is started
|
|
||||||
# This override will only occur if custom_rtc_enabled is true, otherwise the current time is used
|
|
||||||
custom_rtc_enabled =
|
|
||||||
custom_rtc =
|
|
||||||
|
|
||||||
# Sets the systems language index
|
|
||||||
# 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese,
|
|
||||||
# 7: Korean, 8: Dutch, 9: Portuguese, 10: Russian, 11: Taiwanese, 12: British English, 13: Canadian French,
|
|
||||||
# 14: Latin American Spanish, 15: Simplified Chinese, 16: Traditional Chinese, 17: Brazilian Portuguese
|
|
||||||
language_index =
|
|
||||||
|
|
||||||
# The system region that yuzu will use during emulation
|
|
||||||
# -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan
|
|
||||||
region_index =
|
|
||||||
|
|
||||||
# The system time zone that yuzu will use during emulation
|
|
||||||
# 0: Auto-select (default), 1: Default (system archive value), Others: Index for specified time zone
|
|
||||||
time_zone_index =
|
|
||||||
|
|
||||||
# Sets the sound output mode.
|
|
||||||
# 0: Mono, 1 (default): Stereo, 2: Surround
|
|
||||||
sound_index =
|
|
||||||
|
|
||||||
[Miscellaneous]
|
|
||||||
# A filter which removes logs below a certain logging level.
|
|
||||||
# Examples: *:Debug Kernel.SVC:Trace Service.*:Critical
|
|
||||||
log_filter = *:Trace
|
|
||||||
|
|
||||||
# Use developer keys
|
|
||||||
# 0 (default): Disabled, 1: Enabled
|
|
||||||
use_dev_keys =
|
|
||||||
|
|
||||||
[Debugging]
|
|
||||||
# Record frame time data, can be found in the log directory. Boolean value
|
|
||||||
record_frame_times =
|
|
||||||
# Determines whether or not yuzu will dump the ExeFS of all games it attempts to load while loading them
|
|
||||||
dump_exefs=false
|
|
||||||
# Determines whether or not yuzu will dump all NSOs it attempts to load while loading them
|
|
||||||
dump_nso=false
|
|
||||||
# Determines whether or not yuzu will save the filesystem access log.
|
|
||||||
enable_fs_access_log=false
|
|
||||||
# Enables verbose reporting services
|
|
||||||
reporting_services =
|
|
||||||
# Determines whether or not yuzu will report to the game that the emulated console is in Kiosk Mode
|
|
||||||
# false: Retail/Normal Mode (default), true: Kiosk Mode
|
|
||||||
quest_flag =
|
|
||||||
# Determines whether debug asserts should be enabled, which will throw an exception on asserts.
|
|
||||||
# false: Disabled (default), true: Enabled
|
|
||||||
use_debug_asserts =
|
|
||||||
# Determines whether unimplemented HLE service calls should be automatically stubbed.
|
|
||||||
# false: Disabled (default), true: Enabled
|
|
||||||
use_auto_stub =
|
|
||||||
# Enables/Disables the macro JIT compiler
|
|
||||||
disable_macro_jit=false
|
|
||||||
# Determines whether to enable the GDB stub and wait for the debugger to attach before running.
|
|
||||||
# false: Disabled (default), true: Enabled
|
|
||||||
use_gdbstub=false
|
|
||||||
# The port to use for the GDB server, if it is enabled.
|
|
||||||
gdbstub_port=6543
|
|
||||||
|
|
||||||
[WebService]
|
|
||||||
# Whether or not to enable telemetry
|
|
||||||
# 0: No, 1 (default): Yes
|
|
||||||
enable_telemetry =
|
|
||||||
# URL for Web API
|
|
||||||
web_api_url = https://api.yuzu-emu.org
|
|
||||||
# Username and token for yuzu Web Service
|
|
||||||
# See https://profile.yuzu-emu.org/ for more info
|
|
||||||
yuzu_username =
|
|
||||||
yuzu_token =
|
|
||||||
|
|
||||||
[Network]
|
|
||||||
# Name of the network interface device to use with yuzu LAN play.
|
|
||||||
# e.g. On *nix: 'enp7s0', 'wlp6s0u1u3u3', 'lo'
|
|
||||||
# e.g. On Windows: 'Ethernet', 'Wi-Fi'
|
|
||||||
network_interface =
|
|
||||||
|
|
||||||
[AddOns]
|
|
||||||
# Used to disable add-ons
|
|
||||||
# List of title IDs of games that will have add-ons disabled (separated by '|'):
|
|
||||||
title_ids =
|
|
||||||
# For each title ID, have a key/value pair called `disabled_<title_id>` equal to the names of the add-ons to disable (sep. by '|')
|
|
||||||
# e.x. disabled_0100000000010000 = Update|DLC <- disables Updates and DLC on Super Mario Odyssey
|
|
||||||
)";
|
|
||||||
} // namespace DefaultINI
|
|
@ -52,8 +52,8 @@
|
|||||||
#include "core/hle/service/am/applets/applets.h"
|
#include "core/hle/service/am/applets/applets.h"
|
||||||
#include "core/hle/service/filesystem/filesystem.h"
|
#include "core/hle/service/filesystem/filesystem.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
|
#include "frontend_common/config.h"
|
||||||
#include "jni/android_common/android_common.h"
|
#include "jni/android_common/android_common.h"
|
||||||
#include "jni/config.h"
|
|
||||||
#include "jni/id_cache.h"
|
#include "jni/id_cache.h"
|
||||||
#include "jni/native.h"
|
#include "jni/native.h"
|
||||||
#include "video_core/renderer_base.h"
|
#include "video_core/renderer_base.h"
|
||||||
@ -664,8 +664,6 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased(JNIEnv* env, jclass c
|
|||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeSystem(JNIEnv* env, jclass clazz,
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeSystem(JNIEnv* env, jclass clazz,
|
||||||
jboolean reload) {
|
jboolean reload) {
|
||||||
// Create the default config.ini.
|
|
||||||
Config{};
|
|
||||||
// Initialize the emulated system.
|
// Initialize the emulated system.
|
||||||
if (!reload) {
|
if (!reload) {
|
||||||
EmulationSession::GetInstance().System().Initialize();
|
EmulationSession::GetInstance().System().Initialize();
|
||||||
@ -680,17 +678,6 @@ jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore(JNIEnv* env, jclass cl
|
|||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2Ljava_lang_String_2Z(
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2Ljava_lang_String_2Z(
|
||||||
JNIEnv* env, jclass clazz, jstring j_file, jstring j_savestate, jboolean j_delete_savestate) {}
|
JNIEnv* env, jclass clazz, jstring j_file, jstring j_savestate, jboolean j_delete_savestate) {}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadSettings(JNIEnv* env, jclass clazz) {
|
|
||||||
Config{};
|
|
||||||
}
|
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_initGameIni(JNIEnv* env, jclass clazz,
|
|
||||||
jstring j_game_id) {
|
|
||||||
std::string_view game_id = env->GetStringUTFChars(j_game_id, 0);
|
|
||||||
|
|
||||||
env->ReleaseStringUTFChars(j_game_id, game_id.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats(JNIEnv* env, jclass clazz) {
|
jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats(JNIEnv* env, jclass clazz) {
|
||||||
jdoubleArray j_stats = env->NewDoubleArray(4);
|
jdoubleArray j_stats = env->NewDoubleArray(4);
|
||||||
|
|
||||||
@ -707,14 +694,6 @@ jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats(JNIEnv* env, jcl
|
|||||||
return j_stats;
|
return j_stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCpuBackend(JNIEnv* env, jclass clazz) {
|
|
||||||
if (Settings::IsNceEnabled()) {
|
|
||||||
return ToJString(env, "NCE");
|
|
||||||
}
|
|
||||||
|
|
||||||
return ToJString(env, "JIT");
|
|
||||||
}
|
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_DirectoryInitialization_setSysDirectory(JNIEnv* env,
|
void Java_org_yuzu_yuzu_1emu_utils_DirectoryInitialization_setSysDirectory(JNIEnv* env,
|
||||||
jclass clazz,
|
jclass clazz,
|
||||||
jstring j_path) {}
|
jstring j_path) {}
|
||||||
|
@ -5,11 +5,14 @@
|
|||||||
|
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
|
|
||||||
|
#include "android_config.h"
|
||||||
|
#include "android_settings.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
|
#include "frontend_common/config.h"
|
||||||
#include "jni/android_common/android_common.h"
|
#include "jni/android_common/android_common.h"
|
||||||
#include "jni/config.h"
|
|
||||||
#include "uisettings.h"
|
std::unique_ptr<AndroidConfig> config;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Settings::Setting<T>* getSetting(JNIEnv* env, jstring jkey) {
|
Settings::Setting<T>* getSetting(JNIEnv* env, jstring jkey) {
|
||||||
@ -28,6 +31,22 @@ Settings::Setting<T>* getSetting(JNIEnv* env, jstring jkey) {
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
|
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_initializeConfig(JNIEnv* env, jobject obj) {
|
||||||
|
config = std::make_unique<AndroidConfig>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_unloadConfig(JNIEnv* env, jobject obj) {
|
||||||
|
config.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_reloadSettings(JNIEnv* env, jobject obj) {
|
||||||
|
config->AndroidConfig::ReloadAllValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_saveSettings(JNIEnv* env, jobject obj) {
|
||||||
|
config->AndroidConfig::SaveAllValues();
|
||||||
|
}
|
||||||
|
|
||||||
jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getBoolean(JNIEnv* env, jobject obj,
|
jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getBoolean(JNIEnv* env, jobject obj,
|
||||||
jstring jkey, jboolean getDefault) {
|
jstring jkey, jboolean getDefault) {
|
||||||
auto setting = getSetting<bool>(env, jkey);
|
auto setting = getSetting<bool>(env, jkey);
|
||||||
|
@ -127,7 +127,6 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
android:paddingVertical="4dp"
|
android:paddingVertical="4dp"
|
||||||
app:checkedChip="@id/chip_recently_played"
|
|
||||||
app:chipSpacingHorizontal="12dp"
|
app:chipSpacingHorizontal="12dp"
|
||||||
app:singleLine="true"
|
app:singleLine="true"
|
||||||
app:singleSelection="true">
|
app:singleSelection="true">
|
||||||
|
@ -175,16 +175,6 @@
|
|||||||
<item>2</item>
|
<item>2</item>
|
||||||
</integer-array>
|
</integer-array>
|
||||||
|
|
||||||
<string-array name="cpuBackendNames">
|
|
||||||
<item>@string/cpu_backend_dynarmic</item>
|
|
||||||
<item>@string/cpu_backend_nce</item>
|
|
||||||
</string-array>
|
|
||||||
|
|
||||||
<integer-array name="cpuBackendValues">
|
|
||||||
<item>0</item>
|
|
||||||
<item>1</item>
|
|
||||||
</integer-array>
|
|
||||||
|
|
||||||
<string-array name="cpuAccuracyNames">
|
<string-array name="cpuAccuracyNames">
|
||||||
<item>@string/auto</item>
|
<item>@string/auto</item>
|
||||||
<item>@string/cpu_accuracy_accurate</item>
|
<item>@string/cpu_accuracy_accurate</item>
|
||||||
|
@ -91,7 +91,6 @@
|
|||||||
<string name="manage_save_data">Manage save data</string>
|
<string name="manage_save_data">Manage save data</string>
|
||||||
<string name="manage_save_data_description">Save data found. Please select an option below.</string>
|
<string name="manage_save_data_description">Save data found. Please select an option below.</string>
|
||||||
<string name="import_export_saves_description">Import or export save files</string>
|
<string name="import_export_saves_description">Import or export save files</string>
|
||||||
<string name="save_files_exporting">Exporting save files…</string>
|
|
||||||
<string name="save_file_imported_success">Imported successfully</string>
|
<string name="save_file_imported_success">Imported successfully</string>
|
||||||
<string name="save_file_invalid_zip_structure">Invalid save directory structure</string>
|
<string name="save_file_invalid_zip_structure">Invalid save directory structure</string>
|
||||||
<string name="save_file_invalid_zip_structure_description">The first subfolder name must be the title ID of the game.</string>
|
<string name="save_file_invalid_zip_structure_description">The first subfolder name must be the title ID of the game.</string>
|
||||||
@ -185,7 +184,6 @@
|
|||||||
<string name="frame_limit_enable_description">Limits emulation speed to a specified percentage of normal speed.</string>
|
<string name="frame_limit_enable_description">Limits emulation speed to a specified percentage of normal speed.</string>
|
||||||
<string name="frame_limit_slider">Limit speed percent</string>
|
<string name="frame_limit_slider">Limit speed percent</string>
|
||||||
<string name="frame_limit_slider_description">Specifies the percentage to limit emulation speed. 100% is the normal speed. Values higher or lower will increase or decrease the speed limit.</string>
|
<string name="frame_limit_slider_description">Specifies the percentage to limit emulation speed. 100% is the normal speed. Values higher or lower will increase or decrease the speed limit.</string>
|
||||||
<string name="cpu_backend">CPU Backend</string>
|
|
||||||
<string name="cpu_accuracy">CPU accuracy</string>
|
<string name="cpu_accuracy">CPU accuracy</string>
|
||||||
<string name="value_with_units">%1$s%2$s</string>
|
<string name="value_with_units">%1$s%2$s</string>
|
||||||
|
|
||||||
@ -258,7 +256,6 @@
|
|||||||
<string name="cancelling">Cancelling</string>
|
<string name="cancelling">Cancelling</string>
|
||||||
<string name="install">Install</string>
|
<string name="install">Install</string>
|
||||||
<string name="delete">Delete</string>
|
<string name="delete">Delete</string>
|
||||||
<string name="export_success">Exported successfully</string>
|
|
||||||
|
|
||||||
<!-- GPU driver installation -->
|
<!-- GPU driver installation -->
|
||||||
<string name="select_gpu_driver">Select GPU driver</string>
|
<string name="select_gpu_driver">Select GPU driver</string>
|
||||||
@ -417,10 +414,6 @@
|
|||||||
<string name="ratio_force_sixteen_ten">Force 16:10</string>
|
<string name="ratio_force_sixteen_ten">Force 16:10</string>
|
||||||
<string name="ratio_stretch">Stretch to window</string>
|
<string name="ratio_stretch">Stretch to window</string>
|
||||||
|
|
||||||
<!-- CPU Backend -->
|
|
||||||
<string name="cpu_backend_dynarmic">Dynarmic (Slow)</string>
|
|
||||||
<string name="cpu_backend_nce">Native code execution (NCE)</string>
|
|
||||||
|
|
||||||
<!-- CPU Accuracy -->
|
<!-- CPU Accuracy -->
|
||||||
<string name="cpu_accuracy_accurate">Accurate</string>
|
<string name="cpu_accuracy_accurate">Accurate</string>
|
||||||
<string name="cpu_accuracy_unsafe">Unsafe</string>
|
<string name="cpu_accuracy_unsafe">Unsafe</string>
|
||||||
|
@ -12,7 +12,7 @@ bool IsValidChannelCount(u32 channel_count) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool IsValidStreamCounts(u32 total_stream_count, u32 stereo_stream_count) {
|
bool IsValidStreamCounts(u32 total_stream_count, u32 stereo_stream_count) {
|
||||||
return total_stream_count > 0 && static_cast<s32>(stereo_stream_count) >= 0 &&
|
return total_stream_count > 0 && stereo_stream_count > 0 &&
|
||||||
stereo_stream_count <= total_stream_count && IsValidChannelCount(total_stream_count);
|
stereo_stream_count <= total_stream_count && IsValidChannelCount(total_stream_count);
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -148,7 +148,7 @@ Result OpusDecoder::DecodeInterleavedForMultiStream(u32* out_data_size, u64* out
|
|||||||
auto* header_p{reinterpret_cast<const OpusPacketHeader*>(input_data.data())};
|
auto* header_p{reinterpret_cast<const OpusPacketHeader*>(input_data.data())};
|
||||||
OpusPacketHeader header{ReverseHeader(*header_p)};
|
OpusPacketHeader header{ReverseHeader(*header_p)};
|
||||||
|
|
||||||
LOG_TRACE(Service_Audio, "header size 0x{:X} input data size 0x{:X} in_data size 0x{:X}",
|
LOG_ERROR(Service_Audio, "header size 0x{:X} input data size 0x{:X} in_data size 0x{:X}",
|
||||||
header.size, input_data.size_bytes(), in_data.size_bytes());
|
header.size, input_data.size_bytes(), in_data.size_bytes());
|
||||||
|
|
||||||
R_UNLESS(in_data.size_bytes() >= header.size &&
|
R_UNLESS(in_data.size_bytes() >= header.size &&
|
||||||
|
@ -52,7 +52,6 @@ add_library(common STATIC
|
|||||||
fiber.cpp
|
fiber.cpp
|
||||||
fiber.h
|
fiber.h
|
||||||
fixed_point.h
|
fixed_point.h
|
||||||
free_region_manager.h
|
|
||||||
fs/file.cpp
|
fs/file.cpp
|
||||||
fs/file.h
|
fs/file.h
|
||||||
fs/fs.cpp
|
fs/fs.cpp
|
||||||
@ -167,13 +166,6 @@ if (WIN32)
|
|||||||
target_link_libraries(common PRIVATE ntdll)
|
target_link_libraries(common PRIVATE ntdll)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (NOT WIN32)
|
|
||||||
target_sources(common PRIVATE
|
|
||||||
signal_chain.cpp
|
|
||||||
signal_chain.h
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(ANDROID)
|
if(ANDROID)
|
||||||
target_sources(common
|
target_sources(common
|
||||||
PRIVATE
|
PRIVATE
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
#include <boost/icl/interval_set.hpp>
|
|
||||||
|
|
||||||
namespace Common {
|
|
||||||
|
|
||||||
class FreeRegionManager {
|
|
||||||
public:
|
|
||||||
explicit FreeRegionManager() = default;
|
|
||||||
~FreeRegionManager() = default;
|
|
||||||
|
|
||||||
void SetAddressSpace(void* start, size_t size) {
|
|
||||||
this->FreeBlock(start, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<void*, size_t> FreeBlock(void* block_ptr, size_t size) {
|
|
||||||
std::scoped_lock lk(m_mutex);
|
|
||||||
|
|
||||||
// Check to see if we are adjacent to any regions.
|
|
||||||
auto start_address = reinterpret_cast<uintptr_t>(block_ptr);
|
|
||||||
auto end_address = start_address + size;
|
|
||||||
auto it = m_free_regions.find({start_address - 1, end_address + 1});
|
|
||||||
|
|
||||||
// If we are, join with them, ensuring we stay in bounds.
|
|
||||||
if (it != m_free_regions.end()) {
|
|
||||||
start_address = std::min(start_address, it->lower());
|
|
||||||
end_address = std::max(end_address, it->upper());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free the relevant region.
|
|
||||||
m_free_regions.insert({start_address, end_address});
|
|
||||||
|
|
||||||
// Return the adjusted pointers.
|
|
||||||
block_ptr = reinterpret_cast<void*>(start_address);
|
|
||||||
size = end_address - start_address;
|
|
||||||
return {block_ptr, size};
|
|
||||||
}
|
|
||||||
|
|
||||||
void AllocateBlock(void* block_ptr, size_t size) {
|
|
||||||
std::scoped_lock lk(m_mutex);
|
|
||||||
|
|
||||||
auto address = reinterpret_cast<uintptr_t>(block_ptr);
|
|
||||||
m_free_regions.subtract({address, address + size});
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::mutex m_mutex;
|
|
||||||
boost::icl::interval_set<uintptr_t> m_free_regions;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Common
|
|
@ -21,18 +21,15 @@
|
|||||||
#include <boost/icl/interval_set.hpp>
|
#include <boost/icl/interval_set.hpp>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/random.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
|
|
||||||
#endif // ^^^ Linux ^^^
|
#endif // ^^^ Linux ^^^
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <random>
|
|
||||||
|
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/free_region_manager.h"
|
|
||||||
#include "common/host_memory.h"
|
#include "common/host_memory.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
|
||||||
@ -144,7 +141,7 @@ public:
|
|||||||
Release();
|
Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms) {
|
void Map(size_t virtual_offset, size_t host_offset, size_t length) {
|
||||||
std::unique_lock lock{placeholder_mutex};
|
std::unique_lock lock{placeholder_mutex};
|
||||||
if (!IsNiechePlaceholder(virtual_offset, length)) {
|
if (!IsNiechePlaceholder(virtual_offset, length)) {
|
||||||
Split(virtual_offset, length);
|
Split(virtual_offset, length);
|
||||||
@ -163,7 +160,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute) {
|
void Protect(size_t virtual_offset, size_t length, bool read, bool write) {
|
||||||
DWORD new_flags{};
|
DWORD new_flags{};
|
||||||
if (read && write) {
|
if (read && write) {
|
||||||
new_flags = PAGE_READWRITE;
|
new_flags = PAGE_READWRITE;
|
||||||
@ -189,11 +186,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnableDirectMappedAddress() {
|
|
||||||
// TODO
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t backing_size; ///< Size of the backing memory in bytes
|
const size_t backing_size; ///< Size of the backing memory in bytes
|
||||||
const size_t virtual_size; ///< Size of the virtual address placeholder in bytes
|
const size_t virtual_size; ///< Size of the virtual address placeholder in bytes
|
||||||
|
|
||||||
@ -361,64 +353,6 @@ private:
|
|||||||
|
|
||||||
#elif defined(__linux__) || defined(__FreeBSD__) // ^^^ Windows ^^^ vvv Linux vvv
|
#elif defined(__linux__) || defined(__FreeBSD__) // ^^^ Windows ^^^ vvv Linux vvv
|
||||||
|
|
||||||
#ifdef ARCHITECTURE_arm64
|
|
||||||
|
|
||||||
static uint64_t GetRandomU64() {
|
|
||||||
uint64_t ret;
|
|
||||||
ASSERT(getrandom(&ret, sizeof(ret), 0) == 0);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void* ChooseVirtualBase(size_t virtual_size) {
|
|
||||||
constexpr uintptr_t Map39BitSize = (1ULL << 39);
|
|
||||||
constexpr uintptr_t Map36BitSize = (1ULL << 36);
|
|
||||||
|
|
||||||
// Seed the MT with some initial strong randomness.
|
|
||||||
//
|
|
||||||
// This is not a cryptographic application, we just want something more
|
|
||||||
// random than the current time.
|
|
||||||
std::mt19937_64 rng(GetRandomU64());
|
|
||||||
|
|
||||||
// We want to ensure we are allocating at an address aligned to the L2 block size.
|
|
||||||
// For Qualcomm devices, we must also allocate memory above 36 bits.
|
|
||||||
const size_t lower = Map36BitSize / HugePageSize;
|
|
||||||
const size_t upper = (Map39BitSize - virtual_size) / HugePageSize;
|
|
||||||
const size_t range = upper - lower;
|
|
||||||
|
|
||||||
// Try up to 64 times to allocate memory at random addresses in the range.
|
|
||||||
for (int i = 0; i < 64; i++) {
|
|
||||||
// Calculate a possible location.
|
|
||||||
uintptr_t hint_address = ((rng() % range) + lower) * HugePageSize;
|
|
||||||
|
|
||||||
// Try to map.
|
|
||||||
// Note: we may be able to take advantage of MAP_FIXED_NOREPLACE here.
|
|
||||||
void* map_pointer =
|
|
||||||
mmap(reinterpret_cast<void*>(hint_address), virtual_size, PROT_READ | PROT_WRITE,
|
|
||||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
|
|
||||||
|
|
||||||
// If we successfully mapped, we're done.
|
|
||||||
if (reinterpret_cast<uintptr_t>(map_pointer) == hint_address) {
|
|
||||||
return map_pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unmap if necessary, and try again.
|
|
||||||
if (map_pointer != MAP_FAILED) {
|
|
||||||
munmap(map_pointer, virtual_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return MAP_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
static void* ChooseVirtualBase(size_t virtual_size) {
|
|
||||||
return mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE,
|
|
||||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class HostMemory::Impl {
|
class HostMemory::Impl {
|
||||||
public:
|
public:
|
||||||
explicit Impl(size_t backing_size_, size_t virtual_size_)
|
explicit Impl(size_t backing_size_, size_t virtual_size_)
|
||||||
@ -481,7 +415,8 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
virtual_base = virtual_map_base = static_cast<u8*>(ChooseVirtualBase(virtual_size));
|
virtual_base = static_cast<u8*>(mmap(nullptr, virtual_size, PROT_NONE,
|
||||||
|
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0));
|
||||||
if (virtual_base == MAP_FAILED) {
|
if (virtual_base == MAP_FAILED) {
|
||||||
LOG_CRITICAL(HW_Memory, "mmap failed: {}", strerror(errno));
|
LOG_CRITICAL(HW_Memory, "mmap failed: {}", strerror(errno));
|
||||||
throw std::bad_alloc{};
|
throw std::bad_alloc{};
|
||||||
@ -489,7 +424,7 @@ public:
|
|||||||
madvise(virtual_base, virtual_size, MADV_HUGEPAGE);
|
madvise(virtual_base, virtual_size, MADV_HUGEPAGE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
free_manager.SetAddressSpace(virtual_base, virtual_size);
|
placeholders.add({0, virtual_size});
|
||||||
good = true;
|
good = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -497,29 +432,14 @@ public:
|
|||||||
Release();
|
Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms) {
|
void Map(size_t virtual_offset, size_t host_offset, size_t length) {
|
||||||
// Intersect the range with our address space.
|
{
|
||||||
AdjustMap(&virtual_offset, &length);
|
std::scoped_lock lock{placeholder_mutex};
|
||||||
|
placeholders.subtract({virtual_offset, virtual_offset + length});
|
||||||
// We are removing a placeholder.
|
|
||||||
free_manager.AllocateBlock(virtual_base + virtual_offset, length);
|
|
||||||
|
|
||||||
// Deduce mapping protection flags.
|
|
||||||
int flags = PROT_NONE;
|
|
||||||
if (True(perms & MemoryPermission::Read)) {
|
|
||||||
flags |= PROT_READ;
|
|
||||||
}
|
}
|
||||||
if (True(perms & MemoryPermission::Write)) {
|
|
||||||
flags |= PROT_WRITE;
|
|
||||||
}
|
|
||||||
#ifdef ARCHITECTURE_arm64
|
|
||||||
if (True(perms & MemoryPermission::Execute)) {
|
|
||||||
flags |= PROT_EXEC;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void* ret = mmap(virtual_base + virtual_offset, length, flags, MAP_SHARED | MAP_FIXED, fd,
|
void* ret = mmap(virtual_base + virtual_offset, length, PROT_READ | PROT_WRITE,
|
||||||
host_offset);
|
MAP_SHARED | MAP_FIXED, fd, host_offset);
|
||||||
ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno));
|
ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -527,54 +447,47 @@ public:
|
|||||||
// The method name is wrong. We're still talking about the virtual range.
|
// The method name is wrong. We're still talking about the virtual range.
|
||||||
// We don't want to unmap, we want to reserve this memory.
|
// We don't want to unmap, we want to reserve this memory.
|
||||||
|
|
||||||
// Intersect the range with our address space.
|
{
|
||||||
AdjustMap(&virtual_offset, &length);
|
std::scoped_lock lock{placeholder_mutex};
|
||||||
|
auto it = placeholders.find({virtual_offset - 1, virtual_offset + length + 1});
|
||||||
|
|
||||||
// Merge with any adjacent placeholder mappings.
|
if (it != placeholders.end()) {
|
||||||
auto [merged_pointer, merged_size] =
|
size_t prev_upper = virtual_offset + length;
|
||||||
free_manager.FreeBlock(virtual_base + virtual_offset, length);
|
virtual_offset = std::min(virtual_offset, it->lower());
|
||||||
|
length = std::max(it->upper(), prev_upper) - virtual_offset;
|
||||||
|
}
|
||||||
|
|
||||||
void* ret = mmap(merged_pointer, merged_size, PROT_NONE,
|
placeholders.add({virtual_offset, virtual_offset + length});
|
||||||
|
}
|
||||||
|
|
||||||
|
void* ret = mmap(virtual_base + virtual_offset, length, PROT_NONE,
|
||||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
|
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
|
||||||
ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno));
|
ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute) {
|
void Protect(size_t virtual_offset, size_t length, bool read, bool write) {
|
||||||
// Intersect the range with our address space.
|
int flags = 0;
|
||||||
AdjustMap(&virtual_offset, &length);
|
|
||||||
|
|
||||||
int flags = PROT_NONE;
|
|
||||||
if (read) {
|
if (read) {
|
||||||
flags |= PROT_READ;
|
flags |= PROT_READ;
|
||||||
}
|
}
|
||||||
if (write) {
|
if (write) {
|
||||||
flags |= PROT_WRITE;
|
flags |= PROT_WRITE;
|
||||||
}
|
}
|
||||||
#ifdef ARCHITECTURE_arm64
|
|
||||||
if (execute) {
|
|
||||||
flags |= PROT_EXEC;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
int ret = mprotect(virtual_base + virtual_offset, length, flags);
|
int ret = mprotect(virtual_base + virtual_offset, length, flags);
|
||||||
ASSERT_MSG(ret == 0, "mprotect failed: {}", strerror(errno));
|
ASSERT_MSG(ret == 0, "mprotect failed: {}", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnableDirectMappedAddress() {
|
|
||||||
virtual_base = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t backing_size; ///< Size of the backing memory in bytes
|
const size_t backing_size; ///< Size of the backing memory in bytes
|
||||||
const size_t virtual_size; ///< Size of the virtual address placeholder in bytes
|
const size_t virtual_size; ///< Size of the virtual address placeholder in bytes
|
||||||
|
|
||||||
u8* backing_base{reinterpret_cast<u8*>(MAP_FAILED)};
|
u8* backing_base{reinterpret_cast<u8*>(MAP_FAILED)};
|
||||||
u8* virtual_base{reinterpret_cast<u8*>(MAP_FAILED)};
|
u8* virtual_base{reinterpret_cast<u8*>(MAP_FAILED)};
|
||||||
u8* virtual_map_base{reinterpret_cast<u8*>(MAP_FAILED)};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Release all resources in the object
|
/// Release all resources in the object
|
||||||
void Release() {
|
void Release() {
|
||||||
if (virtual_map_base != MAP_FAILED) {
|
if (virtual_base != MAP_FAILED) {
|
||||||
int ret = munmap(virtual_map_base, virtual_size);
|
int ret = munmap(virtual_base, virtual_size);
|
||||||
ASSERT_MSG(ret == 0, "munmap failed: {}", strerror(errno));
|
ASSERT_MSG(ret == 0, "munmap failed: {}", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -589,29 +502,10 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdjustMap(size_t* virtual_offset, size_t* length) {
|
|
||||||
if (virtual_base != nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we are direct mapped, we want to make sure we are operating on a region
|
|
||||||
// that is in range of our virtual mapping.
|
|
||||||
size_t intended_start = *virtual_offset;
|
|
||||||
size_t intended_end = intended_start + *length;
|
|
||||||
size_t address_space_start = reinterpret_cast<size_t>(virtual_map_base);
|
|
||||||
size_t address_space_end = address_space_start + virtual_size;
|
|
||||||
|
|
||||||
if (address_space_start > intended_end || intended_start > address_space_end) {
|
|
||||||
*virtual_offset = 0;
|
|
||||||
*length = 0;
|
|
||||||
} else {
|
|
||||||
*virtual_offset = std::max(intended_start, address_space_start);
|
|
||||||
*length = std::min(intended_end, address_space_end) - *virtual_offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int fd{-1}; // memfd file descriptor, -1 is the error value of memfd_create
|
int fd{-1}; // memfd file descriptor, -1 is the error value of memfd_create
|
||||||
FreeRegionManager free_manager{};
|
|
||||||
|
boost::icl::interval_set<size_t> placeholders; ///< Mapped placeholders
|
||||||
|
std::mutex placeholder_mutex; ///< Mutex for placeholders
|
||||||
};
|
};
|
||||||
|
|
||||||
#else // ^^^ Linux ^^^ vvv Generic vvv
|
#else // ^^^ Linux ^^^ vvv Generic vvv
|
||||||
@ -624,11 +518,11 @@ public:
|
|||||||
throw std::bad_alloc{};
|
throw std::bad_alloc{};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perm) {}
|
void Map(size_t virtual_offset, size_t host_offset, size_t length) {}
|
||||||
|
|
||||||
void Unmap(size_t virtual_offset, size_t length) {}
|
void Unmap(size_t virtual_offset, size_t length) {}
|
||||||
|
|
||||||
void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute) {}
|
void Protect(size_t virtual_offset, size_t length, bool read, bool write) {}
|
||||||
|
|
||||||
u8* backing_base{nullptr};
|
u8* backing_base{nullptr};
|
||||||
u8* virtual_base{nullptr};
|
u8* virtual_base{nullptr};
|
||||||
@ -641,16 +535,15 @@ HostMemory::HostMemory(size_t backing_size_, size_t virtual_size_)
|
|||||||
try {
|
try {
|
||||||
// Try to allocate a fastmem arena.
|
// Try to allocate a fastmem arena.
|
||||||
// The implementation will fail with std::bad_alloc on errors.
|
// The implementation will fail with std::bad_alloc on errors.
|
||||||
impl =
|
impl = std::make_unique<HostMemory::Impl>(AlignUp(backing_size, PageAlignment),
|
||||||
std::make_unique<HostMemory::Impl>(AlignUp(backing_size, PageAlignment),
|
AlignUp(virtual_size, PageAlignment) +
|
||||||
AlignUp(virtual_size, PageAlignment) + HugePageSize);
|
3 * HugePageSize);
|
||||||
backing_base = impl->backing_base;
|
backing_base = impl->backing_base;
|
||||||
virtual_base = impl->virtual_base;
|
virtual_base = impl->virtual_base;
|
||||||
|
|
||||||
if (virtual_base) {
|
if (virtual_base) {
|
||||||
// Ensure the virtual base is aligned to the L2 block size.
|
virtual_base += 2 * HugePageSize - 1;
|
||||||
virtual_base = reinterpret_cast<u8*>(
|
virtual_base -= reinterpret_cast<size_t>(virtual_base) & (HugePageSize - 1);
|
||||||
Common::AlignUp(reinterpret_cast<uintptr_t>(virtual_base), HugePageSize));
|
|
||||||
virtual_base_offset = virtual_base - impl->virtual_base;
|
virtual_base_offset = virtual_base - impl->virtual_base;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -669,8 +562,7 @@ HostMemory::HostMemory(HostMemory&&) noexcept = default;
|
|||||||
|
|
||||||
HostMemory& HostMemory::operator=(HostMemory&&) noexcept = default;
|
HostMemory& HostMemory::operator=(HostMemory&&) noexcept = default;
|
||||||
|
|
||||||
void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length) {
|
||||||
MemoryPermission perms) {
|
|
||||||
ASSERT(virtual_offset % PageAlignment == 0);
|
ASSERT(virtual_offset % PageAlignment == 0);
|
||||||
ASSERT(host_offset % PageAlignment == 0);
|
ASSERT(host_offset % PageAlignment == 0);
|
||||||
ASSERT(length % PageAlignment == 0);
|
ASSERT(length % PageAlignment == 0);
|
||||||
@ -679,7 +571,7 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
|||||||
if (length == 0 || !virtual_base || !impl) {
|
if (length == 0 || !virtual_base || !impl) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
impl->Map(virtual_offset + virtual_base_offset, host_offset, length, perms);
|
impl->Map(virtual_offset + virtual_base_offset, host_offset, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HostMemory::Unmap(size_t virtual_offset, size_t length) {
|
void HostMemory::Unmap(size_t virtual_offset, size_t length) {
|
||||||
@ -692,22 +584,14 @@ void HostMemory::Unmap(size_t virtual_offset, size_t length) {
|
|||||||
impl->Unmap(virtual_offset + virtual_base_offset, length);
|
impl->Unmap(virtual_offset + virtual_base_offset, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HostMemory::Protect(size_t virtual_offset, size_t length, bool read, bool write,
|
void HostMemory::Protect(size_t virtual_offset, size_t length, bool read, bool write) {
|
||||||
bool execute) {
|
|
||||||
ASSERT(virtual_offset % PageAlignment == 0);
|
ASSERT(virtual_offset % PageAlignment == 0);
|
||||||
ASSERT(length % PageAlignment == 0);
|
ASSERT(length % PageAlignment == 0);
|
||||||
ASSERT(virtual_offset + length <= virtual_size);
|
ASSERT(virtual_offset + length <= virtual_size);
|
||||||
if (length == 0 || !virtual_base || !impl) {
|
if (length == 0 || !virtual_base || !impl) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
impl->Protect(virtual_offset + virtual_base_offset, length, read, write, execute);
|
impl->Protect(virtual_offset + virtual_base_offset, length, read, write);
|
||||||
}
|
|
||||||
|
|
||||||
void HostMemory::EnableDirectMappedAddress() {
|
|
||||||
if (impl) {
|
|
||||||
impl->EnableDirectMappedAddress();
|
|
||||||
virtual_size += reinterpret_cast<uintptr_t>(virtual_base);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Common
|
} // namespace Common
|
||||||
|
@ -4,20 +4,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "common/common_funcs.h"
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/virtual_buffer.h"
|
#include "common/virtual_buffer.h"
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
enum class MemoryPermission : u32 {
|
|
||||||
Read = 1 << 0,
|
|
||||||
Write = 1 << 1,
|
|
||||||
ReadWrite = Read | Write,
|
|
||||||
Execute = 1 << 2,
|
|
||||||
};
|
|
||||||
DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A low level linear memory buffer, which supports multiple mappings
|
* A low level linear memory buffer, which supports multiple mappings
|
||||||
* Its purpose is to rebuild a given sparse memory layout, including mirrors.
|
* Its purpose is to rebuild a given sparse memory layout, including mirrors.
|
||||||
@ -40,13 +31,11 @@ public:
|
|||||||
HostMemory(HostMemory&& other) noexcept;
|
HostMemory(HostMemory&& other) noexcept;
|
||||||
HostMemory& operator=(HostMemory&& other) noexcept;
|
HostMemory& operator=(HostMemory&& other) noexcept;
|
||||||
|
|
||||||
void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms);
|
void Map(size_t virtual_offset, size_t host_offset, size_t length);
|
||||||
|
|
||||||
void Unmap(size_t virtual_offset, size_t length);
|
void Unmap(size_t virtual_offset, size_t length);
|
||||||
|
|
||||||
void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute = false);
|
void Protect(size_t virtual_offset, size_t length, bool read, bool write);
|
||||||
|
|
||||||
void EnableDirectMappedAddress();
|
|
||||||
|
|
||||||
[[nodiscard]] u8* BackingBasePointer() noexcept {
|
[[nodiscard]] u8* BackingBasePointer() noexcept {
|
||||||
return backing_base;
|
return backing_base;
|
||||||
|
@ -41,7 +41,6 @@ SWITCHABLE(AspectRatio, true);
|
|||||||
SWITCHABLE(AstcDecodeMode, true);
|
SWITCHABLE(AstcDecodeMode, true);
|
||||||
SWITCHABLE(AstcRecompression, true);
|
SWITCHABLE(AstcRecompression, true);
|
||||||
SWITCHABLE(AudioMode, true);
|
SWITCHABLE(AudioMode, true);
|
||||||
SWITCHABLE(CpuBackend, true);
|
|
||||||
SWITCHABLE(CpuAccuracy, true);
|
SWITCHABLE(CpuAccuracy, true);
|
||||||
SWITCHABLE(FullscreenMode, true);
|
SWITCHABLE(FullscreenMode, true);
|
||||||
SWITCHABLE(GpuAccuracy, true);
|
SWITCHABLE(GpuAccuracy, true);
|
||||||
@ -156,22 +155,6 @@ bool IsFastmemEnabled() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_nce_enabled = false;
|
|
||||||
|
|
||||||
void SetNceEnabled(bool is_39bit) {
|
|
||||||
const bool is_nce_selected = values.cpu_backend.GetValue() == CpuBackend::Nce;
|
|
||||||
is_nce_enabled = IsFastmemEnabled() && is_nce_selected && is_39bit;
|
|
||||||
if (is_nce_selected && !is_nce_enabled) {
|
|
||||||
LOG_WARNING(
|
|
||||||
Common,
|
|
||||||
"Program does not utilize 39-bit address space, unable to natively execute code");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsNceEnabled() {
|
|
||||||
return is_nce_enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsDockedMode() {
|
bool IsDockedMode() {
|
||||||
return values.use_docked_mode.GetValue() == Settings::ConsoleMode::Docked;
|
return values.use_docked_mode.GetValue() == Settings::ConsoleMode::Docked;
|
||||||
}
|
}
|
||||||
@ -223,9 +206,9 @@ const char* TranslateCategory(Category category) {
|
|||||||
case Category::UiAudio:
|
case Category::UiAudio:
|
||||||
return "UiAudio";
|
return "UiAudio";
|
||||||
case Category::UiLayout:
|
case Category::UiLayout:
|
||||||
return "UiLayout";
|
return "UILayout";
|
||||||
case Category::UiGameList:
|
case Category::UiGameList:
|
||||||
return "UiGameList";
|
return "UIGameList";
|
||||||
case Category::Screenshots:
|
case Category::Screenshots:
|
||||||
return "Screenshots";
|
return "Screenshots";
|
||||||
case Category::Shortcuts:
|
case Category::Shortcuts:
|
||||||
|
@ -63,7 +63,6 @@ SWITCHABLE(AspectRatio, true);
|
|||||||
SWITCHABLE(AstcDecodeMode, true);
|
SWITCHABLE(AstcDecodeMode, true);
|
||||||
SWITCHABLE(AstcRecompression, true);
|
SWITCHABLE(AstcRecompression, true);
|
||||||
SWITCHABLE(AudioMode, true);
|
SWITCHABLE(AudioMode, true);
|
||||||
SWITCHABLE(CpuBackend, true);
|
|
||||||
SWITCHABLE(CpuAccuracy, true);
|
SWITCHABLE(CpuAccuracy, true);
|
||||||
SWITCHABLE(FullscreenMode, true);
|
SWITCHABLE(FullscreenMode, true);
|
||||||
SWITCHABLE(GpuAccuracy, true);
|
SWITCHABLE(GpuAccuracy, true);
|
||||||
@ -180,14 +179,6 @@ struct Values {
|
|||||||
&use_speed_limit};
|
&use_speed_limit};
|
||||||
|
|
||||||
// Cpu
|
// Cpu
|
||||||
SwitchableSetting<CpuBackend, true> cpu_backend{
|
|
||||||
linkage, CpuBackend::Dynarmic, CpuBackend::Dynarmic,
|
|
||||||
#ifdef ARCHITECTURE_arm64
|
|
||||||
CpuBackend::Nce,
|
|
||||||
#else
|
|
||||||
CpuBackend::Dynarmic,
|
|
||||||
#endif
|
|
||||||
"cpu_backend", Category::Cpu};
|
|
||||||
SwitchableSetting<CpuAccuracy, true> cpu_accuracy{linkage, CpuAccuracy::Auto,
|
SwitchableSetting<CpuAccuracy, true> cpu_accuracy{linkage, CpuAccuracy::Auto,
|
||||||
CpuAccuracy::Auto, CpuAccuracy::Paranoid,
|
CpuAccuracy::Auto, CpuAccuracy::Paranoid,
|
||||||
"cpu_accuracy", Category::Cpu};
|
"cpu_accuracy", Category::Cpu};
|
||||||
@ -241,7 +232,11 @@ struct Values {
|
|||||||
SwitchableSetting<bool> use_asynchronous_gpu_emulation{
|
SwitchableSetting<bool> use_asynchronous_gpu_emulation{
|
||||||
linkage, true, "use_asynchronous_gpu_emulation", Category::Renderer};
|
linkage, true, "use_asynchronous_gpu_emulation", Category::Renderer};
|
||||||
SwitchableSetting<AstcDecodeMode, true> accelerate_astc{linkage,
|
SwitchableSetting<AstcDecodeMode, true> accelerate_astc{linkage,
|
||||||
|
#ifdef ANDROID
|
||||||
|
AstcDecodeMode::Cpu,
|
||||||
|
#else
|
||||||
AstcDecodeMode::Gpu,
|
AstcDecodeMode::Gpu,
|
||||||
|
#endif
|
||||||
AstcDecodeMode::Cpu,
|
AstcDecodeMode::Cpu,
|
||||||
AstcDecodeMode::CpuAsynchronous,
|
AstcDecodeMode::CpuAsynchronous,
|
||||||
"accelerate_astc",
|
"accelerate_astc",
|
||||||
@ -313,7 +308,11 @@ struct Values {
|
|||||||
linkage, 0, "bg_blue", Category::Renderer, Specialization::Default, true, true};
|
linkage, 0, "bg_blue", Category::Renderer, Specialization::Default, true, true};
|
||||||
|
|
||||||
SwitchableSetting<GpuAccuracy, true> gpu_accuracy{linkage,
|
SwitchableSetting<GpuAccuracy, true> gpu_accuracy{linkage,
|
||||||
|
#ifdef ANDROID
|
||||||
|
GpuAccuracy::Normal,
|
||||||
|
#else
|
||||||
GpuAccuracy::High,
|
GpuAccuracy::High,
|
||||||
|
#endif
|
||||||
GpuAccuracy::Normal,
|
GpuAccuracy::Normal,
|
||||||
GpuAccuracy::Extreme,
|
GpuAccuracy::Extreme,
|
||||||
"gpu_accuracy",
|
"gpu_accuracy",
|
||||||
@ -322,20 +321,38 @@ struct Values {
|
|||||||
true,
|
true,
|
||||||
true};
|
true};
|
||||||
GpuAccuracy current_gpu_accuracy{GpuAccuracy::High};
|
GpuAccuracy current_gpu_accuracy{GpuAccuracy::High};
|
||||||
SwitchableSetting<AnisotropyMode, true> max_anisotropy{
|
SwitchableSetting<AnisotropyMode, true> max_anisotropy{linkage,
|
||||||
linkage, AnisotropyMode::Automatic, AnisotropyMode::Automatic, AnisotropyMode::X16,
|
#ifdef ANDROID
|
||||||
"max_anisotropy", Category::RendererAdvanced};
|
AnisotropyMode::Default,
|
||||||
|
#else
|
||||||
|
AnisotropyMode::Automatic,
|
||||||
|
#endif
|
||||||
|
AnisotropyMode::Automatic,
|
||||||
|
AnisotropyMode::X16,
|
||||||
|
"max_anisotropy",
|
||||||
|
Category::RendererAdvanced};
|
||||||
SwitchableSetting<AstcRecompression, true> astc_recompression{linkage,
|
SwitchableSetting<AstcRecompression, true> astc_recompression{linkage,
|
||||||
AstcRecompression::Uncompressed,
|
AstcRecompression::Uncompressed,
|
||||||
AstcRecompression::Uncompressed,
|
AstcRecompression::Uncompressed,
|
||||||
AstcRecompression::Bc3,
|
AstcRecompression::Bc3,
|
||||||
"astc_recompression",
|
"astc_recompression",
|
||||||
Category::RendererAdvanced};
|
Category::RendererAdvanced};
|
||||||
SwitchableSetting<bool> async_presentation{linkage, false, "async_presentation",
|
SwitchableSetting<bool> async_presentation{linkage,
|
||||||
Category::RendererAdvanced};
|
#ifdef ANDROID
|
||||||
|
true,
|
||||||
|
#else
|
||||||
|
false,
|
||||||
|
#endif
|
||||||
|
"async_presentation", Category::RendererAdvanced};
|
||||||
SwitchableSetting<bool> renderer_force_max_clock{linkage, false, "force_max_clock",
|
SwitchableSetting<bool> renderer_force_max_clock{linkage, false, "force_max_clock",
|
||||||
Category::RendererAdvanced};
|
Category::RendererAdvanced};
|
||||||
SwitchableSetting<bool> use_reactive_flushing{linkage, true, "use_reactive_flushing",
|
SwitchableSetting<bool> use_reactive_flushing{linkage,
|
||||||
|
#ifdef ANDROID
|
||||||
|
false,
|
||||||
|
#else
|
||||||
|
true,
|
||||||
|
#endif
|
||||||
|
"use_reactive_flushing",
|
||||||
Category::RendererAdvanced};
|
Category::RendererAdvanced};
|
||||||
SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders",
|
SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders",
|
||||||
Category::RendererAdvanced};
|
Category::RendererAdvanced};
|
||||||
@ -401,7 +418,11 @@ struct Values {
|
|||||||
Setting<s32> current_user{linkage, 0, "current_user", Category::System};
|
Setting<s32> current_user{linkage, 0, "current_user", Category::System};
|
||||||
|
|
||||||
SwitchableSetting<ConsoleMode> use_docked_mode{linkage,
|
SwitchableSetting<ConsoleMode> use_docked_mode{linkage,
|
||||||
|
#ifdef ANDROID
|
||||||
|
ConsoleMode::Handheld,
|
||||||
|
#else
|
||||||
ConsoleMode::Docked,
|
ConsoleMode::Docked,
|
||||||
|
#endif
|
||||||
"use_docked_mode",
|
"use_docked_mode",
|
||||||
Category::System,
|
Category::System,
|
||||||
Specialization::Radio,
|
Specialization::Radio,
|
||||||
@ -545,8 +566,6 @@ bool IsGPULevelExtreme();
|
|||||||
bool IsGPULevelHigh();
|
bool IsGPULevelHigh();
|
||||||
|
|
||||||
bool IsFastmemEnabled();
|
bool IsFastmemEnabled();
|
||||||
void SetNceEnabled(bool is_64bit);
|
|
||||||
bool IsNceEnabled();
|
|
||||||
|
|
||||||
bool IsDockedMode();
|
bool IsDockedMode();
|
||||||
|
|
||||||
|
@ -129,8 +129,6 @@ ENUM(ShaderBackend, Glsl, Glasm, SpirV);
|
|||||||
|
|
||||||
ENUM(GpuAccuracy, Normal, High, Extreme);
|
ENUM(GpuAccuracy, Normal, High, Extreme);
|
||||||
|
|
||||||
ENUM(CpuBackend, Dynarmic, Nce);
|
|
||||||
|
|
||||||
ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid);
|
ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid);
|
||||||
|
|
||||||
ENUM(MemoryLayout, Memory_4Gb, Memory_6Gb, Memory_8Gb);
|
ENUM(MemoryLayout, Memory_4Gb, Memory_6Gb, Memory_8Gb);
|
||||||
|
@ -6,11 +6,10 @@
|
|||||||
namespace Settings {
|
namespace Settings {
|
||||||
namespace NativeButton {
|
namespace NativeButton {
|
||||||
const std::array<const char*, NumButtons> mapping = {{
|
const std::array<const char*, NumButtons> mapping = {{
|
||||||
"button_a", "button_b", "button_x", "button_y", "button_lstick",
|
"button_a", "button_b", "button_x", "button_y", "button_lstick",
|
||||||
"button_rstick", "button_l", "button_r", "button_zl", "button_zr",
|
"button_rstick", "button_l", "button_r", "button_zl", "button_zr",
|
||||||
"button_plus", "button_minus", "button_dleft", "button_dup", "button_dright",
|
"button_plus", "button_minus", "button_dleft", "button_dup", "button_dright",
|
||||||
"button_ddown", "button_slleft", "button_srleft", "button_home", "button_screenshot",
|
"button_ddown", "button_sl", "button_sr", "button_home", "button_screenshot",
|
||||||
"button_slright", "button_srright",
|
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,15 +29,12 @@ enum Values : int {
|
|||||||
DRight,
|
DRight,
|
||||||
DDown,
|
DDown,
|
||||||
|
|
||||||
SLLeft,
|
SL,
|
||||||
SRLeft,
|
SR,
|
||||||
|
|
||||||
Home,
|
Home,
|
||||||
Screenshot,
|
Screenshot,
|
||||||
|
|
||||||
SLRight,
|
|
||||||
SRRight,
|
|
||||||
|
|
||||||
NumButtons,
|
NumButtons,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <dlfcn.h>
|
|
||||||
|
|
||||||
#include "common/assert.h"
|
|
||||||
#include "common/dynamic_library.h"
|
|
||||||
#include "common/scope_exit.h"
|
|
||||||
#include "common/signal_chain.h"
|
|
||||||
|
|
||||||
namespace Common {
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T* LookupLibcSymbol(const char* name) {
|
|
||||||
#if defined(__BIONIC__)
|
|
||||||
Common::DynamicLibrary provider("libc.so");
|
|
||||||
if (!provider.IsOpen()) {
|
|
||||||
UNREACHABLE_MSG("Failed to open libc!");
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
// For other operating environments, we assume the symbol is not overridden.
|
|
||||||
const char* base = nullptr;
|
|
||||||
Common::DynamicLibrary provider(base);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void* sym = provider.GetSymbolAddress(name);
|
|
||||||
if (sym == nullptr) {
|
|
||||||
sym = dlsym(RTLD_DEFAULT, name);
|
|
||||||
}
|
|
||||||
if (sym == nullptr) {
|
|
||||||
UNREACHABLE_MSG("Unable to find symbol {}!", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return reinterpret_cast<T*>(sym);
|
|
||||||
}
|
|
||||||
|
|
||||||
int SigAction(int signum, const struct sigaction* act, struct sigaction* oldact) {
|
|
||||||
static auto libc_sigaction = LookupLibcSymbol<decltype(sigaction)>("sigaction");
|
|
||||||
return libc_sigaction(signum, act, oldact);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Common
|
|
@ -1,19 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
|
|
||||||
#include <signal.h>
|
|
||||||
|
|
||||||
namespace Common {
|
|
||||||
|
|
||||||
// Android's ART overrides sigaction with its own wrapper. This is problematic for SIGSEGV
|
|
||||||
// in particular, because ART's handler accesses tpidr_el0, which conflicts with NCE.
|
|
||||||
// This extracts the libc symbol and calls it directly.
|
|
||||||
int SigAction(int signum, const struct sigaction* act, struct sigaction* oldact);
|
|
||||||
|
|
||||||
} // namespace Common
|
|
||||||
|
|
||||||
#endif
|
|
@ -521,21 +521,11 @@ add_library(core STATIC
|
|||||||
hle/service/grc/grc.h
|
hle/service/grc/grc.h
|
||||||
hle/service/hid/hid.cpp
|
hle/service/hid/hid.cpp
|
||||||
hle/service/hid/hid.h
|
hle/service/hid/hid.h
|
||||||
hle/service/hid/hid_debug_server.cpp
|
|
||||||
hle/service/hid/hid_debug_server.h
|
|
||||||
hle/service/hid/hid_firmware_settings.cpp
|
|
||||||
hle/service/hid/hid_firmware_settings.h
|
|
||||||
hle/service/hid/hid_server.cpp
|
|
||||||
hle/service/hid/hid_server.h
|
|
||||||
hle/service/hid/hid_system_server.cpp
|
|
||||||
hle/service/hid/hid_system_server.h
|
|
||||||
hle/service/hid/hidbus.cpp
|
hle/service/hid/hidbus.cpp
|
||||||
hle/service/hid/hidbus.h
|
hle/service/hid/hidbus.h
|
||||||
hle/service/hid/irs.cpp
|
hle/service/hid/irs.cpp
|
||||||
hle/service/hid/irs.h
|
hle/service/hid/irs.h
|
||||||
hle/service/hid/irs_ring_lifo.h
|
hle/service/hid/irs_ring_lifo.h
|
||||||
hle/service/hid/resource_manager.cpp
|
|
||||||
hle/service/hid/resource_manager.h
|
|
||||||
hle/service/hid/ring_lifo.h
|
hle/service/hid/ring_lifo.h
|
||||||
hle/service/hid/xcd.cpp
|
hle/service/hid/xcd.cpp
|
||||||
hle/service/hid/xcd.h
|
hle/service/hid/xcd.h
|
||||||
@ -725,7 +715,6 @@ add_library(core STATIC
|
|||||||
hle/service/nvnflinger/producer_listener.h
|
hle/service/nvnflinger/producer_listener.h
|
||||||
hle/service/nvnflinger/status.h
|
hle/service/nvnflinger/status.h
|
||||||
hle/service/nvnflinger/ui/fence.h
|
hle/service/nvnflinger/ui/fence.h
|
||||||
hle/service/nvnflinger/ui/graphic_buffer.cpp
|
|
||||||
hle/service/nvnflinger/ui/graphic_buffer.h
|
hle/service/nvnflinger/ui/graphic_buffer.h
|
||||||
hle/service/nvnflinger/window.h
|
hle/service/nvnflinger/window.h
|
||||||
hle/service/olsc/olsc.cpp
|
hle/service/olsc/olsc.cpp
|
||||||
@ -921,23 +910,6 @@ if (ENABLE_WEB_SERVICE)
|
|||||||
target_link_libraries(core PRIVATE web_service)
|
target_link_libraries(core PRIVATE web_service)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ARCHITECTURE_arm64 AND (ANDROID OR ${CMAKE_SYSTEM_NAME} STREQUAL "Linux"))
|
|
||||||
target_compile_definitions(core PRIVATE -DHAS_NCE)
|
|
||||||
enable_language(C ASM)
|
|
||||||
set(CMAKE_ASM_FLAGS "${CFLAGS} -x assembler-with-cpp")
|
|
||||||
|
|
||||||
target_sources(core PRIVATE
|
|
||||||
arm/nce/arm_nce.cpp
|
|
||||||
arm/nce/arm_nce.h
|
|
||||||
arm/nce/arm_nce.s
|
|
||||||
arm/nce/guest_context.h
|
|
||||||
arm/nce/patch.cpp
|
|
||||||
arm/nce/patch.h
|
|
||||||
arm/nce/instructions.h
|
|
||||||
)
|
|
||||||
target_link_libraries(core PRIVATE merry::oaknut)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
||||||
target_sources(core PRIVATE
|
target_sources(core PRIVATE
|
||||||
arm/dynarmic/arm_dynarmic.h
|
arm/dynarmic/arm_dynarmic.h
|
||||||
|
@ -201,8 +201,6 @@ void ARM_Interface::Run() {
|
|||||||
if (True(hr & HaltReason::DataAbort)) {
|
if (True(hr & HaltReason::DataAbort)) {
|
||||||
if (system.DebuggerEnabled()) {
|
if (system.DebuggerEnabled()) {
|
||||||
system.GetDebugger().NotifyThreadWatchpoint(current_thread, *HaltedWatchpoint());
|
system.GetDebugger().NotifyThreadWatchpoint(current_thread, *HaltedWatchpoint());
|
||||||
} else {
|
|
||||||
LogBacktrace();
|
|
||||||
}
|
}
|
||||||
current_thread->RequestSuspend(SuspendType::Debug);
|
current_thread->RequestSuspend(SuspendType::Debug);
|
||||||
break;
|
break;
|
||||||
|
@ -81,9 +81,6 @@ public:
|
|||||||
// thread context to be 800 bytes in size.
|
// thread context to be 800 bytes in size.
|
||||||
static_assert(sizeof(ThreadContext64) == 0x320);
|
static_assert(sizeof(ThreadContext64) == 0x320);
|
||||||
|
|
||||||
/// Perform any backend-specific initialization.
|
|
||||||
virtual void Initialize() {}
|
|
||||||
|
|
||||||
/// Runs the CPU until an event happens
|
/// Runs the CPU until an event happens
|
||||||
void Run();
|
void Run();
|
||||||
|
|
||||||
|
@ -1,400 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <cinttypes>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "common/signal_chain.h"
|
|
||||||
#include "core/arm/nce/arm_nce.h"
|
|
||||||
#include "core/arm/nce/patch.h"
|
|
||||||
#include "core/core.h"
|
|
||||||
#include "core/memory.h"
|
|
||||||
|
|
||||||
#include "core/hle/kernel/k_process.h"
|
|
||||||
|
|
||||||
#include <signal.h>
|
|
||||||
#include <sys/syscall.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
namespace Core {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
struct sigaction g_orig_action;
|
|
||||||
|
|
||||||
// Verify assembly offsets.
|
|
||||||
using NativeExecutionParameters = Kernel::KThread::NativeExecutionParameters;
|
|
||||||
static_assert(offsetof(NativeExecutionParameters, native_context) == TpidrEl0NativeContext);
|
|
||||||
static_assert(offsetof(NativeExecutionParameters, lock) == TpidrEl0Lock);
|
|
||||||
static_assert(offsetof(NativeExecutionParameters, magic) == TpidrEl0TlsMagic);
|
|
||||||
|
|
||||||
fpsimd_context* GetFloatingPointState(mcontext_t& host_ctx) {
|
|
||||||
_aarch64_ctx* header = reinterpret_cast<_aarch64_ctx*>(&host_ctx.__reserved);
|
|
||||||
while (header->magic != FPSIMD_MAGIC) {
|
|
||||||
header = reinterpret_cast<_aarch64_ctx*>(reinterpret_cast<char*>(header) + header->size);
|
|
||||||
}
|
|
||||||
return reinterpret_cast<fpsimd_context*>(header);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void* ARM_NCE::RestoreGuestContext(void* raw_context) {
|
|
||||||
// Retrieve the host context.
|
|
||||||
auto& host_ctx = static_cast<ucontext_t*>(raw_context)->uc_mcontext;
|
|
||||||
|
|
||||||
// Thread-local parameters will be located in x9.
|
|
||||||
auto* tpidr = reinterpret_cast<NativeExecutionParameters*>(host_ctx.regs[9]);
|
|
||||||
auto* guest_ctx = static_cast<GuestContext*>(tpidr->native_context);
|
|
||||||
|
|
||||||
// Retrieve the host floating point state.
|
|
||||||
auto* fpctx = GetFloatingPointState(host_ctx);
|
|
||||||
|
|
||||||
// Save host callee-saved registers.
|
|
||||||
std::memcpy(guest_ctx->host_ctx.host_saved_vregs.data(), &fpctx->vregs[8],
|
|
||||||
sizeof(guest_ctx->host_ctx.host_saved_vregs));
|
|
||||||
std::memcpy(guest_ctx->host_ctx.host_saved_regs.data(), &host_ctx.regs[19],
|
|
||||||
sizeof(guest_ctx->host_ctx.host_saved_regs));
|
|
||||||
|
|
||||||
// Save stack pointer.
|
|
||||||
guest_ctx->host_ctx.host_sp = host_ctx.sp;
|
|
||||||
|
|
||||||
// Restore all guest state except tpidr_el0.
|
|
||||||
host_ctx.sp = guest_ctx->sp;
|
|
||||||
host_ctx.pc = guest_ctx->pc;
|
|
||||||
host_ctx.pstate = guest_ctx->pstate;
|
|
||||||
fpctx->fpcr = guest_ctx->fpcr;
|
|
||||||
fpctx->fpsr = guest_ctx->fpsr;
|
|
||||||
std::memcpy(host_ctx.regs, guest_ctx->cpu_registers.data(), sizeof(host_ctx.regs));
|
|
||||||
std::memcpy(fpctx->vregs, guest_ctx->vector_registers.data(), sizeof(fpctx->vregs));
|
|
||||||
|
|
||||||
// Return the new thread-local storage pointer.
|
|
||||||
return tpidr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARM_NCE::SaveGuestContext(GuestContext* guest_ctx, void* raw_context) {
|
|
||||||
// Retrieve the host context.
|
|
||||||
auto& host_ctx = static_cast<ucontext_t*>(raw_context)->uc_mcontext;
|
|
||||||
|
|
||||||
// Retrieve the host floating point state.
|
|
||||||
auto* fpctx = GetFloatingPointState(host_ctx);
|
|
||||||
|
|
||||||
// Save all guest registers except tpidr_el0.
|
|
||||||
std::memcpy(guest_ctx->cpu_registers.data(), host_ctx.regs, sizeof(host_ctx.regs));
|
|
||||||
std::memcpy(guest_ctx->vector_registers.data(), fpctx->vregs, sizeof(fpctx->vregs));
|
|
||||||
guest_ctx->fpsr = fpctx->fpsr;
|
|
||||||
guest_ctx->fpcr = fpctx->fpcr;
|
|
||||||
guest_ctx->pstate = static_cast<u32>(host_ctx.pstate);
|
|
||||||
guest_ctx->pc = host_ctx.pc;
|
|
||||||
guest_ctx->sp = host_ctx.sp;
|
|
||||||
|
|
||||||
// Restore stack pointer.
|
|
||||||
host_ctx.sp = guest_ctx->host_ctx.host_sp;
|
|
||||||
|
|
||||||
// Restore host callee-saved registers.
|
|
||||||
std::memcpy(&host_ctx.regs[19], guest_ctx->host_ctx.host_saved_regs.data(),
|
|
||||||
sizeof(guest_ctx->host_ctx.host_saved_regs));
|
|
||||||
std::memcpy(&fpctx->vregs[8], guest_ctx->host_ctx.host_saved_vregs.data(),
|
|
||||||
sizeof(guest_ctx->host_ctx.host_saved_vregs));
|
|
||||||
|
|
||||||
// Return from the call on exit by setting pc to x30.
|
|
||||||
host_ctx.pc = guest_ctx->host_ctx.host_saved_regs[11];
|
|
||||||
|
|
||||||
// Clear esr_el1 and return it.
|
|
||||||
host_ctx.regs[0] = guest_ctx->esr_el1.exchange(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ARM_NCE::HandleGuestFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) {
|
|
||||||
auto& host_ctx = static_cast<ucontext_t*>(raw_context)->uc_mcontext;
|
|
||||||
auto* info = static_cast<siginfo_t*>(raw_info);
|
|
||||||
|
|
||||||
// Try to handle an invalid access.
|
|
||||||
// TODO: handle accesses which split a page?
|
|
||||||
const Common::ProcessAddress addr =
|
|
||||||
(reinterpret_cast<u64>(info->si_addr) & ~Memory::YUZU_PAGEMASK);
|
|
||||||
if (guest_ctx->system->ApplicationMemory().InvalidateNCE(addr, Memory::YUZU_PAGESIZE)) {
|
|
||||||
// We handled the access successfully and are returning to guest code.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We can't handle the access, so determine why we crashed.
|
|
||||||
const bool is_prefetch_abort = host_ctx.pc == reinterpret_cast<u64>(info->si_addr);
|
|
||||||
|
|
||||||
// For data aborts, skip the instruction and return to guest code.
|
|
||||||
// This will allow games to continue in many scenarios where they would otherwise crash.
|
|
||||||
if (!is_prefetch_abort) {
|
|
||||||
host_ctx.pc += 4;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a prefetch abort.
|
|
||||||
guest_ctx->esr_el1.fetch_or(static_cast<u64>(HaltReason::PrefetchAbort));
|
|
||||||
|
|
||||||
// Forcibly mark the context as locked. We are still running.
|
|
||||||
// We may race with SignalInterrupt here:
|
|
||||||
// - If we lose the race, then SignalInterrupt will send us a signal we are masking,
|
|
||||||
// and it will do nothing when it is unmasked, as we have already left guest code.
|
|
||||||
// - If we win the race, then SignalInterrupt will wait for us to unlock first.
|
|
||||||
auto& thread_params = guest_ctx->parent->running_thread->GetNativeExecutionParameters();
|
|
||||||
thread_params.lock.store(SpinLockLocked);
|
|
||||||
|
|
||||||
// Return to host.
|
|
||||||
SaveGuestContext(guest_ctx, raw_context);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARM_NCE::HandleHostFault(int sig, void* raw_info, void* raw_context) {
|
|
||||||
return g_orig_action.sa_sigaction(sig, static_cast<siginfo_t*>(raw_info), raw_context);
|
|
||||||
}
|
|
||||||
|
|
||||||
HaltReason ARM_NCE::RunJit() {
|
|
||||||
// Get the thread parameters.
|
|
||||||
// TODO: pass the current thread down from ::Run
|
|
||||||
auto* thread = Kernel::GetCurrentThreadPointer(system.Kernel());
|
|
||||||
auto* thread_params = &thread->GetNativeExecutionParameters();
|
|
||||||
|
|
||||||
{
|
|
||||||
// Lock our core context.
|
|
||||||
std::scoped_lock lk{lock};
|
|
||||||
|
|
||||||
// We should not be running.
|
|
||||||
ASSERT(running_thread == nullptr);
|
|
||||||
|
|
||||||
// Check if we need to run. If we have already been halted, we are done.
|
|
||||||
u64 halt = guest_ctx.esr_el1.exchange(0);
|
|
||||||
if (halt != 0) {
|
|
||||||
return static_cast<HaltReason>(halt);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark that we are running.
|
|
||||||
running_thread = thread;
|
|
||||||
|
|
||||||
// Acquire the lock on the thread parameters.
|
|
||||||
// This allows us to force synchronization with SignalInterrupt.
|
|
||||||
LockThreadParameters(thread_params);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assign current members.
|
|
||||||
guest_ctx.parent = this;
|
|
||||||
thread_params->native_context = &guest_ctx;
|
|
||||||
thread_params->tpidr_el0 = guest_ctx.tpidr_el0;
|
|
||||||
thread_params->tpidrro_el0 = guest_ctx.tpidrro_el0;
|
|
||||||
thread_params->is_running = true;
|
|
||||||
|
|
||||||
HaltReason halt{};
|
|
||||||
|
|
||||||
// TODO: finding and creating the post handler needs to be locked
|
|
||||||
// to deal with dynamic loading of NROs.
|
|
||||||
const auto& post_handlers = system.ApplicationProcess()->GetPostHandlers();
|
|
||||||
if (auto it = post_handlers.find(guest_ctx.pc); it != post_handlers.end()) {
|
|
||||||
halt = ReturnToRunCodeByTrampoline(thread_params, &guest_ctx, it->second);
|
|
||||||
} else {
|
|
||||||
halt = ReturnToRunCodeByExceptionLevelChange(thread_id, thread_params);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unload members.
|
|
||||||
// The thread does not change, so we can persist the old reference.
|
|
||||||
guest_ctx.tpidr_el0 = thread_params->tpidr_el0;
|
|
||||||
thread_params->native_context = nullptr;
|
|
||||||
thread_params->is_running = false;
|
|
||||||
|
|
||||||
// Unlock the thread parameters.
|
|
||||||
UnlockThreadParameters(thread_params);
|
|
||||||
|
|
||||||
{
|
|
||||||
// Lock the core context.
|
|
||||||
std::scoped_lock lk{lock};
|
|
||||||
|
|
||||||
// On exit, we no longer have an active thread.
|
|
||||||
running_thread = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the halt reason.
|
|
||||||
return halt;
|
|
||||||
}
|
|
||||||
|
|
||||||
HaltReason ARM_NCE::StepJit() {
|
|
||||||
return HaltReason::StepThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 ARM_NCE::GetSvcNumber() const {
|
|
||||||
return guest_ctx.svc_swi;
|
|
||||||
}
|
|
||||||
|
|
||||||
ARM_NCE::ARM_NCE(System& system_, bool uses_wall_clock_, std::size_t core_index_)
|
|
||||||
: ARM_Interface{system_, uses_wall_clock_}, core_index{core_index_} {
|
|
||||||
guest_ctx.system = &system_;
|
|
||||||
}
|
|
||||||
|
|
||||||
ARM_NCE::~ARM_NCE() = default;
|
|
||||||
|
|
||||||
void ARM_NCE::Initialize() {
|
|
||||||
thread_id = gettid();
|
|
||||||
|
|
||||||
// Setup our signals
|
|
||||||
static std::once_flag flag;
|
|
||||||
std::call_once(flag, [] {
|
|
||||||
using HandlerType = decltype(sigaction::sa_sigaction);
|
|
||||||
|
|
||||||
sigset_t signal_mask;
|
|
||||||
sigemptyset(&signal_mask);
|
|
||||||
sigaddset(&signal_mask, ReturnToRunCodeByExceptionLevelChangeSignal);
|
|
||||||
sigaddset(&signal_mask, BreakFromRunCodeSignal);
|
|
||||||
sigaddset(&signal_mask, GuestFaultSignal);
|
|
||||||
|
|
||||||
struct sigaction return_to_run_code_action {};
|
|
||||||
return_to_run_code_action.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
|
||||||
return_to_run_code_action.sa_sigaction = reinterpret_cast<HandlerType>(
|
|
||||||
&ARM_NCE::ReturnToRunCodeByExceptionLevelChangeSignalHandler);
|
|
||||||
return_to_run_code_action.sa_mask = signal_mask;
|
|
||||||
Common::SigAction(ReturnToRunCodeByExceptionLevelChangeSignal, &return_to_run_code_action,
|
|
||||||
nullptr);
|
|
||||||
|
|
||||||
struct sigaction break_from_run_code_action {};
|
|
||||||
break_from_run_code_action.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
|
||||||
break_from_run_code_action.sa_sigaction =
|
|
||||||
reinterpret_cast<HandlerType>(&ARM_NCE::BreakFromRunCodeSignalHandler);
|
|
||||||
break_from_run_code_action.sa_mask = signal_mask;
|
|
||||||
Common::SigAction(BreakFromRunCodeSignal, &break_from_run_code_action, nullptr);
|
|
||||||
|
|
||||||
struct sigaction fault_action {};
|
|
||||||
fault_action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART;
|
|
||||||
fault_action.sa_sigaction =
|
|
||||||
reinterpret_cast<HandlerType>(&ARM_NCE::GuestFaultSignalHandler);
|
|
||||||
fault_action.sa_mask = signal_mask;
|
|
||||||
Common::SigAction(GuestFaultSignal, &fault_action, &g_orig_action);
|
|
||||||
|
|
||||||
// Simplify call for g_orig_action.
|
|
||||||
// These fields occupy the same space in memory, so this should be a no-op in practice.
|
|
||||||
if (!(g_orig_action.sa_flags & SA_SIGINFO)) {
|
|
||||||
g_orig_action.sa_sigaction =
|
|
||||||
reinterpret_cast<decltype(g_orig_action.sa_sigaction)>(g_orig_action.sa_handler);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARM_NCE::SetPC(u64 pc) {
|
|
||||||
guest_ctx.pc = pc;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 ARM_NCE::GetPC() const {
|
|
||||||
return guest_ctx.pc;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 ARM_NCE::GetSP() const {
|
|
||||||
return guest_ctx.sp;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 ARM_NCE::GetReg(int index) const {
|
|
||||||
return guest_ctx.cpu_registers[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARM_NCE::SetReg(int index, u64 value) {
|
|
||||||
guest_ctx.cpu_registers[index] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
u128 ARM_NCE::GetVectorReg(int index) const {
|
|
||||||
return guest_ctx.vector_registers[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARM_NCE::SetVectorReg(int index, u128 value) {
|
|
||||||
guest_ctx.vector_registers[index] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 ARM_NCE::GetPSTATE() const {
|
|
||||||
return guest_ctx.pstate;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARM_NCE::SetPSTATE(u32 pstate) {
|
|
||||||
guest_ctx.pstate = pstate;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 ARM_NCE::GetTlsAddress() const {
|
|
||||||
return guest_ctx.tpidrro_el0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARM_NCE::SetTlsAddress(u64 address) {
|
|
||||||
guest_ctx.tpidrro_el0 = address;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 ARM_NCE::GetTPIDR_EL0() const {
|
|
||||||
return guest_ctx.tpidr_el0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARM_NCE::SetTPIDR_EL0(u64 value) {
|
|
||||||
guest_ctx.tpidr_el0 = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARM_NCE::SaveContext(ThreadContext64& ctx) const {
|
|
||||||
ctx.cpu_registers = guest_ctx.cpu_registers;
|
|
||||||
ctx.sp = guest_ctx.sp;
|
|
||||||
ctx.pc = guest_ctx.pc;
|
|
||||||
ctx.pstate = guest_ctx.pstate;
|
|
||||||
ctx.vector_registers = guest_ctx.vector_registers;
|
|
||||||
ctx.fpcr = guest_ctx.fpcr;
|
|
||||||
ctx.fpsr = guest_ctx.fpsr;
|
|
||||||
ctx.tpidr = guest_ctx.tpidr_el0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARM_NCE::LoadContext(const ThreadContext64& ctx) {
|
|
||||||
guest_ctx.cpu_registers = ctx.cpu_registers;
|
|
||||||
guest_ctx.sp = ctx.sp;
|
|
||||||
guest_ctx.pc = ctx.pc;
|
|
||||||
guest_ctx.pstate = ctx.pstate;
|
|
||||||
guest_ctx.vector_registers = ctx.vector_registers;
|
|
||||||
guest_ctx.fpcr = ctx.fpcr;
|
|
||||||
guest_ctx.fpsr = ctx.fpsr;
|
|
||||||
guest_ctx.tpidr_el0 = ctx.tpidr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARM_NCE::SignalInterrupt() {
|
|
||||||
// Lock core context.
|
|
||||||
std::scoped_lock lk{lock};
|
|
||||||
|
|
||||||
// Add break loop condition.
|
|
||||||
guest_ctx.esr_el1.fetch_or(static_cast<u64>(HaltReason::BreakLoop));
|
|
||||||
|
|
||||||
// If there is no thread running, we are done.
|
|
||||||
if (running_thread == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lock the thread context.
|
|
||||||
auto* params = &running_thread->GetNativeExecutionParameters();
|
|
||||||
LockThreadParameters(params);
|
|
||||||
|
|
||||||
if (params->is_running) {
|
|
||||||
// We should signal to the running thread.
|
|
||||||
// The running thread will unlock the thread context.
|
|
||||||
syscall(SYS_tkill, thread_id, BreakFromRunCodeSignal);
|
|
||||||
} else {
|
|
||||||
// If the thread is no longer running, we have nothing to do.
|
|
||||||
UnlockThreadParameters(params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARM_NCE::ClearInterrupt() {
|
|
||||||
guest_ctx.esr_el1 = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARM_NCE::ClearInstructionCache() {
|
|
||||||
// TODO: This is not possible to implement correctly on Linux because
|
|
||||||
// we do not have any access to ic iallu.
|
|
||||||
|
|
||||||
// Require accesses to complete.
|
|
||||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARM_NCE::InvalidateCacheRange(u64 addr, std::size_t size) {
|
|
||||||
this->ClearInstructionCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARM_NCE::ClearExclusiveState() {
|
|
||||||
// No-op.
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARM_NCE::PageTableChanged(Common::PageTable& page_table,
|
|
||||||
std::size_t new_address_space_size_in_bits) {
|
|
||||||
// No-op. Page table is never used.
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Core
|
|
@ -1,108 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <memory>
|
|
||||||
#include <span>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "core/arm/arm_interface.h"
|
|
||||||
#include "core/arm/nce/guest_context.h"
|
|
||||||
|
|
||||||
namespace Core::Memory {
|
|
||||||
class Memory;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Core {
|
|
||||||
|
|
||||||
class System;
|
|
||||||
|
|
||||||
class ARM_NCE final : public ARM_Interface {
|
|
||||||
public:
|
|
||||||
ARM_NCE(System& system_, bool uses_wall_clock_, std::size_t core_index_);
|
|
||||||
|
|
||||||
~ARM_NCE() override;
|
|
||||||
|
|
||||||
void Initialize() override;
|
|
||||||
void SetPC(u64 pc) override;
|
|
||||||
u64 GetPC() const override;
|
|
||||||
u64 GetSP() const override;
|
|
||||||
u64 GetReg(int index) const override;
|
|
||||||
void SetReg(int index, u64 value) override;
|
|
||||||
u128 GetVectorReg(int index) const override;
|
|
||||||
void SetVectorReg(int index, u128 value) override;
|
|
||||||
|
|
||||||
u32 GetPSTATE() const override;
|
|
||||||
void SetPSTATE(u32 pstate) override;
|
|
||||||
u64 GetTlsAddress() const override;
|
|
||||||
void SetTlsAddress(u64 address) override;
|
|
||||||
void SetTPIDR_EL0(u64 value) override;
|
|
||||||
u64 GetTPIDR_EL0() const override;
|
|
||||||
|
|
||||||
Architecture GetArchitecture() const override {
|
|
||||||
return Architecture::Aarch64;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveContext(ThreadContext32& ctx) const override {}
|
|
||||||
void SaveContext(ThreadContext64& ctx) const override;
|
|
||||||
void LoadContext(const ThreadContext32& ctx) override {}
|
|
||||||
void LoadContext(const ThreadContext64& ctx) override;
|
|
||||||
|
|
||||||
void SignalInterrupt() override;
|
|
||||||
void ClearInterrupt() override;
|
|
||||||
void ClearExclusiveState() override;
|
|
||||||
void ClearInstructionCache() override;
|
|
||||||
void InvalidateCacheRange(u64 addr, std::size_t size) override;
|
|
||||||
void PageTableChanged(Common::PageTable& new_page_table,
|
|
||||||
std::size_t new_address_space_size_in_bits) override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
HaltReason RunJit() override;
|
|
||||||
HaltReason StepJit() override;
|
|
||||||
|
|
||||||
u32 GetSvcNumber() const override;
|
|
||||||
|
|
||||||
const Kernel::DebugWatchpoint* HaltedWatchpoint() const override {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RewindBreakpointInstruction() override {}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Assembly definitions.
|
|
||||||
static HaltReason ReturnToRunCodeByTrampoline(void* tpidr, GuestContext* ctx,
|
|
||||||
u64 trampoline_addr);
|
|
||||||
static HaltReason ReturnToRunCodeByExceptionLevelChange(int tid, void* tpidr);
|
|
||||||
|
|
||||||
static void ReturnToRunCodeByExceptionLevelChangeSignalHandler(int sig, void* info,
|
|
||||||
void* raw_context);
|
|
||||||
static void BreakFromRunCodeSignalHandler(int sig, void* info, void* raw_context);
|
|
||||||
static void GuestFaultSignalHandler(int sig, void* info, void* raw_context);
|
|
||||||
|
|
||||||
static void LockThreadParameters(void* tpidr);
|
|
||||||
static void UnlockThreadParameters(void* tpidr);
|
|
||||||
|
|
||||||
private:
|
|
||||||
// C++ implementation functions for assembly definitions.
|
|
||||||
static void* RestoreGuestContext(void* raw_context);
|
|
||||||
static void SaveGuestContext(GuestContext* ctx, void* raw_context);
|
|
||||||
static bool HandleGuestFault(GuestContext* ctx, void* info, void* raw_context);
|
|
||||||
static void HandleHostFault(int sig, void* info, void* raw_context);
|
|
||||||
|
|
||||||
public:
|
|
||||||
// Members set on initialization.
|
|
||||||
std::size_t core_index{};
|
|
||||||
pid_t thread_id{-1};
|
|
||||||
|
|
||||||
// Core context.
|
|
||||||
GuestContext guest_ctx;
|
|
||||||
|
|
||||||
// Thread and invalidation info.
|
|
||||||
std::mutex lock;
|
|
||||||
Kernel::KThread* running_thread{};
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Core
|
|
@ -1,222 +0,0 @@
|
|||||||
/* SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project */
|
|
||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
|
|
||||||
#include "core/arm/nce/arm_nce_asm_definitions.h"
|
|
||||||
|
|
||||||
#define LOAD_IMMEDIATE_32(reg, val) \
|
|
||||||
mov reg, #(((val) >> 0x00) & 0xFFFF); \
|
|
||||||
movk reg, #(((val) >> 0x10) & 0xFFFF), lsl #16
|
|
||||||
|
|
||||||
|
|
||||||
/* static HaltReason Core::ARM_NCE::ReturnToRunCodeByTrampoline(void* tpidr, Core::GuestContext* ctx, u64 trampoline_addr) */
|
|
||||||
.section .text._ZN4Core7ARM_NCE27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm, "ax", %progbits
|
|
||||||
.global _ZN4Core7ARM_NCE27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm
|
|
||||||
.type _ZN4Core7ARM_NCE27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm, %function
|
|
||||||
_ZN4Core7ARM_NCE27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm:
|
|
||||||
/* Back up host sp to x3. */
|
|
||||||
/* Back up host tpidr_el0 to x4. */
|
|
||||||
mov x3, sp
|
|
||||||
mrs x4, tpidr_el0
|
|
||||||
|
|
||||||
/* Load guest sp. x5 is used as a scratch register. */
|
|
||||||
ldr x5, [x1, #(GuestContextSp)]
|
|
||||||
mov sp, x5
|
|
||||||
|
|
||||||
/* Offset GuestContext pointer to the host member. */
|
|
||||||
add x5, x1, #(GuestContextHostContext)
|
|
||||||
|
|
||||||
/* Save original host sp and tpidr_el0 (x3, x4) to host context. */
|
|
||||||
stp x3, x4, [x5, #(HostContextSpTpidrEl0)]
|
|
||||||
|
|
||||||
/* Save all callee-saved host GPRs. */
|
|
||||||
stp x19, x20, [x5, #(HostContextRegs+0x0)]
|
|
||||||
stp x21, x22, [x5, #(HostContextRegs+0x10)]
|
|
||||||
stp x23, x24, [x5, #(HostContextRegs+0x20)]
|
|
||||||
stp x25, x26, [x5, #(HostContextRegs+0x30)]
|
|
||||||
stp x27, x28, [x5, #(HostContextRegs+0x40)]
|
|
||||||
stp x29, x30, [x5, #(HostContextRegs+0x50)]
|
|
||||||
|
|
||||||
/* Save all callee-saved host FPRs. */
|
|
||||||
stp q8, q9, [x5, #(HostContextVregs+0x0)]
|
|
||||||
stp q10, q11, [x5, #(HostContextVregs+0x20)]
|
|
||||||
stp q12, q13, [x5, #(HostContextVregs+0x40)]
|
|
||||||
stp q14, q15, [x5, #(HostContextVregs+0x60)]
|
|
||||||
|
|
||||||
/* Load guest tpidr_el0 from argument. */
|
|
||||||
msr tpidr_el0, x0
|
|
||||||
|
|
||||||
/* Tail call the trampoline to restore guest state. */
|
|
||||||
br x2
|
|
||||||
|
|
||||||
|
|
||||||
/* static HaltReason Core::ARM_NCE::ReturnToRunCodeByExceptionLevelChange(int tid, void* tpidr) */
|
|
||||||
.section .text._ZN4Core7ARM_NCE37ReturnToRunCodeByExceptionLevelChangeEiPv, "ax", %progbits
|
|
||||||
.global _ZN4Core7ARM_NCE37ReturnToRunCodeByExceptionLevelChangeEiPv
|
|
||||||
.type _ZN4Core7ARM_NCE37ReturnToRunCodeByExceptionLevelChangeEiPv, %function
|
|
||||||
_ZN4Core7ARM_NCE37ReturnToRunCodeByExceptionLevelChangeEiPv:
|
|
||||||
/* This jumps to the signal handler, which will restore the entire context. */
|
|
||||||
/* On entry, x0 = thread id, which is already in the right place. */
|
|
||||||
|
|
||||||
/* Move tpidr to x9 so it is not trampled. */
|
|
||||||
mov x9, x1
|
|
||||||
|
|
||||||
/* Set up arguments. */
|
|
||||||
mov x8, #(__NR_tkill)
|
|
||||||
mov x1, #(ReturnToRunCodeByExceptionLevelChangeSignal)
|
|
||||||
|
|
||||||
/* Tail call the signal handler. */
|
|
||||||
svc #0
|
|
||||||
|
|
||||||
/* Block execution from flowing here. */
|
|
||||||
brk #1000
|
|
||||||
|
|
||||||
|
|
||||||
/* static void Core::ARM_NCE::ReturnToRunCodeByExceptionLevelChangeSignalHandler(int sig, void* info, void* raw_context) */
|
|
||||||
.section .text._ZN4Core7ARM_NCE50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_, "ax", %progbits
|
|
||||||
.global _ZN4Core7ARM_NCE50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_
|
|
||||||
.type _ZN4Core7ARM_NCE50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_, %function
|
|
||||||
_ZN4Core7ARM_NCE50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_:
|
|
||||||
stp x29, x30, [sp, #-0x10]!
|
|
||||||
mov x29, sp
|
|
||||||
|
|
||||||
/* Call the context restorer with the raw context. */
|
|
||||||
mov x0, x2
|
|
||||||
bl _ZN4Core7ARM_NCE19RestoreGuestContextEPv
|
|
||||||
|
|
||||||
/* Save the old value of tpidr_el0. */
|
|
||||||
mrs x8, tpidr_el0
|
|
||||||
ldr x9, [x0, #(TpidrEl0NativeContext)]
|
|
||||||
str x8, [x9, #(GuestContextHostContext + HostContextTpidrEl0)]
|
|
||||||
|
|
||||||
/* Set our new tpidr_el0. */
|
|
||||||
msr tpidr_el0, x0
|
|
||||||
|
|
||||||
/* Unlock the context. */
|
|
||||||
bl _ZN4Core7ARM_NCE22UnlockThreadParametersEPv
|
|
||||||
|
|
||||||
/* Returning from here will enter the guest. */
|
|
||||||
ldp x29, x30, [sp], #0x10
|
|
||||||
ret
|
|
||||||
|
|
||||||
|
|
||||||
/* static void Core::ARM_NCE::BreakFromRunCodeSignalHandler(int sig, void* info, void* raw_context) */
|
|
||||||
.section .text._ZN4Core7ARM_NCE29BreakFromRunCodeSignalHandlerEiPvS1_, "ax", %progbits
|
|
||||||
.global _ZN4Core7ARM_NCE29BreakFromRunCodeSignalHandlerEiPvS1_
|
|
||||||
.type _ZN4Core7ARM_NCE29BreakFromRunCodeSignalHandlerEiPvS1_, %function
|
|
||||||
_ZN4Core7ARM_NCE29BreakFromRunCodeSignalHandlerEiPvS1_:
|
|
||||||
/* Check to see if we have the correct TLS magic. */
|
|
||||||
mrs x8, tpidr_el0
|
|
||||||
ldr w9, [x8, #(TpidrEl0TlsMagic)]
|
|
||||||
|
|
||||||
LOAD_IMMEDIATE_32(w10, TlsMagic)
|
|
||||||
|
|
||||||
cmp w9, w10
|
|
||||||
b.ne 1f
|
|
||||||
|
|
||||||
/* Correct TLS magic, so this is a guest interrupt. */
|
|
||||||
/* Restore host tpidr_el0. */
|
|
||||||
ldr x0, [x8, #(TpidrEl0NativeContext)]
|
|
||||||
ldr x3, [x0, #(GuestContextHostContext + HostContextTpidrEl0)]
|
|
||||||
msr tpidr_el0, x3
|
|
||||||
|
|
||||||
/* Tail call the restorer. */
|
|
||||||
mov x1, x2
|
|
||||||
b _ZN4Core7ARM_NCE16SaveGuestContextEPNS_12GuestContextEPv
|
|
||||||
|
|
||||||
/* Returning from here will enter host code. */
|
|
||||||
|
|
||||||
1:
|
|
||||||
/* Incorrect TLS magic, so this is a spurious signal. */
|
|
||||||
ret
|
|
||||||
|
|
||||||
|
|
||||||
/* static void Core::ARM_NCE::GuestFaultSignalHandler(int sig, void* info, void* raw_context) */
|
|
||||||
.section .text._ZN4Core7ARM_NCE23GuestFaultSignalHandlerEiPvS1_, "ax", %progbits
|
|
||||||
.global _ZN4Core7ARM_NCE23GuestFaultSignalHandlerEiPvS1_
|
|
||||||
.type _ZN4Core7ARM_NCE23GuestFaultSignalHandlerEiPvS1_, %function
|
|
||||||
_ZN4Core7ARM_NCE23GuestFaultSignalHandlerEiPvS1_:
|
|
||||||
/* Check to see if we have the correct TLS magic. */
|
|
||||||
mrs x8, tpidr_el0
|
|
||||||
ldr w9, [x8, #(TpidrEl0TlsMagic)]
|
|
||||||
|
|
||||||
LOAD_IMMEDIATE_32(w10, TlsMagic)
|
|
||||||
|
|
||||||
cmp w9, w10
|
|
||||||
b.eq 1f
|
|
||||||
|
|
||||||
/* Incorrect TLS magic, so this is a host fault. */
|
|
||||||
/* Tail call the handler. */
|
|
||||||
b _ZN4Core7ARM_NCE15HandleHostFaultEiPvS1_
|
|
||||||
|
|
||||||
1:
|
|
||||||
/* Correct TLS magic, so this is a guest fault. */
|
|
||||||
stp x29, x30, [sp, #-0x20]!
|
|
||||||
str x19, [sp, #0x10]
|
|
||||||
mov x29, sp
|
|
||||||
|
|
||||||
/* Save the old tpidr_el0. */
|
|
||||||
mov x19, x8
|
|
||||||
|
|
||||||
/* Restore host tpidr_el0. */
|
|
||||||
ldr x0, [x8, #(TpidrEl0NativeContext)]
|
|
||||||
ldr x3, [x0, #(GuestContextHostContext + HostContextTpidrEl0)]
|
|
||||||
msr tpidr_el0, x3
|
|
||||||
|
|
||||||
/* Call the handler. */
|
|
||||||
bl _ZN4Core7ARM_NCE16HandleGuestFaultEPNS_12GuestContextEPvS3_
|
|
||||||
|
|
||||||
/* If the handler returned false, we want to preserve the host tpidr_el0. */
|
|
||||||
cbz x0, 2f
|
|
||||||
|
|
||||||
/* Otherwise, restore guest tpidr_el0. */
|
|
||||||
msr tpidr_el0, x19
|
|
||||||
|
|
||||||
2:
|
|
||||||
ldr x19, [sp, #0x10]
|
|
||||||
ldp x29, x30, [sp], #0x20
|
|
||||||
ret
|
|
||||||
|
|
||||||
|
|
||||||
/* static void Core::ARM_NCE::LockThreadParameters(void* tpidr) */
|
|
||||||
.section .text._ZN4Core7ARM_NCE20LockThreadParametersEPv, "ax", %progbits
|
|
||||||
.global _ZN4Core7ARM_NCE20LockThreadParametersEPv
|
|
||||||
.type _ZN4Core7ARM_NCE20LockThreadParametersEPv, %function
|
|
||||||
_ZN4Core7ARM_NCE20LockThreadParametersEPv:
|
|
||||||
/* Offset to lock member. */
|
|
||||||
add x0, x0, #(TpidrEl0Lock)
|
|
||||||
|
|
||||||
1:
|
|
||||||
/* Clear the monitor. */
|
|
||||||
clrex
|
|
||||||
|
|
||||||
2:
|
|
||||||
/* Load-linked with acquire ordering. */
|
|
||||||
ldaxr w1, [x0]
|
|
||||||
|
|
||||||
/* If the value was SpinLockLocked, clear monitor and retry. */
|
|
||||||
cbz w1, 1b
|
|
||||||
|
|
||||||
/* Store-conditional SpinLockLocked with relaxed ordering. */
|
|
||||||
stxr w1, wzr, [x0]
|
|
||||||
|
|
||||||
/* If we failed to store, retry. */
|
|
||||||
cbnz w1, 2b
|
|
||||||
|
|
||||||
ret
|
|
||||||
|
|
||||||
|
|
||||||
/* static void Core::ARM_NCE::UnlockThreadParameters(void* tpidr) */
|
|
||||||
.section .text._ZN4Core7ARM_NCE22UnlockThreadParametersEPv, "ax", %progbits
|
|
||||||
.global _ZN4Core7ARM_NCE22UnlockThreadParametersEPv
|
|
||||||
.type _ZN4Core7ARM_NCE22UnlockThreadParametersEPv, %function
|
|
||||||
_ZN4Core7ARM_NCE22UnlockThreadParametersEPv:
|
|
||||||
/* Offset to lock member. */
|
|
||||||
add x0, x0, #(TpidrEl0Lock)
|
|
||||||
|
|
||||||
/* Load SpinLockUnlocked. */
|
|
||||||
mov w1, #(SpinLockUnlocked)
|
|
||||||
|
|
||||||
/* Store value with release ordering. */
|
|
||||||
stlr w1, [x0]
|
|
||||||
|
|
||||||
ret
|
|
@ -1,29 +0,0 @@
|
|||||||
/* SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project */
|
|
||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#define __ASSEMBLY__
|
|
||||||
|
|
||||||
#include <asm-generic/signal.h>
|
|
||||||
#include <asm-generic/unistd.h>
|
|
||||||
|
|
||||||
#define ReturnToRunCodeByExceptionLevelChangeSignal SIGUSR2
|
|
||||||
#define BreakFromRunCodeSignal SIGURG
|
|
||||||
#define GuestFaultSignal SIGSEGV
|
|
||||||
|
|
||||||
#define GuestContextSp 0xF8
|
|
||||||
#define GuestContextHostContext 0x320
|
|
||||||
|
|
||||||
#define HostContextSpTpidrEl0 0xE0
|
|
||||||
#define HostContextTpidrEl0 0xE8
|
|
||||||
#define HostContextRegs 0x0
|
|
||||||
#define HostContextVregs 0x60
|
|
||||||
|
|
||||||
#define TpidrEl0NativeContext 0x10
|
|
||||||
#define TpidrEl0Lock 0x18
|
|
||||||
#define TpidrEl0TlsMagic 0x20
|
|
||||||
#define TlsMagic 0x555a5559
|
|
||||||
|
|
||||||
#define SpinLockLocked 0
|
|
||||||
#define SpinLockUnlocked 1
|
|
@ -1,50 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common/common_funcs.h"
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "core/arm/arm_interface.h"
|
|
||||||
#include "core/arm/nce/arm_nce_asm_definitions.h"
|
|
||||||
|
|
||||||
namespace Core {
|
|
||||||
|
|
||||||
class ARM_NCE;
|
|
||||||
class System;
|
|
||||||
|
|
||||||
struct HostContext {
|
|
||||||
alignas(16) std::array<u64, 12> host_saved_regs{};
|
|
||||||
alignas(16) std::array<u128, 8> host_saved_vregs{};
|
|
||||||
u64 host_sp{};
|
|
||||||
void* host_tpidr_el0{};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GuestContext {
|
|
||||||
std::array<u64, 31> cpu_registers{};
|
|
||||||
u64 sp{};
|
|
||||||
u64 pc{};
|
|
||||||
u32 fpcr{};
|
|
||||||
u32 fpsr{};
|
|
||||||
std::array<u128, 32> vector_registers{};
|
|
||||||
u32 pstate{};
|
|
||||||
alignas(16) HostContext host_ctx{};
|
|
||||||
u64 tpidrro_el0{};
|
|
||||||
u64 tpidr_el0{};
|
|
||||||
std::atomic<u64> esr_el1{};
|
|
||||||
u32 nzcv{};
|
|
||||||
u32 svc_swi{};
|
|
||||||
System* system{};
|
|
||||||
ARM_NCE* parent{};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Verify assembly offsets.
|
|
||||||
static_assert(offsetof(GuestContext, sp) == GuestContextSp);
|
|
||||||
static_assert(offsetof(GuestContext, host_ctx) == GuestContextHostContext);
|
|
||||||
static_assert(offsetof(HostContext, host_sp) == HostContextSpTpidrEl0);
|
|
||||||
static_assert(offsetof(HostContext, host_tpidr_el0) - 8 == HostContextSpTpidrEl0);
|
|
||||||
static_assert(offsetof(HostContext, host_tpidr_el0) == HostContextTpidrEl0);
|
|
||||||
static_assert(offsetof(HostContext, host_saved_regs) == HostContextRegs);
|
|
||||||
static_assert(offsetof(HostContext, host_saved_vregs) == HostContextVregs);
|
|
||||||
|
|
||||||
} // namespace Core
|
|
@ -1,147 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright © 2020 Skyline Team and Contributors
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
#include "common/bit_field.h"
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace Core::NCE {
|
|
||||||
|
|
||||||
enum SystemRegister : u32 {
|
|
||||||
TpidrEl0 = 0x5E82,
|
|
||||||
TpidrroEl0 = 0x5E83,
|
|
||||||
CntfrqEl0 = 0x5F00,
|
|
||||||
CntpctEl0 = 0x5F01,
|
|
||||||
};
|
|
||||||
|
|
||||||
// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/SVC--Supervisor-Call-
|
|
||||||
union SVC {
|
|
||||||
constexpr explicit SVC(u32 raw_) : raw{raw_} {}
|
|
||||||
|
|
||||||
constexpr bool Verify() {
|
|
||||||
return (this->GetSig0() == 0x1 && this->GetSig1() == 0x6A0);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr u32 GetSig0() {
|
|
||||||
return decltype(sig0)::ExtractValue(raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr u32 GetValue() {
|
|
||||||
return decltype(value)::ExtractValue(raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr u32 GetSig1() {
|
|
||||||
return decltype(sig1)::ExtractValue(raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 raw;
|
|
||||||
|
|
||||||
private:
|
|
||||||
BitField<0, 5, u32> sig0; // 0x1
|
|
||||||
BitField<5, 16, u32> value; // 16-bit immediate
|
|
||||||
BitField<21, 11, u32> sig1; // 0x6A0
|
|
||||||
};
|
|
||||||
static_assert(sizeof(SVC) == sizeof(u32));
|
|
||||||
static_assert(SVC(0xD40000C1).Verify());
|
|
||||||
static_assert(SVC(0xD40000C1).GetValue() == 0x6);
|
|
||||||
|
|
||||||
// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/MRS--Move-System-Register-
|
|
||||||
union MRS {
|
|
||||||
constexpr explicit MRS(u32 raw_) : raw{raw_} {}
|
|
||||||
|
|
||||||
constexpr bool Verify() {
|
|
||||||
return (this->GetSig() == 0xD53);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr u32 GetRt() {
|
|
||||||
return decltype(rt)::ExtractValue(raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr u32 GetSystemReg() {
|
|
||||||
return decltype(system_reg)::ExtractValue(raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr u32 GetSig() {
|
|
||||||
return decltype(sig)::ExtractValue(raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 raw;
|
|
||||||
|
|
||||||
private:
|
|
||||||
BitField<0, 5, u32> rt; // destination register
|
|
||||||
BitField<5, 15, u32> system_reg; // source system register
|
|
||||||
BitField<20, 12, u32> sig; // 0xD53
|
|
||||||
};
|
|
||||||
static_assert(sizeof(MRS) == sizeof(u32));
|
|
||||||
static_assert(MRS(0xD53BE020).Verify());
|
|
||||||
static_assert(MRS(0xD53BE020).GetSystemReg() == CntpctEl0);
|
|
||||||
static_assert(MRS(0xD53BE020).GetRt() == 0x0);
|
|
||||||
|
|
||||||
// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/MSR--register---Move-general-purpose-register-to-System-Register-
|
|
||||||
union MSR {
|
|
||||||
constexpr explicit MSR(u32 raw_) : raw{raw_} {}
|
|
||||||
|
|
||||||
constexpr bool Verify() {
|
|
||||||
return this->GetSig() == 0xD51;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr u32 GetRt() {
|
|
||||||
return decltype(rt)::ExtractValue(raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr u32 GetSystemReg() {
|
|
||||||
return decltype(system_reg)::ExtractValue(raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr u32 GetSig() {
|
|
||||||
return decltype(sig)::ExtractValue(raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 raw;
|
|
||||||
|
|
||||||
private:
|
|
||||||
BitField<0, 5, u32> rt; // source register
|
|
||||||
BitField<5, 15, u32> system_reg; // destination system register
|
|
||||||
BitField<20, 12, u32> sig; // 0xD51
|
|
||||||
};
|
|
||||||
static_assert(sizeof(MSR) == sizeof(u32));
|
|
||||||
static_assert(MSR(0xD51BD040).Verify());
|
|
||||||
static_assert(MSR(0xD51BD040).GetSystemReg() == TpidrEl0);
|
|
||||||
static_assert(MSR(0xD51BD040).GetRt() == 0x0);
|
|
||||||
|
|
||||||
// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/LDXR--Load-Exclusive-Register-
|
|
||||||
// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/LDXP--Load-Exclusive-Pair-of-Registers-
|
|
||||||
// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/STXR--Store-Exclusive-Register-
|
|
||||||
// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/STXP--Store-Exclusive-Pair-of-registers-
|
|
||||||
union Exclusive {
|
|
||||||
constexpr explicit Exclusive(u32 raw_) : raw{raw_} {}
|
|
||||||
|
|
||||||
constexpr bool Verify() {
|
|
||||||
return this->GetSig() == 0x10;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr u32 GetSig() {
|
|
||||||
return decltype(sig)::ExtractValue(raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr u32 AsOrdered() {
|
|
||||||
return raw | decltype(o0)::FormatValue(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 raw;
|
|
||||||
|
|
||||||
private:
|
|
||||||
BitField<0, 5, u32> rt; // memory operand
|
|
||||||
BitField<5, 5, u32> rn; // register operand 1
|
|
||||||
BitField<10, 5, u32> rt2; // register operand 2
|
|
||||||
BitField<15, 1, u32> o0; // ordered
|
|
||||||
BitField<16, 5, u32> rs; // status register
|
|
||||||
BitField<21, 2, u32> l; // operation type
|
|
||||||
BitField<23, 7, u32> sig; // 0x10
|
|
||||||
BitField<30, 2, u32> size; // size
|
|
||||||
};
|
|
||||||
static_assert(Exclusive(0xC85FFC00).Verify());
|
|
||||||
static_assert(Exclusive(0xC85FFC00).AsOrdered() == 0xC85FFC00);
|
|
||||||
static_assert(Exclusive(0xC85F7C00).AsOrdered() == 0xC85FFC00);
|
|
||||||
static_assert(Exclusive(0xC8200440).AsOrdered() == 0xC8208440);
|
|
||||||
|
|
||||||
} // namespace Core::NCE
|
|
@ -1,472 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include "common/arm64/native_clock.h"
|
|
||||||
#include "common/bit_cast.h"
|
|
||||||
#include "common/literals.h"
|
|
||||||
#include "core/arm/nce/arm_nce.h"
|
|
||||||
#include "core/arm/nce/guest_context.h"
|
|
||||||
#include "core/arm/nce/instructions.h"
|
|
||||||
#include "core/arm/nce/patch.h"
|
|
||||||
#include "core/core.h"
|
|
||||||
#include "core/core_timing.h"
|
|
||||||
#include "core/hle/kernel/svc.h"
|
|
||||||
|
|
||||||
namespace Core::NCE {
|
|
||||||
|
|
||||||
using namespace Common::Literals;
|
|
||||||
using namespace oaknut::util;
|
|
||||||
|
|
||||||
using NativeExecutionParameters = Kernel::KThread::NativeExecutionParameters;
|
|
||||||
|
|
||||||
constexpr size_t MaxRelativeBranch = 128_MiB;
|
|
||||||
constexpr u32 ModuleCodeIndex = 0x24 / sizeof(u32);
|
|
||||||
|
|
||||||
Patcher::Patcher() : c(m_patch_instructions) {}
|
|
||||||
|
|
||||||
Patcher::~Patcher() = default;
|
|
||||||
|
|
||||||
void Patcher::PatchText(const Kernel::PhysicalMemory& program_image,
|
|
||||||
const Kernel::CodeSet::Segment& code) {
|
|
||||||
|
|
||||||
// Write save context helper function.
|
|
||||||
c.l(m_save_context);
|
|
||||||
WriteSaveContext();
|
|
||||||
|
|
||||||
// Write load context helper function.
|
|
||||||
c.l(m_load_context);
|
|
||||||
WriteLoadContext();
|
|
||||||
|
|
||||||
// Retrieve text segment data.
|
|
||||||
const auto text = std::span{program_image}.subspan(code.offset, code.size);
|
|
||||||
const auto text_words =
|
|
||||||
std::span<const u32>{reinterpret_cast<const u32*>(text.data()), text.size() / sizeof(u32)};
|
|
||||||
|
|
||||||
// Loop through instructions, patching as needed.
|
|
||||||
for (u32 i = ModuleCodeIndex; i < static_cast<u32>(text_words.size()); i++) {
|
|
||||||
const u32 inst = text_words[i];
|
|
||||||
|
|
||||||
const auto AddRelocations = [&] {
|
|
||||||
const uintptr_t this_offset = i * sizeof(u32);
|
|
||||||
const uintptr_t next_offset = this_offset + sizeof(u32);
|
|
||||||
|
|
||||||
// Relocate from here to patch.
|
|
||||||
this->BranchToPatch(this_offset);
|
|
||||||
|
|
||||||
// Relocate from patch to next instruction.
|
|
||||||
return next_offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
// SVC
|
|
||||||
if (auto svc = SVC{inst}; svc.Verify()) {
|
|
||||||
WriteSvcTrampoline(AddRelocations(), svc.GetValue());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// MRS Xn, TPIDR_EL0
|
|
||||||
// MRS Xn, TPIDRRO_EL0
|
|
||||||
if (auto mrs = MRS{inst};
|
|
||||||
mrs.Verify() && (mrs.GetSystemReg() == TpidrroEl0 || mrs.GetSystemReg() == TpidrEl0)) {
|
|
||||||
const auto src_reg = mrs.GetSystemReg() == TpidrroEl0 ? oaknut::SystemReg::TPIDRRO_EL0
|
|
||||||
: oaknut::SystemReg::TPIDR_EL0;
|
|
||||||
const auto dest_reg = oaknut::XReg{static_cast<int>(mrs.GetRt())};
|
|
||||||
WriteMrsHandler(AddRelocations(), dest_reg, src_reg);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// MRS Xn, CNTPCT_EL0
|
|
||||||
if (auto mrs = MRS{inst}; mrs.Verify() && mrs.GetSystemReg() == CntpctEl0) {
|
|
||||||
WriteCntpctHandler(AddRelocations(), oaknut::XReg{static_cast<int>(mrs.GetRt())});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// MRS Xn, CNTFRQ_EL0
|
|
||||||
if (auto mrs = MRS{inst}; mrs.Verify() && mrs.GetSystemReg() == CntfrqEl0) {
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
// MSR TPIDR_EL0, Xn
|
|
||||||
if (auto msr = MSR{inst}; msr.Verify() && msr.GetSystemReg() == TpidrEl0) {
|
|
||||||
WriteMsrHandler(AddRelocations(), oaknut::XReg{static_cast<int>(msr.GetRt())});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine patching mode for the final relocation step
|
|
||||||
const size_t image_size = program_image.size();
|
|
||||||
this->mode = image_size > MaxRelativeBranch ? PatchMode::PreText : PatchMode::PostData;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Patcher::RelocateAndCopy(Common::ProcessAddress load_base,
|
|
||||||
const Kernel::CodeSet::Segment& code,
|
|
||||||
Kernel::PhysicalMemory& program_image,
|
|
||||||
EntryTrampolines* out_trampolines) {
|
|
||||||
const size_t patch_size = GetSectionSize();
|
|
||||||
const size_t image_size = program_image.size();
|
|
||||||
|
|
||||||
// Retrieve text segment data.
|
|
||||||
const auto text = std::span{program_image}.subspan(code.offset, code.size);
|
|
||||||
const auto text_words =
|
|
||||||
std::span<u32>{reinterpret_cast<u32*>(text.data()), text.size() / sizeof(u32)};
|
|
||||||
|
|
||||||
const auto ApplyBranchToPatchRelocation = [&](u32* target, const Relocation& rel) {
|
|
||||||
oaknut::CodeGenerator rc{target};
|
|
||||||
if (mode == PatchMode::PreText) {
|
|
||||||
rc.B(rel.patch_offset - patch_size - rel.module_offset);
|
|
||||||
} else {
|
|
||||||
rc.B(image_size - rel.module_offset + rel.patch_offset);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto ApplyBranchToModuleRelocation = [&](u32* target, const Relocation& rel) {
|
|
||||||
oaknut::CodeGenerator rc{target};
|
|
||||||
if (mode == PatchMode::PreText) {
|
|
||||||
rc.B(patch_size - rel.patch_offset + rel.module_offset);
|
|
||||||
} else {
|
|
||||||
rc.B(rel.module_offset - image_size - rel.patch_offset);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto RebasePatch = [&](ptrdiff_t patch_offset) {
|
|
||||||
if (mode == PatchMode::PreText) {
|
|
||||||
return GetInteger(load_base) + patch_offset;
|
|
||||||
} else {
|
|
||||||
return GetInteger(load_base) + image_size + patch_offset;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto RebasePc = [&](uintptr_t module_offset) {
|
|
||||||
if (mode == PatchMode::PreText) {
|
|
||||||
return GetInteger(load_base) + patch_size + module_offset;
|
|
||||||
} else {
|
|
||||||
return GetInteger(load_base) + module_offset;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// We are now ready to relocate!
|
|
||||||
for (const Relocation& rel : m_branch_to_patch_relocations) {
|
|
||||||
ApplyBranchToPatchRelocation(text_words.data() + rel.module_offset / sizeof(u32), rel);
|
|
||||||
}
|
|
||||||
for (const Relocation& rel : m_branch_to_module_relocations) {
|
|
||||||
ApplyBranchToModuleRelocation(m_patch_instructions.data() + rel.patch_offset / sizeof(u32),
|
|
||||||
rel);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rewrite PC constants and record post trampolines
|
|
||||||
for (const Relocation& rel : m_write_module_pc_relocations) {
|
|
||||||
oaknut::CodeGenerator rc{m_patch_instructions.data() + rel.patch_offset / sizeof(u32)};
|
|
||||||
rc.dx(RebasePc(rel.module_offset));
|
|
||||||
}
|
|
||||||
for (const Trampoline& rel : m_trampolines) {
|
|
||||||
out_trampolines->insert({RebasePc(rel.module_offset), RebasePatch(rel.patch_offset)});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cortex-A57 seems to treat all exclusives as ordered, but newer processors do not.
|
|
||||||
// Convert to ordered to preserve this assumption.
|
|
||||||
for (u32 i = ModuleCodeIndex; i < static_cast<u32>(text_words.size()); i++) {
|
|
||||||
const u32 inst = text_words[i];
|
|
||||||
if (auto exclusive = Exclusive{inst}; exclusive.Verify()) {
|
|
||||||
text_words[i] = exclusive.AsOrdered();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy to program image
|
|
||||||
if (this->mode == PatchMode::PreText) {
|
|
||||||
std::memcpy(program_image.data(), m_patch_instructions.data(),
|
|
||||||
m_patch_instructions.size() * sizeof(u32));
|
|
||||||
} else {
|
|
||||||
program_image.resize(image_size + patch_size);
|
|
||||||
std::memcpy(program_image.data() + image_size, m_patch_instructions.data(),
|
|
||||||
m_patch_instructions.size() * sizeof(u32));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t Patcher::GetSectionSize() const noexcept {
|
|
||||||
return Common::AlignUp(m_patch_instructions.size() * sizeof(u32), Core::Memory::YUZU_PAGESIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Patcher::WriteLoadContext() {
|
|
||||||
// This function was called, which modifies X30, so use that as a scratch register.
|
|
||||||
// SP contains the guest X30, so save our return X30 to SP + 8, since we have allocated 16 bytes
|
|
||||||
// of stack.
|
|
||||||
c.STR(X30, SP, 8);
|
|
||||||
c.MRS(X30, oaknut::SystemReg::TPIDR_EL0);
|
|
||||||
c.LDR(X30, X30, offsetof(NativeExecutionParameters, native_context));
|
|
||||||
|
|
||||||
// Load system registers.
|
|
||||||
c.LDR(W0, X30, offsetof(GuestContext, fpsr));
|
|
||||||
c.MSR(oaknut::SystemReg::FPSR, X0);
|
|
||||||
c.LDR(W0, X30, offsetof(GuestContext, fpcr));
|
|
||||||
c.MSR(oaknut::SystemReg::FPCR, X0);
|
|
||||||
c.LDR(W0, X30, offsetof(GuestContext, nzcv));
|
|
||||||
c.MSR(oaknut::SystemReg::NZCV, X0);
|
|
||||||
|
|
||||||
// Load all vector registers.
|
|
||||||
static constexpr size_t VEC_OFF = offsetof(GuestContext, vector_registers);
|
|
||||||
for (int i = 0; i <= 30; i += 2) {
|
|
||||||
c.LDP(oaknut::QReg{i}, oaknut::QReg{i + 1}, X30, VEC_OFF + 16 * i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load all general-purpose registers except X30.
|
|
||||||
for (int i = 0; i <= 28; i += 2) {
|
|
||||||
c.LDP(oaknut::XReg{i}, oaknut::XReg{i + 1}, X30, 8 * i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reload our return X30 from the stack and return.
|
|
||||||
// The patch code will reload the guest X30 for us.
|
|
||||||
c.LDR(X30, SP, 8);
|
|
||||||
c.RET();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Patcher::WriteSaveContext() {
|
|
||||||
// This function was called, which modifies X30, so use that as a scratch register.
|
|
||||||
// SP contains the guest X30, so save our X30 to SP + 8, since we have allocated 16 bytes of
|
|
||||||
// stack.
|
|
||||||
c.STR(X30, SP, 8);
|
|
||||||
c.MRS(X30, oaknut::SystemReg::TPIDR_EL0);
|
|
||||||
c.LDR(X30, X30, offsetof(NativeExecutionParameters, native_context));
|
|
||||||
|
|
||||||
// Store all general-purpose registers except X30.
|
|
||||||
for (int i = 0; i <= 28; i += 2) {
|
|
||||||
c.STP(oaknut::XReg{i}, oaknut::XReg{i + 1}, X30, 8 * i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store all vector registers.
|
|
||||||
static constexpr size_t VEC_OFF = offsetof(GuestContext, vector_registers);
|
|
||||||
for (int i = 0; i <= 30; i += 2) {
|
|
||||||
c.STP(oaknut::QReg{i}, oaknut::QReg{i + 1}, X30, VEC_OFF + 16 * i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store guest system registers, X30 and SP, using X0 as a scratch register.
|
|
||||||
c.STR(X0, SP, PRE_INDEXED, -16);
|
|
||||||
c.LDR(X0, SP, 16);
|
|
||||||
c.STR(X0, X30, 8 * 30);
|
|
||||||
c.ADD(X0, SP, 32);
|
|
||||||
c.STR(X0, X30, offsetof(GuestContext, sp));
|
|
||||||
c.MRS(X0, oaknut::SystemReg::FPSR);
|
|
||||||
c.STR(W0, X30, offsetof(GuestContext, fpsr));
|
|
||||||
c.MRS(X0, oaknut::SystemReg::FPCR);
|
|
||||||
c.STR(W0, X30, offsetof(GuestContext, fpcr));
|
|
||||||
c.MRS(X0, oaknut::SystemReg::NZCV);
|
|
||||||
c.STR(W0, X30, offsetof(GuestContext, nzcv));
|
|
||||||
c.LDR(X0, SP, POST_INDEXED, 16);
|
|
||||||
|
|
||||||
// Reload our return X30 from the stack, and return.
|
|
||||||
c.LDR(X30, SP, 8);
|
|
||||||
c.RET();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Patcher::WriteSvcTrampoline(ModuleDestLabel module_dest, u32 svc_id) {
|
|
||||||
// We are about to start saving state, so we need to lock the context.
|
|
||||||
this->LockContext();
|
|
||||||
|
|
||||||
// Store guest X30 to the stack. Then, save the context and restore the stack.
|
|
||||||
// This will save all registers except PC, but we know PC at patch time.
|
|
||||||
c.STR(X30, SP, PRE_INDEXED, -16);
|
|
||||||
c.BL(m_save_context);
|
|
||||||
c.LDR(X30, SP, POST_INDEXED, 16);
|
|
||||||
|
|
||||||
// Now that we've saved all registers, we can use any registers as scratch.
|
|
||||||
// Store PC + 4 to arm interface, since we know the instruction offset from the entry point.
|
|
||||||
oaknut::Label pc_after_svc;
|
|
||||||
c.MRS(X1, oaknut::SystemReg::TPIDR_EL0);
|
|
||||||
c.LDR(X1, X1, offsetof(NativeExecutionParameters, native_context));
|
|
||||||
c.LDR(X2, pc_after_svc);
|
|
||||||
c.STR(X2, X1, offsetof(GuestContext, pc));
|
|
||||||
|
|
||||||
// Store SVC number to execute when we return
|
|
||||||
c.MOV(X2, svc_id);
|
|
||||||
c.STR(W2, X1, offsetof(GuestContext, svc_swi));
|
|
||||||
|
|
||||||
// We are calling a SVC. Clear esr_el1 and return it.
|
|
||||||
static_assert(std::is_same_v<std::underlying_type_t<HaltReason>, u64>);
|
|
||||||
oaknut::Label retry;
|
|
||||||
c.ADD(X2, X1, offsetof(GuestContext, esr_el1));
|
|
||||||
c.l(retry);
|
|
||||||
c.LDAXR(X0, X2);
|
|
||||||
c.STLXR(W3, XZR, X2);
|
|
||||||
c.CBNZ(W3, retry);
|
|
||||||
|
|
||||||
// Add "calling SVC" flag. Since this is X0, this is now our return value.
|
|
||||||
c.ORR(X0, X0, static_cast<u64>(HaltReason::SupervisorCall));
|
|
||||||
|
|
||||||
// Offset the GuestContext pointer to the HostContext member.
|
|
||||||
// STP has limited range of [-512, 504] which we can't reach otherwise
|
|
||||||
// NB: Due to this all offsets below are from the start of HostContext.
|
|
||||||
c.ADD(X1, X1, offsetof(GuestContext, host_ctx));
|
|
||||||
|
|
||||||
// Reload host TPIDR_EL0 and SP.
|
|
||||||
static_assert(offsetof(HostContext, host_sp) + 8 == offsetof(HostContext, host_tpidr_el0));
|
|
||||||
c.LDP(X2, X3, X1, offsetof(HostContext, host_sp));
|
|
||||||
c.MOV(SP, X2);
|
|
||||||
c.MSR(oaknut::SystemReg::TPIDR_EL0, X3);
|
|
||||||
|
|
||||||
// Load callee-saved host registers and return to host.
|
|
||||||
static constexpr size_t HOST_REGS_OFF = offsetof(HostContext, host_saved_regs);
|
|
||||||
static constexpr size_t HOST_VREGS_OFF = offsetof(HostContext, host_saved_vregs);
|
|
||||||
c.LDP(X19, X20, X1, HOST_REGS_OFF);
|
|
||||||
c.LDP(X21, X22, X1, HOST_REGS_OFF + 2 * sizeof(u64));
|
|
||||||
c.LDP(X23, X24, X1, HOST_REGS_OFF + 4 * sizeof(u64));
|
|
||||||
c.LDP(X25, X26, X1, HOST_REGS_OFF + 6 * sizeof(u64));
|
|
||||||
c.LDP(X27, X28, X1, HOST_REGS_OFF + 8 * sizeof(u64));
|
|
||||||
c.LDP(X29, X30, X1, HOST_REGS_OFF + 10 * sizeof(u64));
|
|
||||||
c.LDP(Q8, Q9, X1, HOST_VREGS_OFF);
|
|
||||||
c.LDP(Q10, Q11, X1, HOST_VREGS_OFF + 2 * sizeof(u128));
|
|
||||||
c.LDP(Q12, Q13, X1, HOST_VREGS_OFF + 4 * sizeof(u128));
|
|
||||||
c.LDP(Q14, Q15, X1, HOST_VREGS_OFF + 6 * sizeof(u128));
|
|
||||||
c.RET();
|
|
||||||
|
|
||||||
// Write the post-SVC trampoline address, which will jump back to the guest after restoring its
|
|
||||||
// state.
|
|
||||||
m_trampolines.push_back({c.offset(), module_dest});
|
|
||||||
|
|
||||||
// Host called this location. Save the return address so we can
|
|
||||||
// unwind the stack properly when jumping back.
|
|
||||||
c.MRS(X2, oaknut::SystemReg::TPIDR_EL0);
|
|
||||||
c.LDR(X2, X2, offsetof(NativeExecutionParameters, native_context));
|
|
||||||
c.ADD(X0, X2, offsetof(GuestContext, host_ctx));
|
|
||||||
c.STR(X30, X0, offsetof(HostContext, host_saved_regs) + 11 * sizeof(u64));
|
|
||||||
|
|
||||||
// Reload all guest registers except X30 and PC.
|
|
||||||
// The function also expects 16 bytes of stack already allocated.
|
|
||||||
c.STR(X30, SP, PRE_INDEXED, -16);
|
|
||||||
c.BL(m_load_context);
|
|
||||||
c.LDR(X30, SP, POST_INDEXED, 16);
|
|
||||||
|
|
||||||
// Use X1 as a scratch register to restore X30.
|
|
||||||
c.STR(X1, SP, PRE_INDEXED, -16);
|
|
||||||
c.MRS(X1, oaknut::SystemReg::TPIDR_EL0);
|
|
||||||
c.LDR(X1, X1, offsetof(NativeExecutionParameters, native_context));
|
|
||||||
c.LDR(X30, X1, offsetof(GuestContext, cpu_registers) + sizeof(u64) * 30);
|
|
||||||
c.LDR(X1, SP, POST_INDEXED, 16);
|
|
||||||
|
|
||||||
// Unlock the context.
|
|
||||||
this->UnlockContext();
|
|
||||||
|
|
||||||
// Jump back to the instruction after the emulated SVC.
|
|
||||||
this->BranchToModule(module_dest);
|
|
||||||
|
|
||||||
// Store PC after call.
|
|
||||||
c.l(pc_after_svc);
|
|
||||||
this->WriteModulePc(module_dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Patcher::WriteMrsHandler(ModuleDestLabel module_dest, oaknut::XReg dest_reg,
|
|
||||||
oaknut::SystemReg src_reg) {
|
|
||||||
// Retrieve emulated TLS register from GuestContext.
|
|
||||||
c.MRS(dest_reg, oaknut::SystemReg::TPIDR_EL0);
|
|
||||||
if (src_reg == oaknut::SystemReg::TPIDRRO_EL0) {
|
|
||||||
c.LDR(dest_reg, dest_reg, offsetof(NativeExecutionParameters, tpidrro_el0));
|
|
||||||
} else {
|
|
||||||
c.LDR(dest_reg, dest_reg, offsetof(NativeExecutionParameters, tpidr_el0));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Jump back to the instruction after the emulated MRS.
|
|
||||||
this->BranchToModule(module_dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Patcher::WriteMsrHandler(ModuleDestLabel module_dest, oaknut::XReg src_reg) {
|
|
||||||
const auto scratch_reg = src_reg.index() == 0 ? X1 : X0;
|
|
||||||
c.STR(scratch_reg, SP, PRE_INDEXED, -16);
|
|
||||||
|
|
||||||
// Save guest value to NativeExecutionParameters::tpidr_el0.
|
|
||||||
c.MRS(scratch_reg, oaknut::SystemReg::TPIDR_EL0);
|
|
||||||
c.STR(src_reg, scratch_reg, offsetof(NativeExecutionParameters, tpidr_el0));
|
|
||||||
|
|
||||||
// Restore scratch register.
|
|
||||||
c.LDR(scratch_reg, SP, POST_INDEXED, 16);
|
|
||||||
|
|
||||||
// Jump back to the instruction after the emulated MSR.
|
|
||||||
this->BranchToModule(module_dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Patcher::WriteCntpctHandler(ModuleDestLabel module_dest, oaknut::XReg dest_reg) {
|
|
||||||
static Common::Arm64::NativeClock clock{};
|
|
||||||
const auto factor = clock.GetGuestCNTFRQFactor();
|
|
||||||
const auto raw_factor = Common::BitCast<std::array<u64, 2>>(factor);
|
|
||||||
|
|
||||||
const auto use_x2_x3 = dest_reg.index() == 0 || dest_reg.index() == 1;
|
|
||||||
oaknut::XReg scratch0 = use_x2_x3 ? X2 : X0;
|
|
||||||
oaknut::XReg scratch1 = use_x2_x3 ? X3 : X1;
|
|
||||||
|
|
||||||
oaknut::Label factorlo;
|
|
||||||
oaknut::Label factorhi;
|
|
||||||
|
|
||||||
// Save scratches.
|
|
||||||
c.STP(scratch0, scratch1, SP, PRE_INDEXED, -16);
|
|
||||||
|
|
||||||
// Load counter value.
|
|
||||||
c.MRS(dest_reg, oaknut::SystemReg::CNTVCT_EL0);
|
|
||||||
|
|
||||||
// Load scaling factor.
|
|
||||||
c.LDR(scratch0, factorlo);
|
|
||||||
c.LDR(scratch1, factorhi);
|
|
||||||
|
|
||||||
// Multiply low bits and get result.
|
|
||||||
c.UMULH(scratch0, dest_reg, scratch0);
|
|
||||||
|
|
||||||
// Multiply high bits and add low bit result.
|
|
||||||
c.MADD(dest_reg, dest_reg, scratch1, scratch0);
|
|
||||||
|
|
||||||
// Reload scratches.
|
|
||||||
c.LDP(scratch0, scratch1, SP, POST_INDEXED, 16);
|
|
||||||
|
|
||||||
// Jump back to the instruction after the emulated MRS.
|
|
||||||
this->BranchToModule(module_dest);
|
|
||||||
|
|
||||||
// Scaling factor constant values.
|
|
||||||
c.l(factorlo);
|
|
||||||
c.dx(raw_factor[0]);
|
|
||||||
c.l(factorhi);
|
|
||||||
c.dx(raw_factor[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Patcher::LockContext() {
|
|
||||||
oaknut::Label retry;
|
|
||||||
|
|
||||||
// Save scratches.
|
|
||||||
c.STP(X0, X1, SP, PRE_INDEXED, -16);
|
|
||||||
|
|
||||||
// Reload lock pointer.
|
|
||||||
c.l(retry);
|
|
||||||
c.CLREX();
|
|
||||||
c.MRS(X0, oaknut::SystemReg::TPIDR_EL0);
|
|
||||||
c.ADD(X0, X0, offsetof(NativeExecutionParameters, lock));
|
|
||||||
|
|
||||||
static_assert(SpinLockLocked == 0);
|
|
||||||
|
|
||||||
// Load-linked with acquire ordering.
|
|
||||||
c.LDAXR(W1, X0);
|
|
||||||
|
|
||||||
// If the value was SpinLockLocked, clear monitor and retry.
|
|
||||||
c.CBZ(W1, retry);
|
|
||||||
|
|
||||||
// Store-conditional SpinLockLocked with relaxed ordering.
|
|
||||||
c.STXR(W1, WZR, X0);
|
|
||||||
|
|
||||||
// If we failed to store, retry.
|
|
||||||
c.CBNZ(W1, retry);
|
|
||||||
|
|
||||||
// We succeeded! Reload scratches.
|
|
||||||
c.LDP(X0, X1, SP, POST_INDEXED, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Patcher::UnlockContext() {
|
|
||||||
// Save scratches.
|
|
||||||
c.STP(X0, X1, SP, PRE_INDEXED, -16);
|
|
||||||
|
|
||||||
// Load lock pointer.
|
|
||||||
c.MRS(X0, oaknut::SystemReg::TPIDR_EL0);
|
|
||||||
c.ADD(X0, X0, offsetof(NativeExecutionParameters, lock));
|
|
||||||
|
|
||||||
// Load SpinLockUnlocked.
|
|
||||||
c.MOV(W1, SpinLockUnlocked);
|
|
||||||
|
|
||||||
// Store value with release ordering.
|
|
||||||
c.STLR(W1, X0);
|
|
||||||
|
|
||||||
// Load scratches.
|
|
||||||
c.LDP(X0, X1, SP, POST_INDEXED, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Core::NCE
|
|
@ -1,101 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <span>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Wshorten-64-to-32"
|
|
||||||
#include <oaknut/code_block.hpp>
|
|
||||||
#include <oaknut/oaknut.hpp>
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "core/hle/kernel/code_set.h"
|
|
||||||
#include "core/hle/kernel/k_typed_address.h"
|
|
||||||
#include "core/hle/kernel/physical_memory.h"
|
|
||||||
|
|
||||||
namespace Core::NCE {
|
|
||||||
|
|
||||||
enum class PatchMode : u32 {
|
|
||||||
None,
|
|
||||||
PreText, ///< Patch section is inserted before .text
|
|
||||||
PostData, ///< Patch section is inserted after .data
|
|
||||||
};
|
|
||||||
|
|
||||||
using ModuleTextAddress = u64;
|
|
||||||
using PatchTextAddress = u64;
|
|
||||||
using EntryTrampolines = std::unordered_map<ModuleTextAddress, PatchTextAddress>;
|
|
||||||
|
|
||||||
class Patcher {
|
|
||||||
public:
|
|
||||||
explicit Patcher();
|
|
||||||
~Patcher();
|
|
||||||
|
|
||||||
void PatchText(const Kernel::PhysicalMemory& program_image,
|
|
||||||
const Kernel::CodeSet::Segment& code);
|
|
||||||
void RelocateAndCopy(Common::ProcessAddress load_base, const Kernel::CodeSet::Segment& code,
|
|
||||||
Kernel::PhysicalMemory& program_image, EntryTrampolines* out_trampolines);
|
|
||||||
size_t GetSectionSize() const noexcept;
|
|
||||||
|
|
||||||
[[nodiscard]] PatchMode GetPatchMode() const noexcept {
|
|
||||||
return mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
using ModuleDestLabel = uintptr_t;
|
|
||||||
|
|
||||||
struct Trampoline {
|
|
||||||
ptrdiff_t patch_offset;
|
|
||||||
uintptr_t module_offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
void WriteLoadContext();
|
|
||||||
void WriteSaveContext();
|
|
||||||
void LockContext();
|
|
||||||
void UnlockContext();
|
|
||||||
void WriteSvcTrampoline(ModuleDestLabel module_dest, u32 svc_id);
|
|
||||||
void WriteMrsHandler(ModuleDestLabel module_dest, oaknut::XReg dest_reg,
|
|
||||||
oaknut::SystemReg src_reg);
|
|
||||||
void WriteMsrHandler(ModuleDestLabel module_dest, oaknut::XReg src_reg);
|
|
||||||
void WriteCntpctHandler(ModuleDestLabel module_dest, oaknut::XReg dest_reg);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void BranchToPatch(uintptr_t module_dest) {
|
|
||||||
m_branch_to_patch_relocations.push_back({c.offset(), module_dest});
|
|
||||||
}
|
|
||||||
|
|
||||||
void BranchToModule(uintptr_t module_dest) {
|
|
||||||
m_branch_to_module_relocations.push_back({c.offset(), module_dest});
|
|
||||||
c.dw(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WriteModulePc(uintptr_t module_dest) {
|
|
||||||
m_write_module_pc_relocations.push_back({c.offset(), module_dest});
|
|
||||||
c.dx(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// List of patch instructions we have generated.
|
|
||||||
std::vector<u32> m_patch_instructions{};
|
|
||||||
|
|
||||||
// Relocation type for relative branch from module to patch.
|
|
||||||
struct Relocation {
|
|
||||||
ptrdiff_t patch_offset; ///< Offset in bytes from the start of the patch section.
|
|
||||||
uintptr_t module_offset; ///< Offset in bytes from the start of the text section.
|
|
||||||
};
|
|
||||||
|
|
||||||
oaknut::VectorCodeGenerator c;
|
|
||||||
std::vector<Trampoline> m_trampolines;
|
|
||||||
std::vector<Relocation> m_branch_to_patch_relocations{};
|
|
||||||
std::vector<Relocation> m_branch_to_module_relocations{};
|
|
||||||
std::vector<Relocation> m_write_module_pc_relocations{};
|
|
||||||
oaknut::Label m_save_context{};
|
|
||||||
oaknut::Label m_load_context{};
|
|
||||||
PatchMode mode{PatchMode::None};
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Core::NCE
|
|
@ -211,8 +211,6 @@ void CpuManager::RunThread(std::stop_token token, std::size_t core) {
|
|||||||
system.GPU().ObtainContext();
|
system.GPU().ObtainContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
system.ArmInterface(core).Initialize();
|
|
||||||
|
|
||||||
auto& kernel = system.Kernel();
|
auto& kernel = system.Kernel();
|
||||||
auto& scheduler = *kernel.CurrentScheduler();
|
auto& scheduler = *kernel.CurrentScheduler();
|
||||||
auto* thread = scheduler.GetSchedulerCurrentThread();
|
auto* thread = scheduler.GetSchedulerCurrentThread();
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
#ifdef HAS_NCE
|
#ifdef ANDROID
|
||||||
constexpr size_t VirtualReserveSize = 1ULL << 38;
|
constexpr size_t VirtualReserveSize = 1ULL << 38;
|
||||||
#else
|
#else
|
||||||
constexpr size_t VirtualReserveSize = 1ULL << 39;
|
constexpr size_t VirtualReserveSize = 1ULL << 39;
|
||||||
@ -15,7 +15,6 @@ constexpr size_t VirtualReserveSize = 1ULL << 39;
|
|||||||
DeviceMemory::DeviceMemory()
|
DeviceMemory::DeviceMemory()
|
||||||
: buffer{Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetIntendedMemorySize(),
|
: buffer{Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetIntendedMemorySize(),
|
||||||
VirtualReserveSize} {}
|
VirtualReserveSize} {}
|
||||||
|
|
||||||
DeviceMemory::~DeviceMemory() = default;
|
DeviceMemory::~DeviceMemory() = default;
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
@ -38,6 +38,14 @@ using TouchParams = std::array<Common::ParamPackage, MaxTouchDevices>;
|
|||||||
using ConsoleMotionValues = ConsoleMotionInfo;
|
using ConsoleMotionValues = ConsoleMotionInfo;
|
||||||
using TouchValues = std::array<Common::Input::TouchStatus, MaxTouchDevices>;
|
using TouchValues = std::array<Common::Input::TouchStatus, MaxTouchDevices>;
|
||||||
|
|
||||||
|
struct TouchFinger {
|
||||||
|
u64 last_touch{};
|
||||||
|
Common::Point<float> position{};
|
||||||
|
u32 id{};
|
||||||
|
TouchAttribute attribute{};
|
||||||
|
bool pressed{};
|
||||||
|
};
|
||||||
|
|
||||||
// Contains all motion related data that is used on the services
|
// Contains all motion related data that is used on the services
|
||||||
struct ConsoleMotion {
|
struct ConsoleMotion {
|
||||||
Common::Vec3f accel{};
|
Common::Vec3f accel{};
|
||||||
|
@ -243,12 +243,10 @@ void EmulatedController::LoadTASParams() {
|
|||||||
tas_button_params[Settings::NativeButton::DUp].Set("button", 13);
|
tas_button_params[Settings::NativeButton::DUp].Set("button", 13);
|
||||||
tas_button_params[Settings::NativeButton::DRight].Set("button", 14);
|
tas_button_params[Settings::NativeButton::DRight].Set("button", 14);
|
||||||
tas_button_params[Settings::NativeButton::DDown].Set("button", 15);
|
tas_button_params[Settings::NativeButton::DDown].Set("button", 15);
|
||||||
tas_button_params[Settings::NativeButton::SLLeft].Set("button", 16);
|
tas_button_params[Settings::NativeButton::SL].Set("button", 16);
|
||||||
tas_button_params[Settings::NativeButton::SRLeft].Set("button", 17);
|
tas_button_params[Settings::NativeButton::SR].Set("button", 17);
|
||||||
tas_button_params[Settings::NativeButton::Home].Set("button", 18);
|
tas_button_params[Settings::NativeButton::Home].Set("button", 18);
|
||||||
tas_button_params[Settings::NativeButton::Screenshot].Set("button", 19);
|
tas_button_params[Settings::NativeButton::Screenshot].Set("button", 19);
|
||||||
tas_button_params[Settings::NativeButton::SLRight].Set("button", 20);
|
|
||||||
tas_button_params[Settings::NativeButton::SRRight].Set("button", 21);
|
|
||||||
|
|
||||||
tas_stick_params[Settings::NativeAnalog::LStick].Set("axis_x", 0);
|
tas_stick_params[Settings::NativeAnalog::LStick].Set("axis_x", 0);
|
||||||
tas_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1);
|
tas_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1);
|
||||||
@ -298,12 +296,10 @@ void EmulatedController::LoadVirtualGamepadParams() {
|
|||||||
virtual_button_params[Settings::NativeButton::DUp].Set("button", 13);
|
virtual_button_params[Settings::NativeButton::DUp].Set("button", 13);
|
||||||
virtual_button_params[Settings::NativeButton::DRight].Set("button", 14);
|
virtual_button_params[Settings::NativeButton::DRight].Set("button", 14);
|
||||||
virtual_button_params[Settings::NativeButton::DDown].Set("button", 15);
|
virtual_button_params[Settings::NativeButton::DDown].Set("button", 15);
|
||||||
virtual_button_params[Settings::NativeButton::SLLeft].Set("button", 16);
|
virtual_button_params[Settings::NativeButton::SL].Set("button", 16);
|
||||||
virtual_button_params[Settings::NativeButton::SRLeft].Set("button", 17);
|
virtual_button_params[Settings::NativeButton::SR].Set("button", 17);
|
||||||
virtual_button_params[Settings::NativeButton::Home].Set("button", 18);
|
virtual_button_params[Settings::NativeButton::Home].Set("button", 18);
|
||||||
virtual_button_params[Settings::NativeButton::Screenshot].Set("button", 19);
|
virtual_button_params[Settings::NativeButton::Screenshot].Set("button", 19);
|
||||||
virtual_button_params[Settings::NativeButton::SLRight].Set("button", 20);
|
|
||||||
virtual_button_params[Settings::NativeButton::SRRight].Set("button", 21);
|
|
||||||
|
|
||||||
virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_x", 0);
|
virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_x", 0);
|
||||||
virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1);
|
virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1);
|
||||||
@ -871,16 +867,12 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
|
|||||||
controller.npad_button_state.down.Assign(current_status.value);
|
controller.npad_button_state.down.Assign(current_status.value);
|
||||||
controller.debug_pad_button_state.d_down.Assign(current_status.value);
|
controller.debug_pad_button_state.d_down.Assign(current_status.value);
|
||||||
break;
|
break;
|
||||||
case Settings::NativeButton::SLLeft:
|
case Settings::NativeButton::SL:
|
||||||
controller.npad_button_state.left_sl.Assign(current_status.value);
|
controller.npad_button_state.left_sl.Assign(current_status.value);
|
||||||
break;
|
|
||||||
case Settings::NativeButton::SLRight:
|
|
||||||
controller.npad_button_state.right_sl.Assign(current_status.value);
|
controller.npad_button_state.right_sl.Assign(current_status.value);
|
||||||
break;
|
break;
|
||||||
case Settings::NativeButton::SRLeft:
|
case Settings::NativeButton::SR:
|
||||||
controller.npad_button_state.left_sr.Assign(current_status.value);
|
controller.npad_button_state.left_sr.Assign(current_status.value);
|
||||||
break;
|
|
||||||
case Settings::NativeButton::SRRight:
|
|
||||||
controller.npad_button_state.right_sr.Assign(current_status.value);
|
controller.npad_button_state.right_sr.Assign(current_status.value);
|
||||||
break;
|
break;
|
||||||
case Settings::NativeButton::Home:
|
case Settings::NativeButton::Home:
|
||||||
@ -1898,16 +1890,12 @@ NpadButton EmulatedController::GetTurboButtonMask() const {
|
|||||||
case Settings::NativeButton::DDown:
|
case Settings::NativeButton::DDown:
|
||||||
button_mask.down.Assign(1);
|
button_mask.down.Assign(1);
|
||||||
break;
|
break;
|
||||||
case Settings::NativeButton::SLLeft:
|
case Settings::NativeButton::SL:
|
||||||
button_mask.left_sl.Assign(1);
|
button_mask.left_sl.Assign(1);
|
||||||
break;
|
|
||||||
case Settings::NativeButton::SLRight:
|
|
||||||
button_mask.right_sl.Assign(1);
|
button_mask.right_sl.Assign(1);
|
||||||
break;
|
break;
|
||||||
case Settings::NativeButton::SRLeft:
|
case Settings::NativeButton::SR:
|
||||||
button_mask.left_sr.Assign(1);
|
button_mask.left_sr.Assign(1);
|
||||||
break;
|
|
||||||
case Settings::NativeButton::SRRight:
|
|
||||||
button_mask.right_sr.Assign(1);
|
button_mask.right_sr.Assign(1);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -218,13 +218,6 @@ enum class NpadIdType : u32 {
|
|||||||
Invalid = 0xFFFFFFFF,
|
Invalid = 0xFFFFFFFF,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class NpadInterfaceType : u8 {
|
|
||||||
Bluetooth = 1,
|
|
||||||
Rail = 2,
|
|
||||||
Usb = 3,
|
|
||||||
Embedded = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is nn::hid::NpadStyleIndex
|
// This is nn::hid::NpadStyleIndex
|
||||||
enum class NpadStyleIndex : u8 {
|
enum class NpadStyleIndex : u8 {
|
||||||
None = 0,
|
None = 0,
|
||||||
@ -363,14 +356,6 @@ struct TouchState {
|
|||||||
};
|
};
|
||||||
static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size");
|
static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size");
|
||||||
|
|
||||||
struct TouchFinger {
|
|
||||||
u64 last_touch{};
|
|
||||||
Common::Point<float> position{};
|
|
||||||
u32 id{};
|
|
||||||
TouchAttribute attribute{};
|
|
||||||
bool pressed{};
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is nn::hid::TouchScreenConfigurationForNx
|
// This is nn::hid::TouchScreenConfigurationForNx
|
||||||
struct TouchScreenConfigurationForNx {
|
struct TouchScreenConfigurationForNx {
|
||||||
TouchScreenModeForNx mode{TouchScreenModeForNx::UseSystemSetting};
|
TouchScreenModeForNx mode{TouchScreenModeForNx::UseSystemSetting};
|
||||||
|
@ -5,14 +5,13 @@
|
|||||||
#include "core/hid/hid_types.h"
|
#include "core/hid/hid_types.h"
|
||||||
#include "core/hid/input_interpreter.h"
|
#include "core/hid/input_interpreter.h"
|
||||||
#include "core/hle/service/hid/controllers/npad.h"
|
#include "core/hle/service/hid/controllers/npad.h"
|
||||||
#include "core/hle/service/hid/hid_server.h"
|
#include "core/hle/service/hid/hid.h"
|
||||||
#include "core/hle/service/hid/resource_manager.h"
|
|
||||||
#include "core/hle/service/sm/sm.h"
|
#include "core/hle/service/sm/sm.h"
|
||||||
|
|
||||||
InputInterpreter::InputInterpreter(Core::System& system)
|
InputInterpreter::InputInterpreter(Core::System& system)
|
||||||
: npad{system.ServiceManager()
|
: npad{system.ServiceManager()
|
||||||
.GetService<Service::HID::IHidServer>("hid")
|
.GetService<Service::HID::Hid>("hid")
|
||||||
->GetResourceManager()
|
->GetAppletResource()
|
||||||
->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} {
|
->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} {
|
||||||
ResetButtonStates();
|
ResetButtonStates();
|
||||||
}
|
}
|
||||||
|
@ -75,26 +75,12 @@ struct CodeSet final {
|
|||||||
return segments[2];
|
return segments[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAS_NCE
|
|
||||||
Segment& PatchSegment() {
|
|
||||||
return patch_segment;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Segment& PatchSegment() const {
|
|
||||||
return patch_segment;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// The overall data that backs this code set.
|
/// The overall data that backs this code set.
|
||||||
Kernel::PhysicalMemory memory;
|
Kernel::PhysicalMemory memory;
|
||||||
|
|
||||||
/// The segments that comprise this code set.
|
/// The segments that comprise this code set.
|
||||||
std::array<Segment, 3> segments;
|
std::array<Segment, 3> segments;
|
||||||
|
|
||||||
#ifdef HAS_NCE
|
|
||||||
Segment patch_segment;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// The entry point address for this code set.
|
/// The entry point address for this code set.
|
||||||
KProcessAddress entrypoint = 0;
|
KProcessAddress entrypoint = 0;
|
||||||
};
|
};
|
||||||
|
@ -25,8 +25,8 @@ constexpr std::array<KAddressSpaceInfo, 13> AddressSpaceInfos{{
|
|||||||
{ .bit_width = 36, .address = 2_GiB , .size = 64_GiB - 2_GiB , .type = KAddressSpaceInfo::Type::MapLarge, },
|
{ .bit_width = 36, .address = 2_GiB , .size = 64_GiB - 2_GiB , .type = KAddressSpaceInfo::Type::MapLarge, },
|
||||||
{ .bit_width = 36, .address = Size_Invalid, .size = 8_GiB , .type = KAddressSpaceInfo::Type::Heap, },
|
{ .bit_width = 36, .address = Size_Invalid, .size = 8_GiB , .type = KAddressSpaceInfo::Type::Heap, },
|
||||||
{ .bit_width = 36, .address = Size_Invalid, .size = 6_GiB , .type = KAddressSpaceInfo::Type::Alias, },
|
{ .bit_width = 36, .address = Size_Invalid, .size = 6_GiB , .type = KAddressSpaceInfo::Type::Alias, },
|
||||||
#ifdef HAS_NCE
|
#ifdef ANDROID
|
||||||
// With NCE, we use a 38-bit address space due to memory limitations. This should (safely) truncate ASLR region.
|
// With Android, we use a 38-bit address space due to memory limitations. This should (safely) truncate ASLR region.
|
||||||
{ .bit_width = 39, .address = 128_MiB , .size = 256_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::Map39Bit, },
|
{ .bit_width = 39, .address = 128_MiB , .size = 256_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::Map39Bit, },
|
||||||
#else
|
#else
|
||||||
{ .bit_width = 39, .address = 128_MiB , .size = 512_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::Map39Bit, },
|
{ .bit_width = 39, .address = 128_MiB , .size = 512_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::Map39Bit, },
|
||||||
|
@ -88,22 +88,6 @@ Result FlushDataCache(AddressType addr, u64 size) {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr Common::MemoryPermission ConvertToMemoryPermission(KMemoryPermission perm) {
|
|
||||||
Common::MemoryPermission perms{};
|
|
||||||
if (True(perm & KMemoryPermission::UserRead)) {
|
|
||||||
perms |= Common::MemoryPermission::Read;
|
|
||||||
}
|
|
||||||
if (True(perm & KMemoryPermission::UserWrite)) {
|
|
||||||
perms |= Common::MemoryPermission::Write;
|
|
||||||
}
|
|
||||||
#ifdef HAS_NCE
|
|
||||||
if (True(perm & KMemoryPermission::UserExecute)) {
|
|
||||||
perms |= Common::MemoryPermission::Execute;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return perms;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void KPageTableBase::MemoryRange::Open() {
|
void KPageTableBase::MemoryRange::Open() {
|
||||||
@ -186,8 +170,7 @@ Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool
|
|||||||
KMemoryManager::Pool pool, KProcessAddress code_address,
|
KMemoryManager::Pool pool, KProcessAddress code_address,
|
||||||
size_t code_size, KSystemResource* system_resource,
|
size_t code_size, KSystemResource* system_resource,
|
||||||
KResourceLimit* resource_limit,
|
KResourceLimit* resource_limit,
|
||||||
Core::Memory::Memory& memory,
|
Core::Memory::Memory& memory) {
|
||||||
KProcessAddress aslr_space_start) {
|
|
||||||
// Calculate region extents.
|
// Calculate region extents.
|
||||||
const size_t as_width = GetAddressSpaceWidth(as_type);
|
const size_t as_width = GetAddressSpaceWidth(as_type);
|
||||||
const KProcessAddress start = 0;
|
const KProcessAddress start = 0;
|
||||||
@ -228,8 +211,7 @@ Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool
|
|||||||
heap_region_size = GetSpaceSize(KAddressSpaceInfo::Type::Heap);
|
heap_region_size = GetSpaceSize(KAddressSpaceInfo::Type::Heap);
|
||||||
stack_region_size = GetSpaceSize(KAddressSpaceInfo::Type::Stack);
|
stack_region_size = GetSpaceSize(KAddressSpaceInfo::Type::Stack);
|
||||||
kernel_map_region_size = GetSpaceSize(KAddressSpaceInfo::Type::MapSmall);
|
kernel_map_region_size = GetSpaceSize(KAddressSpaceInfo::Type::MapSmall);
|
||||||
m_code_region_start = m_address_space_start + aslr_space_start +
|
m_code_region_start = GetSpaceStart(KAddressSpaceInfo::Type::Map39Bit);
|
||||||
GetSpaceStart(KAddressSpaceInfo::Type::Map39Bit);
|
|
||||||
m_code_region_end = m_code_region_start + GetSpaceSize(KAddressSpaceInfo::Type::Map39Bit);
|
m_code_region_end = m_code_region_start + GetSpaceSize(KAddressSpaceInfo::Type::Map39Bit);
|
||||||
m_alias_code_region_start = m_code_region_start;
|
m_alias_code_region_start = m_code_region_start;
|
||||||
m_alias_code_region_end = m_code_region_end;
|
m_alias_code_region_end = m_code_region_end;
|
||||||
@ -5661,8 +5643,7 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
|
|||||||
case OperationType::Map: {
|
case OperationType::Map: {
|
||||||
ASSERT(virt_addr != 0);
|
ASSERT(virt_addr != 0);
|
||||||
ASSERT(Common::IsAligned(GetInteger(virt_addr), PageSize));
|
ASSERT(Common::IsAligned(GetInteger(virt_addr), PageSize));
|
||||||
m_memory->MapMemoryRegion(*m_impl, virt_addr, num_pages * PageSize, phys_addr,
|
m_memory->MapMemoryRegion(*m_impl, virt_addr, num_pages * PageSize, phys_addr);
|
||||||
ConvertToMemoryPermission(properties.perm));
|
|
||||||
|
|
||||||
// Open references to pages, if we should.
|
// Open references to pages, if we should.
|
||||||
if (this->IsHeapPhysicalAddress(phys_addr)) {
|
if (this->IsHeapPhysicalAddress(phys_addr)) {
|
||||||
@ -5677,18 +5658,8 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
|
|||||||
}
|
}
|
||||||
case OperationType::ChangePermissions:
|
case OperationType::ChangePermissions:
|
||||||
case OperationType::ChangePermissionsAndRefresh:
|
case OperationType::ChangePermissionsAndRefresh:
|
||||||
case OperationType::ChangePermissionsAndRefreshAndFlush: {
|
case OperationType::ChangePermissionsAndRefreshAndFlush:
|
||||||
const bool read = True(properties.perm & Kernel::KMemoryPermission::UserRead);
|
|
||||||
const bool write = True(properties.perm & Kernel::KMemoryPermission::UserWrite);
|
|
||||||
// todo: this doesn't really belong here and should go into m_memory to handle rasterizer
|
|
||||||
// access todo: ignore exec on non-direct-mapped case
|
|
||||||
const bool exec = True(properties.perm & Kernel::KMemoryPermission::UserExecute);
|
|
||||||
if (Settings::IsFastmemEnabled()) {
|
|
||||||
m_system.DeviceMemory().buffer.Protect(GetInteger(virt_addr), num_pages * PageSize,
|
|
||||||
read, write, exec);
|
|
||||||
}
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
@ -5716,8 +5687,7 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
|
|||||||
const size_t size{node.GetNumPages() * PageSize};
|
const size_t size{node.GetNumPages() * PageSize};
|
||||||
|
|
||||||
// Map the pages.
|
// Map the pages.
|
||||||
m_memory->MapMemoryRegion(*m_impl, virt_addr, size, node.GetAddress(),
|
m_memory->MapMemoryRegion(*m_impl, virt_addr, size, node.GetAddress());
|
||||||
ConvertToMemoryPermission(properties.perm));
|
|
||||||
|
|
||||||
virt_addr += size;
|
virt_addr += size;
|
||||||
}
|
}
|
||||||
|
@ -235,8 +235,7 @@ public:
|
|||||||
bool enable_device_address_space_merge, bool from_back,
|
bool enable_device_address_space_merge, bool from_back,
|
||||||
KMemoryManager::Pool pool, KProcessAddress code_address,
|
KMemoryManager::Pool pool, KProcessAddress code_address,
|
||||||
size_t code_size, KSystemResource* system_resource,
|
size_t code_size, KSystemResource* system_resource,
|
||||||
KResourceLimit* resource_limit, Core::Memory::Memory& memory,
|
KResourceLimit* resource_limit, Core::Memory::Memory& memory);
|
||||||
KProcessAddress aslr_space_start);
|
|
||||||
|
|
||||||
void Finalize();
|
void Finalize();
|
||||||
|
|
||||||
|
@ -300,7 +300,7 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params, const KPa
|
|||||||
False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge);
|
False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge);
|
||||||
R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool,
|
R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool,
|
||||||
params.code_address, params.code_num_pages * PageSize,
|
params.code_address, params.code_num_pages * PageSize,
|
||||||
m_system_resource, res_limit, this->GetMemory(), 0));
|
m_system_resource, res_limit, this->GetMemory()));
|
||||||
}
|
}
|
||||||
ON_RESULT_FAILURE_2 {
|
ON_RESULT_FAILURE_2 {
|
||||||
m_page_table.Finalize();
|
m_page_table.Finalize();
|
||||||
@ -332,7 +332,7 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params, const KPa
|
|||||||
|
|
||||||
Result KProcess::Initialize(const Svc::CreateProcessParameter& params,
|
Result KProcess::Initialize(const Svc::CreateProcessParameter& params,
|
||||||
std::span<const u32> user_caps, KResourceLimit* res_limit,
|
std::span<const u32> user_caps, KResourceLimit* res_limit,
|
||||||
KMemoryManager::Pool pool, KProcessAddress aslr_space_start) {
|
KMemoryManager::Pool pool) {
|
||||||
ASSERT(res_limit != nullptr);
|
ASSERT(res_limit != nullptr);
|
||||||
|
|
||||||
// Set members.
|
// Set members.
|
||||||
@ -393,7 +393,7 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params,
|
|||||||
False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge);
|
False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge);
|
||||||
R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool,
|
R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool,
|
||||||
params.code_address, code_size, m_system_resource, res_limit,
|
params.code_address, code_size, m_system_resource, res_limit,
|
||||||
this->GetMemory(), aslr_space_start));
|
this->GetMemory()));
|
||||||
}
|
}
|
||||||
ON_RESULT_FAILURE_2 {
|
ON_RESULT_FAILURE_2 {
|
||||||
m_page_table.Finalize();
|
m_page_table.Finalize();
|
||||||
@ -1128,7 +1128,7 @@ KProcess::KProcess(KernelCore& kernel)
|
|||||||
KProcess::~KProcess() = default;
|
KProcess::~KProcess() = default;
|
||||||
|
|
||||||
Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size,
|
Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size,
|
||||||
KProcessAddress aslr_space_start, bool is_hbl) {
|
bool is_hbl) {
|
||||||
// Create a resource limit for the process.
|
// Create a resource limit for the process.
|
||||||
const auto physical_memory_size =
|
const auto physical_memory_size =
|
||||||
m_kernel.MemoryManager().GetSize(Kernel::KMemoryManager::Pool::Application);
|
m_kernel.MemoryManager().GetSize(Kernel::KMemoryManager::Pool::Application);
|
||||||
@ -1179,7 +1179,7 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
|
|||||||
.name = {},
|
.name = {},
|
||||||
.version = {},
|
.version = {},
|
||||||
.program_id = metadata.GetTitleID(),
|
.program_id = metadata.GetTitleID(),
|
||||||
.code_address = code_address + GetInteger(aslr_space_start),
|
.code_address = code_address,
|
||||||
.code_num_pages = static_cast<s32>(code_size / PageSize),
|
.code_num_pages = static_cast<s32>(code_size / PageSize),
|
||||||
.flags = flag,
|
.flags = flag,
|
||||||
.reslimit = Svc::InvalidHandle,
|
.reslimit = Svc::InvalidHandle,
|
||||||
@ -1193,7 +1193,7 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
|
|||||||
|
|
||||||
// Initialize for application process.
|
// Initialize for application process.
|
||||||
R_TRY(this->Initialize(params, metadata.GetKernelCapabilities(), res_limit,
|
R_TRY(this->Initialize(params, metadata.GetKernelCapabilities(), res_limit,
|
||||||
KMemoryManager::Pool::Application, aslr_space_start));
|
KMemoryManager::Pool::Application));
|
||||||
|
|
||||||
// Assign remaining properties.
|
// Assign remaining properties.
|
||||||
m_is_hbl = is_hbl;
|
m_is_hbl = is_hbl;
|
||||||
@ -1214,17 +1214,6 @@ void KProcess::LoadModule(CodeSet code_set, KProcessAddress base_addr) {
|
|||||||
ReprotectSegment(code_set.CodeSegment(), Svc::MemoryPermission::ReadExecute);
|
ReprotectSegment(code_set.CodeSegment(), Svc::MemoryPermission::ReadExecute);
|
||||||
ReprotectSegment(code_set.RODataSegment(), Svc::MemoryPermission::Read);
|
ReprotectSegment(code_set.RODataSegment(), Svc::MemoryPermission::Read);
|
||||||
ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite);
|
ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite);
|
||||||
|
|
||||||
#ifdef ARCHITECTURE_arm64
|
|
||||||
if (Settings::IsNceEnabled()) {
|
|
||||||
auto& buffer = m_kernel.System().DeviceMemory().buffer;
|
|
||||||
const auto& code = code_set.CodeSegment();
|
|
||||||
const auto& patch = code_set.PatchSegment();
|
|
||||||
buffer.Protect(GetInteger(base_addr + code.addr), code.size, true, true, true);
|
|
||||||
buffer.Protect(GetInteger(base_addr + patch.addr), patch.size, true, true, true);
|
|
||||||
ReprotectSegment(code_set.PatchSegment(), Svc::MemoryPermission::None);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KProcess::InsertWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type) {
|
bool KProcess::InsertWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type) {
|
||||||
|
@ -120,9 +120,6 @@ private:
|
|||||||
std::atomic<s64> m_num_ipc_messages{};
|
std::atomic<s64> m_num_ipc_messages{};
|
||||||
std::atomic<s64> m_num_ipc_replies{};
|
std::atomic<s64> m_num_ipc_replies{};
|
||||||
std::atomic<s64> m_num_ipc_receives{};
|
std::atomic<s64> m_num_ipc_receives{};
|
||||||
#ifdef HAS_NCE
|
|
||||||
std::unordered_map<u64, u64> m_post_handlers{};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Result StartTermination();
|
Result StartTermination();
|
||||||
@ -153,8 +150,7 @@ public:
|
|||||||
std::span<const u32> caps, KResourceLimit* res_limit,
|
std::span<const u32> caps, KResourceLimit* res_limit,
|
||||||
KMemoryManager::Pool pool, bool immortal);
|
KMemoryManager::Pool pool, bool immortal);
|
||||||
Result Initialize(const Svc::CreateProcessParameter& params, std::span<const u32> user_caps,
|
Result Initialize(const Svc::CreateProcessParameter& params, std::span<const u32> user_caps,
|
||||||
KResourceLimit* res_limit, KMemoryManager::Pool pool,
|
KResourceLimit* res_limit, KMemoryManager::Pool pool);
|
||||||
KProcessAddress aslr_space_start);
|
|
||||||
void Exit();
|
void Exit();
|
||||||
|
|
||||||
const char* GetName() const {
|
const char* GetName() const {
|
||||||
@ -470,12 +466,6 @@ public:
|
|||||||
|
|
||||||
static void Switch(KProcess* cur_process, KProcess* next_process);
|
static void Switch(KProcess* cur_process, KProcess* next_process);
|
||||||
|
|
||||||
#ifdef HAS_NCE
|
|
||||||
std::unordered_map<u64, u64>& GetPostHandlers() noexcept {
|
|
||||||
return m_post_handlers;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Attempts to insert a watchpoint into a free slot. Returns false if none are available.
|
// Attempts to insert a watchpoint into a free slot. Returns false if none are available.
|
||||||
bool InsertWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type);
|
bool InsertWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type);
|
||||||
@ -489,7 +479,7 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Result LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size,
|
Result LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size,
|
||||||
KProcessAddress aslr_space_start, bool is_hbl);
|
bool is_hbl);
|
||||||
|
|
||||||
void LoadModule(CodeSet code_set, KProcessAddress base_addr);
|
void LoadModule(CodeSet code_set, KProcessAddress base_addr);
|
||||||
|
|
||||||
|
@ -23,11 +23,10 @@ public:
|
|||||||
Result Initialize(Svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge,
|
Result Initialize(Svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge,
|
||||||
bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address,
|
bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address,
|
||||||
size_t code_size, KSystemResource* system_resource,
|
size_t code_size, KSystemResource* system_resource,
|
||||||
KResourceLimit* resource_limit, Core::Memory::Memory& memory,
|
KResourceLimit* resource_limit, Core::Memory::Memory& memory) {
|
||||||
KProcessAddress aslr_space_start) {
|
R_RETURN(m_page_table.InitializeForProcess(as_type, enable_aslr, enable_das_merge,
|
||||||
R_RETURN(m_page_table.InitializeForProcess(
|
from_back, pool, code_address, code_size,
|
||||||
as_type, enable_aslr, enable_das_merge, from_back, pool, code_address, code_size,
|
system_resource, resource_limit, memory));
|
||||||
system_resource, resource_limit, memory, aslr_space_start));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Finalize() {
|
void Finalize() {
|
||||||
|
@ -655,21 +655,6 @@ public:
|
|||||||
return m_stack_top;
|
return m_stack_top;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
// TODO: This shouldn't be defined in kernel namespace
|
|
||||||
struct NativeExecutionParameters {
|
|
||||||
u64 tpidr_el0{};
|
|
||||||
u64 tpidrro_el0{};
|
|
||||||
void* native_context{};
|
|
||||||
std::atomic<u32> lock{1};
|
|
||||||
bool is_running{};
|
|
||||||
u32 magic{Common::MakeMagic('Y', 'U', 'Z', 'U')};
|
|
||||||
};
|
|
||||||
|
|
||||||
NativeExecutionParameters& GetNativeExecutionParameters() {
|
|
||||||
return m_native_execution_parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
KThread* RemoveWaiterByKey(bool* out_has_waiters, KProcessAddress key,
|
KThread* RemoveWaiterByKey(bool* out_has_waiters, KProcessAddress key,
|
||||||
bool is_kernel_address_key);
|
bool is_kernel_address_key);
|
||||||
@ -929,7 +914,6 @@ private:
|
|||||||
ThreadWaitReasonForDebugging m_wait_reason_for_debugging{};
|
ThreadWaitReasonForDebugging m_wait_reason_for_debugging{};
|
||||||
uintptr_t m_argument{};
|
uintptr_t m_argument{};
|
||||||
KProcessAddress m_stack_top{};
|
KProcessAddress m_stack_top{};
|
||||||
NativeExecutionParameters m_native_execution_parameters{};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using ConditionVariableThreadTreeType = ConditionVariableThreadTree;
|
using ConditionVariableThreadTreeType = ConditionVariableThreadTree;
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "common/settings.h"
|
|
||||||
#include "core/arm/dynarmic/arm_dynarmic_32.h"
|
#include "core/arm/dynarmic/arm_dynarmic_32.h"
|
||||||
#include "core/arm/dynarmic/arm_dynarmic_64.h"
|
#include "core/arm/dynarmic/arm_dynarmic_64.h"
|
||||||
#ifdef HAS_NCE
|
|
||||||
#include "core/arm/nce/arm_nce.h"
|
|
||||||
#endif
|
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
@ -18,8 +14,7 @@ PhysicalCore::PhysicalCore(std::size_t core_index, Core::System& system, KSchedu
|
|||||||
: m_core_index{core_index}, m_system{system}, m_scheduler{scheduler} {
|
: m_core_index{core_index}, m_system{system}, m_scheduler{scheduler} {
|
||||||
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
|
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
|
||||||
// TODO(bunnei): Initialization relies on a core being available. We may later replace this with
|
// TODO(bunnei): Initialization relies on a core being available. We may later replace this with
|
||||||
// an NCE interface or a 32-bit instance of Dynarmic. This should be abstracted out to a CPU
|
// a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager.
|
||||||
// manager.
|
|
||||||
auto& kernel = system.Kernel();
|
auto& kernel = system.Kernel();
|
||||||
m_arm_interface = std::make_unique<Core::ARM_Dynarmic_64>(
|
m_arm_interface = std::make_unique<Core::ARM_Dynarmic_64>(
|
||||||
system, kernel.IsMulticore(),
|
system, kernel.IsMulticore(),
|
||||||
@ -33,13 +28,6 @@ PhysicalCore::PhysicalCore(std::size_t core_index, Core::System& system, KSchedu
|
|||||||
PhysicalCore::~PhysicalCore() = default;
|
PhysicalCore::~PhysicalCore() = default;
|
||||||
|
|
||||||
void PhysicalCore::Initialize(bool is_64_bit) {
|
void PhysicalCore::Initialize(bool is_64_bit) {
|
||||||
#if defined(HAS_NCE)
|
|
||||||
if (Settings::IsNceEnabled()) {
|
|
||||||
m_arm_interface = std::make_unique<Core::ARM_NCE>(m_system, m_system.Kernel().IsMulticore(),
|
|
||||||
m_core_index);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
|
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
|
||||||
auto& kernel = m_system.Kernel();
|
auto& kernel = m_system.Kernel();
|
||||||
if (!is_64_bit) {
|
if (!is_64_bit) {
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
#include "core/file_sys/patch_manager.h"
|
#include "core/file_sys/patch_manager.h"
|
||||||
#include "core/file_sys/registered_cache.h"
|
#include "core/file_sys/registered_cache.h"
|
||||||
#include "core/file_sys/savedata_factory.h"
|
#include "core/file_sys/savedata_factory.h"
|
||||||
#include "core/hid/hid_types.h"
|
|
||||||
#include "core/hle/kernel/k_event.h"
|
#include "core/hle/kernel/k_event.h"
|
||||||
#include "core/hle/kernel/k_transfer_memory.h"
|
#include "core/hle/kernel/k_transfer_memory.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
@ -22,7 +21,6 @@
|
|||||||
#include "core/hle/service/am/applet_ae.h"
|
#include "core/hle/service/am/applet_ae.h"
|
||||||
#include "core/hle/service/am/applet_oe.h"
|
#include "core/hle/service/am/applet_oe.h"
|
||||||
#include "core/hle/service/am/applets/applet_cabinet.h"
|
#include "core/hle/service/am/applets/applet_cabinet.h"
|
||||||
#include "core/hle/service/am/applets/applet_controller.h"
|
|
||||||
#include "core/hle/service/am/applets/applet_mii_edit_types.h"
|
#include "core/hle/service/am/applets/applet_mii_edit_types.h"
|
||||||
#include "core/hle/service/am/applets/applet_profile_select.h"
|
#include "core/hle/service/am/applets/applet_profile_select.h"
|
||||||
#include "core/hle/service/am/applets/applet_software_keyboard_types.h"
|
#include "core/hle/service/am/applets/applet_software_keyboard_types.h"
|
||||||
@ -37,7 +35,6 @@
|
|||||||
#include "core/hle/service/caps/caps_su.h"
|
#include "core/hle/service/caps/caps_su.h"
|
||||||
#include "core/hle/service/caps/caps_types.h"
|
#include "core/hle/service/caps/caps_types.h"
|
||||||
#include "core/hle/service/filesystem/filesystem.h"
|
#include "core/hle/service/filesystem/filesystem.h"
|
||||||
#include "core/hle/service/hid/controllers/npad.h"
|
|
||||||
#include "core/hle/service/ipc_helpers.h"
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
#include "core/hle/service/ns/ns.h"
|
#include "core/hle/service/ns/ns.h"
|
||||||
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
|
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
|
||||||
@ -76,7 +73,7 @@ IWindowController::IWindowController(Core::System& system_)
|
|||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, nullptr, "CreateWindow"},
|
{0, nullptr, "CreateWindow"},
|
||||||
{1, &IWindowController::GetAppletResourceUserId, "GetAppletResourceUserId"},
|
{1, &IWindowController::GetAppletResourceUserId, "GetAppletResourceUserId"},
|
||||||
{2, &IWindowController::GetAppletResourceUserIdOfCallerApplet, "GetAppletResourceUserIdOfCallerApplet"},
|
{2, nullptr, "GetAppletResourceUserIdOfCallerApplet"},
|
||||||
{10, &IWindowController::AcquireForegroundRights, "AcquireForegroundRights"},
|
{10, &IWindowController::AcquireForegroundRights, "AcquireForegroundRights"},
|
||||||
{11, nullptr, "ReleaseForegroundRights"},
|
{11, nullptr, "ReleaseForegroundRights"},
|
||||||
{12, nullptr, "RejectToChangeIntoBackground"},
|
{12, nullptr, "RejectToChangeIntoBackground"},
|
||||||
@ -100,16 +97,6 @@ void IWindowController::GetAppletResourceUserId(HLERequestContext& ctx) {
|
|||||||
rb.Push<u64>(process_id);
|
rb.Push<u64>(process_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IWindowController::GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx) {
|
|
||||||
const u64 process_id = 0;
|
|
||||||
|
|
||||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.Push<u64>(process_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IWindowController::AcquireForegroundRights(HLERequestContext& ctx) {
|
void IWindowController::AcquireForegroundRights(HLERequestContext& ctx) {
|
||||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
@ -1578,7 +1565,7 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_)
|
|||||||
{6, nullptr, "GetPopInteractiveInDataEvent"},
|
{6, nullptr, "GetPopInteractiveInDataEvent"},
|
||||||
{10, &ILibraryAppletSelfAccessor::ExitProcessAndReturn, "ExitProcessAndReturn"},
|
{10, &ILibraryAppletSelfAccessor::ExitProcessAndReturn, "ExitProcessAndReturn"},
|
||||||
{11, &ILibraryAppletSelfAccessor::GetLibraryAppletInfo, "GetLibraryAppletInfo"},
|
{11, &ILibraryAppletSelfAccessor::GetLibraryAppletInfo, "GetLibraryAppletInfo"},
|
||||||
{12, &ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo, "GetMainAppletIdentityInfo"},
|
{12, nullptr, "GetMainAppletIdentityInfo"},
|
||||||
{13, nullptr, "CanUseApplicationCore"},
|
{13, nullptr, "CanUseApplicationCore"},
|
||||||
{14, &ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo, "GetCallerAppletIdentityInfo"},
|
{14, &ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo, "GetCallerAppletIdentityInfo"},
|
||||||
{15, nullptr, "GetMainAppletApplicationControlProperty"},
|
{15, nullptr, "GetMainAppletApplicationControlProperty"},
|
||||||
@ -1622,9 +1609,6 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_)
|
|||||||
case Applets::AppletId::SoftwareKeyboard:
|
case Applets::AppletId::SoftwareKeyboard:
|
||||||
PushInShowSoftwareKeyboard();
|
PushInShowSoftwareKeyboard();
|
||||||
break;
|
break;
|
||||||
case Applets::AppletId::Controller:
|
|
||||||
PushInShowController();
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1682,33 +1666,13 @@ void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) {
|
|||||||
rb.PushRaw(applet_info);
|
rb.PushRaw(applet_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ctx) {
|
|
||||||
struct AppletIdentityInfo {
|
|
||||||
Applets::AppletId applet_id;
|
|
||||||
INSERT_PADDING_BYTES(0x4);
|
|
||||||
u64 application_id;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size.");
|
|
||||||
|
|
||||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
|
||||||
|
|
||||||
const AppletIdentityInfo applet_info{
|
|
||||||
.applet_id = Applets::AppletId::QLaunch,
|
|
||||||
.application_id = 0x0100000000001000ull,
|
|
||||||
};
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 6};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushRaw(applet_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) {
|
void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) {
|
||||||
struct AppletIdentityInfo {
|
struct AppletIdentityInfo {
|
||||||
Applets::AppletId applet_id;
|
Applets::AppletId applet_id;
|
||||||
INSERT_PADDING_BYTES(0x4);
|
INSERT_PADDING_BYTES(0x4);
|
||||||
u64 application_id;
|
u64 application_id;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size.");
|
|
||||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||||
|
|
||||||
const AppletIdentityInfo applet_info{
|
const AppletIdentityInfo applet_info{
|
||||||
@ -1773,55 +1737,6 @@ void ILibraryAppletSelfAccessor::PushInShowAlbum() {
|
|||||||
queue_data.emplace_back(std::move(settings_data));
|
queue_data.emplace_back(std::move(settings_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ILibraryAppletSelfAccessor::PushInShowController() {
|
|
||||||
const Applets::CommonArguments common_args = {
|
|
||||||
.arguments_version = Applets::CommonArgumentVersion::Version3,
|
|
||||||
.size = Applets::CommonArgumentSize::Version3,
|
|
||||||
.library_version = static_cast<u32>(Applets::ControllerAppletVersion::Version8),
|
|
||||||
.theme_color = Applets::ThemeColor::BasicBlack,
|
|
||||||
.play_startup_sound = true,
|
|
||||||
.system_tick = system.CoreTiming().GetClockTicks(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Applets::ControllerSupportArgNew user_args = {
|
|
||||||
.header = {.player_count_min = 1,
|
|
||||||
.player_count_max = 4,
|
|
||||||
.enable_take_over_connection = true,
|
|
||||||
.enable_left_justify = false,
|
|
||||||
.enable_permit_joy_dual = true,
|
|
||||||
.enable_single_mode = false,
|
|
||||||
.enable_identification_color = false},
|
|
||||||
.identification_colors = {},
|
|
||||||
.enable_explain_text = false,
|
|
||||||
.explain_text = {},
|
|
||||||
};
|
|
||||||
|
|
||||||
Applets::ControllerSupportArgPrivate private_args = {
|
|
||||||
.arg_private_size = sizeof(Applets::ControllerSupportArgPrivate),
|
|
||||||
.arg_size = sizeof(Applets::ControllerSupportArgNew),
|
|
||||||
.is_home_menu = true,
|
|
||||||
.flag_1 = true,
|
|
||||||
.mode = Applets::ControllerSupportMode::ShowControllerSupport,
|
|
||||||
.caller = Applets::ControllerSupportCaller::
|
|
||||||
Application, // switchbrew: Always zero except with
|
|
||||||
// ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem,
|
|
||||||
// which sets this to the input param
|
|
||||||
.style_set = Core::HID::NpadStyleSet::None,
|
|
||||||
.joy_hold_type = 0,
|
|
||||||
};
|
|
||||||
std::vector<u8> common_args_data(sizeof(common_args));
|
|
||||||
std::vector<u8> private_args_data(sizeof(private_args));
|
|
||||||
std::vector<u8> user_args_data(sizeof(user_args));
|
|
||||||
|
|
||||||
std::memcpy(common_args_data.data(), &common_args, sizeof(common_args));
|
|
||||||
std::memcpy(private_args_data.data(), &private_args, sizeof(private_args));
|
|
||||||
std::memcpy(user_args_data.data(), &user_args, sizeof(user_args));
|
|
||||||
|
|
||||||
queue_data.emplace_back(std::move(common_args_data));
|
|
||||||
queue_data.emplace_back(std::move(private_args_data));
|
|
||||||
queue_data.emplace_back(std::move(user_args_data));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ILibraryAppletSelfAccessor::PushInShowCabinetData() {
|
void ILibraryAppletSelfAccessor::PushInShowCabinetData() {
|
||||||
const Applets::CommonArguments arguments{
|
const Applets::CommonArguments arguments{
|
||||||
.arguments_version = Applets::CommonArgumentVersion::Version3,
|
.arguments_version = Applets::CommonArgumentVersion::Version3,
|
||||||
|
@ -87,7 +87,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void GetAppletResourceUserId(HLERequestContext& ctx);
|
void GetAppletResourceUserId(HLERequestContext& ctx);
|
||||||
void GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx);
|
|
||||||
void AcquireForegroundRights(HLERequestContext& ctx);
|
void AcquireForegroundRights(HLERequestContext& ctx);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -346,7 +345,6 @@ private:
|
|||||||
void PopInData(HLERequestContext& ctx);
|
void PopInData(HLERequestContext& ctx);
|
||||||
void PushOutData(HLERequestContext& ctx);
|
void PushOutData(HLERequestContext& ctx);
|
||||||
void GetLibraryAppletInfo(HLERequestContext& ctx);
|
void GetLibraryAppletInfo(HLERequestContext& ctx);
|
||||||
void GetMainAppletIdentityInfo(HLERequestContext& ctx);
|
|
||||||
void ExitProcessAndReturn(HLERequestContext& ctx);
|
void ExitProcessAndReturn(HLERequestContext& ctx);
|
||||||
void GetCallerAppletIdentityInfo(HLERequestContext& ctx);
|
void GetCallerAppletIdentityInfo(HLERequestContext& ctx);
|
||||||
void GetDesirableKeyboardLayout(HLERequestContext& ctx);
|
void GetDesirableKeyboardLayout(HLERequestContext& ctx);
|
||||||
@ -357,7 +355,6 @@ private:
|
|||||||
void PushInShowCabinetData();
|
void PushInShowCabinetData();
|
||||||
void PushInShowMiiEditData();
|
void PushInShowMiiEditData();
|
||||||
void PushInShowSoftwareKeyboard();
|
void PushInShowSoftwareKeyboard();
|
||||||
void PushInShowController();
|
|
||||||
|
|
||||||
std::deque<std::vector<u8>> queue_data;
|
std::deque<std::vector<u8>> queue_data;
|
||||||
};
|
};
|
||||||
|
@ -56,7 +56,7 @@ enum class ControllerSupportResult : u32 {
|
|||||||
struct ControllerSupportArgPrivate {
|
struct ControllerSupportArgPrivate {
|
||||||
u32 arg_private_size{};
|
u32 arg_private_size{};
|
||||||
u32 arg_size{};
|
u32 arg_size{};
|
||||||
bool is_home_menu{};
|
bool flag_0{};
|
||||||
bool flag_1{};
|
bool flag_1{};
|
||||||
ControllerSupportMode mode{};
|
ControllerSupportMode mode{};
|
||||||
ControllerSupportCaller caller{};
|
ControllerSupportCaller caller{};
|
||||||
|
@ -127,7 +127,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void GetCore(HLERequestContext& ctx) {
|
void GetCore(HLERequestContext& ctx) {
|
||||||
LOG_WARNING(Service_BTM, "called");
|
LOG_DEBUG(Service_BTM, "called");
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
@ -263,13 +263,13 @@ public:
|
|||||||
explicit IBtmSystemCore(Core::System& system_) : ServiceFramework{system_, "IBtmSystemCore"} {
|
explicit IBtmSystemCore(Core::System& system_) : ServiceFramework{system_, "IBtmSystemCore"} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &IBtmSystemCore::StartGamepadPairing, "StartGamepadPairing"},
|
{0, nullptr, "StartGamepadPairing"},
|
||||||
{1, &IBtmSystemCore::CancelGamepadPairing, "CancelGamepadPairing"},
|
{1, nullptr, "CancelGamepadPairing"},
|
||||||
{2, nullptr, "ClearGamepadPairingDatabase"},
|
{2, nullptr, "ClearGamepadPairingDatabase"},
|
||||||
{3, nullptr, "GetPairedGamepadCount"},
|
{3, nullptr, "GetPairedGamepadCount"},
|
||||||
{4, nullptr, "EnableRadio"},
|
{4, nullptr, "EnableRadio"},
|
||||||
{5, nullptr, "DisableRadio"},
|
{5, nullptr, "DisableRadio"},
|
||||||
{6, &IBtmSystemCore::IsRadioEnabled, "IsRadioEnabled"},
|
{6, nullptr, "GetRadioOnOff"},
|
||||||
{7, nullptr, "AcquireRadioEvent"},
|
{7, nullptr, "AcquireRadioEvent"},
|
||||||
{8, nullptr, "AcquireGamepadPairingEvent"},
|
{8, nullptr, "AcquireGamepadPairingEvent"},
|
||||||
{9, nullptr, "IsGamepadPairingStarted"},
|
{9, nullptr, "IsGamepadPairingStarted"},
|
||||||
@ -280,58 +280,18 @@ public:
|
|||||||
{14, nullptr, "AcquireAudioDeviceConnectionEvent"},
|
{14, nullptr, "AcquireAudioDeviceConnectionEvent"},
|
||||||
{15, nullptr, "ConnectAudioDevice"},
|
{15, nullptr, "ConnectAudioDevice"},
|
||||||
{16, nullptr, "IsConnectingAudioDevice"},
|
{16, nullptr, "IsConnectingAudioDevice"},
|
||||||
{17, &IBtmSystemCore::GetConnectedAudioDevices, "GetConnectedAudioDevices"},
|
{17, nullptr, "GetConnectedAudioDevices"},
|
||||||
{18, nullptr, "DisconnectAudioDevice"},
|
{18, nullptr, "DisconnectAudioDevice"},
|
||||||
{19, nullptr, "AcquirePairedAudioDeviceInfoChangedEvent"},
|
{19, nullptr, "AcquirePairedAudioDeviceInfoChangedEvent"},
|
||||||
{20, nullptr, "GetPairedAudioDevices"},
|
{20, nullptr, "GetPairedAudioDevices"},
|
||||||
{21, nullptr, "RemoveAudioDevicePairing"},
|
{21, nullptr, "RemoveAudioDevicePairing"},
|
||||||
{22, &IBtmSystemCore::RequestAudioDeviceConnectionRejection, "RequestAudioDeviceConnectionRejection"},
|
{22, nullptr, "RequestAudioDeviceConnectionRejection"},
|
||||||
{23, &IBtmSystemCore::CancelAudioDeviceConnectionRejection, "CancelAudioDeviceConnectionRejection"}
|
{23, nullptr, "CancelAudioDeviceConnectionRejection"}
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
void IsRadioEnabled(HLERequestContext& ctx) {
|
|
||||||
LOG_DEBUG(Service_BTM, "(STUBBED) called"); // Spams a lot when controller applet is running
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.Push(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StartGamepadPairing(HLERequestContext& ctx) {
|
|
||||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CancelGamepadPairing(HLERequestContext& ctx) {
|
|
||||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CancelAudioDeviceConnectionRejection(HLERequestContext& ctx) {
|
|
||||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetConnectedAudioDevices(HLERequestContext& ctx) {
|
|
||||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.Push<u32>(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RequestAudioDeviceConnectionRejection(HLERequestContext& ctx) {
|
|
||||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class BTM_SYS final : public ServiceFramework<BTM_SYS> {
|
class BTM_SYS final : public ServiceFramework<BTM_SYS> {
|
||||||
@ -348,7 +308,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void GetCore(HLERequestContext& ctx) {
|
void GetCore(HLERequestContext& ctx) {
|
||||||
LOG_WARNING(Service_BTM, "called");
|
LOG_DEBUG(Service_BTM, "called");
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
|
@ -32,7 +32,7 @@ public:
|
|||||||
{10200, nullptr, "SendFriendRequestForApplication"},
|
{10200, nullptr, "SendFriendRequestForApplication"},
|
||||||
{10211, nullptr, "AddFacedFriendRequestForApplication"},
|
{10211, nullptr, "AddFacedFriendRequestForApplication"},
|
||||||
{10400, &IFriendService::GetBlockedUserListIds, "GetBlockedUserListIds"},
|
{10400, &IFriendService::GetBlockedUserListIds, "GetBlockedUserListIds"},
|
||||||
{10420, &IFriendService::CheckBlockedUserListAvailability, "CheckBlockedUserListAvailability"},
|
{10420, nullptr, "IsBlockedUserListCacheAvailable"},
|
||||||
{10421, nullptr, "EnsureBlockedUserListAvailable"},
|
{10421, nullptr, "EnsureBlockedUserListAvailable"},
|
||||||
{10500, nullptr, "GetProfileList"},
|
{10500, nullptr, "GetProfileList"},
|
||||||
{10600, nullptr, "DeclareOpenOnlinePlaySession"},
|
{10600, nullptr, "DeclareOpenOnlinePlaySession"},
|
||||||
@ -206,17 +206,6 @@ private:
|
|||||||
rb.Push(true);
|
rb.Push(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckBlockedUserListAvailability(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto uuid{rp.PopRaw<Common::UUID>()};
|
|
||||||
|
|
||||||
LOG_WARNING(Service_Friend, "(STUBBED) called, uuid=0x{}", uuid.RawString());
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.Push(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
KernelHelpers::ServiceContext service_context;
|
KernelHelpers::ServiceContext service_context;
|
||||||
|
|
||||||
Kernel::KEvent* completion_event;
|
Kernel::KEvent* completion_event;
|
||||||
|
@ -8,17 +8,12 @@ namespace Service::HID {
|
|||||||
ControllerBase::ControllerBase(Core::HID::HIDCore& hid_core_) : hid_core(hid_core_) {}
|
ControllerBase::ControllerBase(Core::HID::HIDCore& hid_core_) : hid_core(hid_core_) {}
|
||||||
ControllerBase::~ControllerBase() = default;
|
ControllerBase::~ControllerBase() = default;
|
||||||
|
|
||||||
Result ControllerBase::Activate() {
|
void ControllerBase::ActivateController() {
|
||||||
if (is_activated) {
|
if (is_activated) {
|
||||||
return ResultSuccess;
|
return;
|
||||||
}
|
}
|
||||||
is_activated = true;
|
is_activated = true;
|
||||||
OnInit();
|
OnInit();
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ControllerBase::Activate(u64 aruid) {
|
|
||||||
return Activate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControllerBase::DeactivateController() {
|
void ControllerBase::DeactivateController() {
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/hle/result.h"
|
|
||||||
|
|
||||||
namespace Core::Timing {
|
namespace Core::Timing {
|
||||||
class CoreTiming;
|
class CoreTiming;
|
||||||
@ -32,8 +31,7 @@ public:
|
|||||||
// When the controller is requesting a motion update for the shared memory
|
// When the controller is requesting a motion update for the shared memory
|
||||||
virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) {}
|
virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) {}
|
||||||
|
|
||||||
Result Activate();
|
void ActivateController();
|
||||||
Result Activate(u64 aruid);
|
|
||||||
|
|
||||||
void DeactivateController();
|
void DeactivateController();
|
||||||
|
|
||||||
|
@ -344,7 +344,6 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
|
|||||||
controller.device->SetPollingMode(Core::HID::EmulatedDeviceIndex::AllDevices,
|
controller.device->SetPollingMode(Core::HID::EmulatedDeviceIndex::AllDevices,
|
||||||
Common::Input::PollingMode::Active);
|
Common::Input::PollingMode::Active);
|
||||||
}
|
}
|
||||||
|
|
||||||
SignalStyleSetChangedEvent(npad_id);
|
SignalStyleSetChangedEvent(npad_id);
|
||||||
WriteEmptyEntry(controller.shared_memory);
|
WriteEmptyEntry(controller.shared_memory);
|
||||||
hid_core.SetLastActiveController(npad_id);
|
hid_core.SetLastActiveController(npad_id);
|
||||||
@ -458,14 +457,12 @@ void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) {
|
|||||||
pad_entry.l_stick = stick_state.left;
|
pad_entry.l_stick = stick_state.left;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (controller_type == Core::HID::NpadStyleIndex::JoyconLeft ||
|
if (controller_type == Core::HID::NpadStyleIndex::JoyconLeft) {
|
||||||
controller_type == Core::HID::NpadStyleIndex::JoyconDual) {
|
|
||||||
pad_entry.npad_buttons.left_sl.Assign(button_state.left_sl);
|
pad_entry.npad_buttons.left_sl.Assign(button_state.left_sl);
|
||||||
pad_entry.npad_buttons.left_sr.Assign(button_state.left_sr);
|
pad_entry.npad_buttons.left_sr.Assign(button_state.left_sr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (controller_type == Core::HID::NpadStyleIndex::JoyconRight ||
|
if (controller_type == Core::HID::NpadStyleIndex::JoyconRight) {
|
||||||
controller_type == Core::HID::NpadStyleIndex::JoyconDual) {
|
|
||||||
pad_entry.npad_buttons.right_sl.Assign(button_state.right_sl);
|
pad_entry.npad_buttons.right_sl.Assign(button_state.right_sl);
|
||||||
pad_entry.npad_buttons.right_sr.Assign(button_state.right_sr);
|
pad_entry.npad_buttons.right_sr.Assign(button_state.right_sr);
|
||||||
}
|
}
|
||||||
@ -1727,19 +1724,4 @@ const Controller_NPad::SixaxisParameters& Controller_NPad::GetSixaxisState(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller_NPad::AppletDetailedUiType Controller_NPad::GetAppletDetailedUiType(
|
|
||||||
Core::HID::NpadIdType npad_id) {
|
|
||||||
|
|
||||||
auto controller = GetControllerFromNpadIdType(npad_id);
|
|
||||||
auto shared_memory = controller.shared_memory;
|
|
||||||
Service::HID::Controller_NPad::AppletFooterUiType applet_footer_type =
|
|
||||||
shared_memory->applet_footer_type;
|
|
||||||
|
|
||||||
Controller_NPad::AppletDetailedUiType detailed_ui_type{
|
|
||||||
.ui_variant = 0,
|
|
||||||
.footer = applet_footer_type,
|
|
||||||
};
|
|
||||||
return detailed_ui_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Service::HID
|
} // namespace Service::HID
|
||||||
|
@ -78,46 +78,6 @@ public:
|
|||||||
MaxActivationMode = 3,
|
MaxActivationMode = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
// This is nn::hid::system::AppletFooterUiAttributesSet
|
|
||||||
struct AppletFooterUiAttributes {
|
|
||||||
INSERT_PADDING_BYTES(0x4);
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is nn::hid::system::AppletFooterUiType
|
|
||||||
enum class AppletFooterUiType : u8 {
|
|
||||||
None = 0,
|
|
||||||
HandheldNone = 1,
|
|
||||||
HandheldJoyConLeftOnly = 2,
|
|
||||||
HandheldJoyConRightOnly = 3,
|
|
||||||
HandheldJoyConLeftJoyConRight = 4,
|
|
||||||
JoyDual = 5,
|
|
||||||
JoyDualLeftOnly = 6,
|
|
||||||
JoyDualRightOnly = 7,
|
|
||||||
JoyLeftHorizontal = 8,
|
|
||||||
JoyLeftVertical = 9,
|
|
||||||
JoyRightHorizontal = 10,
|
|
||||||
JoyRightVertical = 11,
|
|
||||||
SwitchProController = 12,
|
|
||||||
CompatibleProController = 13,
|
|
||||||
CompatibleJoyCon = 14,
|
|
||||||
LarkHvc1 = 15,
|
|
||||||
LarkHvc2 = 16,
|
|
||||||
LarkNesLeft = 17,
|
|
||||||
LarkNesRight = 18,
|
|
||||||
Lucia = 19,
|
|
||||||
Verification = 20,
|
|
||||||
Lagon = 21,
|
|
||||||
};
|
|
||||||
|
|
||||||
using AppletFooterUiVariant = u8;
|
|
||||||
|
|
||||||
// This is "nn::hid::system::AppletDetailedUiType".
|
|
||||||
struct AppletDetailedUiType {
|
|
||||||
AppletFooterUiVariant ui_variant;
|
|
||||||
INSERT_PADDING_BYTES(0x2);
|
|
||||||
AppletFooterUiType footer;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(AppletDetailedUiType) == 0x4, "AppletDetailedUiType is an invalid size");
|
|
||||||
// This is nn::hid::NpadCommunicationMode
|
// This is nn::hid::NpadCommunicationMode
|
||||||
enum class NpadCommunicationMode : u64 {
|
enum class NpadCommunicationMode : u64 {
|
||||||
Mode_5ms = 0,
|
Mode_5ms = 0,
|
||||||
@ -126,13 +86,6 @@ public:
|
|||||||
Default = 3,
|
Default = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class NpadRevision : u32 {
|
|
||||||
Revision0 = 0,
|
|
||||||
Revision1 = 1,
|
|
||||||
Revision2 = 2,
|
|
||||||
Revision3 = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set);
|
void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set);
|
||||||
Core::HID::NpadStyleTag GetSupportedStyleSet() const;
|
Core::HID::NpadStyleTag GetSupportedStyleSet() const;
|
||||||
|
|
||||||
@ -243,7 +196,6 @@ public:
|
|||||||
static Result IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle);
|
static Result IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle);
|
||||||
static Result VerifyValidSixAxisSensorHandle(
|
static Result VerifyValidSixAxisSensorHandle(
|
||||||
const Core::HID::SixAxisSensorHandle& device_handle);
|
const Core::HID::SixAxisSensorHandle& device_handle);
|
||||||
AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr std::size_t NPAD_COUNT = 10;
|
static constexpr std::size_t NPAD_COUNT = 10;
|
||||||
@ -401,6 +353,37 @@ private:
|
|||||||
static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18,
|
static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18,
|
||||||
"NfcXcdDeviceHandleStateImpl is an invalid size");
|
"NfcXcdDeviceHandleStateImpl is an invalid size");
|
||||||
|
|
||||||
|
// This is nn::hid::system::AppletFooterUiAttributesSet
|
||||||
|
struct AppletFooterUiAttributes {
|
||||||
|
INSERT_PADDING_BYTES(0x4);
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is nn::hid::system::AppletFooterUiType
|
||||||
|
enum class AppletFooterUiType : u8 {
|
||||||
|
None = 0,
|
||||||
|
HandheldNone = 1,
|
||||||
|
HandheldJoyConLeftOnly = 2,
|
||||||
|
HandheldJoyConRightOnly = 3,
|
||||||
|
HandheldJoyConLeftJoyConRight = 4,
|
||||||
|
JoyDual = 5,
|
||||||
|
JoyDualLeftOnly = 6,
|
||||||
|
JoyDualRightOnly = 7,
|
||||||
|
JoyLeftHorizontal = 8,
|
||||||
|
JoyLeftVertical = 9,
|
||||||
|
JoyRightHorizontal = 10,
|
||||||
|
JoyRightVertical = 11,
|
||||||
|
SwitchProController = 12,
|
||||||
|
CompatibleProController = 13,
|
||||||
|
CompatibleJoyCon = 14,
|
||||||
|
LarkHvc1 = 15,
|
||||||
|
LarkHvc2 = 16,
|
||||||
|
LarkNesLeft = 17,
|
||||||
|
LarkNesRight = 18,
|
||||||
|
Lucia = 19,
|
||||||
|
Verification = 20,
|
||||||
|
Lagon = 21,
|
||||||
|
};
|
||||||
|
|
||||||
// This is nn::hid::NpadLarkType
|
// This is nn::hid::NpadLarkType
|
||||||
enum class NpadLarkType : u32 {
|
enum class NpadLarkType : u32 {
|
||||||
Invalid,
|
Invalid,
|
||||||
|
@ -44,7 +44,7 @@ Result Controller_Palma::InitializePalma(const PalmaConnectionHandle& handle) {
|
|||||||
if (handle.npad_id != active_handle.npad_id) {
|
if (handle.npad_id != active_handle.npad_id) {
|
||||||
return InvalidPalmaHandle;
|
return InvalidPalmaHandle;
|
||||||
}
|
}
|
||||||
Activate();
|
ActivateController();
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -3,12 +3,220 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace Core {
|
#include <chrono>
|
||||||
class System;
|
|
||||||
|
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||||
|
#include "core/hle/service/kernel_helpers.h"
|
||||||
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
|
namespace Core::Timing {
|
||||||
|
struct EventType;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::SM {
|
||||||
|
class ServiceManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Service::HID {
|
namespace Service::HID {
|
||||||
|
|
||||||
|
enum class HidController : std::size_t {
|
||||||
|
DebugPad,
|
||||||
|
Touchscreen,
|
||||||
|
Mouse,
|
||||||
|
Keyboard,
|
||||||
|
XPad,
|
||||||
|
HomeButton,
|
||||||
|
SleepButton,
|
||||||
|
CaptureButton,
|
||||||
|
InputDetector,
|
||||||
|
UniquePad,
|
||||||
|
NPad,
|
||||||
|
Gesture,
|
||||||
|
ConsoleSixAxisSensor,
|
||||||
|
DebugMouse,
|
||||||
|
Palma,
|
||||||
|
|
||||||
|
MaxControllers,
|
||||||
|
};
|
||||||
|
|
||||||
|
class IAppletResource final : public ServiceFramework<IAppletResource> {
|
||||||
|
public:
|
||||||
|
explicit IAppletResource(Core::System& system_,
|
||||||
|
KernelHelpers::ServiceContext& service_context_);
|
||||||
|
~IAppletResource() override;
|
||||||
|
|
||||||
|
void ActivateController(HidController controller);
|
||||||
|
void DeactivateController(HidController controller);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T& GetController(HidController controller) {
|
||||||
|
return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
const T& GetController(HidController controller) const {
|
||||||
|
return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename T>
|
||||||
|
void MakeController(HidController controller, u8* shared_memory) {
|
||||||
|
if constexpr (std::is_constructible_v<T, Core::System&, u8*>) {
|
||||||
|
controllers[static_cast<std::size_t>(controller)] =
|
||||||
|
std::make_unique<T>(system, shared_memory);
|
||||||
|
} else {
|
||||||
|
controllers[static_cast<std::size_t>(controller)] =
|
||||||
|
std::make_unique<T>(system.HIDCore(), shared_memory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void MakeControllerWithServiceContext(HidController controller, u8* shared_memory) {
|
||||||
|
controllers[static_cast<std::size_t>(controller)] =
|
||||||
|
std::make_unique<T>(system.HIDCore(), shared_memory, service_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetSharedMemoryHandle(HLERequestContext& ctx);
|
||||||
|
void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||||
|
void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||||
|
void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||||
|
void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||||
|
|
||||||
|
KernelHelpers::ServiceContext& service_context;
|
||||||
|
|
||||||
|
std::shared_ptr<Core::Timing::EventType> npad_update_event;
|
||||||
|
std::shared_ptr<Core::Timing::EventType> default_update_event;
|
||||||
|
std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event;
|
||||||
|
std::shared_ptr<Core::Timing::EventType> motion_update_event;
|
||||||
|
|
||||||
|
std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
|
||||||
|
controllers{};
|
||||||
|
};
|
||||||
|
|
||||||
|
class Hid final : public ServiceFramework<Hid> {
|
||||||
|
public:
|
||||||
|
explicit Hid(Core::System& system_, std::shared_ptr<IAppletResource> applet_resource_);
|
||||||
|
~Hid() override;
|
||||||
|
|
||||||
|
std::shared_ptr<IAppletResource> GetAppletResource();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void CreateAppletResource(HLERequestContext& ctx);
|
||||||
|
void ActivateDebugPad(HLERequestContext& ctx);
|
||||||
|
void ActivateTouchScreen(HLERequestContext& ctx);
|
||||||
|
void ActivateMouse(HLERequestContext& ctx);
|
||||||
|
void ActivateKeyboard(HLERequestContext& ctx);
|
||||||
|
void SendKeyboardLockKeyEvent(HLERequestContext& ctx);
|
||||||
|
void ActivateXpad(HLERequestContext& ctx);
|
||||||
|
void GetXpadIDs(HLERequestContext& ctx);
|
||||||
|
void ActivateSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void DeactivateSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void StartSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void StopSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void IsSixAxisSensorFusionEnabled(HLERequestContext& ctx);
|
||||||
|
void EnableSixAxisSensorFusion(HLERequestContext& ctx);
|
||||||
|
void SetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||||
|
void GetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||||
|
void ResetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||||
|
void SetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||||
|
void GetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||||
|
void ResetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||||
|
void IsSixAxisSensorAtRest(HLERequestContext& ctx);
|
||||||
|
void IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void EnableSixAxisSensorUnalteredPassthrough(HLERequestContext& ctx);
|
||||||
|
void IsSixAxisSensorUnalteredPassthroughEnabled(HLERequestContext& ctx);
|
||||||
|
void LoadSixAxisSensorCalibrationParameter(HLERequestContext& ctx);
|
||||||
|
void GetSixAxisSensorIcInformation(HLERequestContext& ctx);
|
||||||
|
void ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx);
|
||||||
|
void ActivateGesture(HLERequestContext& ctx);
|
||||||
|
void SetSupportedNpadStyleSet(HLERequestContext& ctx);
|
||||||
|
void GetSupportedNpadStyleSet(HLERequestContext& ctx);
|
||||||
|
void SetSupportedNpadIdType(HLERequestContext& ctx);
|
||||||
|
void ActivateNpad(HLERequestContext& ctx);
|
||||||
|
void DeactivateNpad(HLERequestContext& ctx);
|
||||||
|
void AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx);
|
||||||
|
void DisconnectNpad(HLERequestContext& ctx);
|
||||||
|
void GetPlayerLedPattern(HLERequestContext& ctx);
|
||||||
|
void ActivateNpadWithRevision(HLERequestContext& ctx);
|
||||||
|
void SetNpadJoyHoldType(HLERequestContext& ctx);
|
||||||
|
void GetNpadJoyHoldType(HLERequestContext& ctx);
|
||||||
|
void SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx);
|
||||||
|
void SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx);
|
||||||
|
void SetNpadJoyAssignmentModeDual(HLERequestContext& ctx);
|
||||||
|
void MergeSingleJoyAsDualJoy(HLERequestContext& ctx);
|
||||||
|
void StartLrAssignmentMode(HLERequestContext& ctx);
|
||||||
|
void StopLrAssignmentMode(HLERequestContext& ctx);
|
||||||
|
void SetNpadHandheldActivationMode(HLERequestContext& ctx);
|
||||||
|
void GetNpadHandheldActivationMode(HLERequestContext& ctx);
|
||||||
|
void SwapNpadAssignment(HLERequestContext& ctx);
|
||||||
|
void IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx);
|
||||||
|
void EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx);
|
||||||
|
void SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx);
|
||||||
|
void SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx);
|
||||||
|
void SetNpadCaptureButtonAssignment(HLERequestContext& ctx);
|
||||||
|
void ClearNpadCaptureButtonAssignment(HLERequestContext& ctx);
|
||||||
|
void GetVibrationDeviceInfo(HLERequestContext& ctx);
|
||||||
|
void SendVibrationValue(HLERequestContext& ctx);
|
||||||
|
void GetActualVibrationValue(HLERequestContext& ctx);
|
||||||
|
void CreateActiveVibrationDeviceList(HLERequestContext& ctx);
|
||||||
|
void PermitVibration(HLERequestContext& ctx);
|
||||||
|
void IsVibrationPermitted(HLERequestContext& ctx);
|
||||||
|
void SendVibrationValues(HLERequestContext& ctx);
|
||||||
|
void SendVibrationGcErmCommand(HLERequestContext& ctx);
|
||||||
|
void GetActualVibrationGcErmCommand(HLERequestContext& ctx);
|
||||||
|
void BeginPermitVibrationSession(HLERequestContext& ctx);
|
||||||
|
void EndPermitVibrationSession(HLERequestContext& ctx);
|
||||||
|
void IsVibrationDeviceMounted(HLERequestContext& ctx);
|
||||||
|
void ActivateConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void StartConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void StopConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void ActivateSevenSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void StartSevenSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void StopSevenSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void InitializeSevenSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void FinalizeSevenSixAxisSensor(HLERequestContext& ctx);
|
||||||
|
void ResetSevenSixAxisSensorTimestamp(HLERequestContext& ctx);
|
||||||
|
void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx);
|
||||||
|
void GetPalmaConnectionHandle(HLERequestContext& ctx);
|
||||||
|
void InitializePalma(HLERequestContext& ctx);
|
||||||
|
void AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx);
|
||||||
|
void GetPalmaOperationInfo(HLERequestContext& ctx);
|
||||||
|
void PlayPalmaActivity(HLERequestContext& ctx);
|
||||||
|
void SetPalmaFrModeType(HLERequestContext& ctx);
|
||||||
|
void ReadPalmaStep(HLERequestContext& ctx);
|
||||||
|
void EnablePalmaStep(HLERequestContext& ctx);
|
||||||
|
void ResetPalmaStep(HLERequestContext& ctx);
|
||||||
|
void ReadPalmaApplicationSection(HLERequestContext& ctx);
|
||||||
|
void WritePalmaApplicationSection(HLERequestContext& ctx);
|
||||||
|
void ReadPalmaUniqueCode(HLERequestContext& ctx);
|
||||||
|
void SetPalmaUniqueCodeInvalid(HLERequestContext& ctx);
|
||||||
|
void WritePalmaActivityEntry(HLERequestContext& ctx);
|
||||||
|
void WritePalmaRgbLedPatternEntry(HLERequestContext& ctx);
|
||||||
|
void WritePalmaWaveEntry(HLERequestContext& ctx);
|
||||||
|
void SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
|
||||||
|
void GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
|
||||||
|
void SuspendPalmaFeature(HLERequestContext& ctx);
|
||||||
|
void GetPalmaOperationResult(HLERequestContext& ctx);
|
||||||
|
void ReadPalmaPlayLog(HLERequestContext& ctx);
|
||||||
|
void ResetPalmaPlayLog(HLERequestContext& ctx);
|
||||||
|
void SetIsPalmaAllConnectable(HLERequestContext& ctx);
|
||||||
|
void SetIsPalmaPairedConnectable(HLERequestContext& ctx);
|
||||||
|
void PairPalma(HLERequestContext& ctx);
|
||||||
|
void SetPalmaBoostMode(HLERequestContext& ctx);
|
||||||
|
void CancelWritePalmaWaveEntry(HLERequestContext& ctx);
|
||||||
|
void EnablePalmaBoostMode(HLERequestContext& ctx);
|
||||||
|
void GetPalmaBluetoothAddress(HLERequestContext& ctx);
|
||||||
|
void SetDisallowedPalmaConnection(HLERequestContext& ctx);
|
||||||
|
void SetNpadCommunicationMode(HLERequestContext& ctx);
|
||||||
|
void GetNpadCommunicationMode(HLERequestContext& ctx);
|
||||||
|
void SetTouchScreenConfiguration(HLERequestContext& ctx);
|
||||||
|
void IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx);
|
||||||
|
|
||||||
|
std::shared_ptr<IAppletResource> applet_resource;
|
||||||
|
|
||||||
|
KernelHelpers::ServiceContext service_context;
|
||||||
|
};
|
||||||
|
|
||||||
void LoopProcess(Core::System& system);
|
void LoopProcess(Core::System& system);
|
||||||
|
|
||||||
} // namespace Service::HID
|
} // namespace Service::HID
|
||||||
|
@ -1,159 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include "core/hle/service/hid/hid_debug_server.h"
|
|
||||||
#include "core/hle/service/hid/resource_manager.h"
|
|
||||||
#include "core/hle/service/ipc_helpers.h"
|
|
||||||
|
|
||||||
namespace Service::HID {
|
|
||||||
|
|
||||||
IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource)
|
|
||||||
: ServiceFramework{system_, "hid:dbg"}, resource_manager{resource} {
|
|
||||||
// clang-format off
|
|
||||||
static const FunctionInfo functions[] = {
|
|
||||||
{0, nullptr, "DeactivateDebugPad"},
|
|
||||||
{1, nullptr, "SetDebugPadAutoPilotState"},
|
|
||||||
{2, nullptr, "UnsetDebugPadAutoPilotState"},
|
|
||||||
{10, nullptr, "DeactivateTouchScreen"},
|
|
||||||
{11, nullptr, "SetTouchScreenAutoPilotState"},
|
|
||||||
{12, nullptr, "UnsetTouchScreenAutoPilotState"},
|
|
||||||
{13, nullptr, "GetTouchScreenConfiguration"},
|
|
||||||
{14, nullptr, "ProcessTouchScreenAutoTune"},
|
|
||||||
{15, nullptr, "ForceStopTouchScreenManagement"},
|
|
||||||
{16, nullptr, "ForceRestartTouchScreenManagement"},
|
|
||||||
{17, nullptr, "IsTouchScreenManaged"},
|
|
||||||
{20, nullptr, "DeactivateMouse"},
|
|
||||||
{21, nullptr, "SetMouseAutoPilotState"},
|
|
||||||
{22, nullptr, "UnsetMouseAutoPilotState"},
|
|
||||||
{25, nullptr, "SetDebugMouseAutoPilotState"},
|
|
||||||
{26, nullptr, "UnsetDebugMouseAutoPilotState"},
|
|
||||||
{30, nullptr, "DeactivateKeyboard"},
|
|
||||||
{31, nullptr, "SetKeyboardAutoPilotState"},
|
|
||||||
{32, nullptr, "UnsetKeyboardAutoPilotState"},
|
|
||||||
{50, nullptr, "DeactivateXpad"},
|
|
||||||
{51, nullptr, "SetXpadAutoPilotState"},
|
|
||||||
{52, nullptr, "UnsetXpadAutoPilotState"},
|
|
||||||
{53, nullptr, "DeactivateJoyXpad"},
|
|
||||||
{60, nullptr, "ClearNpadSystemCommonPolicy"},
|
|
||||||
{61, nullptr, "DeactivateNpad"},
|
|
||||||
{62, nullptr, "ForceDisconnectNpad"},
|
|
||||||
{91, nullptr, "DeactivateGesture"},
|
|
||||||
{110, nullptr, "DeactivateHomeButton"},
|
|
||||||
{111, nullptr, "SetHomeButtonAutoPilotState"},
|
|
||||||
{112, nullptr, "UnsetHomeButtonAutoPilotState"},
|
|
||||||
{120, nullptr, "DeactivateSleepButton"},
|
|
||||||
{121, nullptr, "SetSleepButtonAutoPilotState"},
|
|
||||||
{122, nullptr, "UnsetSleepButtonAutoPilotState"},
|
|
||||||
{123, nullptr, "DeactivateInputDetector"},
|
|
||||||
{130, nullptr, "DeactivateCaptureButton"},
|
|
||||||
{131, nullptr, "SetCaptureButtonAutoPilotState"},
|
|
||||||
{132, nullptr, "UnsetCaptureButtonAutoPilotState"},
|
|
||||||
{133, nullptr, "SetShiftAccelerometerCalibrationValue"},
|
|
||||||
{134, nullptr, "GetShiftAccelerometerCalibrationValue"},
|
|
||||||
{135, nullptr, "SetShiftGyroscopeCalibrationValue"},
|
|
||||||
{136, nullptr, "GetShiftGyroscopeCalibrationValue"},
|
|
||||||
{140, nullptr, "DeactivateConsoleSixAxisSensor"},
|
|
||||||
{141, nullptr, "GetConsoleSixAxisSensorSamplingFrequency"},
|
|
||||||
{142, nullptr, "DeactivateSevenSixAxisSensor"},
|
|
||||||
{143, nullptr, "GetConsoleSixAxisSensorCountStates"},
|
|
||||||
{144, nullptr, "GetAccelerometerFsr"},
|
|
||||||
{145, nullptr, "SetAccelerometerFsr"},
|
|
||||||
{146, nullptr, "GetAccelerometerOdr"},
|
|
||||||
{147, nullptr, "SetAccelerometerOdr"},
|
|
||||||
{148, nullptr, "GetGyroscopeFsr"},
|
|
||||||
{149, nullptr, "SetGyroscopeFsr"},
|
|
||||||
{150, nullptr, "GetGyroscopeOdr"},
|
|
||||||
{151, nullptr, "SetGyroscopeOdr"},
|
|
||||||
{152, nullptr, "GetWhoAmI"},
|
|
||||||
{201, nullptr, "ActivateFirmwareUpdate"},
|
|
||||||
{202, nullptr, "DeactivateFirmwareUpdate"},
|
|
||||||
{203, nullptr, "StartFirmwareUpdate"},
|
|
||||||
{204, nullptr, "GetFirmwareUpdateStage"},
|
|
||||||
{205, nullptr, "GetFirmwareVersion"},
|
|
||||||
{206, nullptr, "GetDestinationFirmwareVersion"},
|
|
||||||
{207, nullptr, "DiscardFirmwareInfoCacheForRevert"},
|
|
||||||
{208, nullptr, "StartFirmwareUpdateForRevert"},
|
|
||||||
{209, nullptr, "GetAvailableFirmwareVersionForRevert"},
|
|
||||||
{210, nullptr, "IsFirmwareUpdatingDevice"},
|
|
||||||
{211, nullptr, "StartFirmwareUpdateIndividual"},
|
|
||||||
{215, nullptr, "SetUsbFirmwareForceUpdateEnabled"},
|
|
||||||
{216, nullptr, "SetAllKuinaDevicesToFirmwareUpdateMode"},
|
|
||||||
{221, nullptr, "UpdateControllerColor"},
|
|
||||||
{222, nullptr, "ConnectUsbPadsAsync"},
|
|
||||||
{223, nullptr, "DisconnectUsbPadsAsync"},
|
|
||||||
{224, nullptr, "UpdateDesignInfo"},
|
|
||||||
{225, nullptr, "GetUniquePadDriverState"},
|
|
||||||
{226, nullptr, "GetSixAxisSensorDriverStates"},
|
|
||||||
{227, nullptr, "GetRxPacketHistory"},
|
|
||||||
{228, nullptr, "AcquireOperationEventHandle"},
|
|
||||||
{229, nullptr, "ReadSerialFlash"},
|
|
||||||
{230, nullptr, "WriteSerialFlash"},
|
|
||||||
{231, nullptr, "GetOperationResult"},
|
|
||||||
{232, nullptr, "EnableShipmentMode"},
|
|
||||||
{233, nullptr, "ClearPairingInfo"},
|
|
||||||
{234, nullptr, "GetUniquePadDeviceTypeSetInternal"},
|
|
||||||
{235, nullptr, "EnableAnalogStickPower"},
|
|
||||||
{236, nullptr, "RequestKuinaUartClockCal"},
|
|
||||||
{237, nullptr, "GetKuinaUartClockCal"},
|
|
||||||
{238, nullptr, "SetKuinaUartClockTrim"},
|
|
||||||
{239, nullptr, "KuinaLoopbackTest"},
|
|
||||||
{240, nullptr, "RequestBatteryVoltage"},
|
|
||||||
{241, nullptr, "GetBatteryVoltage"},
|
|
||||||
{242, nullptr, "GetUniquePadPowerInfo"},
|
|
||||||
{243, nullptr, "RebootUniquePad"},
|
|
||||||
{244, nullptr, "RequestKuinaFirmwareVersion"},
|
|
||||||
{245, nullptr, "GetKuinaFirmwareVersion"},
|
|
||||||
{246, nullptr, "GetVidPid"},
|
|
||||||
{247, nullptr, "GetAnalogStickCalibrationValue"},
|
|
||||||
{248, nullptr, "GetUniquePadIdsFull"},
|
|
||||||
{249, nullptr, "ConnectUniquePad"},
|
|
||||||
{250, nullptr, "IsVirtual"},
|
|
||||||
{251, nullptr, "GetAnalogStickModuleParam"},
|
|
||||||
{301, nullptr, "GetAbstractedPadHandles"},
|
|
||||||
{302, nullptr, "GetAbstractedPadState"},
|
|
||||||
{303, nullptr, "GetAbstractedPadsState"},
|
|
||||||
{321, nullptr, "SetAutoPilotVirtualPadState"},
|
|
||||||
{322, nullptr, "UnsetAutoPilotVirtualPadState"},
|
|
||||||
{323, nullptr, "UnsetAllAutoPilotVirtualPadState"},
|
|
||||||
{324, nullptr, "AttachHdlsWorkBuffer"},
|
|
||||||
{325, nullptr, "ReleaseHdlsWorkBuffer"},
|
|
||||||
{326, nullptr, "DumpHdlsNpadAssignmentState"},
|
|
||||||
{327, nullptr, "DumpHdlsStates"},
|
|
||||||
{328, nullptr, "ApplyHdlsNpadAssignmentState"},
|
|
||||||
{329, nullptr, "ApplyHdlsStateList"},
|
|
||||||
{330, nullptr, "AttachHdlsVirtualDevice"},
|
|
||||||
{331, nullptr, "DetachHdlsVirtualDevice"},
|
|
||||||
{332, nullptr, "SetHdlsState"},
|
|
||||||
{350, nullptr, "AddRegisteredDevice"},
|
|
||||||
{400, nullptr, "DisableExternalMcuOnNxDevice"},
|
|
||||||
{401, nullptr, "DisableRailDeviceFiltering"},
|
|
||||||
{402, nullptr, "EnableWiredPairing"},
|
|
||||||
{403, nullptr, "EnableShipmentModeAutoClear"},
|
|
||||||
{404, nullptr, "SetRailEnabled"},
|
|
||||||
{500, nullptr, "SetFactoryInt"},
|
|
||||||
{501, nullptr, "IsFactoryBootEnabled"},
|
|
||||||
{550, nullptr, "SetAnalogStickModelDataTemporarily"},
|
|
||||||
{551, nullptr, "GetAnalogStickModelData"},
|
|
||||||
{552, nullptr, "ResetAnalogStickModelData"},
|
|
||||||
{600, nullptr, "ConvertPadState"},
|
|
||||||
{650, nullptr, "AddButtonPlayData"},
|
|
||||||
{651, nullptr, "StartButtonPlayData"},
|
|
||||||
{652, nullptr, "StopButtonPlayData"},
|
|
||||||
{2000, nullptr, "DeactivateDigitizer"},
|
|
||||||
{2001, nullptr, "SetDigitizerAutoPilotState"},
|
|
||||||
{2002, nullptr, "UnsetDigitizerAutoPilotState"},
|
|
||||||
{2002, nullptr, "ReloadFirmwareDebugSettings"},
|
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
|
||||||
}
|
|
||||||
|
|
||||||
IHidDebugServer::~IHidDebugServer() = default;
|
|
||||||
|
|
||||||
std::shared_ptr<ResourceManager> IHidDebugServer::GetResourceManager() {
|
|
||||||
resource_manager->Initialize();
|
|
||||||
return resource_manager;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Service::HID
|
|
@ -1,26 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "core/hle/service/service.h"
|
|
||||||
|
|
||||||
namespace Core {
|
|
||||||
class System;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Service::HID {
|
|
||||||
class ResourceManager;
|
|
||||||
|
|
||||||
class IHidDebugServer final : public ServiceFramework<IHidDebugServer> {
|
|
||||||
public:
|
|
||||||
explicit IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource);
|
|
||||||
~IHidDebugServer() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::shared_ptr<ResourceManager> GetResourceManager();
|
|
||||||
|
|
||||||
std::shared_ptr<ResourceManager> resource_manager;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Service::HID
|
|
@ -1,99 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include "core/hle/service/hid/hid_firmware_settings.h"
|
|
||||||
|
|
||||||
namespace Service::HID {
|
|
||||||
|
|
||||||
HidFirmwareSettings::HidFirmwareSettings() {
|
|
||||||
LoadSettings(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HidFirmwareSettings::Reload() {
|
|
||||||
LoadSettings(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HidFirmwareSettings::LoadSettings(bool reload_config) {
|
|
||||||
if (is_initalized && !reload_config) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Use nn::settings::fwdbg::GetSettingsItemValue to load config values
|
|
||||||
|
|
||||||
is_debug_pad_enabled = true;
|
|
||||||
is_device_managed = true;
|
|
||||||
is_touch_i2c_managed = is_device_managed;
|
|
||||||
is_future_devices_emulated = false;
|
|
||||||
is_mcu_hardware_error_emulated = false;
|
|
||||||
is_rail_enabled = true;
|
|
||||||
is_firmware_update_failure_emulated = false;
|
|
||||||
is_firmware_update_failure = {};
|
|
||||||
is_ble_disabled = false;
|
|
||||||
is_dscale_disabled = false;
|
|
||||||
is_handheld_forced = true;
|
|
||||||
features_per_id_disabled = {};
|
|
||||||
is_touch_firmware_auto_update_disabled = false;
|
|
||||||
is_initalized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HidFirmwareSettings::IsDebugPadEnabled() {
|
|
||||||
LoadSettings(false);
|
|
||||||
return is_debug_pad_enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HidFirmwareSettings::IsDeviceManaged() {
|
|
||||||
LoadSettings(false);
|
|
||||||
return is_device_managed;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HidFirmwareSettings::IsEmulateFutureDevice() {
|
|
||||||
LoadSettings(false);
|
|
||||||
return is_future_devices_emulated;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HidFirmwareSettings::IsTouchI2cManaged() {
|
|
||||||
LoadSettings(false);
|
|
||||||
return is_touch_i2c_managed;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HidFirmwareSettings::IsHandheldForced() {
|
|
||||||
LoadSettings(false);
|
|
||||||
return is_handheld_forced;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HidFirmwareSettings::IsRailEnabled() {
|
|
||||||
LoadSettings(false);
|
|
||||||
return is_rail_enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HidFirmwareSettings::IsHardwareErrorEmulated() {
|
|
||||||
LoadSettings(false);
|
|
||||||
return is_mcu_hardware_error_emulated;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HidFirmwareSettings::IsBleDisabled() {
|
|
||||||
LoadSettings(false);
|
|
||||||
return is_ble_disabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HidFirmwareSettings::IsDscaleDisabled() {
|
|
||||||
LoadSettings(false);
|
|
||||||
return is_dscale_disabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HidFirmwareSettings::IsTouchAutoUpdateDisabled() {
|
|
||||||
LoadSettings(false);
|
|
||||||
return is_touch_firmware_auto_update_disabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
HidFirmwareSettings::FirmwareSetting HidFirmwareSettings::GetFirmwareUpdateFailure() {
|
|
||||||
LoadSettings(false);
|
|
||||||
return is_firmware_update_failure;
|
|
||||||
}
|
|
||||||
|
|
||||||
HidFirmwareSettings::FeaturesPerId HidFirmwareSettings::FeaturesDisabledPerId() {
|
|
||||||
LoadSettings(false);
|
|
||||||
return features_per_id_disabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Service::HID
|
|
@ -1,54 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace Service::HID {
|
|
||||||
|
|
||||||
/// Loads firmware config from nn::settings::fwdbg
|
|
||||||
class HidFirmwareSettings {
|
|
||||||
public:
|
|
||||||
using FirmwareSetting = std::array<u8, 4>;
|
|
||||||
using FeaturesPerId = std::array<bool, 0xA8>;
|
|
||||||
|
|
||||||
HidFirmwareSettings();
|
|
||||||
|
|
||||||
void Reload();
|
|
||||||
void LoadSettings(bool reload_config);
|
|
||||||
|
|
||||||
bool IsDebugPadEnabled();
|
|
||||||
bool IsDeviceManaged();
|
|
||||||
bool IsEmulateFutureDevice();
|
|
||||||
bool IsTouchI2cManaged();
|
|
||||||
bool IsHandheldForced();
|
|
||||||
bool IsRailEnabled();
|
|
||||||
bool IsHardwareErrorEmulated();
|
|
||||||
bool IsBleDisabled();
|
|
||||||
bool IsDscaleDisabled();
|
|
||||||
bool IsTouchAutoUpdateDisabled();
|
|
||||||
|
|
||||||
FirmwareSetting GetFirmwareUpdateFailure();
|
|
||||||
FeaturesPerId FeaturesDisabledPerId();
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool is_initalized{};
|
|
||||||
|
|
||||||
// Debug settings
|
|
||||||
bool is_debug_pad_enabled{};
|
|
||||||
bool is_device_managed{};
|
|
||||||
bool is_touch_i2c_managed{};
|
|
||||||
bool is_future_devices_emulated{};
|
|
||||||
bool is_mcu_hardware_error_emulated{};
|
|
||||||
bool is_rail_enabled{};
|
|
||||||
bool is_firmware_update_failure_emulated{};
|
|
||||||
bool is_ble_disabled{};
|
|
||||||
bool is_dscale_disabled{};
|
|
||||||
bool is_handheld_forced{};
|
|
||||||
bool is_touch_firmware_auto_update_disabled{};
|
|
||||||
FirmwareSetting is_firmware_update_failure{};
|
|
||||||
FeaturesPerId features_per_id_disabled{};
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Service::HID
|
|
File diff suppressed because it is too large
Load Diff
@ -1,149 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "core/hle/service/service.h"
|
|
||||||
|
|
||||||
namespace Core {
|
|
||||||
class System;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Service::HID {
|
|
||||||
class ResourceManager;
|
|
||||||
class HidFirmwareSettings;
|
|
||||||
|
|
||||||
class IHidServer final : public ServiceFramework<IHidServer> {
|
|
||||||
public:
|
|
||||||
explicit IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> resource,
|
|
||||||
std::shared_ptr<HidFirmwareSettings> settings);
|
|
||||||
~IHidServer() override;
|
|
||||||
|
|
||||||
std::shared_ptr<ResourceManager> GetResourceManager();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void CreateAppletResource(HLERequestContext& ctx);
|
|
||||||
void ActivateDebugPad(HLERequestContext& ctx);
|
|
||||||
void ActivateTouchScreen(HLERequestContext& ctx);
|
|
||||||
void ActivateMouse(HLERequestContext& ctx);
|
|
||||||
void ActivateKeyboard(HLERequestContext& ctx);
|
|
||||||
void SendKeyboardLockKeyEvent(HLERequestContext& ctx);
|
|
||||||
void AcquireXpadIdEventHandle(HLERequestContext& ctx);
|
|
||||||
void ReleaseXpadIdEventHandle(HLERequestContext& ctx);
|
|
||||||
void ActivateXpad(HLERequestContext& ctx);
|
|
||||||
void GetXpadIds(HLERequestContext& ctx);
|
|
||||||
void ActivateJoyXpad(HLERequestContext& ctx);
|
|
||||||
void GetJoyXpadLifoHandle(HLERequestContext& ctx);
|
|
||||||
void GetJoyXpadIds(HLERequestContext& ctx);
|
|
||||||
void ActivateSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void DeactivateSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void GetSixAxisSensorLifoHandle(HLERequestContext& ctx);
|
|
||||||
void ActivateJoySixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void DeactivateJoySixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void GetJoySixAxisSensorLifoHandle(HLERequestContext& ctx);
|
|
||||||
void StartSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void StopSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void IsSixAxisSensorFusionEnabled(HLERequestContext& ctx);
|
|
||||||
void EnableSixAxisSensorFusion(HLERequestContext& ctx);
|
|
||||||
void SetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
|
||||||
void GetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
|
||||||
void ResetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
|
||||||
void SetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
|
||||||
void GetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
|
||||||
void ResetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
|
||||||
void IsSixAxisSensorAtRest(HLERequestContext& ctx);
|
|
||||||
void IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void EnableSixAxisSensorUnalteredPassthrough(HLERequestContext& ctx);
|
|
||||||
void IsSixAxisSensorUnalteredPassthroughEnabled(HLERequestContext& ctx);
|
|
||||||
void LoadSixAxisSensorCalibrationParameter(HLERequestContext& ctx);
|
|
||||||
void GetSixAxisSensorIcInformation(HLERequestContext& ctx);
|
|
||||||
void ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx);
|
|
||||||
void ActivateGesture(HLERequestContext& ctx);
|
|
||||||
void SetSupportedNpadStyleSet(HLERequestContext& ctx);
|
|
||||||
void GetSupportedNpadStyleSet(HLERequestContext& ctx);
|
|
||||||
void SetSupportedNpadIdType(HLERequestContext& ctx);
|
|
||||||
void ActivateNpad(HLERequestContext& ctx);
|
|
||||||
void DeactivateNpad(HLERequestContext& ctx);
|
|
||||||
void AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx);
|
|
||||||
void DisconnectNpad(HLERequestContext& ctx);
|
|
||||||
void GetPlayerLedPattern(HLERequestContext& ctx);
|
|
||||||
void ActivateNpadWithRevision(HLERequestContext& ctx);
|
|
||||||
void SetNpadJoyHoldType(HLERequestContext& ctx);
|
|
||||||
void GetNpadJoyHoldType(HLERequestContext& ctx);
|
|
||||||
void SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx);
|
|
||||||
void SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx);
|
|
||||||
void SetNpadJoyAssignmentModeDual(HLERequestContext& ctx);
|
|
||||||
void MergeSingleJoyAsDualJoy(HLERequestContext& ctx);
|
|
||||||
void StartLrAssignmentMode(HLERequestContext& ctx);
|
|
||||||
void StopLrAssignmentMode(HLERequestContext& ctx);
|
|
||||||
void SetNpadHandheldActivationMode(HLERequestContext& ctx);
|
|
||||||
void GetNpadHandheldActivationMode(HLERequestContext& ctx);
|
|
||||||
void SwapNpadAssignment(HLERequestContext& ctx);
|
|
||||||
void IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx);
|
|
||||||
void EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx);
|
|
||||||
void SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx);
|
|
||||||
void SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx);
|
|
||||||
void SetNpadCaptureButtonAssignment(HLERequestContext& ctx);
|
|
||||||
void ClearNpadCaptureButtonAssignment(HLERequestContext& ctx);
|
|
||||||
void GetVibrationDeviceInfo(HLERequestContext& ctx);
|
|
||||||
void SendVibrationValue(HLERequestContext& ctx);
|
|
||||||
void GetActualVibrationValue(HLERequestContext& ctx);
|
|
||||||
void CreateActiveVibrationDeviceList(HLERequestContext& ctx);
|
|
||||||
void PermitVibration(HLERequestContext& ctx);
|
|
||||||
void IsVibrationPermitted(HLERequestContext& ctx);
|
|
||||||
void SendVibrationValues(HLERequestContext& ctx);
|
|
||||||
void SendVibrationGcErmCommand(HLERequestContext& ctx);
|
|
||||||
void GetActualVibrationGcErmCommand(HLERequestContext& ctx);
|
|
||||||
void BeginPermitVibrationSession(HLERequestContext& ctx);
|
|
||||||
void EndPermitVibrationSession(HLERequestContext& ctx);
|
|
||||||
void IsVibrationDeviceMounted(HLERequestContext& ctx);
|
|
||||||
void ActivateConsoleSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void StartConsoleSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void StopConsoleSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void ActivateSevenSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void StartSevenSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void StopSevenSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void InitializeSevenSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void FinalizeSevenSixAxisSensor(HLERequestContext& ctx);
|
|
||||||
void ResetSevenSixAxisSensorTimestamp(HLERequestContext& ctx);
|
|
||||||
void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx);
|
|
||||||
void GetPalmaConnectionHandle(HLERequestContext& ctx);
|
|
||||||
void InitializePalma(HLERequestContext& ctx);
|
|
||||||
void AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx);
|
|
||||||
void GetPalmaOperationInfo(HLERequestContext& ctx);
|
|
||||||
void PlayPalmaActivity(HLERequestContext& ctx);
|
|
||||||
void SetPalmaFrModeType(HLERequestContext& ctx);
|
|
||||||
void ReadPalmaStep(HLERequestContext& ctx);
|
|
||||||
void EnablePalmaStep(HLERequestContext& ctx);
|
|
||||||
void ResetPalmaStep(HLERequestContext& ctx);
|
|
||||||
void ReadPalmaApplicationSection(HLERequestContext& ctx);
|
|
||||||
void WritePalmaApplicationSection(HLERequestContext& ctx);
|
|
||||||
void ReadPalmaUniqueCode(HLERequestContext& ctx);
|
|
||||||
void SetPalmaUniqueCodeInvalid(HLERequestContext& ctx);
|
|
||||||
void WritePalmaActivityEntry(HLERequestContext& ctx);
|
|
||||||
void WritePalmaRgbLedPatternEntry(HLERequestContext& ctx);
|
|
||||||
void WritePalmaWaveEntry(HLERequestContext& ctx);
|
|
||||||
void SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
|
|
||||||
void GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
|
|
||||||
void SuspendPalmaFeature(HLERequestContext& ctx);
|
|
||||||
void GetPalmaOperationResult(HLERequestContext& ctx);
|
|
||||||
void ReadPalmaPlayLog(HLERequestContext& ctx);
|
|
||||||
void ResetPalmaPlayLog(HLERequestContext& ctx);
|
|
||||||
void SetIsPalmaAllConnectable(HLERequestContext& ctx);
|
|
||||||
void SetIsPalmaPairedConnectable(HLERequestContext& ctx);
|
|
||||||
void PairPalma(HLERequestContext& ctx);
|
|
||||||
void SetPalmaBoostMode(HLERequestContext& ctx);
|
|
||||||
void CancelWritePalmaWaveEntry(HLERequestContext& ctx);
|
|
||||||
void EnablePalmaBoostMode(HLERequestContext& ctx);
|
|
||||||
void GetPalmaBluetoothAddress(HLERequestContext& ctx);
|
|
||||||
void SetDisallowedPalmaConnection(HLERequestContext& ctx);
|
|
||||||
void SetNpadCommunicationMode(HLERequestContext& ctx);
|
|
||||||
void GetNpadCommunicationMode(HLERequestContext& ctx);
|
|
||||||
void SetTouchScreenConfiguration(HLERequestContext& ctx);
|
|
||||||
void IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx);
|
|
||||||
|
|
||||||
std::shared_ptr<ResourceManager> resource_manager;
|
|
||||||
std::shared_ptr<HidFirmwareSettings> firmware_settings;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Service::HID
|
|
@ -1,551 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include "core/hid/hid_core.h"
|
|
||||||
#include "core/hle/service/hid/controllers/npad.h"
|
|
||||||
#include "core/hle/service/hid/controllers/touchscreen.h"
|
|
||||||
#include "core/hle/service/hid/errors.h"
|
|
||||||
#include "core/hle/service/hid/hid_system_server.h"
|
|
||||||
#include "core/hle/service/hid/resource_manager.h"
|
|
||||||
#include "core/hle/service/ipc_helpers.h"
|
|
||||||
|
|
||||||
namespace Service::HID {
|
|
||||||
|
|
||||||
IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<ResourceManager> resource)
|
|
||||||
: ServiceFramework{system_, "hid:sys"}, service_context{system_, service_name},
|
|
||||||
resource_manager{resource} {
|
|
||||||
// clang-format off
|
|
||||||
static const FunctionInfo functions[] = {
|
|
||||||
{31, nullptr, "SendKeyboardLockKeyEvent"},
|
|
||||||
{101, nullptr, "AcquireHomeButtonEventHandle"},
|
|
||||||
{111, nullptr, "ActivateHomeButton"},
|
|
||||||
{121, nullptr, "AcquireSleepButtonEventHandle"},
|
|
||||||
{131, nullptr, "ActivateSleepButton"},
|
|
||||||
{141, nullptr, "AcquireCaptureButtonEventHandle"},
|
|
||||||
{151, nullptr, "ActivateCaptureButton"},
|
|
||||||
{161, nullptr, "GetPlatformConfig"},
|
|
||||||
{210, nullptr, "AcquireNfcDeviceUpdateEventHandle"},
|
|
||||||
{211, nullptr, "GetNpadsWithNfc"},
|
|
||||||
{212, nullptr, "AcquireNfcActivateEventHandle"},
|
|
||||||
{213, nullptr, "ActivateNfc"},
|
|
||||||
{214, nullptr, "GetXcdHandleForNpadWithNfc"},
|
|
||||||
{215, nullptr, "IsNfcActivated"},
|
|
||||||
{230, nullptr, "AcquireIrSensorEventHandle"},
|
|
||||||
{231, nullptr, "ActivateIrSensor"},
|
|
||||||
{232, nullptr, "GetIrSensorState"},
|
|
||||||
{233, nullptr, "GetXcdHandleForNpadWithIrSensor"},
|
|
||||||
{301, nullptr, "ActivateNpadSystem"},
|
|
||||||
{303, &IHidSystemServer::ApplyNpadSystemCommonPolicy, "ApplyNpadSystemCommonPolicy"},
|
|
||||||
{304, &IHidSystemServer::EnableAssigningSingleOnSlSrPress, "EnableAssigningSingleOnSlSrPress"},
|
|
||||||
{305, &IHidSystemServer::DisableAssigningSingleOnSlSrPress, "DisableAssigningSingleOnSlSrPress"},
|
|
||||||
{306, &IHidSystemServer::GetLastActiveNpad, "GetLastActiveNpad"},
|
|
||||||
{307, nullptr, "GetNpadSystemExtStyle"},
|
|
||||||
{308, &IHidSystemServer::ApplyNpadSystemCommonPolicyFull, "ApplyNpadSystemCommonPolicyFull"},
|
|
||||||
{309, &IHidSystemServer::GetNpadFullKeyGripColor, "GetNpadFullKeyGripColor"},
|
|
||||||
{310, &IHidSystemServer::GetMaskedSupportedNpadStyleSet, "GetMaskedSupportedNpadStyleSet"},
|
|
||||||
{311, nullptr, "SetNpadPlayerLedBlinkingDevice"},
|
|
||||||
{312, &IHidSystemServer::SetSupportedNpadStyleSetAll, "SetSupportedNpadStyleSetAll"},
|
|
||||||
{313, nullptr, "GetNpadCaptureButtonAssignment"},
|
|
||||||
{314, nullptr, "GetAppletFooterUiType"},
|
|
||||||
{315, &IHidSystemServer::GetAppletDetailedUiType, "GetAppletDetailedUiType"},
|
|
||||||
{316, &IHidSystemServer::GetNpadInterfaceType, "GetNpadInterfaceType"},
|
|
||||||
{317, &IHidSystemServer::GetNpadLeftRightInterfaceType, "GetNpadLeftRightInterfaceType"},
|
|
||||||
{318, &IHidSystemServer::HasBattery, "HasBattery"},
|
|
||||||
{319, &IHidSystemServer::HasLeftRightBattery, "HasLeftRightBattery"},
|
|
||||||
{321, &IHidSystemServer::GetUniquePadsFromNpad, "GetUniquePadsFromNpad"},
|
|
||||||
{322, &IHidSystemServer::GetIrSensorState, "GetIrSensorState"},
|
|
||||||
{323, nullptr, "GetXcdHandleForNpadWithIrSensor"},
|
|
||||||
{324, nullptr, "GetUniquePadButtonSet"},
|
|
||||||
{325, nullptr, "GetUniquePadColor"},
|
|
||||||
{326, nullptr, "GetUniquePadAppletDetailedUiType"},
|
|
||||||
{327, nullptr, "GetAbstractedPadIdDataFromNpad"},
|
|
||||||
{328, nullptr, "AttachAbstractedPadToNpad"},
|
|
||||||
{329, nullptr, "DetachAbstractedPadAll"},
|
|
||||||
{330, nullptr, "CheckAbstractedPadConnection"},
|
|
||||||
{500, nullptr, "SetAppletResourceUserId"},
|
|
||||||
{501, nullptr, "RegisterAppletResourceUserId"},
|
|
||||||
{502, nullptr, "UnregisterAppletResourceUserId"},
|
|
||||||
{503, nullptr, "EnableAppletToGetInput"},
|
|
||||||
{504, nullptr, "SetAruidValidForVibration"},
|
|
||||||
{505, nullptr, "EnableAppletToGetSixAxisSensor"},
|
|
||||||
{506, nullptr, "EnableAppletToGetPadInput"},
|
|
||||||
{507, nullptr, "EnableAppletToGetTouchScreen"},
|
|
||||||
{510, nullptr, "SetVibrationMasterVolume"},
|
|
||||||
{511, nullptr, "GetVibrationMasterVolume"},
|
|
||||||
{512, nullptr, "BeginPermitVibrationSession"},
|
|
||||||
{513, nullptr, "EndPermitVibrationSession"},
|
|
||||||
{514, nullptr, "Unknown514"},
|
|
||||||
{520, nullptr, "EnableHandheldHids"},
|
|
||||||
{521, nullptr, "DisableHandheldHids"},
|
|
||||||
{522, nullptr, "SetJoyConRailEnabled"},
|
|
||||||
{523, nullptr, "IsJoyConRailEnabled"},
|
|
||||||
{524, nullptr, "IsHandheldHidsEnabled"},
|
|
||||||
{525, nullptr, "IsJoyConAttachedOnAllRail"},
|
|
||||||
{540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"},
|
|
||||||
{541, nullptr, "GetPlayReportControllerUsages"},
|
|
||||||
{542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"},
|
|
||||||
{543, nullptr, "GetRegisteredDevicesOld"},
|
|
||||||
{544, &IHidSystemServer::AcquireConnectionTriggerTimeoutEvent, "AcquireConnectionTriggerTimeoutEvent"},
|
|
||||||
{545, nullptr, "SendConnectionTrigger"},
|
|
||||||
{546, &IHidSystemServer::AcquireDeviceRegisteredEventForControllerSupport, "AcquireDeviceRegisteredEventForControllerSupport"},
|
|
||||||
{547, nullptr, "GetAllowedBluetoothLinksCount"},
|
|
||||||
{548, &IHidSystemServer::GetRegisteredDevices, "GetRegisteredDevices"},
|
|
||||||
{549, nullptr, "GetConnectableRegisteredDevices"},
|
|
||||||
{700, nullptr, "ActivateUniquePad"},
|
|
||||||
{702, &IHidSystemServer::AcquireUniquePadConnectionEventHandle, "AcquireUniquePadConnectionEventHandle"},
|
|
||||||
{703, &IHidSystemServer::GetUniquePadIds, "GetUniquePadIds"},
|
|
||||||
{751, &IHidSystemServer::AcquireJoyDetachOnBluetoothOffEventHandle, "AcquireJoyDetachOnBluetoothOffEventHandle"},
|
|
||||||
{800, nullptr, "ListSixAxisSensorHandles"},
|
|
||||||
{801, nullptr, "IsSixAxisSensorUserCalibrationSupported"},
|
|
||||||
{802, nullptr, "ResetSixAxisSensorCalibrationValues"},
|
|
||||||
{803, nullptr, "StartSixAxisSensorUserCalibration"},
|
|
||||||
{804, nullptr, "CancelSixAxisSensorUserCalibration"},
|
|
||||||
{805, nullptr, "GetUniquePadBluetoothAddress"},
|
|
||||||
{806, nullptr, "DisconnectUniquePad"},
|
|
||||||
{807, nullptr, "GetUniquePadType"},
|
|
||||||
{808, nullptr, "GetUniquePadInterface"},
|
|
||||||
{809, nullptr, "GetUniquePadSerialNumber"},
|
|
||||||
{810, nullptr, "GetUniquePadControllerNumber"},
|
|
||||||
{811, nullptr, "GetSixAxisSensorUserCalibrationStage"},
|
|
||||||
{812, nullptr, "GetConsoleUniqueSixAxisSensorHandle"},
|
|
||||||
{821, nullptr, "StartAnalogStickManualCalibration"},
|
|
||||||
{822, nullptr, "RetryCurrentAnalogStickManualCalibrationStage"},
|
|
||||||
{823, nullptr, "CancelAnalogStickManualCalibration"},
|
|
||||||
{824, nullptr, "ResetAnalogStickManualCalibration"},
|
|
||||||
{825, nullptr, "GetAnalogStickState"},
|
|
||||||
{826, nullptr, "GetAnalogStickManualCalibrationStage"},
|
|
||||||
{827, nullptr, "IsAnalogStickButtonPressed"},
|
|
||||||
{828, nullptr, "IsAnalogStickInReleasePosition"},
|
|
||||||
{829, nullptr, "IsAnalogStickInCircumference"},
|
|
||||||
{830, nullptr, "SetNotificationLedPattern"},
|
|
||||||
{831, nullptr, "SetNotificationLedPatternWithTimeout"},
|
|
||||||
{832, nullptr, "PrepareHidsForNotificationWake"},
|
|
||||||
{850, &IHidSystemServer::IsUsbFullKeyControllerEnabled, "IsUsbFullKeyControllerEnabled"},
|
|
||||||
{851, nullptr, "EnableUsbFullKeyController"},
|
|
||||||
{852, nullptr, "IsUsbConnected"},
|
|
||||||
{870, &IHidSystemServer::IsHandheldButtonPressedOnConsoleMode, "IsHandheldButtonPressedOnConsoleMode"},
|
|
||||||
{900, nullptr, "ActivateInputDetector"},
|
|
||||||
{901, nullptr, "NotifyInputDetector"},
|
|
||||||
{1000, &IHidSystemServer::InitializeFirmwareUpdate, "InitializeFirmwareUpdate"},
|
|
||||||
{1001, nullptr, "GetFirmwareVersion"},
|
|
||||||
{1002, nullptr, "GetAvailableFirmwareVersion"},
|
|
||||||
{1003, nullptr, "IsFirmwareUpdateAvailable"},
|
|
||||||
{1004, nullptr, "CheckFirmwareUpdateRequired"},
|
|
||||||
{1005, nullptr, "StartFirmwareUpdate"},
|
|
||||||
{1006, nullptr, "AbortFirmwareUpdate"},
|
|
||||||
{1007, nullptr, "GetFirmwareUpdateState"},
|
|
||||||
{1008, nullptr, "ActivateAudioControl"},
|
|
||||||
{1009, nullptr, "AcquireAudioControlEventHandle"},
|
|
||||||
{1010, nullptr, "GetAudioControlStates"},
|
|
||||||
{1011, nullptr, "DeactivateAudioControl"},
|
|
||||||
{1050, nullptr, "IsSixAxisSensorAccurateUserCalibrationSupported"},
|
|
||||||
{1051, nullptr, "StartSixAxisSensorAccurateUserCalibration"},
|
|
||||||
{1052, nullptr, "CancelSixAxisSensorAccurateUserCalibration"},
|
|
||||||
{1053, nullptr, "GetSixAxisSensorAccurateUserCalibrationState"},
|
|
||||||
{1100, nullptr, "GetHidbusSystemServiceObject"},
|
|
||||||
{1120, nullptr, "SetFirmwareHotfixUpdateSkipEnabled"},
|
|
||||||
{1130, nullptr, "InitializeUsbFirmwareUpdate"},
|
|
||||||
{1131, nullptr, "FinalizeUsbFirmwareUpdate"},
|
|
||||||
{1132, nullptr, "CheckUsbFirmwareUpdateRequired"},
|
|
||||||
{1133, nullptr, "StartUsbFirmwareUpdate"},
|
|
||||||
{1134, nullptr, "GetUsbFirmwareUpdateState"},
|
|
||||||
{1135, &IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory, "InitializeUsbFirmwareUpdateWithoutMemory"},
|
|
||||||
{1150, nullptr, "SetTouchScreenMagnification"},
|
|
||||||
{1151, nullptr, "GetTouchScreenFirmwareVersion"},
|
|
||||||
{1152, nullptr, "SetTouchScreenDefaultConfiguration"},
|
|
||||||
{1153, &IHidSystemServer::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"},
|
|
||||||
{1154, nullptr, "IsFirmwareAvailableForNotification"},
|
|
||||||
{1155, nullptr, "SetForceHandheldStyleVibration"},
|
|
||||||
{1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"},
|
|
||||||
{1157, nullptr, "CancelConnectionTrigger"},
|
|
||||||
{1200, nullptr, "IsButtonConfigSupported"},
|
|
||||||
{1201, nullptr, "IsButtonConfigEmbeddedSupported"},
|
|
||||||
{1202, nullptr, "DeleteButtonConfig"},
|
|
||||||
{1203, nullptr, "DeleteButtonConfigEmbedded"},
|
|
||||||
{1204, nullptr, "SetButtonConfigEnabled"},
|
|
||||||
{1205, nullptr, "SetButtonConfigEmbeddedEnabled"},
|
|
||||||
{1206, nullptr, "IsButtonConfigEnabled"},
|
|
||||||
{1207, nullptr, "IsButtonConfigEmbeddedEnabled"},
|
|
||||||
{1208, nullptr, "SetButtonConfigEmbedded"},
|
|
||||||
{1209, nullptr, "SetButtonConfigFull"},
|
|
||||||
{1210, nullptr, "SetButtonConfigLeft"},
|
|
||||||
{1211, nullptr, "SetButtonConfigRight"},
|
|
||||||
{1212, nullptr, "GetButtonConfigEmbedded"},
|
|
||||||
{1213, nullptr, "GetButtonConfigFull"},
|
|
||||||
{1214, nullptr, "GetButtonConfigLeft"},
|
|
||||||
{1215, nullptr, "GetButtonConfigRight"},
|
|
||||||
{1250, nullptr, "IsCustomButtonConfigSupported"},
|
|
||||||
{1251, nullptr, "IsDefaultButtonConfigEmbedded"},
|
|
||||||
{1252, nullptr, "IsDefaultButtonConfigFull"},
|
|
||||||
{1253, nullptr, "IsDefaultButtonConfigLeft"},
|
|
||||||
{1254, nullptr, "IsDefaultButtonConfigRight"},
|
|
||||||
{1255, nullptr, "IsButtonConfigStorageEmbeddedEmpty"},
|
|
||||||
{1256, nullptr, "IsButtonConfigStorageFullEmpty"},
|
|
||||||
{1257, nullptr, "IsButtonConfigStorageLeftEmpty"},
|
|
||||||
{1258, nullptr, "IsButtonConfigStorageRightEmpty"},
|
|
||||||
{1259, nullptr, "GetButtonConfigStorageEmbeddedDeprecated"},
|
|
||||||
{1260, nullptr, "GetButtonConfigStorageFullDeprecated"},
|
|
||||||
{1261, nullptr, "GetButtonConfigStorageLeftDeprecated"},
|
|
||||||
{1262, nullptr, "GetButtonConfigStorageRightDeprecated"},
|
|
||||||
{1263, nullptr, "SetButtonConfigStorageEmbeddedDeprecated"},
|
|
||||||
{1264, nullptr, "SetButtonConfigStorageFullDeprecated"},
|
|
||||||
{1265, nullptr, "SetButtonConfigStorageLeftDeprecated"},
|
|
||||||
{1266, nullptr, "SetButtonConfigStorageRightDeprecated"},
|
|
||||||
{1267, nullptr, "DeleteButtonConfigStorageEmbedded"},
|
|
||||||
{1268, nullptr, "DeleteButtonConfigStorageFull"},
|
|
||||||
{1269, nullptr, "DeleteButtonConfigStorageLeft"},
|
|
||||||
{1270, nullptr, "DeleteButtonConfigStorageRight"},
|
|
||||||
{1271, nullptr, "IsUsingCustomButtonConfig"},
|
|
||||||
{1272, nullptr, "IsAnyCustomButtonConfigEnabled"},
|
|
||||||
{1273, nullptr, "SetAllCustomButtonConfigEnabled"},
|
|
||||||
{1274, nullptr, "SetDefaultButtonConfig"},
|
|
||||||
{1275, nullptr, "SetAllDefaultButtonConfig"},
|
|
||||||
{1276, nullptr, "SetHidButtonConfigEmbedded"},
|
|
||||||
{1277, nullptr, "SetHidButtonConfigFull"},
|
|
||||||
{1278, nullptr, "SetHidButtonConfigLeft"},
|
|
||||||
{1279, nullptr, "SetHidButtonConfigRight"},
|
|
||||||
{1280, nullptr, "GetHidButtonConfigEmbedded"},
|
|
||||||
{1281, nullptr, "GetHidButtonConfigFull"},
|
|
||||||
{1282, nullptr, "GetHidButtonConfigLeft"},
|
|
||||||
{1283, nullptr, "GetHidButtonConfigRight"},
|
|
||||||
{1284, nullptr, "GetButtonConfigStorageEmbedded"},
|
|
||||||
{1285, nullptr, "GetButtonConfigStorageFull"},
|
|
||||||
{1286, nullptr, "GetButtonConfigStorageLeft"},
|
|
||||||
{1287, nullptr, "GetButtonConfigStorageRight"},
|
|
||||||
{1288, nullptr, "SetButtonConfigStorageEmbedded"},
|
|
||||||
{1289, nullptr, "SetButtonConfigStorageFull"},
|
|
||||||
{1290, nullptr, "DeleteButtonConfigStorageRight"},
|
|
||||||
{1291, nullptr, "DeleteButtonConfigStorageRight"},
|
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
|
||||||
|
|
||||||
joy_detach_event = service_context.CreateEvent("IHidSystemServer::JoyDetachEvent");
|
|
||||||
acquire_device_registered_event =
|
|
||||||
service_context.CreateEvent("IHidSystemServer::AcquireDeviceRegisteredEvent");
|
|
||||||
acquire_connection_trigger_timeout_event =
|
|
||||||
service_context.CreateEvent("IHidSystemServer::AcquireConnectionTriggerTimeoutEvent");
|
|
||||||
unique_pad_connection_event =
|
|
||||||
service_context.CreateEvent("IHidSystemServer::AcquireUniquePadConnectionEventHandle");
|
|
||||||
}
|
|
||||||
|
|
||||||
IHidSystemServer::~IHidSystemServer() {
|
|
||||||
service_context.CloseEvent(joy_detach_event);
|
|
||||||
service_context.CloseEvent(acquire_device_registered_event);
|
|
||||||
service_context.CloseEvent(acquire_connection_trigger_timeout_event);
|
|
||||||
service_context.CloseEvent(unique_pad_connection_event);
|
|
||||||
};
|
|
||||||
|
|
||||||
void IHidSystemServer::ApplyNpadSystemCommonPolicy(HLERequestContext& ctx) {
|
|
||||||
LOG_WARNING(Service_HID, "called");
|
|
||||||
|
|
||||||
GetResourceManager()
|
|
||||||
->GetController<Controller_NPad>(HidController::NPad)
|
|
||||||
.ApplyNpadSystemCommonPolicy();
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::EnableAssigningSingleOnSlSrPress(HLERequestContext& ctx) {
|
|
||||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::DisableAssigningSingleOnSlSrPress(HLERequestContext& ctx) {
|
|
||||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::GetLastActiveNpad(HLERequestContext& ctx) {
|
|
||||||
LOG_DEBUG(Service_HID, "(STUBBED) called"); // Spams a lot when controller applet is running
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushEnum(system.HIDCore().GetLastActiveController());
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::ApplyNpadSystemCommonPolicyFull(HLERequestContext& ctx) {
|
|
||||||
LOG_WARNING(Service_HID, "called");
|
|
||||||
|
|
||||||
GetResourceManager()
|
|
||||||
->GetController<Controller_NPad>(HidController::NPad)
|
|
||||||
.ApplyNpadSystemCommonPolicy();
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::GetNpadFullKeyGripColor(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_HID, "(STUBBED) called, npad_id_type={}",
|
|
||||||
npad_id_type); // Spams a lot when controller applet is running
|
|
||||||
|
|
||||||
Core::HID::NpadColor left_color{};
|
|
||||||
Core::HID::NpadColor right_color{};
|
|
||||||
// TODO: Get colors from Npad
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushRaw(left_color);
|
|
||||||
rb.PushRaw(right_color);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::GetMaskedSupportedNpadStyleSet(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
|
|
||||||
LOG_INFO(Service_HID, "(STUBBED) called");
|
|
||||||
|
|
||||||
Core::HID::NpadStyleSet supported_styleset =
|
|
||||||
GetResourceManager()
|
|
||||||
->GetController<Controller_NPad>(HidController::NPad)
|
|
||||||
.GetSupportedStyleSet()
|
|
||||||
.raw;
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushEnum(supported_styleset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::SetSupportedNpadStyleSetAll(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
|
|
||||||
LOG_INFO(Service_HID, "(STUBBED) called");
|
|
||||||
|
|
||||||
Core::HID::NpadStyleSet supported_styleset =
|
|
||||||
GetResourceManager()
|
|
||||||
->GetController<Controller_NPad>(HidController::NPad)
|
|
||||||
.GetSupportedStyleSet()
|
|
||||||
.raw;
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushEnum(supported_styleset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::GetAppletDetailedUiType(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_HID, "called, npad_id_type={}",
|
|
||||||
npad_id_type); // Spams a lot when controller applet is running
|
|
||||||
|
|
||||||
const Service::HID::Controller_NPad::AppletDetailedUiType detailed_ui_type =
|
|
||||||
GetResourceManager()
|
|
||||||
->GetController<Controller_NPad>(HidController::NPad)
|
|
||||||
.GetAppletDetailedUiType(npad_id_type);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushRaw(detailed_ui_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::GetNpadInterfaceType(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_HID, "(STUBBED) called, npad_id_type={}",
|
|
||||||
npad_id_type); // Spams a lot when controller applet is running
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushEnum(Core::HID::NpadInterfaceType::Bluetooth);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::GetNpadLeftRightInterfaceType(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_HID, "(STUBBED) called, npad_id_type={}",
|
|
||||||
npad_id_type); // Spams a lot when controller applet is running
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushEnum(Core::HID::NpadInterfaceType::Bluetooth);
|
|
||||||
rb.PushEnum(Core::HID::NpadInterfaceType::Bluetooth);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::HasBattery(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_HID, "(STUBBED) called, npad_id_type={}",
|
|
||||||
npad_id_type); // Spams a lot when controller applet is running
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.Push(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::HasLeftRightBattery(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_HID, "(STUBBED) called, npad_id_type={}",
|
|
||||||
npad_id_type); // Spams a lot when controller applet is running
|
|
||||||
|
|
||||||
struct LeftRightBattery {
|
|
||||||
bool left;
|
|
||||||
bool right;
|
|
||||||
};
|
|
||||||
|
|
||||||
LeftRightBattery left_right_battery{
|
|
||||||
.left = false,
|
|
||||||
.right = false,
|
|
||||||
};
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushRaw(left_right_battery);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::GetUniquePadsFromNpad(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_HID, "(STUBBED) called, npad_id_type={}",
|
|
||||||
npad_id_type); // Spams a lot when controller applet is running
|
|
||||||
|
|
||||||
const std::vector<Core::HID::UniquePadId> unique_pads{};
|
|
||||||
|
|
||||||
if (!unique_pads.empty()) {
|
|
||||||
ctx.WriteBuffer(unique_pads);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.Push(static_cast<u32>(unique_pads.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::GetIrSensorState(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
|
|
||||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx) {
|
|
||||||
LOG_INFO(Service_AM, "(STUBBED) called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushCopyObjects(acquire_device_registered_event->GetReadableEvent());
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx) {
|
|
||||||
LOG_INFO(Service_HID, "(STUBBED) called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushCopyObjects(acquire_device_registered_event->GetReadableEvent());
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::GetRegisteredDevices(HLERequestContext& ctx) {
|
|
||||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
|
||||||
|
|
||||||
struct RegisterData {
|
|
||||||
std::array<u8, 0x68> data;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(RegisterData) == 0x68, "RegisterData is an invalid size");
|
|
||||||
std::vector<RegisterData> registered_devices{};
|
|
||||||
|
|
||||||
if (!registered_devices.empty()) {
|
|
||||||
ctx.WriteBuffer(registered_devices);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.Push<u64>(registered_devices.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::AcquireUniquePadConnectionEventHandle(HLERequestContext& ctx) {
|
|
||||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
|
||||||
rb.PushCopyObjects(unique_pad_connection_event->GetReadableEvent());
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::GetUniquePadIds(HLERequestContext& ctx) {
|
|
||||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.Push<u64>(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::AcquireJoyDetachOnBluetoothOffEventHandle(HLERequestContext& ctx) {
|
|
||||||
LOG_INFO(Service_AM, "called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushCopyObjects(joy_detach_event->GetReadableEvent());
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::IsUsbFullKeyControllerEnabled(HLERequestContext& ctx) {
|
|
||||||
const bool is_enabled = false;
|
|
||||||
|
|
||||||
LOG_WARNING(Service_HID, "(STUBBED) called, is_enabled={}", is_enabled);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.Push(is_enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::IsHandheldButtonPressedOnConsoleMode(HLERequestContext& ctx) {
|
|
||||||
const bool button_pressed = false;
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_HID, "(STUBBED) called, is_enabled={}",
|
|
||||||
button_pressed); // Spams a lot when controller applet is open
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.Push(button_pressed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::InitializeFirmwareUpdate(HLERequestContext& ctx) {
|
|
||||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx) {
|
|
||||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHidSystemServer::GetTouchScreenDefaultConfiguration(HLERequestContext& ctx) {
|
|
||||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
|
||||||
|
|
||||||
Core::HID::TouchScreenConfigurationForNx touchscreen_config{
|
|
||||||
.mode = Core::HID::TouchScreenModeForNx::Finger,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 &&
|
|
||||||
touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) {
|
|
||||||
touchscreen_config.mode = Core::HID::TouchScreenModeForNx::UseSystemSetting;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 6};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushRaw(touchscreen_config);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<ResourceManager> IHidSystemServer::GetResourceManager() {
|
|
||||||
resource_manager->Initialize();
|
|
||||||
return resource_manager;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Service::HID
|
|
@ -1,63 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "core/hle/service/kernel_helpers.h"
|
|
||||||
#include "core/hle/service/service.h"
|
|
||||||
|
|
||||||
namespace Core {
|
|
||||||
class System;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Kernel {
|
|
||||||
class KEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Service::HID {
|
|
||||||
class ResourceManager;
|
|
||||||
|
|
||||||
class IHidSystemServer final : public ServiceFramework<IHidSystemServer> {
|
|
||||||
public:
|
|
||||||
explicit IHidSystemServer(Core::System& system_, std::shared_ptr<ResourceManager> resource);
|
|
||||||
~IHidSystemServer() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void ApplyNpadSystemCommonPolicy(HLERequestContext& ctx);
|
|
||||||
void EnableAssigningSingleOnSlSrPress(HLERequestContext& ctx);
|
|
||||||
void DisableAssigningSingleOnSlSrPress(HLERequestContext& ctx);
|
|
||||||
void GetLastActiveNpad(HLERequestContext& ctx);
|
|
||||||
void ApplyNpadSystemCommonPolicyFull(HLERequestContext& ctx);
|
|
||||||
void GetNpadFullKeyGripColor(HLERequestContext& ctx);
|
|
||||||
void GetMaskedSupportedNpadStyleSet(HLERequestContext& ctx);
|
|
||||||
void SetSupportedNpadStyleSetAll(HLERequestContext& ctx);
|
|
||||||
void GetAppletDetailedUiType(HLERequestContext& ctx);
|
|
||||||
void GetNpadInterfaceType(HLERequestContext& ctx);
|
|
||||||
void GetNpadLeftRightInterfaceType(HLERequestContext& ctx);
|
|
||||||
void HasBattery(HLERequestContext& ctx);
|
|
||||||
void HasLeftRightBattery(HLERequestContext& ctx);
|
|
||||||
void GetUniquePadsFromNpad(HLERequestContext& ctx);
|
|
||||||
void GetIrSensorState(HLERequestContext& ctx);
|
|
||||||
void AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx);
|
|
||||||
void AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx);
|
|
||||||
void GetRegisteredDevices(HLERequestContext& ctx);
|
|
||||||
void AcquireUniquePadConnectionEventHandle(HLERequestContext& ctx);
|
|
||||||
void GetUniquePadIds(HLERequestContext& ctx);
|
|
||||||
void AcquireJoyDetachOnBluetoothOffEventHandle(HLERequestContext& ctx);
|
|
||||||
void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx);
|
|
||||||
void IsHandheldButtonPressedOnConsoleMode(HLERequestContext& ctx);
|
|
||||||
void InitializeFirmwareUpdate(HLERequestContext& ctx);
|
|
||||||
void InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx);
|
|
||||||
void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx);
|
|
||||||
|
|
||||||
std::shared_ptr<ResourceManager> GetResourceManager();
|
|
||||||
|
|
||||||
Kernel::KEvent* acquire_connection_trigger_timeout_event;
|
|
||||||
Kernel::KEvent* acquire_device_registered_event;
|
|
||||||
Kernel::KEvent* joy_detach_event;
|
|
||||||
Kernel::KEvent* unique_pad_connection_event;
|
|
||||||
KernelHelpers::ServiceContext service_context;
|
|
||||||
std::shared_ptr<ResourceManager> resource_manager;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Service::HID
|
|
@ -3,12 +3,15 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "core/core.h"
|
|
||||||
#include "core/hid/hid_types.h"
|
#include "core/hid/hid_types.h"
|
||||||
#include "core/hid/irs_types.h"
|
#include "core/hid/irs_types.h"
|
||||||
#include "core/hle/service/hid/irsensor/processor_base.h"
|
#include "core/hle/service/hid/irsensor/processor_base.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Core::HID {
|
namespace Core::HID {
|
||||||
class EmulatedController;
|
class EmulatedController;
|
||||||
} // namespace Core::HID
|
} // namespace Core::HID
|
||||||
|
@ -1,184 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
|
||||||
#include "core/core.h"
|
|
||||||
#include "core/core_timing.h"
|
|
||||||
#include "core/hid/hid_core.h"
|
|
||||||
#include "core/hle/kernel/k_shared_memory.h"
|
|
||||||
#include "core/hle/service/hid/resource_manager.h"
|
|
||||||
#include "core/hle/service/ipc_helpers.h"
|
|
||||||
|
|
||||||
#include "core/hle/service/hid/controllers/console_sixaxis.h"
|
|
||||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
|
||||||
#include "core/hle/service/hid/controllers/debug_pad.h"
|
|
||||||
#include "core/hle/service/hid/controllers/gesture.h"
|
|
||||||
#include "core/hle/service/hid/controllers/keyboard.h"
|
|
||||||
#include "core/hle/service/hid/controllers/mouse.h"
|
|
||||||
#include "core/hle/service/hid/controllers/npad.h"
|
|
||||||
#include "core/hle/service/hid/controllers/palma.h"
|
|
||||||
#include "core/hle/service/hid/controllers/stubbed.h"
|
|
||||||
#include "core/hle/service/hid/controllers/touchscreen.h"
|
|
||||||
#include "core/hle/service/hid/controllers/xpad.h"
|
|
||||||
|
|
||||||
namespace Service::HID {
|
|
||||||
|
|
||||||
// Updating period for each HID device.
|
|
||||||
// Period time is obtained by measuring the number of samples in a second on HW using a homebrew
|
|
||||||
// Correct npad_update_ns is 4ms this is overclocked to lower input lag
|
|
||||||
constexpr auto npad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz)
|
|
||||||
constexpr auto default_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 1000Hz)
|
|
||||||
constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz)
|
|
||||||
constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz)
|
|
||||||
|
|
||||||
ResourceManager::ResourceManager(Core::System& system_)
|
|
||||||
: system{system_}, service_context{system_, "hid"} {}
|
|
||||||
|
|
||||||
ResourceManager::~ResourceManager() = default;
|
|
||||||
|
|
||||||
void ResourceManager::Initialize() {
|
|
||||||
if (is_initialized) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
u8* shared_memory = system.Kernel().GetHidSharedMem().GetPointer();
|
|
||||||
MakeController<Controller_DebugPad>(HidController::DebugPad, shared_memory);
|
|
||||||
MakeController<Controller_Touchscreen>(HidController::Touchscreen, shared_memory);
|
|
||||||
MakeController<Controller_Mouse>(HidController::Mouse, shared_memory);
|
|
||||||
MakeController<Controller_Keyboard>(HidController::Keyboard, shared_memory);
|
|
||||||
MakeController<Controller_XPad>(HidController::XPad, shared_memory);
|
|
||||||
MakeController<Controller_Stubbed>(HidController::HomeButton, shared_memory);
|
|
||||||
MakeController<Controller_Stubbed>(HidController::SleepButton, shared_memory);
|
|
||||||
MakeController<Controller_Stubbed>(HidController::CaptureButton, shared_memory);
|
|
||||||
MakeController<Controller_Stubbed>(HidController::InputDetector, shared_memory);
|
|
||||||
MakeController<Controller_Stubbed>(HidController::UniquePad, shared_memory);
|
|
||||||
MakeControllerWithServiceContext<Controller_NPad>(HidController::NPad, shared_memory);
|
|
||||||
MakeController<Controller_Gesture>(HidController::Gesture, shared_memory);
|
|
||||||
MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor, shared_memory);
|
|
||||||
MakeController<Controller_Stubbed>(HidController::DebugMouse, shared_memory);
|
|
||||||
MakeControllerWithServiceContext<Controller_Palma>(HidController::Palma, shared_memory);
|
|
||||||
|
|
||||||
// Homebrew doesn't try to activate some controllers, so we activate them by default
|
|
||||||
GetController<Controller_NPad>(HidController::NPad).Activate();
|
|
||||||
GetController<Controller_Touchscreen>(HidController::Touchscreen).Activate();
|
|
||||||
|
|
||||||
GetController<Controller_Stubbed>(HidController::HomeButton).SetCommonHeaderOffset(0x4C00);
|
|
||||||
GetController<Controller_Stubbed>(HidController::SleepButton).SetCommonHeaderOffset(0x4E00);
|
|
||||||
GetController<Controller_Stubbed>(HidController::CaptureButton).SetCommonHeaderOffset(0x5000);
|
|
||||||
GetController<Controller_Stubbed>(HidController::InputDetector).SetCommonHeaderOffset(0x5200);
|
|
||||||
GetController<Controller_Stubbed>(HidController::UniquePad).SetCommonHeaderOffset(0x5A00);
|
|
||||||
GetController<Controller_Stubbed>(HidController::DebugMouse).SetCommonHeaderOffset(0x3DC00);
|
|
||||||
|
|
||||||
system.HIDCore().ReloadInputDevices();
|
|
||||||
is_initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResourceManager::UpdateControllers(std::uintptr_t user_data,
|
|
||||||
std::chrono::nanoseconds ns_late) {
|
|
||||||
auto& core_timing = system.CoreTiming();
|
|
||||||
|
|
||||||
for (const auto& controller : controllers) {
|
|
||||||
// Keyboard has it's own update event
|
|
||||||
if (controller == controllers[static_cast<size_t>(HidController::Keyboard)]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Mouse has it's own update event
|
|
||||||
if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Npad has it's own update event
|
|
||||||
if (controller == controllers[static_cast<size_t>(HidController::NPad)]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
controller->OnUpdate(core_timing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResourceManager::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
|
||||||
auto& core_timing = system.CoreTiming();
|
|
||||||
|
|
||||||
controllers[static_cast<size_t>(HidController::NPad)]->OnUpdate(core_timing);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResourceManager::UpdateMouseKeyboard(std::uintptr_t user_data,
|
|
||||||
std::chrono::nanoseconds ns_late) {
|
|
||||||
auto& core_timing = system.CoreTiming();
|
|
||||||
|
|
||||||
controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(core_timing);
|
|
||||||
controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(core_timing);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResourceManager::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
|
||||||
auto& core_timing = system.CoreTiming();
|
|
||||||
|
|
||||||
controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(core_timing);
|
|
||||||
}
|
|
||||||
|
|
||||||
IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource)
|
|
||||||
: ServiceFramework{system_, "IAppletResource"} {
|
|
||||||
static const FunctionInfo functions[] = {
|
|
||||||
{0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
|
|
||||||
};
|
|
||||||
RegisterHandlers(functions);
|
|
||||||
|
|
||||||
resource->Initialize();
|
|
||||||
|
|
||||||
// Register update callbacks
|
|
||||||
npad_update_event = Core::Timing::CreateEvent(
|
|
||||||
"HID::UpdatePadCallback",
|
|
||||||
[this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
|
|
||||||
-> std::optional<std::chrono::nanoseconds> {
|
|
||||||
const auto guard = LockService();
|
|
||||||
resource->UpdateNpad(user_data, ns_late);
|
|
||||||
return std::nullopt;
|
|
||||||
});
|
|
||||||
default_update_event = Core::Timing::CreateEvent(
|
|
||||||
"HID::UpdateDefaultCallback",
|
|
||||||
[this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
|
|
||||||
-> std::optional<std::chrono::nanoseconds> {
|
|
||||||
const auto guard = LockService();
|
|
||||||
resource->UpdateControllers(user_data, ns_late);
|
|
||||||
return std::nullopt;
|
|
||||||
});
|
|
||||||
mouse_keyboard_update_event = Core::Timing::CreateEvent(
|
|
||||||
"HID::UpdateMouseKeyboardCallback",
|
|
||||||
[this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
|
|
||||||
-> std::optional<std::chrono::nanoseconds> {
|
|
||||||
const auto guard = LockService();
|
|
||||||
resource->UpdateMouseKeyboard(user_data, ns_late);
|
|
||||||
return std::nullopt;
|
|
||||||
});
|
|
||||||
motion_update_event = Core::Timing::CreateEvent(
|
|
||||||
"HID::UpdateMotionCallback",
|
|
||||||
[this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
|
|
||||||
-> std::optional<std::chrono::nanoseconds> {
|
|
||||||
const auto guard = LockService();
|
|
||||||
resource->UpdateMotion(user_data, ns_late);
|
|
||||||
return std::nullopt;
|
|
||||||
});
|
|
||||||
|
|
||||||
system.CoreTiming().ScheduleLoopingEvent(npad_update_ns, npad_update_ns, npad_update_event);
|
|
||||||
system.CoreTiming().ScheduleLoopingEvent(default_update_ns, default_update_ns,
|
|
||||||
default_update_event);
|
|
||||||
system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns,
|
|
||||||
mouse_keyboard_update_event);
|
|
||||||
system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns,
|
|
||||||
motion_update_event);
|
|
||||||
}
|
|
||||||
|
|
||||||
IAppletResource::~IAppletResource() {
|
|
||||||
system.CoreTiming().UnscheduleEvent(npad_update_event, 0);
|
|
||||||
system.CoreTiming().UnscheduleEvent(default_update_event, 0);
|
|
||||||
system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0);
|
|
||||||
system.CoreTiming().UnscheduleEvent(motion_update_event, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IAppletResource::GetSharedMemoryHandle(HLERequestContext& ctx) {
|
|
||||||
LOG_DEBUG(Service_HID, "called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushCopyObjects(&system.Kernel().GetHidSharedMem());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Service::HID
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user