Compare commits

..

61 Commits

Author SHA1 Message Date
9ae76f3691 Android 188 2024-01-10 01:00:45 +00:00
c4504ac86e Merge yuzu-emu#12579 2024-01-10 01:00:45 +00:00
4fdc900581 Merge pull request #12634 from lat9nq/apple-intl-2
externals: Update txdb_to_nx
2024-01-09 18:42:57 -05:00
d99830b59c externals: Update txdb_to_nx
Includes a fix lat9nq/tzdb_to_nx@1e82342 that fixes a build issue on Mac OS.
2024-01-09 17:29:38 -05:00
23c11e50f9 Merge pull request #12609 from liamwhite/wrong-name-again
vi: minor cleanups
2024-01-09 11:15:56 -06:00
5fde5e62a8 Merge pull request #12622 from liamwhite/format
ci: make verify format workflow output more helpful
2024-01-09 07:31:34 -05:00
f124461674 Fix typos in src/core (#12625)
* Fix typos in src/core

* Fix typo correction

* Fix indentation of MemoryStateNames

* Fix indent
2024-01-08 13:31:48 -06:00
30743eff56 ci: make verify format workflow output more helpful 2024-01-08 09:52:25 -05:00
4f83b00f6f general: fix trailing whitespace 2024-01-08 09:34:32 -05:00
ea710e6523 vi: connect vsync event handle lifetime to application display service interface 2024-01-07 21:47:41 -05:00
ae88ea79b2 vi: fix name of nvnflinger 2024-01-07 21:31:03 -05:00
82b58668ed Merge pull request #12608 from szepeviktor/typos
Fix typos in video_core
2024-01-07 20:42:54 -05:00
bd80929ac1 Merge pull request #12606 from german77/npad_close
service: hid: Delete shared memory handle when unused
2024-01-07 20:41:11 -05:00
2a4ac7cfac Merge pull request #12600 from german77/npad-impl
service: hid: Hook interface implementations
2024-01-07 20:41:06 -05:00
ab513c378a Merge pull request #12599 from german77/settings
service: set: Use official names
2024-01-07 20:40:56 -05:00
a959fb011f Fix "Propietary" typo elsewhere 2024-01-07 23:15:38 +00:00
53085a45e0 Fix typos in video_core 2024-01-07 22:44:55 +00:00
bc2d1262d7 service: hid: Delete shared memory handle when unused 2024-01-07 12:55:24 -06:00
1220309323 Merge pull request #12560 from GayPotatoEmma/master
android: add basic support for google game dashboard
2024-01-07 10:43:53 -05:00
a972341b5d Merge pull request #12601 from german77/rocket
service: hid: Make sure there's an active aruid handle
2024-01-07 07:33:38 -05:00
87430acff1 Merge pull request #12576 from t895/total-save-manager
android: Re-add global save manager
2024-01-07 07:33:31 -05:00
0b4cc6e14c service: hid: Make sure there's an active aruid handle 2024-01-06 23:49:52 -06:00
5105b90017 service: hid: Implement GetLastActiveNpad 2024-01-06 23:30:43 -06:00
3516a2d0bf service: hid: Implement AssigningSingleOnSlSrPress 2024-01-06 23:30:42 -06:00
f224ef6185 service: hid: Implement SetNpadSystemExtStateEnabled 2024-01-06 23:30:41 -06:00
8e27a485d8 service: set: Rename files 2024-01-06 23:16:03 -06:00
a36f4d0a9f service: hid: Implement CaptureButtonAssignment 2024-01-06 21:18:44 -06:00
b71840bbd2 Merge pull request #12596 from german77/hid_qlaunch
service: hid: Add functions needed by QLaunch
2024-01-06 21:51:29 -05:00
71fbc87dbd Merge pull request #12593 from german77/pending-delete
service: hid: Handle pending delete
2024-01-06 21:51:22 -05:00
37b0870ee3 service: set: Use official names 2024-01-06 17:37:36 -06:00
3dbe998f9b service: hid: Add functions needed by Qlaunch 2024-01-06 16:10:37 -06:00
edfbf363de service: hid: Handle pending delete 2024-01-06 15:42:19 -06:00
12fd2ae86d Merge pull request #12582 from german77/hid-core
hid_core: Move hid to it's own subproject
2024-01-06 15:38:59 -06:00
ee847f8ff0 hid_core: Move hid to it's own subproject 2024-01-05 11:41:15 -06:00
92a331af76 Merge pull request #12437 from ameerj/gl-amd-fixes
OpenGL: Fixes and workaround updates for AMD
2024-01-04 15:53:44 -05:00
a8f62bff43 Merge pull request #12575 from t895/inconsistent-settings-application
frontend_common: config: Only write setting related to opened config file
2024-01-04 15:51:24 -05:00
519904e8a8 Merge pull request #12571 from t895/apply-orientation-on-start
android: Expose more orientation options
2024-01-04 15:51:08 -05:00
8d3463dbdd Merge pull request #12570 from t895/generic-config-pain
frontend_common: config: Move WriteIntegerSetting definition to header
2024-01-04 15:51:00 -05:00
b125cb97a2 Merge pull request #12568 from t895/actions-button
actions: android: Allow for manually triggering Android builds
2024-01-04 15:50:54 -05:00
d7e7a69e00 Merge pull request #12558 from t895/zip-storage-method
android: Disable compression for zip exports
2024-01-04 15:50:47 -05:00
246cffb624 Merge pull request #12557 from merryhime/termination-ipi
KThread: Send termination interrupt to all cores a thread has affinity to
2024-01-04 15:50:40 -05:00
0e93cad4f0 Merge pull request #12549 from german77/npadresource
service: hid: Implement NpadResource and NpadData
2024-01-04 15:50:33 -05:00
53d4dbacf0 android: Re-add global save manager
Reworked to correctly collect and import/export saves that could exist in either /nand/user/save/000...000/<user id> or /nand/user/save/account/<user id raw string>
2024-01-04 00:56:40 -05:00
39d28a5131 android: Save global config synchronously in onCloseGameFoldersFragment
Could cause multiple global saves at once that went untracked previously
2024-01-03 22:50:21 -05:00
fa04dea7c4 frontend_common: config: Only write setting related to opened config file
If we tried to write a switchable setting to config that was not using global in the global config instance, we could write the per-game setting accidentally. This ensures that we always use the global setting for global config and the currently applied setting for custom config.
2024-01-03 22:49:41 -05:00
1c278974a8 android: Don't save settings on config destruction
Android doesn't have a proper way of destroying its config object so it's best to stick to the built-in methods to control saving config
2024-01-03 22:12:15 -05:00
2b838b6d06 android: Update orientation on emulation fragment start 2024-01-03 21:35:45 -05:00
82ea082997 android: Expose all orientation locking options 2024-01-03 21:35:45 -05:00
5562322290 service: hid: Remove data races when handling shared memory 2024-01-03 20:21:16 -06:00
6a244465ce service: hid: Implement NpadResource and NpadData 2024-01-03 20:21:14 -06:00
e5de3d5a77 android: add basic support for google game dashboard 2024-01-04 01:07:43 +01:00
bdf87ba0f8 frontend_common: config: Move WriteIntegerSetting definition to header
Fixes a compiler error where the compiler could not see the definition of the method in qt_config and others.
2024-01-03 17:57:20 -05:00
3b314a68a1 actions: android: Prevent resolving tag commit to PR link 2024-01-03 17:01:31 -05:00
06c68fb196 actions: android: Resolve PR commits to link 2024-01-03 17:00:49 -05:00
9a31122c82 actions: android: Move trigger logic to be yuzu-android specific 2024-01-03 03:15:07 -05:00
dace726d08 android: Add internal option to disable compression for zip exports
Disables compression for user data and save exports
2024-01-02 18:11:22 -05:00
0f7fc94111 KThread: Send termination interrupt to all cores a thread has affinity to
KThread::RequestTerminate may run from a thread which is not the CurrentCore, and thus
masking this out is erroneous.
2024-01-02 21:34:34 +00:00
139b4cc9ea Settings: Indicate AMD's compatibility with SPIR-V on OGL 2023-12-21 22:00:49 -05:00
d5d0d2cb0e spirv_emit_context: Fix BaseInstance for OGL spirv 2023-12-21 21:53:24 -05:00
a5b2b8b91b emit_glsl_image: Use inlined texelFetch offsets 2023-12-20 19:24:11 -05:00
b4b301d22e gl_device: Remove AMD blacklists that are no longer applicable 2023-12-20 18:19:15 -05:00
336 changed files with 4390 additions and 2553 deletions

View File

@ -3,38 +3,33 @@
# SPDX-FileCopyrightText: 2019 yuzu Emulator Project # SPDX-FileCopyrightText: 2019 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
if grep -nrI '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .ci* dist/*.desktop \ shopt -s nullglob globstar
if grep -nrI '\s$' src **/*.yml **/*.txt **/*.md Doxyfile .gitignore .gitmodules .ci* dist/*.desktop \
dist/*.svg dist/*.xml; then dist/*.svg dist/*.xml; then
echo Trailing whitespace found, aborting echo Trailing whitespace found, aborting
exit 1 exit 1
fi fi
# Default clang-format points to default 3.5 version one # Default clang-format points to default 3.5 version one
CLANG_FORMAT=${CLANG_FORMAT:-clang-format-15} CLANG_FORMAT="${CLANG_FORMAT:-clang-format-15}"
$CLANG_FORMAT --version "$CLANG_FORMAT" --version
if [ "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then
# Get list of every file modified in this pull request
files_to_lint="$(git diff --name-only --diff-filter=ACMRTUXB $TRAVIS_COMMIT_RANGE | grep '^src/[^.]*[.]\(cpp\|h\)$' || true)"
else
# Check everything for branch pushes
files_to_lint="$(find src/ -name '*.cpp' -or -name '*.h')"
fi
# Turn off tracing for this because it's too verbose # Turn off tracing for this because it's too verbose
set +x set +x
for f in $files_to_lint; do # Check everything for branch pushes
d=$(diff -u "$f" <($CLANG_FORMAT "$f") || true) FILES_TO_LINT="$(find src/ -name '*.cpp' -or -name '*.h')"
if ! [ -z "$d" ]; then
echo "!!! $f not compliant to coding style, here is the fix:" for f in $FILES_TO_LINT; do
echo "$d" echo "$f"
fail=1 "$CLANG_FORMAT" -i "$f"
fi
done done
set -x DIFF=$(git diff)
if [ "$fail" = 1 ]; then if [ ! -z "$DIFF" ]; then
echo "!!! Not compliant to coding style, here is the fix:"
echo "$DIFF"
exit 1 exit 1
fi fi

View File

@ -9,7 +9,7 @@ chmod a+x ./.ci/scripts/linux/docker.sh
sudo chown -R 1027 ./ sudo chown -R 1027 ./
# The environment variables listed below: # The environment variables listed below:
# AZURECIREPO TITLEBARFORMATIDLE TITLEBARFORMATRUNNING DISPLAYVERSION # AZURECIREPO TITLEBARFORMATIDLE TITLEBARFORMATRUNNING DISPLAYVERSION
# are requested in src/common/CMakeLists.txt and appear to be provided somewhere in Azure DevOps # are requested in src/common/CMakeLists.txt and appear to be provided somewhere in Azure DevOps
docker run -e AZURECIREPO -e TITLEBARFORMATIDLE -e TITLEBARFORMATRUNNING -e DISPLAYVERSION -e ENABLE_COMPATIBILITY_REPORTING -e CCACHE_DIR=/yuzu/ccache -v "$(pwd):/yuzu" -w /yuzu yuzuemu/build-environments:linux-fresh /bin/bash /yuzu/.ci/scripts/linux/docker.sh "$1" docker run -e AZURECIREPO -e TITLEBARFORMATIDLE -e TITLEBARFORMATRUNNING -e DISPLAYVERSION -e ENABLE_COMPATIBILITY_REPORTING -e CCACHE_DIR=/yuzu/ccache -v "$(pwd):/yuzu" -w /yuzu yuzuemu/build-environments:linux-fresh /bin/bash /yuzu/.ci/scripts/linux/docker.sh "$1"

View File

@ -10,7 +10,7 @@ const CHANGE_LABEL = 'android-merge';
// how far back in time should we consider the changes are "recent"? (default: 24 hours) // how far back in time should we consider the changes are "recent"? (default: 24 hours)
const DETECTION_TIME_FRAME = (parseInt(process.env.DETECTION_TIME_FRAME)) || (24 * 3600 * 1000); const DETECTION_TIME_FRAME = (parseInt(process.env.DETECTION_TIME_FRAME)) || (24 * 3600 * 1000);
async function checkBaseChanges(github, context) { async function checkBaseChanges(github) {
// query the commit date of the latest commit on this branch // query the commit date of the latest commit on this branch
const query = `query($owner:String!, $name:String!, $ref:String!) { const query = `query($owner:String!, $name:String!, $ref:String!) {
repository(name:$name, owner:$owner) { repository(name:$name, owner:$owner) {
@ -22,8 +22,8 @@ async function checkBaseChanges(github, context) {
} }
}`; }`;
const variables = { const variables = {
owner: context.repo.owner, owner: 'yuzu-emu',
name: context.repo.repo, name: 'yuzu',
ref: 'refs/heads/master', ref: 'refs/heads/master',
}; };
const result = await github.graphql(query, variables); const result = await github.graphql(query, variables);
@ -38,8 +38,8 @@ async function checkBaseChanges(github, context) {
return false; return false;
} }
async function checkAndroidChanges(github, context) { async function checkAndroidChanges(github) {
if (checkBaseChanges(github, context)) return true; if (checkBaseChanges(github)) return true;
const query = `query($owner:String!, $name:String!, $label:String!) { const query = `query($owner:String!, $name:String!, $label:String!) {
repository(name:$name, owner:$owner) { repository(name:$name, owner:$owner) {
pullRequests(labels: [$label], states: OPEN, first: 100) { pullRequests(labels: [$label], states: OPEN, first: 100) {
@ -48,8 +48,8 @@ async function checkAndroidChanges(github, context) {
} }
}`; }`;
const variables = { const variables = {
owner: context.repo.owner, owner: 'yuzu-emu',
name: context.repo.repo, name: 'yuzu',
label: CHANGE_LABEL, label: CHANGE_LABEL,
}; };
const result = await github.graphql(query, variables); const result = await github.graphql(query, variables);
@ -90,8 +90,8 @@ async function tagAndPush(github, owner, repo, execa, commit=false) {
console.log(`New tag: ${newTag}`); console.log(`New tag: ${newTag}`);
if (commit) { if (commit) {
let channelName = channel[0].toUpperCase() + channel.slice(1); let channelName = channel[0].toUpperCase() + channel.slice(1);
console.info(`Committing pending commit as ${channelName} #${tagNumber + 1}`); console.info(`Committing pending commit as ${channelName} ${tagNumber + 1}`);
await execa("git", ['commit', '-m', `${channelName} #${tagNumber + 1}`]); await execa("git", ['commit', '-m', `${channelName} ${tagNumber + 1}`]);
} }
console.info('Pushing tags to GitHub ...'); console.info('Pushing tags to GitHub ...');
await execa("git", ['tag', newTag]); await execa("git", ['tag', newTag]);
@ -157,7 +157,7 @@ async function mergePullRequests(pulls, execa) {
process1.stdout.pipe(process.stdout); process1.stdout.pipe(process.stdout);
await process1; await process1;
const process2 = execa("git", ["commit", "-m", `Merge PR ${pr}`]); const process2 = execa("git", ["commit", "-m", `Merge yuzu-emu#${pr}`]);
process2.stdout.pipe(process.stdout); process2.stdout.pipe(process.stdout);
await process2; await process2;
@ -182,7 +182,30 @@ async function mergePullRequests(pulls, execa) {
return mergeResults; return mergeResults;
} }
async function resetBranch(execa) {
console.log("::group::Reset master branch");
let hasFailed = false;
try {
await execa("git", ["remote", "add", "source", "https://github.com/yuzu-emu/yuzu.git"]);
await execa("git", ["fetch", "source"]);
const process1 = await execa("git", ["rev-parse", "source/master"]);
const headCommit = process1.stdout;
await execa("git", ["reset", "--hard", headCommit]);
} catch (err) {
console.log(`::error title=Failed to reset master branch`);
hasFailed = true;
}
console.log("::endgroup::");
if (hasFailed) {
throw 'Failed to reset the master branch. Aborting!';
}
}
async function mergebot(github, context, execa) { async function mergebot(github, context, execa) {
// Reset our local copy of master to what appears on yuzu-emu/yuzu - master
await resetBranch(execa);
const query = `query ($owner:String!, $name:String!, $label:String!) { const query = `query ($owner:String!, $name:String!, $label:String!) {
repository(name:$name, owner:$owner) { repository(name:$name, owner:$owner) {
pullRequests(labels: [$label], states: OPEN, first: 100) { pullRequests(labels: [$label], states: OPEN, first: 100) {
@ -193,8 +216,8 @@ async function mergebot(github, context, execa) {
} }
}`; }`;
const variables = { const variables = {
owner: context.repo.owner, owner: 'yuzu-emu',
name: context.repo.repo, name: 'yuzu',
label: CHANGE_LABEL, label: CHANGE_LABEL,
}; };
const result = await github.graphql(query, variables); const result = await github.graphql(query, variables);
@ -209,7 +232,7 @@ async function mergebot(github, context, execa) {
await fetchPullRequests(pulls, "https://github.com/yuzu-emu/yuzu", execa); await fetchPullRequests(pulls, "https://github.com/yuzu-emu/yuzu", execa);
const mergeResults = await mergePullRequests(pulls, execa); const mergeResults = await mergePullRequests(pulls, execa);
await generateReadme(pulls, context, mergeResults, execa); await generateReadme(pulls, context, mergeResults, execa);
await tagAndPush(github, context.repo.owner, `${context.repo.repo}-android`, execa, true); await tagAndPush(github, 'yuzu-emu', `yuzu-android`, execa, true);
} }
module.exports.mergebot = mergebot; module.exports.mergebot = mergebot;

View File

@ -16,7 +16,7 @@ on:
jobs: jobs:
android: android:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: ${{ github.event.inputs.android != 'false' && github.repository == 'yuzu-emu/yuzu' }} if: ${{ github.event.inputs.android != 'false' && github.repository == 'yuzu-emu/yuzu-android' }}
steps: steps:
# this checkout is required to make sure the GitHub Actions scripts are available # this checkout is required to make sure the GitHub Actions scripts are available
- uses: actions/checkout@v3 - uses: actions/checkout@v3
@ -33,7 +33,7 @@ jobs:
script: | script: |
if (context.payload.inputs && context.payload.inputs.android === 'true') return true; if (context.payload.inputs && context.payload.inputs.android === 'true') return true;
const checkAndroidChanges = require('./.github/workflows/android-merge.js').checkAndroidChanges; const checkAndroidChanges = require('./.github/workflows/android-merge.js').checkAndroidChanges;
return checkAndroidChanges(github, context); return checkAndroidChanges(github);
- run: npm install execa@5 - run: npm install execa@5
if: ${{ steps.check-changes.outputs.result == 'true' }} if: ${{ steps.check-changes.outputs.result == 'true' }}
- uses: actions/checkout@v3 - uses: actions/checkout@v3

View File

@ -1,4 +1,4 @@
Copyright (c) <year> <owner> Copyright (c) <year> <owner>
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

View File

@ -1,4 +1,4 @@
Copyright (c) <year> <owner>. Copyright (c) <year> <owner>.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

View File

@ -35,7 +35,7 @@ Mozilla Public License Version 2.0
means any form of the work other than Source Code Form. means any form of the work other than Source Code Form.
1.7. "Larger Work" 1.7. "Larger Work"
means a work that combines Covered Software with other material, in means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software. a separate file or files, that is not Covered Software.
1.8. "License" 1.8. "License"

View File

@ -1,10 +1,6 @@
| Pull Request | Commit | Title | Author | Merged? | | Pull Request | Commit | Title | Author | Merged? |
|----|----|----|----|----| |----|----|----|----|----|
| [12549](https://github.com/yuzu-emu/yuzu//pull/12549) | [`d3531b682`](https://github.com/yuzu-emu/yuzu//pull/12549/files) | service: hid: Implement NpadResource and NpadData | [german77](https://github.com/german77/) | Yes | | [12579](https://github.com/yuzu-emu/yuzu-android//pull/12579) | [`66ae60a9e`](https://github.com/yuzu-emu/yuzu-android//pull/12579/files) | Core: Implement Device Mapping & GPU SMMU | [FernandoS27](https://github.com/FernandoS27/) | Yes |
| [12557](https://github.com/yuzu-emu/yuzu//pull/12557) | [`0f7fc9411`](https://github.com/yuzu-emu/yuzu//pull/12557/files) | KThread: Send termination interrupt to all cores a thread has affinity to | [merryhime](https://github.com/merryhime/) | Yes |
| [12558](https://github.com/yuzu-emu/yuzu//pull/12558) | [`dace726d0`](https://github.com/yuzu-emu/yuzu//pull/12558/files) | android: Disable compression for zip exports | [t895](https://github.com/t895/) | Yes |
| [12560](https://github.com/yuzu-emu/yuzu//pull/12560) | [`e5de3d5a7`](https://github.com/yuzu-emu/yuzu//pull/12560/files) | android: add basic support for google game dashboard | [GayPotatoEmma](https://github.com/GayPotatoEmma/) | Yes |
| [12571](https://github.com/yuzu-emu/yuzu//pull/12571) | [`48e5e4fd1`](https://github.com/yuzu-emu/yuzu//pull/12571/files) | android: Expose more orientation options | [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.

View File

@ -138,7 +138,7 @@ if (NOT WIN32 AND NOT ANDROID)
--cross-prefix=${TOOLCHAIN}/bin/aarch64-linux-android- --cross-prefix=${TOOLCHAIN}/bin/aarch64-linux-android-
--sysroot=${SYSROOT} --sysroot=${SYSROOT}
--target-os=android --target-os=android
--extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld" --extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld"
--extra-ldflags="-nostdlib" --extra-ldflags="-nostdlib"
) )
endif() endif()

View File

@ -185,6 +185,7 @@ add_subdirectory(common)
add_subdirectory(core) add_subdirectory(core)
add_subdirectory(audio_core) add_subdirectory(audio_core)
add_subdirectory(video_core) add_subdirectory(video_core)
add_subdirectory(hid_core)
add_subdirectory(network) add_subdirectory(network)
add_subdirectory(input_common) add_subdirectory(input_common)
add_subdirectory(frontend_common) add_subdirectory(frontend_common)

View File

@ -547,6 +547,15 @@ object NativeLibrary {
*/ */
external fun getSavePath(programId: String): String external fun getSavePath(programId: String): String
/**
* Gets the root save directory for the default profile as either
* /user/save/account/<user id raw string> or /user/save/000...000/<user id>
*
* @param future If true, returns the /user/save/account/... directory
* @return Save data path that may not exist yet
*/
external fun getDefaultProfileSaveDataRoot(future: Boolean): String
/** /**
* Adds a file to the manual filesystem provider in our EmulationSession instance * Adds a file to the manual filesystem provider in our EmulationSession instance
* @param path Path to the file we're adding. Can be a string representation of a [Uri] or * @param path Path to the file we're adding. Can be a string representation of a [Uri] or

View File

@ -467,14 +467,14 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
EmulationOrientation.SensorLandscape -> EmulationOrientation.SensorLandscape ->
ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
EmulationOrientation.Landscape -> ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE EmulationOrientation.Landscape -> ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
EmulationOrientation.ReverseLandscape -> EmulationOrientation.ReverseLandscape ->
ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
EmulationOrientation.SensorPortrait -> EmulationOrientation.SensorPortrait ->
ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
EmulationOrientation.Portrait -> ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT EmulationOrientation.Portrait -> ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
EmulationOrientation.ReversePortrait -> EmulationOrientation.ReversePortrait ->
ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT
} }

View File

@ -7,20 +7,39 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.transition.MaterialSharedAxis import com.google.android.material.transition.MaterialSharedAxis
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.adapters.InstallableAdapter import org.yuzu.yuzu_emu.adapters.InstallableAdapter
import org.yuzu.yuzu_emu.databinding.FragmentInstallablesBinding 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.model.TaskState
import org.yuzu.yuzu_emu.ui.main.MainActivity import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.FileUtil
import java.io.BufferedInputStream
import java.io.BufferedOutputStream
import java.io.File
import java.math.BigInteger
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
@ -56,6 +75,17 @@ class InstallableFragment : Fragment() {
binding.root.findNavController().popBackStack() binding.root.findNavController().popBackStack()
} }
viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
homeViewModel.openImportSaves.collect {
if (it) {
importSaves.launch(arrayOf("application/zip"))
homeViewModel.setOpenImportSaves(false)
}
}
}
}
val installables = listOf( val installables = listOf(
Installable( Installable(
R.string.user_data, R.string.user_data,
@ -63,6 +93,43 @@ class InstallableFragment : Fragment() {
install = { mainActivity.importUserData.launch(arrayOf("application/zip")) }, install = { mainActivity.importUserData.launch(arrayOf("application/zip")) },
export = { mainActivity.exportUserData.launch("export.zip") } export = { mainActivity.exportUserData.launch("export.zip") }
), ),
Installable(
R.string.manage_save_data,
R.string.manage_save_data_description,
install = {
MessageDialogFragment.newInstance(
requireActivity(),
titleId = R.string.import_save_warning,
descriptionId = R.string.import_save_warning_description,
positiveAction = { homeViewModel.setOpenImportSaves(true) }
).show(parentFragmentManager, MessageDialogFragment.TAG)
},
export = {
val oldSaveDataFolder = File(
"${DirectoryInitialization.userDirectory}/nand" +
NativeLibrary.getDefaultProfileSaveDataRoot(false)
)
val futureSaveDataFolder = File(
"${DirectoryInitialization.userDirectory}/nand" +
NativeLibrary.getDefaultProfileSaveDataRoot(true)
)
if (!oldSaveDataFolder.exists() && !futureSaveDataFolder.exists()) {
Toast.makeText(
YuzuApplication.appContext,
R.string.no_save_data_found,
Toast.LENGTH_SHORT
).show()
return@Installable
} else {
exportSaves.launch(
"${getString(R.string.save_data)} " +
LocalDateTime.now().format(
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
)
)
}
}
),
Installable( Installable(
R.string.install_game_content, R.string.install_game_content,
R.string.install_game_content_description, R.string.install_game_content_description,
@ -121,4 +188,156 @@ class InstallableFragment : Fragment() {
windowInsets windowInsets
} }
private val importSaves =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
if (result == null) {
return@registerForActivityResult
}
val inputZip = requireContext().contentResolver.openInputStream(result)
val cacheSaveDir = File("${requireContext().cacheDir.path}/saves/")
cacheSaveDir.mkdir()
if (inputZip == null) {
Toast.makeText(
YuzuApplication.appContext,
getString(R.string.fatal_error),
Toast.LENGTH_LONG
).show()
return@registerForActivityResult
}
IndeterminateProgressDialogFragment.newInstance(
requireActivity(),
R.string.save_files_importing,
false
) {
try {
FileUtil.unzipToInternalStorage(BufferedInputStream(inputZip), cacheSaveDir)
val files = cacheSaveDir.listFiles()
var successfulImports = 0
var failedImports = 0
if (files != null) {
for (file in files) {
if (file.isDirectory) {
val baseSaveDir =
NativeLibrary.getSavePath(BigInteger(file.name, 16).toString())
if (baseSaveDir.isEmpty()) {
failedImports++
continue
}
val internalSaveFolder = File(
"${DirectoryInitialization.userDirectory}/nand$baseSaveDir"
)
internalSaveFolder.deleteRecursively()
internalSaveFolder.mkdir()
file.copyRecursively(target = internalSaveFolder, overwrite = true)
successfulImports++
}
}
}
withContext(Dispatchers.Main) {
if (successfulImports == 0) {
MessageDialogFragment.newInstance(
requireActivity(),
titleId = R.string.save_file_invalid_zip_structure,
descriptionId = R.string.save_file_invalid_zip_structure_description
).show(parentFragmentManager, MessageDialogFragment.TAG)
return@withContext
}
val successString = if (failedImports > 0) {
"""
${
requireContext().resources.getQuantityString(
R.plurals.saves_import_success,
successfulImports,
successfulImports
)
}
${
requireContext().resources.getQuantityString(
R.plurals.saves_import_failed,
failedImports,
failedImports
)
}
"""
} else {
requireContext().resources.getQuantityString(
R.plurals.saves_import_success,
successfulImports,
successfulImports
)
}
MessageDialogFragment.newInstance(
requireActivity(),
titleId = R.string.import_complete,
descriptionString = successString
).show(parentFragmentManager, MessageDialogFragment.TAG)
}
cacheSaveDir.deleteRecursively()
} catch (e: Exception) {
Toast.makeText(
YuzuApplication.appContext,
getString(R.string.fatal_error),
Toast.LENGTH_LONG
).show()
}
}.show(parentFragmentManager, IndeterminateProgressDialogFragment.TAG)
}
private val exportSaves = registerForActivityResult(
ActivityResultContracts.CreateDocument("application/zip")
) { result ->
if (result == null) {
return@registerForActivityResult
}
IndeterminateProgressDialogFragment.newInstance(
requireActivity(),
R.string.save_files_exporting,
false
) {
val cacheSaveDir = File("${requireContext().cacheDir.path}/saves/")
cacheSaveDir.mkdir()
val oldSaveDataFolder = File(
"${DirectoryInitialization.userDirectory}/nand" +
NativeLibrary.getDefaultProfileSaveDataRoot(false)
)
if (oldSaveDataFolder.exists()) {
oldSaveDataFolder.copyRecursively(cacheSaveDir)
}
val futureSaveDataFolder = File(
"${DirectoryInitialization.userDirectory}/nand" +
NativeLibrary.getDefaultProfileSaveDataRoot(true)
)
if (futureSaveDataFolder.exists()) {
futureSaveDataFolder.copyRecursively(cacheSaveDir)
}
val saveFilesTotal = cacheSaveDir.listFiles()?.size ?: 0
if (saveFilesTotal == 0) {
cacheSaveDir.deleteRecursively()
return@newInstance getString(R.string.no_save_data_found)
}
val zipResult = FileUtil.zipFromInternalStorage(
cacheSaveDir,
cacheSaveDir.path,
BufferedOutputStream(requireContext().contentResolver.openOutputStream(result))
)
cacheSaveDir.deleteRecursively()
return@newInstance when (zipResult) {
TaskState.Completed -> getString(R.string.export_success)
TaskState.Cancelled, TaskState.Failed -> getString(R.string.export_failed)
}
}.show(parentFragmentManager, IndeterminateProgressDialogFragment.TAG)
}
} }

View File

@ -167,13 +167,14 @@ class GamesViewModel : ViewModel() {
} }
} }
fun onCloseGameFoldersFragment() = fun onCloseGameFoldersFragment() {
NativeConfig.saveGlobalConfig()
viewModelScope.launch { viewModelScope.launch {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
NativeConfig.saveGlobalConfig()
getGameDirs(true) getGameDirs(true)
} }
} }
}
private fun getGameDirs(reloadList: Boolean = false) { private fun getGameDirs(reloadList: Boolean = false) {
val gameDirs = NativeConfig.getGameDirs() val gameDirs = NativeConfig.getGameDirs()

View File

@ -14,12 +14,6 @@ AndroidConfig::AndroidConfig(const std::string& config_name, ConfigType config_t
} }
} }
AndroidConfig::~AndroidConfig() {
if (global) {
AndroidConfig::SaveAllValues();
}
}
void AndroidConfig::ReloadAllValues() { void AndroidConfig::ReloadAllValues() {
Reload(); Reload();
ReadAndroidValues(); ReadAndroidValues();

View File

@ -9,7 +9,6 @@ class AndroidConfig final : public Config {
public: public:
explicit AndroidConfig(const std::string& config_name = "config", explicit AndroidConfig(const std::string& config_name = "config",
ConfigType config_type = ConfigType::GlobalConfig); ConfigType config_type = ConfigType::GlobalConfig);
~AndroidConfig() override;
void ReloadAllValues() override; void ReloadAllValues() override;
void SaveAllValues() override; void SaveAllValues() override;

View File

@ -45,15 +45,15 @@
#include "core/frontend/applets/profile_select.h" #include "core/frontend/applets/profile_select.h"
#include "core/frontend/applets/software_keyboard.h" #include "core/frontend/applets/software_keyboard.h"
#include "core/frontend/applets/web_browser.h" #include "core/frontend/applets/web_browser.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hid/hid_types.h"
#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/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 "frontend_common/config.h"
#include "hid_core/frontend/emulated_controller.h"
#include "hid_core/hid_core.h"
#include "hid_core/hid_types.h"
#include "jni/android_common/android_common.h" #include "jni/android_common/android_common.h"
#include "jni/id_cache.h" #include "jni/id_cache.h"
#include "jni/native.h" #include "jni/native.h"
@ -862,6 +862,9 @@ jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getAddonsForFile(JNIEnv* env,
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject jobj, jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject jobj,
jstring jprogramId) { jstring jprogramId) {
auto program_id = EmulationSession::GetProgramId(env, jprogramId); auto program_id = EmulationSession::GetProgramId(env, jprogramId);
if (program_id == 0) {
return ToJString(env, "");
}
auto& system = EmulationSession::GetInstance().System(); auto& system = EmulationSession::GetInstance().System();
@ -880,6 +883,19 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject j
return ToJString(env, user_save_data_path); return ToJString(env, user_save_data_path);
} }
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getDefaultProfileSaveDataRoot(JNIEnv* env,
jobject jobj,
jboolean jfuture) {
Service::Account::ProfileManager manager;
// TODO: Pass in a selected user once we get the relevant UI working
const auto user_id = manager.GetUser(static_cast<std::size_t>(0));
ASSERT(user_id);
const auto user_save_data_root =
FileSys::SaveDataFactory::GetUserGameSaveDataRoot(user_id->AsU128(), jfuture);
return ToJString(env, user_save_data_root);
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_addFileToFilesystemProvider(JNIEnv* env, jobject jobj, void Java_org_yuzu_yuzu_1emu_NativeLibrary_addFileToFilesystemProvider(JNIEnv* env, jobject jobj,
jstring jpath) { jstring jpath) {
EmulationSession::GetInstance().ConfigureFilesystemProvider(GetJString(env, jpath)); EmulationSession::GetInstance().ConfigureFilesystemProvider(GetJString(env, jpath));

View File

@ -133,6 +133,15 @@
<string name="add_game_folder">Add game folder</string> <string name="add_game_folder">Add game folder</string>
<string name="folder_already_added">This folder was already added!</string> <string name="folder_already_added">This folder was already added!</string>
<string name="game_folder_properties">Game folder properties</string> <string name="game_folder_properties">Game folder properties</string>
<plurals name="saves_import_failed">
<item quantity="one">Failed to import %d save</item>
<item quantity="other">Failed to import %d saves</item>
</plurals>
<plurals name="saves_import_success">
<item quantity="one">Successfully imported %d save</item>
<item quantity="other">Successfully imported %d saves</item>
</plurals>
<string name="no_save_data_found">No save data found</string>
<!-- Applet launcher strings --> <!-- Applet launcher strings -->
<string name="applets">Applet launcher</string> <string name="applets">Applet launcher</string>
@ -276,6 +285,7 @@
<string name="global">Global</string> <string name="global">Global</string>
<string name="custom">Custom</string> <string name="custom">Custom</string>
<string name="notice">Notice</string> <string name="notice">Notice</string>
<string name="import_complete">Import complete</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>

View File

@ -8,6 +8,7 @@
#include "audio_core/sink/sink_stream.h" #include "audio_core/sink/sink_stream.h"
#include "core/core.h" #include "core/core.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/guest_memory.h"
#include "core/memory.h" #include "core/memory.h"
namespace AudioCore { namespace AudioCore {

View File

@ -9,6 +9,7 @@
#include "common/fixed_point.h" #include "common/fixed_point.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/scratch_buffer.h" #include "common/scratch_buffer.h"
#include "core/guest_memory.h"
#include "core/memory.h" #include "core/memory.h"
namespace AudioCore::Renderer { namespace AudioCore::Renderer {

View File

@ -45,6 +45,7 @@ using f32 = float; ///< 32-bit floating point
using f64 = double; ///< 64-bit floating point using f64 = double; ///< 64-bit floating point
using VAddr = u64; ///< Represents a pointer in the userspace virtual address space. using VAddr = u64; ///< Represents a pointer in the userspace virtual address space.
using DAddr = u64; ///< Represents a pointer in the device specific virtual address space.
using PAddr = u64; ///< Represents a pointer in the ARM11 physical address space. using PAddr = u64; ///< Represents a pointer in the ARM11 physical address space.
using GPUVAddr = u64; ///< Represents a pointer in the GPU virtual address space. using GPUVAddr = u64; ///< Represents a pointer in the GPU virtual address space.

View File

@ -37,6 +37,8 @@ add_library(core STATIC
debugger/gdbstub_arch.h debugger/gdbstub_arch.h
debugger/gdbstub.cpp debugger/gdbstub.cpp
debugger/gdbstub.h debugger/gdbstub.h
device_memory_manager.h
device_memory_manager.inc
device_memory.cpp device_memory.cpp
device_memory.h device_memory.h
file_sys/fssystem/fs_i_storage.h file_sys/fssystem/fs_i_storage.h
@ -183,22 +185,6 @@ add_library(core STATIC
frontend/framebuffer_layout.cpp frontend/framebuffer_layout.cpp
frontend/framebuffer_layout.h frontend/framebuffer_layout.h
frontend/graphics_context.h frontend/graphics_context.h
hid/emulated_console.cpp
hid/emulated_console.h
hid/emulated_controller.cpp
hid/emulated_controller.h
hid/emulated_devices.cpp
hid/emulated_devices.h
hid/hid_core.cpp
hid/hid_core.h
hid/hid_types.h
hid/input_converter.cpp
hid/input_converter.h
hid/input_interpreter.cpp
hid/input_interpreter.h
hid/irs_types.h
hid/motion_input.cpp
hid/motion_input.h
hle/api_version.h hle/api_version.h
hle/ipc.h hle/ipc.h
hle/kernel/board/nintendo/nx/k_memory_layout.cpp hle/kernel/board/nintendo/nx/k_memory_layout.cpp
@ -531,94 +517,16 @@ add_library(core STATIC
hle/service/hid/hid.h hle/service/hid/hid.h
hle/service/hid/hid_debug_server.cpp hle/service/hid/hid_debug_server.cpp
hle/service/hid/hid_debug_server.h 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.cpp
hle/service/hid/hid_server.h hle/service/hid/hid_server.h
hle/service/hid/hid_system_server.cpp hle/service/hid/hid_system_server.cpp
hle/service/hid/hid_system_server.h hle/service/hid/hid_system_server.h
hle/service/hid/hid_util.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/resource_manager.cpp
hle/service/hid/resource_manager.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
hle/service/hid/errors.h
hle/service/hid/controllers/npad/npad_data.cpp
hle/service/hid/controllers/npad/npad_data.h
hle/service/hid/controllers/npad/npad_resource.cpp
hle/service/hid/controllers/npad/npad_resource.h
hle/service/hid/controllers/types/debug_pad_types.h
hle/service/hid/controllers/types/keyboard_types.h
hle/service/hid/controllers/types/mouse_types.h
hle/service/hid/controllers/types/npad_types.h
hle/service/hid/controllers/types/shared_memory_format.h
hle/service/hid/controllers/types/touch_types.h
hle/service/hid/controllers/applet_resource.cpp
hle/service/hid/controllers/applet_resource.h
hle/service/hid/controllers/capture_button.cpp
hle/service/hid/controllers/capture_button.h
hle/service/hid/controllers/console_six_axis.cpp
hle/service/hid/controllers/console_six_axis.h
hle/service/hid/controllers/controller_base.cpp
hle/service/hid/controllers/controller_base.h
hle/service/hid/controllers/debug_mouse.cpp
hle/service/hid/controllers/debug_mouse.h
hle/service/hid/controllers/debug_pad.cpp
hle/service/hid/controllers/debug_pad.h
hle/service/hid/controllers/digitizer.cpp
hle/service/hid/controllers/digitizer.h
hle/service/hid/controllers/gesture.cpp
hle/service/hid/controllers/gesture.h
hle/service/hid/controllers/home_button.cpp
hle/service/hid/controllers/home_button.h
hle/service/hid/controllers/keyboard.cpp
hle/service/hid/controllers/keyboard.h
hle/service/hid/controllers/mouse.cpp
hle/service/hid/controllers/mouse.h
hle/service/hid/controllers/npad.cpp
hle/service/hid/controllers/npad.h
hle/service/hid/controllers/palma.cpp
hle/service/hid/controllers/palma.h
hle/service/hid/controllers/seven_six_axis.cpp
hle/service/hid/controllers/seven_six_axis.h
hle/service/hid/controllers/shared_memory_holder.cpp
hle/service/hid/controllers/shared_memory_holder.h
hle/service/hid/controllers/six_axis.cpp
hle/service/hid/controllers/six_axis.h
hle/service/hid/controllers/sleep_button.cpp
hle/service/hid/controllers/sleep_button.h
hle/service/hid/controllers/touchscreen.cpp
hle/service/hid/controllers/touchscreen.h
hle/service/hid/controllers/unique_pad.cpp
hle/service/hid/controllers/unique_pad.h
hle/service/hid/hidbus/hidbus_base.cpp
hle/service/hid/hidbus/hidbus_base.h
hle/service/hid/hidbus/ringcon.cpp
hle/service/hid/hidbus/ringcon.h
hle/service/hid/hidbus/starlink.cpp
hle/service/hid/hidbus/starlink.h
hle/service/hid/hidbus/stubbed.cpp
hle/service/hid/hidbus/stubbed.h
hle/service/hid/irsensor/clustering_processor.cpp
hle/service/hid/irsensor/clustering_processor.h
hle/service/hid/irsensor/image_transfer_processor.cpp
hle/service/hid/irsensor/image_transfer_processor.h
hle/service/hid/irsensor/ir_led_processor.cpp
hle/service/hid/irsensor/ir_led_processor.h
hle/service/hid/irsensor/moment_processor.cpp
hle/service/hid/irsensor/moment_processor.h
hle/service/hid/irsensor/pointing_processor.cpp
hle/service/hid/irsensor/pointing_processor.h
hle/service/hid/irsensor/processor_base.cpp
hle/service/hid/irsensor/processor_base.h
hle/service/hid/irsensor/tera_plugin_processor.cpp
hle/service/hid/irsensor/tera_plugin_processor.h
hle/service/lbl/lbl.cpp hle/service/lbl/lbl.cpp
hle/service/lbl/lbl.h hle/service/lbl/lbl.h
hle/service/ldn/lan_discovery.cpp hle/service/ldn/lan_discovery.cpp
@ -699,6 +607,8 @@ add_library(core STATIC
hle/service/ns/pdm_qry.h hle/service/ns/pdm_qry.h
hle/service/nvdrv/core/container.cpp hle/service/nvdrv/core/container.cpp
hle/service/nvdrv/core/container.h hle/service/nvdrv/core/container.h
hle/service/nvdrv/core/heap_mapper.cpp
hle/service/nvdrv/core/heap_mapper.h
hle/service/nvdrv/core/nvmap.cpp hle/service/nvdrv/core/nvmap.cpp
hle/service/nvdrv/core/nvmap.h hle/service/nvdrv/core/nvmap.h
hle/service/nvdrv/core/syncpoint_manager.cpp hle/service/nvdrv/core/syncpoint_manager.cpp
@ -802,24 +712,24 @@ add_library(core STATIC
hle/service/server_manager.h hle/service/server_manager.h
hle/service/service.cpp hle/service/service.cpp
hle/service/service.h hle/service/service.h
hle/service/set/set.cpp
hle/service/set/set.h
hle/service/set/appln_settings.cpp hle/service/set/appln_settings.cpp
hle/service/set/appln_settings.h hle/service/set/appln_settings.h
hle/service/set/device_settings.cpp hle/service/set/device_settings.cpp
hle/service/set/device_settings.h hle/service/set/device_settings.h
hle/service/set/factory_settings_server.cpp
hle/service/set/factory_settings_server.h
hle/service/set/firmware_debug_settings_server.cpp
hle/service/set/firmware_debug_settings_server.h
hle/service/set/private_settings.cpp hle/service/set/private_settings.cpp
hle/service/set/private_settings.h hle/service/set/private_settings.h
hle/service/set/set_cal.cpp
hle/service/set/set_cal.h
hle/service/set/set_fd.cpp
hle/service/set/set_fd.h
hle/service/set/set_sys.cpp
hle/service/set/set_sys.h
hle/service/set/settings.cpp hle/service/set/settings.cpp
hle/service/set/settings.h hle/service/set/settings.h
hle/service/set/settings_server.cpp
hle/service/set/settings_server.h
hle/service/set/system_settings.cpp hle/service/set/system_settings.cpp
hle/service/set/system_settings.h hle/service/set/system_settings.h
hle/service/set/system_settings_server.cpp
hle/service/set/system_settings_server.h
hle/service/sm/sm.cpp hle/service/sm/sm.cpp
hle/service/sm/sm.h hle/service/sm/sm.h
hle/service/sm/sm_controller.cpp hle/service/sm/sm_controller.cpp
@ -959,7 +869,7 @@ endif()
create_target_directory_groups(core) create_target_directory_groups(core)
target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core nx_tzdb) target_link_libraries(core PUBLIC common PRIVATE audio_core hid_core network video_core nx_tzdb)
target_link_libraries(core PUBLIC Boost::headers PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls RenderDoc::API) target_link_libraries(core PUBLIC Boost::headers PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls RenderDoc::API)
if (MINGW) if (MINGW)
target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY}) target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY})

View File

@ -28,7 +28,7 @@
#include "core/file_sys/savedata_factory.h" #include "core/file_sys/savedata_factory.h"
#include "core/file_sys/vfs_concat.h" #include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_real.h" #include "core/file_sys/vfs_real.h"
#include "core/hid/hid_core.h" #include "core/gpu_dirty_memory_manager.h"
#include "core/hle/kernel/k_memory_manager.h" #include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_resource_limit.h"
@ -52,6 +52,7 @@
#include "core/telemetry_session.h" #include "core/telemetry_session.h"
#include "core/tools/freezer.h" #include "core/tools/freezer.h"
#include "core/tools/renderdoc.h" #include "core/tools/renderdoc.h"
#include "hid_core/hid_core.h"
#include "network/network.h" #include "network/network.h"
#include "video_core/host1x/host1x.h" #include "video_core/host1x/host1x.h"
#include "video_core/renderer_base.h" #include "video_core/renderer_base.h"
@ -564,6 +565,9 @@ struct System::Impl {
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{}; std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{};
std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES>
gpu_dirty_memory_managers;
std::deque<std::vector<u8>> user_channel; std::deque<std::vector<u8>> user_channel;
}; };
@ -650,8 +654,14 @@ size_t System::GetCurrentHostThreadID() const {
return impl->kernel.GetCurrentHostThreadID(); return impl->kernel.GetCurrentHostThreadID();
} }
void System::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) { std::span<GPUDirtyMemoryManager> System::GetGPUDirtyMemoryManager() {
return this->ApplicationProcess()->GatherGPUDirtyMemory(callback); return impl->gpu_dirty_memory_managers;
}
void System::GatherGPUDirtyMemory(std::function<void(PAddr, size_t)>& callback) {
for (auto& manager : impl->gpu_dirty_memory_managers) {
manager.Gather(callback);
}
} }
PerfStatsResults System::GetAndResetPerfStats() { PerfStatsResults System::GetAndResetPerfStats() {

View File

@ -8,6 +8,7 @@
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <span>
#include <string> #include <string>
#include <vector> #include <vector>
@ -116,6 +117,7 @@ class CpuManager;
class Debugger; class Debugger;
class DeviceMemory; class DeviceMemory;
class ExclusiveMonitor; class ExclusiveMonitor;
class GPUDirtyMemoryManager;
class PerfStats; class PerfStats;
class Reporter; class Reporter;
class SpeedLimiter; class SpeedLimiter;
@ -224,7 +226,9 @@ public:
/// Prepare the core emulation for a reschedule /// Prepare the core emulation for a reschedule
void PrepareReschedule(u32 core_index); void PrepareReschedule(u32 core_index);
void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback); std::span<GPUDirtyMemoryManager> GetGPUDirtyMemoryManager();
void GatherGPUDirtyMemory(std::function<void(PAddr, size_t)>& callback);
[[nodiscard]] size_t GetCurrentHostThreadID() const; [[nodiscard]] size_t GetCurrentHostThreadID() const;

View File

@ -64,7 +64,7 @@ public:
return [this] { ShutdownThreadFunction(); }; return [this] { ShutdownThreadFunction(); };
} }
void PreemptSingleCore(bool from_running_enviroment = true); void PreemptSingleCore(bool from_running_environment = true);
std::size_t CurrentCore() const { std::size_t CurrentCore() const {
return current_core.load(); return current_core.load();

View File

@ -559,28 +559,28 @@ void GDBStub::HandleVCont(std::string_view command, std::vector<DebuggerAction>&
} }
constexpr std::array<std::pair<const char*, Kernel::Svc::MemoryState>, 22> MemoryStateNames{{ constexpr std::array<std::pair<const char*, Kernel::Svc::MemoryState>, 22> MemoryStateNames{{
{"----- Free -----", Kernel::Svc::MemoryState::Free}, {"----- Free ------", Kernel::Svc::MemoryState::Free},
{"Io ", Kernel::Svc::MemoryState::Io}, {"Io ", Kernel::Svc::MemoryState::Io},
{"Static ", Kernel::Svc::MemoryState::Static}, {"Static ", Kernel::Svc::MemoryState::Static},
{"Code ", Kernel::Svc::MemoryState::Code}, {"Code ", Kernel::Svc::MemoryState::Code},
{"CodeData ", Kernel::Svc::MemoryState::CodeData}, {"CodeData ", Kernel::Svc::MemoryState::CodeData},
{"Normal ", Kernel::Svc::MemoryState::Normal}, {"Normal ", Kernel::Svc::MemoryState::Normal},
{"Shared ", Kernel::Svc::MemoryState::Shared}, {"Shared ", Kernel::Svc::MemoryState::Shared},
{"AliasCode ", Kernel::Svc::MemoryState::AliasCode}, {"AliasCode ", Kernel::Svc::MemoryState::AliasCode},
{"AliasCodeData ", Kernel::Svc::MemoryState::AliasCodeData}, {"AliasCodeData ", Kernel::Svc::MemoryState::AliasCodeData},
{"Ipc ", Kernel::Svc::MemoryState::Ipc}, {"Ipc ", Kernel::Svc::MemoryState::Ipc},
{"Stack ", Kernel::Svc::MemoryState::Stack}, {"Stack ", Kernel::Svc::MemoryState::Stack},
{"ThreadLocal ", Kernel::Svc::MemoryState::ThreadLocal}, {"ThreadLocal ", Kernel::Svc::MemoryState::ThreadLocal},
{"Transfered ", Kernel::Svc::MemoryState::Transfered}, {"Transferred ", Kernel::Svc::MemoryState::Transferred},
{"SharedTransfered", Kernel::Svc::MemoryState::SharedTransfered}, {"SharedTransferred", Kernel::Svc::MemoryState::SharedTransferred},
{"SharedCode ", Kernel::Svc::MemoryState::SharedCode}, {"SharedCode ", Kernel::Svc::MemoryState::SharedCode},
{"Inaccessible ", Kernel::Svc::MemoryState::Inaccessible}, {"Inaccessible ", Kernel::Svc::MemoryState::Inaccessible},
{"NonSecureIpc ", Kernel::Svc::MemoryState::NonSecureIpc}, {"NonSecureIpc ", Kernel::Svc::MemoryState::NonSecureIpc},
{"NonDeviceIpc ", Kernel::Svc::MemoryState::NonDeviceIpc}, {"NonDeviceIpc ", Kernel::Svc::MemoryState::NonDeviceIpc},
{"Kernel ", Kernel::Svc::MemoryState::Kernel}, {"Kernel ", Kernel::Svc::MemoryState::Kernel},
{"GeneratedCode ", Kernel::Svc::MemoryState::GeneratedCode}, {"GeneratedCode ", Kernel::Svc::MemoryState::GeneratedCode},
{"CodeOut ", Kernel::Svc::MemoryState::CodeOut}, {"CodeOut ", Kernel::Svc::MemoryState::CodeOut},
{"Coverage ", Kernel::Svc::MemoryState::Coverage}, {"Coverage ", Kernel::Svc::MemoryState::Coverage},
}}; }};
static constexpr const char* GetMemoryStateName(Kernel::Svc::MemoryState state) { static constexpr const char* GetMemoryStateName(Kernel::Svc::MemoryState state) {

View File

@ -31,6 +31,12 @@ public:
DramMemoryMap::Base; DramMemoryMap::Base;
} }
template <typename T>
PAddr GetRawPhysicalAddr(const T* ptr) const {
return static_cast<PAddr>(reinterpret_cast<uintptr_t>(ptr) -
reinterpret_cast<uintptr_t>(buffer.BackingBasePointer()));
}
template <typename T> template <typename T>
T* GetPointer(Common::PhysicalAddress addr) { T* GetPointer(Common::PhysicalAddress addr) {
return reinterpret_cast<T*>(buffer.BackingBasePointer() + return reinterpret_cast<T*>(buffer.BackingBasePointer() +
@ -43,6 +49,16 @@ public:
(GetInteger(addr) - DramMemoryMap::Base)); (GetInteger(addr) - DramMemoryMap::Base));
} }
template <typename T>
T* GetPointerFromRaw(PAddr addr) {
return reinterpret_cast<T*>(buffer.BackingBasePointer() + addr);
}
template <typename T>
const T* GetPointerFromRaw(PAddr addr) const {
return reinterpret_cast<T*>(buffer.BackingBasePointer() + addr);
}
Common::HostMemory buffer; Common::HostMemory buffer;
}; };

View File

@ -0,0 +1,208 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include <atomic>
#include <deque>
#include <memory>
#include <mutex>
#include "common/common_types.h"
#include "common/scratch_buffer.h"
#include "common/virtual_buffer.h"
namespace Core {
constexpr size_t DEVICE_PAGEBITS = 12ULL;
constexpr size_t DEVICE_PAGESIZE = 1ULL << DEVICE_PAGEBITS;
constexpr size_t DEVICE_PAGEMASK = DEVICE_PAGESIZE - 1ULL;
class DeviceMemory;
namespace Memory {
class Memory;
}
template <typename DTraits>
struct DeviceMemoryManagerAllocator;
template <typename Traits>
class DeviceMemoryManager {
using DeviceInterface = typename Traits::DeviceInterface;
using DeviceMethods = typename Traits::DeviceMethods;
public:
DeviceMemoryManager(const DeviceMemory& device_memory);
~DeviceMemoryManager();
void BindInterface(DeviceInterface* device_inter);
DAddr Allocate(size_t size);
void AllocateFixed(DAddr start, size_t size);
void Free(DAddr start, size_t size);
void Map(DAddr address, VAddr virtual_address, size_t size, size_t process_id,
bool track = false);
void Unmap(DAddr address, size_t size);
void TrackContinuityImpl(DAddr address, VAddr virtual_address, size_t size, size_t process_id);
void TrackContinuity(DAddr address, VAddr virtual_address, size_t size, size_t process_id) {
std::scoped_lock lk(mapping_guard);
TrackContinuityImpl(address, virtual_address, size, process_id);
}
// Write / Read
template <typename T>
T* GetPointer(DAddr address);
template <typename T>
const T* GetPointer(DAddr address) const;
template <typename Func>
void ApplyOpOnPAddr(PAddr address, Common::ScratchBuffer<u32>& buffer, Func&& operation) {
DAddr subbits = static_cast<DAddr>(address & page_mask);
const u32 base = compressed_device_addr[(address >> page_bits)];
if ((base >> MULTI_FLAG_BITS) == 0) [[likely]] {
const DAddr d_address = (static_cast<DAddr>(base) << page_bits) + subbits;
operation(d_address);
return;
}
InnerGatherDeviceAddresses(buffer, address);
for (u32 value : buffer) {
operation((static_cast<DAddr>(value) << page_bits) + subbits);
}
}
template <typename Func>
void ApplyOpOnPointer(const u8* p, Common::ScratchBuffer<u32>& buffer, Func&& operation) {
PAddr address = GetRawPhysicalAddr<u8>(p);
ApplyOpOnPAddr(address, buffer, operation);
}
PAddr GetPhysicalRawAddressFromDAddr(DAddr address) const {
PAddr subbits = static_cast<PAddr>(address & page_mask);
auto paddr = compressed_physical_ptr[(address >> page_bits)];
if (paddr == 0) {
return 0;
}
return (static_cast<PAddr>(paddr - 1) << page_bits) + subbits;
}
template <typename T>
void Write(DAddr address, T value);
template <typename T>
T Read(DAddr address) const;
u8* GetSpan(const DAddr src_addr, const std::size_t size);
const u8* GetSpan(const DAddr src_addr, const std::size_t size) const;
void ReadBlock(DAddr address, void* dest_pointer, size_t size);
void ReadBlockUnsafe(DAddr address, void* dest_pointer, size_t size);
void WriteBlock(DAddr address, const void* src_pointer, size_t size);
void WriteBlockUnsafe(DAddr address, const void* src_pointer, size_t size);
size_t RegisterProcess(Memory::Memory* memory);
void UnregisterProcess(size_t id);
void UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta);
static constexpr size_t AS_BITS = Traits::device_virtual_bits;
private:
static constexpr size_t device_virtual_bits = Traits::device_virtual_bits;
static constexpr size_t device_as_size = 1ULL << device_virtual_bits;
static constexpr size_t physical_min_bits = 32;
static constexpr size_t physical_max_bits = 33;
static constexpr size_t page_bits = 12;
static constexpr size_t page_size = 1ULL << page_bits;
static constexpr size_t page_mask = page_size - 1ULL;
static constexpr u32 physical_address_base = 1U << page_bits;
static constexpr u32 MULTI_FLAG_BITS = 31;
static constexpr u32 MULTI_FLAG = 1U << MULTI_FLAG_BITS;
static constexpr u32 MULTI_MASK = ~MULTI_FLAG;
template <typename T>
T* GetPointerFromRaw(PAddr addr) {
return reinterpret_cast<T*>(physical_base + addr);
}
template <typename T>
const T* GetPointerFromRaw(PAddr addr) const {
return reinterpret_cast<T*>(physical_base + addr);
}
template <typename T>
PAddr GetRawPhysicalAddr(const T* ptr) const {
return static_cast<PAddr>(reinterpret_cast<uintptr_t>(ptr) - physical_base);
}
void WalkBlock(const DAddr addr, const std::size_t size, auto on_unmapped, auto on_memory,
auto increment);
void InnerGatherDeviceAddresses(Common::ScratchBuffer<u32>& buffer, PAddr address);
std::unique_ptr<DeviceMemoryManagerAllocator<Traits>> impl;
const uintptr_t physical_base;
DeviceInterface* device_inter;
Common::VirtualBuffer<u32> compressed_physical_ptr;
Common::VirtualBuffer<u32> compressed_device_addr;
Common::VirtualBuffer<u32> continuity_tracker;
// Process memory interfaces
std::deque<size_t> id_pool;
std::deque<Memory::Memory*> registered_processes;
// Memory protection management
static constexpr size_t guest_max_as_bits = 39;
static constexpr size_t guest_as_size = 1ULL << guest_max_as_bits;
static constexpr size_t guest_mask = guest_as_size - 1ULL;
static constexpr size_t process_id_start_bit = guest_max_as_bits;
std::pair<size_t, VAddr> ExtractCPUBacking(size_t page_index) {
auto content = cpu_backing_address[page_index];
const VAddr address = content & guest_mask;
const size_t process_id = static_cast<size_t>(content >> process_id_start_bit);
return std::make_pair(process_id, address);
}
void InsertCPUBacking(size_t page_index, VAddr address, size_t process_id) {
cpu_backing_address[page_index] = address | (process_id << process_id_start_bit);
}
Common::VirtualBuffer<VAddr> cpu_backing_address;
static constexpr size_t subentries = 8 / sizeof(u8);
static constexpr size_t subentries_mask = subentries - 1;
class CounterEntry final {
public:
CounterEntry() = default;
std::atomic_uint8_t& Count(std::size_t page) {
return values[page & subentries_mask];
}
const std::atomic_uint8_t& Count(std::size_t page) const {
return values[page & subentries_mask];
}
private:
std::array<std::atomic_uint8_t, subentries> values{};
};
static_assert(sizeof(CounterEntry) == subentries * sizeof(u8),
"CounterEntry should be 8 bytes!");
static constexpr size_t num_counter_entries =
(1ULL << (device_virtual_bits - page_bits)) / subentries;
using CachedPages = std::array<CounterEntry, num_counter_entries>;
std::unique_ptr<CachedPages> cached_pages;
std::mutex counter_guard;
std::mutex mapping_guard;
};
} // namespace Core

View File

@ -0,0 +1,588 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <atomic>
#include <limits>
#include <memory>
#include <type_traits>
#include "common/address_space.h"
#include "common/address_space.inc"
#include "common/alignment.h"
#include "common/assert.h"
#include "common/div_ceil.h"
#include "common/scope_exit.h"
#include "common/settings.h"
#include "core/device_memory.h"
#include "core/device_memory_manager.h"
#include "core/memory.h"
namespace Core {
namespace {
class MultiAddressContainer {
public:
MultiAddressContainer() = default;
~MultiAddressContainer() = default;
void GatherValues(u32 start_entry, Common::ScratchBuffer<u32>& buffer) {
buffer.resize(8);
buffer.resize(0);
size_t index = 0;
const auto add_value = [&](u32 value) {
buffer[index] = value;
index++;
buffer.resize(index);
};
u32 iter_entry = start_entry;
Entry* current = &storage[iter_entry - 1];
add_value(current->value);
while (current->next_entry != 0) {
iter_entry = current->next_entry;
current = &storage[iter_entry - 1];
add_value(current->value);
}
}
u32 Register(u32 value) {
return RegisterImplementation(value);
}
void Register(u32 value, u32 start_entry) {
auto entry_id = RegisterImplementation(value);
u32 iter_entry = start_entry;
Entry* current = &storage[iter_entry - 1];
while (current->next_entry != 0) {
iter_entry = current->next_entry;
current = &storage[iter_entry - 1];
}
current->next_entry = entry_id;
}
std::pair<bool, u32> Unregister(u32 value, u32 start_entry) {
u32 iter_entry = start_entry;
Entry* previous{};
Entry* current = &storage[iter_entry - 1];
Entry* next{};
bool more_than_one_remaining = false;
u32 result_start{start_entry};
size_t count = 0;
while (current->value != value) {
count++;
previous = current;
iter_entry = current->next_entry;
current = &storage[iter_entry - 1];
}
// Find next
u32 next_entry = current->next_entry;
if (next_entry != 0) {
next = &storage[next_entry - 1];
more_than_one_remaining = next->next_entry != 0 || previous != nullptr;
}
if (previous) {
previous->next_entry = next_entry;
} else {
result_start = next_entry;
}
free_entries.emplace_back(iter_entry);
return std::make_pair(more_than_one_remaining || count > 1, result_start);
}
u32 ReleaseEntry(u32 start_entry) {
Entry* current = &storage[start_entry - 1];
free_entries.emplace_back(start_entry);
return current->value;
}
private:
u32 RegisterImplementation(u32 value) {
auto entry_id = GetNewEntry();
auto& entry = storage[entry_id - 1];
entry.next_entry = 0;
entry.value = value;
return entry_id;
}
u32 GetNewEntry() {
if (!free_entries.empty()) {
u32 result = free_entries.front();
free_entries.pop_front();
return result;
}
storage.emplace_back();
u32 new_entry = static_cast<u32>(storage.size());
return new_entry;
}
struct Entry {
u32 next_entry{};
u32 value{};
};
std::deque<Entry> storage;
std::deque<u32> free_entries;
};
struct EmptyAllocator {
EmptyAllocator([[maybe_unused]] DAddr address) {}
};
} // namespace
template <typename DTraits>
struct DeviceMemoryManagerAllocator {
static constexpr size_t device_virtual_bits = DTraits::device_virtual_bits;
static constexpr DAddr first_address = 1ULL << Memory::YUZU_PAGEBITS;
static constexpr DAddr max_device_area = 1ULL << device_virtual_bits;
DeviceMemoryManagerAllocator() : main_allocator(first_address) {}
Common::FlatAllocator<DAddr, 0, device_virtual_bits> main_allocator;
MultiAddressContainer multi_dev_address;
/// Returns true when vaddr -> vaddr+size is fully contained in the buffer
template <bool pin_area>
[[nodiscard]] bool IsInBounds(VAddr addr, u64 size) const noexcept {
return addr >= 0 && addr + size <= max_device_area;
}
DAddr Allocate(size_t size) {
return main_allocator.Allocate(size);
}
void AllocateFixed(DAddr b_address, size_t b_size) {
main_allocator.AllocateFixed(b_address, b_size);
}
void Free(DAddr b_address, size_t b_size) {
main_allocator.Free(b_address, b_size);
}
};
template <typename Traits>
DeviceMemoryManager<Traits>::DeviceMemoryManager(const DeviceMemory& device_memory_)
: physical_base{reinterpret_cast<const uintptr_t>(device_memory_.buffer.BackingBasePointer())},
device_inter{nullptr}, compressed_physical_ptr(device_as_size >> Memory::YUZU_PAGEBITS),
compressed_device_addr(1ULL << ((Settings::values.memory_layout_mode.GetValue() ==
Settings::MemoryLayout::Memory_4Gb
? physical_min_bits
: physical_max_bits) -
Memory::YUZU_PAGEBITS)),
continuity_tracker(device_as_size >> Memory::YUZU_PAGEBITS),
cpu_backing_address(device_as_size >> Memory::YUZU_PAGEBITS) {
impl = std::make_unique<DeviceMemoryManagerAllocator<Traits>>();
cached_pages = std::make_unique<CachedPages>();
const size_t total_virtual = device_as_size >> Memory::YUZU_PAGEBITS;
for (size_t i = 0; i < total_virtual; i++) {
compressed_physical_ptr[i] = 0;
continuity_tracker[i] = 1;
cpu_backing_address[i] = 0;
}
const size_t total_phys = 1ULL << ((Settings::values.memory_layout_mode.GetValue() ==
Settings::MemoryLayout::Memory_4Gb
? physical_min_bits
: physical_max_bits) -
Memory::YUZU_PAGEBITS);
for (size_t i = 0; i < total_phys; i++) {
compressed_device_addr[i] = 0;
}
}
template <typename Traits>
DeviceMemoryManager<Traits>::~DeviceMemoryManager() = default;
template <typename Traits>
void DeviceMemoryManager<Traits>::BindInterface(DeviceInterface* device_inter_) {
device_inter = device_inter_;
}
template <typename Traits>
DAddr DeviceMemoryManager<Traits>::Allocate(size_t size) {
return impl->Allocate(size);
}
template <typename Traits>
void DeviceMemoryManager<Traits>::AllocateFixed(DAddr start, size_t size) {
return impl->AllocateFixed(start, size);
}
template <typename Traits>
void DeviceMemoryManager<Traits>::Free(DAddr start, size_t size) {
impl->Free(start, size);
}
template <typename Traits>
void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size_t size,
size_t process_id, bool track) {
Core::Memory::Memory* process_memory = registered_processes[process_id];
size_t start_page_d = address >> Memory::YUZU_PAGEBITS;
size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS;
std::scoped_lock lk(mapping_guard);
for (size_t i = 0; i < num_pages; i++) {
const VAddr new_vaddress = virtual_address + i * Memory::YUZU_PAGESIZE;
auto* ptr = process_memory->GetPointerSilent(Common::ProcessAddress(new_vaddress));
if (ptr == nullptr) [[unlikely]] {
compressed_physical_ptr[start_page_d + i] = 0;
continue;
}
auto phys_addr = static_cast<u32>(GetRawPhysicalAddr(ptr) >> Memory::YUZU_PAGEBITS) + 1U;
compressed_physical_ptr[start_page_d + i] = phys_addr;
InsertCPUBacking(start_page_d + i, new_vaddress, process_id);
const u32 base_dev = compressed_device_addr[phys_addr - 1U];
const u32 new_dev = static_cast<u32>(start_page_d + i);
if (base_dev == 0) [[likely]] {
compressed_device_addr[phys_addr - 1U] = new_dev;
continue;
}
u32 start_id = base_dev & MULTI_MASK;
if ((base_dev >> MULTI_FLAG_BITS) == 0) {
start_id = impl->multi_dev_address.Register(base_dev);
compressed_device_addr[phys_addr - 1U] = MULTI_FLAG | start_id;
}
impl->multi_dev_address.Register(new_dev, start_id);
}
if (track) {
TrackContinuityImpl(address, virtual_address, size, process_id);
}
}
template <typename Traits>
void DeviceMemoryManager<Traits>::Unmap(DAddr address, size_t size) {
size_t start_page_d = address >> Memory::YUZU_PAGEBITS;
size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS;
device_inter->InvalidateRegion(address, size);
std::scoped_lock lk(mapping_guard);
for (size_t i = 0; i < num_pages; i++) {
auto phys_addr = compressed_physical_ptr[start_page_d + i];
compressed_physical_ptr[start_page_d + i] = 0;
cpu_backing_address[start_page_d + i] = 0;
if (phys_addr != 0) [[likely]] {
const u32 base_dev = compressed_device_addr[phys_addr - 1U];
if ((base_dev >> MULTI_FLAG_BITS) == 0) [[likely]] {
compressed_device_addr[phys_addr - 1] = 0;
continue;
}
const auto [more_entries, new_start] = impl->multi_dev_address.Unregister(
static_cast<u32>(start_page_d + i), base_dev & MULTI_MASK);
if (!more_entries) {
compressed_device_addr[phys_addr - 1] =
impl->multi_dev_address.ReleaseEntry(new_start);
continue;
}
compressed_device_addr[phys_addr - 1] = new_start | MULTI_FLAG;
}
}
}
template <typename Traits>
void DeviceMemoryManager<Traits>::TrackContinuityImpl(DAddr address, VAddr virtual_address,
size_t size, size_t process_id) {
Core::Memory::Memory* process_memory = registered_processes[process_id];
size_t start_page_d = address >> Memory::YUZU_PAGEBITS;
size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS;
uintptr_t last_ptr = 0;
size_t page_count = 1;
for (size_t i = num_pages; i > 0; i--) {
size_t index = i - 1;
const VAddr new_vaddress = virtual_address + index * Memory::YUZU_PAGESIZE;
const uintptr_t new_ptr = reinterpret_cast<uintptr_t>(
process_memory->GetPointerSilent(Common::ProcessAddress(new_vaddress)));
if (new_ptr + page_size == last_ptr) {
page_count++;
} else {
page_count = 1;
}
last_ptr = new_ptr;
continuity_tracker[start_page_d + index] = static_cast<u32>(page_count);
}
}
template <typename Traits>
u8* DeviceMemoryManager<Traits>::GetSpan(const DAddr src_addr, const std::size_t size) {
size_t page_index = src_addr >> page_bits;
size_t subbits = src_addr & page_mask;
if ((static_cast<size_t>(continuity_tracker[page_index]) << page_bits) >= size + subbits) {
return GetPointer<u8>(src_addr);
}
return nullptr;
}
template <typename Traits>
const u8* DeviceMemoryManager<Traits>::GetSpan(const DAddr src_addr, const std::size_t size) const {
size_t page_index = src_addr >> page_bits;
size_t subbits = src_addr & page_mask;
if ((static_cast<size_t>(continuity_tracker[page_index]) << page_bits) >= size + subbits) {
return GetPointer<u8>(src_addr);
}
return nullptr;
}
template <typename Traits>
void DeviceMemoryManager<Traits>::InnerGatherDeviceAddresses(Common::ScratchBuffer<u32>& buffer,
PAddr address) {
size_t phys_addr = address >> page_bits;
std::scoped_lock lk(mapping_guard);
u32 backing = compressed_device_addr[phys_addr];
if ((backing >> MULTI_FLAG_BITS) != 0) {
impl->multi_dev_address.GatherValues(backing & MULTI_MASK, buffer);
return;
}
buffer.resize(1);
buffer[0] = backing;
}
template <typename Traits>
template <typename T>
T* DeviceMemoryManager<Traits>::GetPointer(DAddr address) {
const size_t index = address >> Memory::YUZU_PAGEBITS;
const size_t offset = address & Memory::YUZU_PAGEMASK;
auto phys_addr = compressed_physical_ptr[index];
if (phys_addr == 0) [[unlikely]] {
return nullptr;
}
return GetPointerFromRaw<T>((static_cast<PAddr>(phys_addr - 1) << Memory::YUZU_PAGEBITS) +
offset);
}
template <typename Traits>
template <typename T>
const T* DeviceMemoryManager<Traits>::GetPointer(DAddr address) const {
const size_t index = address >> Memory::YUZU_PAGEBITS;
const size_t offset = address & Memory::YUZU_PAGEMASK;
auto phys_addr = compressed_physical_ptr[index];
if (phys_addr == 0) [[unlikely]] {
return nullptr;
}
return GetPointerFromRaw<T>((static_cast<PAddr>(phys_addr - 1) << Memory::YUZU_PAGEBITS) +
offset);
}
template <typename Traits>
template <typename T>
void DeviceMemoryManager<Traits>::Write(DAddr address, T value) {
T* ptr = GetPointer<T>(address);
if (!ptr) [[unlikely]] {
return;
}
std::memcpy(ptr, &value, sizeof(T));
}
template <typename Traits>
template <typename T>
T DeviceMemoryManager<Traits>::Read(DAddr address) const {
const T* ptr = GetPointer<T>(address);
T result{};
if (!ptr) [[unlikely]] {
return result;
}
std::memcpy(&result, ptr, sizeof(T));
return result;
}
template <typename Traits>
void DeviceMemoryManager<Traits>::WalkBlock(DAddr addr, std::size_t size, auto on_unmapped,
auto on_memory, auto increment) {
std::size_t remaining_size = size;
std::size_t page_index = addr >> Memory::YUZU_PAGEBITS;
std::size_t page_offset = addr & Memory::YUZU_PAGEMASK;
while (remaining_size) {
const size_t next_pages = static_cast<std::size_t>(continuity_tracker[page_index]);
const std::size_t copy_amount =
std::min((next_pages << Memory::YUZU_PAGEBITS) - page_offset, remaining_size);
const auto current_vaddr =
static_cast<u64>((page_index << Memory::YUZU_PAGEBITS) + page_offset);
SCOPE_EXIT({
page_index += next_pages;
page_offset = 0;
increment(copy_amount);
remaining_size -= copy_amount;
});
auto phys_addr = compressed_physical_ptr[page_index];
if (phys_addr == 0) {
on_unmapped(copy_amount, current_vaddr);
continue;
}
auto* mem_ptr = GetPointerFromRaw<u8>(
(static_cast<PAddr>(phys_addr - 1) << Memory::YUZU_PAGEBITS) + page_offset);
on_memory(copy_amount, mem_ptr);
}
}
template <typename Traits>
void DeviceMemoryManager<Traits>::ReadBlock(DAddr address, void* dest_pointer, size_t size) {
device_inter->FlushRegion(address, size);
WalkBlock(
address, size,
[&](size_t copy_amount, DAddr current_vaddr) {
LOG_ERROR(
HW_Memory,
"Unmapped Device ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
current_vaddr, address, size);
std::memset(dest_pointer, 0, copy_amount);
},
[&](size_t copy_amount, const u8* const src_ptr) {
std::memcpy(dest_pointer, src_ptr, copy_amount);
},
[&](const std::size_t copy_amount) {
dest_pointer = static_cast<u8*>(dest_pointer) + copy_amount;
});
}
template <typename Traits>
void DeviceMemoryManager<Traits>::WriteBlock(DAddr address, const void* src_pointer, size_t size) {
WalkBlock(
address, size,
[&](size_t copy_amount, DAddr current_vaddr) {
LOG_ERROR(
HW_Memory,
"Unmapped Device WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
current_vaddr, address, size);
},
[&](size_t copy_amount, u8* const dst_ptr) {
std::memcpy(dst_ptr, src_pointer, copy_amount);
},
[&](const std::size_t copy_amount) {
src_pointer = static_cast<const u8*>(src_pointer) + copy_amount;
});
device_inter->InvalidateRegion(address, size);
}
template <typename Traits>
void DeviceMemoryManager<Traits>::ReadBlockUnsafe(DAddr address, void* dest_pointer, size_t size) {
WalkBlock(
address, size,
[&](size_t copy_amount, DAddr current_vaddr) {
LOG_ERROR(
HW_Memory,
"Unmapped Device ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
current_vaddr, address, size);
std::memset(dest_pointer, 0, copy_amount);
},
[&](size_t copy_amount, const u8* const src_ptr) {
std::memcpy(dest_pointer, src_ptr, copy_amount);
},
[&](const std::size_t copy_amount) {
dest_pointer = static_cast<u8*>(dest_pointer) + copy_amount;
});
}
template <typename Traits>
void DeviceMemoryManager<Traits>::WriteBlockUnsafe(DAddr address, const void* src_pointer,
size_t size) {
WalkBlock(
address, size,
[&](size_t copy_amount, DAddr current_vaddr) {
LOG_ERROR(
HW_Memory,
"Unmapped Device WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
current_vaddr, address, size);
},
[&](size_t copy_amount, u8* const dst_ptr) {
std::memcpy(dst_ptr, src_pointer, copy_amount);
},
[&](const std::size_t copy_amount) {
src_pointer = static_cast<const u8*>(src_pointer) + copy_amount;
});
}
template <typename Traits>
size_t DeviceMemoryManager<Traits>::RegisterProcess(Memory::Memory* memory_device_inter) {
size_t new_id;
if (!id_pool.empty()) {
new_id = id_pool.front();
id_pool.pop_front();
registered_processes[new_id] = memory_device_inter;
} else {
registered_processes.emplace_back(memory_device_inter);
new_id = registered_processes.size() - 1U;
}
return new_id;
}
template <typename Traits>
void DeviceMemoryManager<Traits>::UnregisterProcess(size_t id) {
registered_processes[id] = nullptr;
id_pool.push_front(id);
}
template <typename Traits>
void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) {
bool locked = false;
auto lock = [&] {
if (!locked) {
counter_guard.lock();
locked = true;
}
};
SCOPE_EXIT({
if (locked) {
counter_guard.unlock();
}
});
u64 uncache_begin = 0;
u64 cache_begin = 0;
u64 uncache_bytes = 0;
u64 cache_bytes = 0;
const auto MarkRegionCaching = &DeviceMemoryManager<Traits>::DeviceMethods::MarkRegionCaching;
std::atomic_thread_fence(std::memory_order_acquire);
const size_t page_end = Common::DivCeil(addr + size, Memory::YUZU_PAGESIZE);
size_t page = addr >> Memory::YUZU_PAGEBITS;
auto [process_id, base_vaddress] = ExtractCPUBacking(page);
size_t vpage = base_vaddress >> Memory::YUZU_PAGEBITS;
auto* memory_device_inter = registered_processes[process_id];
for (; page != page_end; ++page) {
std::atomic_uint8_t& count = cached_pages->at(page >> 3).Count(page);
if (delta > 0) {
ASSERT_MSG(count.load(std::memory_order::relaxed) < std::numeric_limits<u8>::max(),
"Count may overflow!");
} else if (delta < 0) {
ASSERT_MSG(count.load(std::memory_order::relaxed) > 0, "Count may underflow!");
} else {
ASSERT_MSG(false, "Delta must be non-zero!");
}
// Adds or subtracts 1, as count is a unsigned 8-bit value
count.fetch_add(static_cast<u8>(delta), std::memory_order_release);
// Assume delta is either -1 or 1
if (count.load(std::memory_order::relaxed) == 0) {
if (uncache_bytes == 0) {
uncache_begin = vpage;
}
uncache_bytes += Memory::YUZU_PAGESIZE;
} else if (uncache_bytes > 0) {
lock();
MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
uncache_bytes, false);
uncache_bytes = 0;
}
if (count.load(std::memory_order::relaxed) == 1 && delta > 0) {
if (cache_bytes == 0) {
cache_begin = vpage;
}
cache_bytes += Memory::YUZU_PAGESIZE;
} else if (cache_bytes > 0) {
lock();
MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes,
true);
cache_bytes = 0;
}
vpage++;
}
if (uncache_bytes > 0) {
lock();
MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes,
false);
}
if (cache_bytes > 0) {
lock();
MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes,
true);
}
}
} // namespace Core

View File

@ -26,7 +26,7 @@
#include "core/file_sys/vfs_vector.h" #include "core/file_sys/vfs_vector.h"
#include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/ns/language.h" #include "core/hle/service/ns/language.h"
#include "core/hle/service/set/set.h" #include "core/hle/service/set/settings_server.h"
#include "core/loader/loader.h" #include "core/loader/loader.h"
#include "core/loader/nso.h" #include "core/loader/nso.h"
#include "core/memory/cheat_engine.h" #include "core/memory/cheat_engine.h"

View File

@ -189,6 +189,15 @@ std::string SaveDataFactory::GetFullPath(Core::System& system, VirtualDir dir,
} }
} }
std::string SaveDataFactory::GetUserGameSaveDataRoot(u128 user_id, bool future) {
if (future) {
Common::UUID uuid;
std::memcpy(uuid.uuid.data(), user_id.data(), sizeof(Common::UUID));
return fmt::format("/user/save/account/{}", uuid.RawString());
}
return fmt::format("/user/save/{:016X}/{:016X}{:016X}", 0, user_id[1], user_id[0]);
}
SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
u128 user_id) const { u128 user_id) const {
const auto path = const auto path =

View File

@ -101,6 +101,7 @@ public:
static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space); static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space);
static std::string GetFullPath(Core::System& system, VirtualDir dir, SaveDataSpaceId space, static std::string GetFullPath(Core::System& system, VirtualDir dir, SaveDataSpaceId space,
SaveDataType type, u64 title_id, u128 user_id, u64 save_id); SaveDataType type, u64 title_id, u128 user_id, u64 save_id);
static std::string GetUserGameSaveDataRoot(u128 user_id, bool future);
SaveDataSize ReadSaveDataSize(SaveDataType type, u64 title_id, u128 user_id) const; SaveDataSize ReadSaveDataSize(SaveDataType type, u64 title_id, u128 user_id) const;
void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,

View File

@ -6,9 +6,9 @@
#include "common/settings.h" #include "common/settings.h"
#include "common/settings_enums.h" #include "common/settings_enums.h"
#include "core/frontend/applets/controller.h" #include "core/frontend/applets/controller.h"
#include "core/hid/emulated_controller.h" #include "hid_core/frontend/emulated_controller.h"
#include "core/hid/hid_core.h" #include "hid_core/hid_core.h"
#include "core/hid/hid_types.h" #include "hid_core/hid_types.h"
namespace Core::Frontend { namespace Core::Frontend {

View File

@ -10,7 +10,7 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "core/memory.h" #include "core/device_memory_manager.h"
namespace Core { namespace Core {
@ -23,7 +23,7 @@ public:
~GPUDirtyMemoryManager() = default; ~GPUDirtyMemoryManager() = default;
void Collect(VAddr address, size_t size) { void Collect(PAddr address, size_t size) {
TransformAddress t = BuildTransform(address, size); TransformAddress t = BuildTransform(address, size);
TransformAddress tmp, original; TransformAddress tmp, original;
do { do {
@ -47,7 +47,7 @@ public:
std::memory_order_relaxed)); std::memory_order_relaxed));
} }
void Gather(std::function<void(VAddr, size_t)>& callback) { void Gather(std::function<void(PAddr, size_t)>& callback) {
{ {
std::scoped_lock lk(guard); std::scoped_lock lk(guard);
TransformAddress t = current.exchange(default_transform, std::memory_order_relaxed); TransformAddress t = current.exchange(default_transform, std::memory_order_relaxed);
@ -65,7 +65,7 @@ public:
mask = mask >> empty_bits; mask = mask >> empty_bits;
const size_t continuous_bits = std::countr_one(mask); const size_t continuous_bits = std::countr_one(mask);
callback((static_cast<VAddr>(transform.address) << page_bits) + offset, callback((static_cast<PAddr>(transform.address) << page_bits) + offset,
continuous_bits << align_bits); continuous_bits << align_bits);
mask = continuous_bits < align_size ? (mask >> continuous_bits) : 0; mask = continuous_bits < align_size ? (mask >> continuous_bits) : 0;
offset += continuous_bits << align_bits; offset += continuous_bits << align_bits;
@ -80,7 +80,7 @@ private:
u32 mask; u32 mask;
}; };
constexpr static size_t page_bits = Memory::YUZU_PAGEBITS - 1; constexpr static size_t page_bits = DEVICE_PAGEBITS - 1;
constexpr static size_t page_size = 1ULL << page_bits; constexpr static size_t page_size = 1ULL << page_bits;
constexpr static size_t page_mask = page_size - 1; constexpr static size_t page_mask = page_size - 1;
@ -89,7 +89,7 @@ private:
constexpr static size_t align_mask = align_size - 1; constexpr static size_t align_mask = align_size - 1;
constexpr static TransformAddress default_transform = {.address = ~0U, .mask = 0U}; constexpr static TransformAddress default_transform = {.address = ~0U, .mask = 0U};
bool IsValid(VAddr address) { bool IsValid(PAddr address) {
return address < (1ULL << 39); return address < (1ULL << 39);
} }
@ -103,7 +103,7 @@ private:
return mask; return mask;
} }
TransformAddress BuildTransform(VAddr address, size_t size) { TransformAddress BuildTransform(PAddr address, size_t size) {
const size_t minor_address = address & page_mask; const size_t minor_address = address & page_mask;
const size_t minor_bit = minor_address >> align_bits; const size_t minor_bit = minor_address >> align_bits;
const size_t top_bit = (minor_address + size + align_mask) >> align_bits; const size_t top_bit = (minor_address + size + align_mask) >> align_bits;

214
src/core/guest_memory.h Normal file
View File

@ -0,0 +1,214 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <iterator>
#include <memory>
#include <optional>
#include <span>
#include <vector>
#include "common/assert.h"
#include "common/scratch_buffer.h"
namespace Core::Memory {
enum GuestMemoryFlags : u32 {
Read = 1 << 0,
Write = 1 << 1,
Safe = 1 << 2,
Cached = 1 << 3,
SafeRead = Read | Safe,
SafeWrite = Write | Safe,
SafeReadWrite = SafeRead | SafeWrite,
SafeReadCachedWrite = SafeReadWrite | Cached,
UnsafeRead = Read,
UnsafeWrite = Write,
UnsafeReadWrite = UnsafeRead | UnsafeWrite,
UnsafeReadCachedWrite = UnsafeReadWrite | Cached,
};
namespace {
template <typename M, typename T, GuestMemoryFlags FLAGS>
class GuestMemory {
using iterator = T*;
using const_iterator = const T*;
using value_type = T;
using element_type = T;
using iterator_category = std::contiguous_iterator_tag;
public:
GuestMemory() = delete;
explicit GuestMemory(M& memory, u64 addr, std::size_t size,
Common::ScratchBuffer<T>* backup = nullptr)
: m_memory{memory}, m_addr{addr}, m_size{size} {
static_assert(FLAGS & GuestMemoryFlags::Read || FLAGS & GuestMemoryFlags::Write);
if constexpr (FLAGS & GuestMemoryFlags::Read) {
Read(addr, size, backup);
}
}
~GuestMemory() = default;
T* data() noexcept {
return m_data_span.data();
}
const T* data() const noexcept {
return m_data_span.data();
}
size_t size() const noexcept {
return m_size;
}
size_t size_bytes() const noexcept {
return this->size() * sizeof(T);
}
[[nodiscard]] T* begin() noexcept {
return this->data();
}
[[nodiscard]] const T* begin() const noexcept {
return this->data();
}
[[nodiscard]] T* end() noexcept {
return this->data() + this->size();
}
[[nodiscard]] const T* end() const noexcept {
return this->data() + this->size();
}
T& operator[](size_t index) noexcept {
return m_data_span[index];
}
const T& operator[](size_t index) const noexcept {
return m_data_span[index];
}
void SetAddressAndSize(u64 addr, std::size_t size) noexcept {
m_addr = addr;
m_size = size;
m_addr_changed = true;
}
std::span<T> Read(u64 addr, std::size_t size,
Common::ScratchBuffer<T>* backup = nullptr) noexcept {
m_addr = addr;
m_size = size;
if (m_size == 0) {
m_is_data_copy = true;
return {};
}
if (this->TrySetSpan()) {
if constexpr (FLAGS & GuestMemoryFlags::Safe) {
m_memory.FlushRegion(m_addr, this->size_bytes());
}
} else {
if (backup) {
backup->resize_destructive(this->size());
m_data_span = *backup;
} else {
m_data_copy.resize(this->size());
m_data_span = std::span(m_data_copy);
}
m_is_data_copy = true;
m_span_valid = true;
if constexpr (FLAGS & GuestMemoryFlags::Safe) {
m_memory.ReadBlock(m_addr, this->data(), this->size_bytes());
} else {
m_memory.ReadBlockUnsafe(m_addr, this->data(), this->size_bytes());
}
}
return m_data_span;
}
void Write(std::span<T> write_data) noexcept {
if constexpr (FLAGS & GuestMemoryFlags::Cached) {
m_memory.WriteBlockCached(m_addr, write_data.data(), this->size_bytes());
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
m_memory.WriteBlock(m_addr, write_data.data(), this->size_bytes());
} else {
m_memory.WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes());
}
}
bool TrySetSpan() noexcept {
if (u8* ptr = m_memory.GetSpan(m_addr, this->size_bytes()); ptr) {
m_data_span = {reinterpret_cast<T*>(ptr), this->size()};
m_span_valid = true;
return true;
}
return false;
}
protected:
bool IsDataCopy() const noexcept {
return m_is_data_copy;
}
bool AddressChanged() const noexcept {
return m_addr_changed;
}
M& m_memory;
u64 m_addr{};
size_t m_size{};
std::span<T> m_data_span{};
std::vector<T> m_data_copy{};
bool m_span_valid{false};
bool m_is_data_copy{false};
bool m_addr_changed{false};
};
template <typename M, typename T, GuestMemoryFlags FLAGS>
class GuestMemoryScoped : public GuestMemory<M, T, FLAGS> {
public:
GuestMemoryScoped() = delete;
explicit GuestMemoryScoped(M& memory, u64 addr, std::size_t size,
Common::ScratchBuffer<T>* backup = nullptr)
: GuestMemory<M, T, FLAGS>(memory, addr, size, backup) {
if constexpr (!(FLAGS & GuestMemoryFlags::Read)) {
if (!this->TrySetSpan()) {
if (backup) {
this->m_data_span = *backup;
this->m_span_valid = true;
this->m_is_data_copy = true;
}
}
}
}
~GuestMemoryScoped() {
if constexpr (FLAGS & GuestMemoryFlags::Write) {
if (this->size() == 0) [[unlikely]] {
return;
}
if (this->AddressChanged() || this->IsDataCopy()) {
ASSERT(this->m_span_valid);
if constexpr (FLAGS & GuestMemoryFlags::Cached) {
this->m_memory.WriteBlockCached(this->m_addr, this->data(), this->size_bytes());
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
this->m_memory.WriteBlock(this->m_addr, this->data(), this->size_bytes());
} else {
this->m_memory.WriteBlockUnsafe(this->m_addr, this->data(), this->size_bytes());
}
} else if constexpr ((FLAGS & GuestMemoryFlags::Safe) ||
(FLAGS & GuestMemoryFlags::Cached)) {
this->m_memory.InvalidateRegion(this->m_addr, this->size_bytes());
}
}
}
};
} // namespace
} // namespace Core::Memory

View File

@ -81,12 +81,12 @@ enum class KMemoryState : u32 {
ThreadLocal = static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagLinearMapped, ThreadLocal = static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagLinearMapped,
Transfered = static_cast<u32>(Svc::MemoryState::Transfered) | FlagsMisc | Transferred = static_cast<u32>(Svc::MemoryState::Transferred) | FlagsMisc |
FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc | FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc |
FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
SharedTransfered = static_cast<u32>(Svc::MemoryState::SharedTransfered) | FlagsMisc | SharedTransferred = static_cast<u32>(Svc::MemoryState::SharedTransferred) | FlagsMisc |
FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
SharedCode = static_cast<u32>(Svc::MemoryState::SharedCode) | FlagMapped | SharedCode = static_cast<u32>(Svc::MemoryState::SharedCode) | FlagMapped |
FlagReferenceCounted | FlagLinearMapped | FlagCanUseNonSecureIpc | FlagReferenceCounted | FlagLinearMapped | FlagCanUseNonSecureIpc |
@ -130,8 +130,8 @@ static_assert(static_cast<u32>(KMemoryState::AliasCodeData) == 0x0FFFBD09);
static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x045C3C0A); static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x045C3C0A);
static_assert(static_cast<u32>(KMemoryState::Stack) == 0x045C3C0B); static_assert(static_cast<u32>(KMemoryState::Stack) == 0x045C3C0B);
static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0400000C); static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0400000C);
static_assert(static_cast<u32>(KMemoryState::Transfered) == 0x055C3C0D); static_assert(static_cast<u32>(KMemoryState::Transferred) == 0x055C3C0D);
static_assert(static_cast<u32>(KMemoryState::SharedTransfered) == 0x045C380E); static_assert(static_cast<u32>(KMemoryState::SharedTransferred) == 0x045C380E);
static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0440380F); static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0440380F);
static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010); static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010);
static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x045C3811); static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x045C3811);

View File

@ -486,8 +486,8 @@ KProcessAddress KPageTableBase::GetRegionAddress(Svc::MemoryState state) const {
case Svc::MemoryState::Shared: case Svc::MemoryState::Shared:
case Svc::MemoryState::AliasCode: case Svc::MemoryState::AliasCode:
case Svc::MemoryState::AliasCodeData: case Svc::MemoryState::AliasCodeData:
case Svc::MemoryState::Transfered: case Svc::MemoryState::Transferred:
case Svc::MemoryState::SharedTransfered: case Svc::MemoryState::SharedTransferred:
case Svc::MemoryState::SharedCode: case Svc::MemoryState::SharedCode:
case Svc::MemoryState::GeneratedCode: case Svc::MemoryState::GeneratedCode:
case Svc::MemoryState::CodeOut: case Svc::MemoryState::CodeOut:
@ -522,8 +522,8 @@ size_t KPageTableBase::GetRegionSize(Svc::MemoryState state) const {
case Svc::MemoryState::Shared: case Svc::MemoryState::Shared:
case Svc::MemoryState::AliasCode: case Svc::MemoryState::AliasCode:
case Svc::MemoryState::AliasCodeData: case Svc::MemoryState::AliasCodeData:
case Svc::MemoryState::Transfered: case Svc::MemoryState::Transferred:
case Svc::MemoryState::SharedTransfered: case Svc::MemoryState::SharedTransferred:
case Svc::MemoryState::SharedCode: case Svc::MemoryState::SharedCode:
case Svc::MemoryState::GeneratedCode: case Svc::MemoryState::GeneratedCode:
case Svc::MemoryState::CodeOut: case Svc::MemoryState::CodeOut:
@ -564,8 +564,8 @@ bool KPageTableBase::CanContain(KProcessAddress addr, size_t size, Svc::MemorySt
case Svc::MemoryState::AliasCodeData: case Svc::MemoryState::AliasCodeData:
case Svc::MemoryState::Stack: case Svc::MemoryState::Stack:
case Svc::MemoryState::ThreadLocal: case Svc::MemoryState::ThreadLocal:
case Svc::MemoryState::Transfered: case Svc::MemoryState::Transferred:
case Svc::MemoryState::SharedTransfered: case Svc::MemoryState::SharedTransferred:
case Svc::MemoryState::SharedCode: case Svc::MemoryState::SharedCode:
case Svc::MemoryState::GeneratedCode: case Svc::MemoryState::GeneratedCode:
case Svc::MemoryState::CodeOut: case Svc::MemoryState::CodeOut:

View File

@ -5,6 +5,7 @@
#include "common/scope_exit.h" #include "common/scope_exit.h"
#include "common/settings.h" #include "common/settings.h"
#include "core/core.h" #include "core/core.h"
#include "core/gpu_dirty_memory_manager.h"
#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_scoped_resource_reservation.h"
#include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_shared_memory.h"
@ -314,7 +315,7 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params, const KPa
// Ensure our memory is initialized. // Ensure our memory is initialized.
m_memory.SetCurrentPageTable(*this); m_memory.SetCurrentPageTable(*this);
m_memory.SetGPUDirtyManagers(m_dirty_memory_managers); m_memory.SetGPUDirtyManagers(m_kernel.System().GetGPUDirtyMemoryManager());
// Ensure we can insert the code region. // Ensure we can insert the code region.
R_UNLESS(m_page_table.CanContain(params.code_address, params.code_num_pages * PageSize, R_UNLESS(m_page_table.CanContain(params.code_address, params.code_num_pages * PageSize,
@ -411,7 +412,7 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params,
// Ensure our memory is initialized. // Ensure our memory is initialized.
m_memory.SetCurrentPageTable(*this); m_memory.SetCurrentPageTable(*this);
m_memory.SetGPUDirtyManagers(m_dirty_memory_managers); m_memory.SetGPUDirtyManagers(m_kernel.System().GetGPUDirtyMemoryManager());
// Ensure we can insert the code region. // Ensure we can insert the code region.
R_UNLESS(m_page_table.CanContain(params.code_address, code_size, KMemoryState::Code), R_UNLESS(m_page_table.CanContain(params.code_address, code_size, KMemoryState::Code),
@ -1135,8 +1136,7 @@ void KProcess::Switch(KProcess* cur_process, KProcess* next_process) {}
KProcess::KProcess(KernelCore& kernel) KProcess::KProcess(KernelCore& kernel)
: KAutoObjectWithSlabHeapAndContainer(kernel), m_page_table{kernel}, m_state_lock{kernel}, : KAutoObjectWithSlabHeapAndContainer(kernel), m_page_table{kernel}, m_state_lock{kernel},
m_list_lock{kernel}, m_cond_var{kernel.System()}, m_address_arbiter{kernel.System()}, m_list_lock{kernel}, m_cond_var{kernel.System()}, m_address_arbiter{kernel.System()},
m_handle_table{kernel}, m_dirty_memory_managers{}, m_handle_table{kernel}, m_exclusive_monitor{}, m_memory{kernel.System()} {}
m_exclusive_monitor{}, m_memory{kernel.System()} {}
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,
@ -1318,10 +1318,4 @@ bool KProcess::RemoveWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointT
return true; return true;
} }
void KProcess::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) {
for (auto& manager : m_dirty_memory_managers) {
manager.Gather(callback);
}
}
} // namespace Kernel } // namespace Kernel

View File

@ -7,7 +7,6 @@
#include "core/arm/arm_interface.h" #include "core/arm/arm_interface.h"
#include "core/file_sys/program_metadata.h" #include "core/file_sys/program_metadata.h"
#include "core/gpu_dirty_memory_manager.h"
#include "core/hle/kernel/code_set.h" #include "core/hle/kernel/code_set.h"
#include "core/hle/kernel/k_address_arbiter.h" #include "core/hle/kernel/k_address_arbiter.h"
#include "core/hle/kernel/k_capabilities.h" #include "core/hle/kernel/k_capabilities.h"
@ -128,7 +127,6 @@ private:
#ifdef HAS_NCE #ifdef HAS_NCE
std::unordered_map<u64, u64> m_post_handlers{}; std::unordered_map<u64, u64> m_post_handlers{};
#endif #endif
std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES> m_dirty_memory_managers;
std::unique_ptr<Core::ExclusiveMonitor> m_exclusive_monitor; std::unique_ptr<Core::ExclusiveMonitor> m_exclusive_monitor;
Core::Memory::Memory m_memory; Core::Memory::Memory m_memory;
@ -511,8 +509,6 @@ public:
return m_memory; return m_memory;
} }
void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback);
Core::ExclusiveMonitor& GetExclusiveMonitor() const { Core::ExclusiveMonitor& GetExclusiveMonitor() const {
return *m_exclusive_monitor; return *m_exclusive_monitor;
} }

View File

@ -76,8 +76,8 @@ Result KTransferMemory::Map(KProcessAddress address, size_t size, Svc::MemoryPer
// Map the memory. // Map the memory.
const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None) const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None)
? KMemoryState::Transfered ? KMemoryState::Transferred
: KMemoryState::SharedTransfered; : KMemoryState::SharedTransferred;
R_TRY(GetCurrentProcess(m_kernel).GetPageTable().MapPageGroup( R_TRY(GetCurrentProcess(m_kernel).GetPageTable().MapPageGroup(
address, *m_page_group, state, KMemoryPermission::UserReadWrite)); address, *m_page_group, state, KMemoryPermission::UserReadWrite));
@ -96,8 +96,8 @@ Result KTransferMemory::Unmap(KProcessAddress address, size_t size) {
// Unmap the memory. // Unmap the memory.
const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None) const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None)
? KMemoryState::Transfered ? KMemoryState::Transferred
: KMemoryState::SharedTransfered; : KMemoryState::SharedTransferred;
R_TRY(GetCurrentProcess(m_kernel).GetPageTable().UnmapPageGroup(address, *m_page_group, state)); R_TRY(GetCurrentProcess(m_kernel).GetPageTable().UnmapPageGroup(address, *m_page_group, state));
// Mark ourselves as unmapped. // Mark ourselves as unmapped.

View File

@ -90,7 +90,7 @@ Result MapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t add
// Verify that the mapping is in range. // Verify that the mapping is in range.
R_UNLESS(GetCurrentProcess(system.Kernel()) R_UNLESS(GetCurrentProcess(system.Kernel())
.GetPageTable() .GetPageTable()
.CanContain(address, size, KMemoryState::Transfered), .CanContain(address, size, KMemoryState::Transferred),
ResultInvalidMemoryRegion); ResultInvalidMemoryRegion);
// Map the transfer memory. // Map the transfer memory.
@ -117,7 +117,7 @@ Result UnmapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t a
// Verify that the mapping is in range. // Verify that the mapping is in range.
R_UNLESS(GetCurrentProcess(system.Kernel()) R_UNLESS(GetCurrentProcess(system.Kernel())
.GetPageTable() .GetPageTable()
.CanContain(address, size, KMemoryState::Transfered), .CanContain(address, size, KMemoryState::Transferred),
ResultInvalidMemoryRegion); ResultInvalidMemoryRegion);
// Unmap the transfer memory. // Unmap the transfer memory.

View File

@ -27,8 +27,8 @@ enum class MemoryState : u32 {
Ipc = 0x0A, Ipc = 0x0A,
Stack = 0x0B, Stack = 0x0B,
ThreadLocal = 0x0C, ThreadLocal = 0x0C,
Transfered = 0x0D, Transferred = 0x0D,
SharedTransfered = 0x0E, SharedTransferred = 0x0E,
SharedCode = 0x0F, SharedCode = 0x0F,
Inaccessible = 0x10, Inaccessible = 0x10,
NonSecureIpc = 0x11, NonSecureIpc = 0x11,

View File

@ -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"
@ -37,7 +36,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"
@ -48,6 +46,8 @@
#include "core/hle/service/vi/vi.h" #include "core/hle/service/vi/vi.h"
#include "core/hle/service/vi/vi_results.h" #include "core/hle/service/vi/vi_results.h"
#include "core/memory.h" #include "core/memory.h"
#include "hid_core/hid_types.h"
#include "hid_core/resources/npad/npad.h"
namespace Service::AM { namespace Service::AM {

View File

@ -5,13 +5,13 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/core.h" #include "core/core.h"
#include "core/frontend/applets/cabinet.h" #include "core/frontend/applets/cabinet.h"
#include "core/hid/hid_core.h"
#include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_readable_event.h"
#include "core/hle/service/am/am.h" #include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_cabinet.h" #include "core/hle/service/am/applets/applet_cabinet.h"
#include "core/hle/service/mii/mii_manager.h" #include "core/hle/service/mii/mii_manager.h"
#include "core/hle/service/nfc/common/device.h" #include "core/hle/service/nfc/common/device.h"
#include "hid_core/hid_core.h"
namespace Service::AM::Applets { namespace Service::AM::Applets {

View File

@ -9,13 +9,13 @@
#include "common/string_util.h" #include "common/string_util.h"
#include "core/core.h" #include "core/core.h"
#include "core/frontend/applets/controller.h" #include "core/frontend/applets/controller.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hid/hid_types.h"
#include "core/hle/result.h" #include "core/hle/result.h"
#include "core/hle/service/am/am.h" #include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_controller.h" #include "core/hle/service/am/applets/applet_controller.h"
#include "core/hle/service/hid/controllers/npad.h" #include "hid_core/frontend/emulated_controller.h"
#include "hid_core/hid_core.h"
#include "hid_core/hid_types.h"
#include "hid_core/resources/npad/npad.h"
namespace Service::AM::Applets { namespace Service::AM::Applets {

View File

@ -76,7 +76,7 @@ struct UiSettingsDisplayOptions {
bool is_system_or_launcher; bool is_system_or_launcher;
bool is_registration_permitted; bool is_registration_permitted;
bool show_skip_button; bool show_skip_button;
bool aditional_select; bool additional_select;
bool show_user_selector; bool show_user_selector;
bool is_unqualified_user_selectable; bool is_unqualified_user_selectable;
}; };

View File

@ -85,7 +85,7 @@ Result AlbumManager::GetAlbumFileList(std::vector<AlbumEntry>& out_entries, Albu
} }
Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
ContentType contex_type, s64 start_posix_time, ContentType content_type, s64 start_posix_time,
s64 end_posix_time, u64 aruid) const { s64 end_posix_time, u64 aruid) const {
if (!is_mounted) { if (!is_mounted) {
return ResultIsNotMounted; return ResultIsNotMounted;
@ -94,7 +94,7 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& ou
std::vector<ApplicationAlbumEntry> album_entries; std::vector<ApplicationAlbumEntry> album_entries;
const auto start_date = ConvertToAlbumDateTime(start_posix_time); const auto start_date = ConvertToAlbumDateTime(start_posix_time);
const auto end_date = ConvertToAlbumDateTime(end_posix_time); const auto end_date = ConvertToAlbumDateTime(end_posix_time);
const auto result = GetAlbumFileList(album_entries, contex_type, start_date, end_date, aruid); const auto result = GetAlbumFileList(album_entries, content_type, start_date, end_date, aruid);
if (result.IsError()) { if (result.IsError()) {
return result; return result;
@ -113,14 +113,14 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& ou
} }
Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries, Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries,
ContentType contex_type, AlbumFileDateTime start_date, ContentType content_type, AlbumFileDateTime start_date,
AlbumFileDateTime end_date, u64 aruid) const { AlbumFileDateTime end_date, u64 aruid) const {
if (!is_mounted) { if (!is_mounted) {
return ResultIsNotMounted; return ResultIsNotMounted;
} }
for (auto& [file_id, path] : album_files) { for (auto& [file_id, path] : album_files) {
if (file_id.type != contex_type) { if (file_id.type != content_type) {
continue; continue;
} }
if (file_id.date > start_date) { if (file_id.date > start_date) {
@ -139,7 +139,7 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_en
.hash{}, .hash{},
.datetime = file_id.date, .datetime = file_id.date,
.storage = file_id.storage, .storage = file_id.storage,
.content = contex_type, .content = content_type,
.unknown = 1, .unknown = 1,
}; };
out_entries.push_back(entry); out_entries.push_back(entry);

View File

@ -45,10 +45,10 @@ public:
Result GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage, Result GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage,
u8 flags) const; u8 flags) const;
Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
ContentType contex_type, s64 start_posix_time, s64 end_posix_time, ContentType content_type, s64 start_posix_time, s64 end_posix_time,
u64 aruid) const; u64 aruid) const;
Result GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries, Result GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries,
ContentType contex_type, AlbumFileDateTime start_date, ContentType content_type, AlbumFileDateTime start_date,
AlbumFileDateTime end_date, u64 aruid) const; AlbumFileDateTime end_date, u64 aruid) const;
Result GetAutoSavingStorage(bool& out_is_autosaving) const; Result GetAutoSavingStorage(bool& out_is_autosaving) const;
Result LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output, Result LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output,

View File

@ -12,7 +12,7 @@ constexpr Result ResultUnknown5(ErrorModule::Capture, 5);
constexpr Result ResultUnknown6(ErrorModule::Capture, 6); constexpr Result ResultUnknown6(ErrorModule::Capture, 6);
constexpr Result ResultUnknown7(ErrorModule::Capture, 7); constexpr Result ResultUnknown7(ErrorModule::Capture, 7);
constexpr Result ResultOutOfRange(ErrorModule::Capture, 8); constexpr Result ResultOutOfRange(ErrorModule::Capture, 8);
constexpr Result ResulInvalidTimestamp(ErrorModule::Capture, 12); constexpr Result ResultInvalidTimestamp(ErrorModule::Capture, 12);
constexpr Result ResultInvalidStorage(ErrorModule::Capture, 13); constexpr Result ResultInvalidStorage(ErrorModule::Capture, 13);
constexpr Result ResultInvalidFileContents(ErrorModule::Capture, 14); constexpr Result ResultInvalidFileContents(ErrorModule::Capture, 14);
constexpr Result ResultIsNotMounted(ErrorModule::Capture, 21); constexpr Result ResultIsNotMounted(ErrorModule::Capture, 21);

View File

@ -131,7 +131,7 @@ private:
u8 is_favorite; u8 is_favorite;
u8 same_app; u8 same_app;
u8 same_app_played; u8 same_app_played;
u8 arbitary_app_played; u8 arbitrary_app_played;
u64 group_id; u64 group_id;
}; };
static_assert(sizeof(SizedFriendFilter) == 0x10, "SizedFriendFilter is an invalid size"); static_assert(sizeof(SizedFriendFilter) == 0x10, "SizedFriendFilter is an invalid size");

View File

@ -5,36 +5,36 @@
#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/kernel.h"
#include "core/hle/service/hid/hid.h" #include "core/hle/service/hid/hid.h"
#include "core/hle/service/hid/hid_debug_server.h" #include "core/hle/service/hid/hid_debug_server.h"
#include "core/hle/service/hid/hid_firmware_settings.h"
#include "core/hle/service/hid/hid_server.h" #include "core/hle/service/hid/hid_server.h"
#include "core/hle/service/hid/hid_system_server.h" #include "core/hle/service/hid/hid_system_server.h"
#include "core/hle/service/hid/hidbus.h" #include "core/hle/service/hid/hidbus.h"
#include "core/hle/service/hid/irs.h" #include "core/hle/service/hid/irs.h"
#include "core/hle/service/hid/resource_manager.h"
#include "core/hle/service/hid/xcd.h" #include "core/hle/service/hid/xcd.h"
#include "core/hle/service/server_manager.h" #include "core/hle/service/server_manager.h"
#include "hid_core/resource_manager.h"
#include "hid_core/resources/hid_firmware_settings.h"
namespace Service::HID { namespace Service::HID {
void LoopProcess(Core::System& system) { void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system); auto server_manager = std::make_unique<ServerManager>(system);
std::shared_ptr<ResourceManager> resouce_manager = std::make_shared<ResourceManager>(system); std::shared_ptr<ResourceManager> resource_manager = std::make_shared<ResourceManager>(system);
std::shared_ptr<HidFirmwareSettings> firmware_settings = std::shared_ptr<HidFirmwareSettings> firmware_settings =
std::make_shared<HidFirmwareSettings>(); std::make_shared<HidFirmwareSettings>();
// TODO: Remove this hack until this service is emulated properly. // TODO: Remove this hack until this service is emulated properly.
const auto process_list = system.Kernel().GetProcessList(); const auto process_list = system.Kernel().GetProcessList();
if (!process_list.empty()) { if (!process_list.empty()) {
resouce_manager->Initialize(); resource_manager->Initialize();
resouce_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), true); resource_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), true);
} }
server_manager->RegisterNamedService( server_manager->RegisterNamedService(
"hid", std::make_shared<IHidServer>(system, resouce_manager, firmware_settings)); "hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings));
server_manager->RegisterNamedService( server_manager->RegisterNamedService(
"hid:dbg", std::make_shared<IHidDebugServer>(system, resouce_manager)); "hid:dbg", std::make_shared<IHidDebugServer>(system, resource_manager));
server_manager->RegisterNamedService( server_manager->RegisterNamedService(
"hid:sys", std::make_shared<IHidSystemServer>(system, resouce_manager)); "hid:sys", std::make_shared<IHidSystemServer>(system, resource_manager));
server_manager->RegisterNamedService("hidbus", std::make_shared<HidBus>(system)); server_manager->RegisterNamedService("hidbus", std::make_shared<HidBus>(system));

View File

@ -2,8 +2,8 @@
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
#include "core/hle/service/hid/hid_debug_server.h" #include "core/hle/service/hid/hid_debug_server.h"
#include "core/hle/service/hid/resource_manager.h"
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
#include "hid_core/resource_manager.h"
namespace Service::HID { namespace Service::HID {

View File

@ -5,30 +5,29 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/settings.h" #include "common/settings.h"
#include "core/hid/hid_core.h"
#include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/kernel.h"
#include "core/hle/service/hid/errors.h"
#include "core/hle/service/hid/hid_firmware_settings.h"
#include "core/hle/service/hid/hid_server.h" #include "core/hle/service/hid/hid_server.h"
#include "core/hle/service/hid/hid_util.h"
#include "core/hle/service/hid/resource_manager.h"
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
#include "core/memory.h" #include "core/memory.h"
#include "hid_core/hid_result.h"
#include "hid_core/hid_util.h"
#include "hid_core/resource_manager.h"
#include "hid_core/resources/hid_firmware_settings.h"
#include "core/hle/service/hid/controllers/console_six_axis.h" #include "hid_core/resources/controller_base.h"
#include "core/hle/service/hid/controllers/controller_base.h" #include "hid_core/resources/debug_pad/debug_pad.h"
#include "core/hle/service/hid/controllers/debug_pad.h" #include "hid_core/resources/keyboard/keyboard.h"
#include "core/hle/service/hid/controllers/gesture.h" #include "hid_core/resources/mouse/mouse.h"
#include "core/hle/service/hid/controllers/keyboard.h" #include "hid_core/resources/npad/npad.h"
#include "core/hle/service/hid/controllers/mouse.h" #include "hid_core/resources/npad/npad_types.h"
#include "core/hle/service/hid/controllers/npad.h" #include "hid_core/resources/palma/palma.h"
#include "core/hle/service/hid/controllers/palma.h" #include "hid_core/resources/six_axis/console_six_axis.h"
#include "core/hle/service/hid/controllers/seven_six_axis.h" #include "hid_core/resources/six_axis/seven_six_axis.h"
#include "core/hle/service/hid/controllers/six_axis.h" #include "hid_core/resources/six_axis/six_axis.h"
#include "core/hle/service/hid/controllers/touchscreen.h" #include "hid_core/resources/touch_screen/gesture.h"
#include "core/hle/service/hid/controllers/types/npad_types.h" #include "hid_core/resources/touch_screen/touch_screen.h"
namespace Service::HID { namespace Service::HID {
@ -1445,8 +1444,8 @@ void IHidServer::SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_HID, "(STUBBED) called, use_center_clamp={}, applet_resource_user_id={}", LOG_INFO(Service_HID, "called, use_center_clamp={}, applet_resource_user_id={}",
parameters.use_center_clamp, parameters.applet_resource_user_id); parameters.use_center_clamp, parameters.applet_resource_user_id);
GetResourceManager()->GetNpad()->SetNpadAnalogStickUseCenterClamp( GetResourceManager()->GetNpad()->SetNpadAnalogStickUseCenterClamp(
parameters.applet_resource_user_id, parameters.use_center_clamp); parameters.applet_resource_user_id, parameters.use_center_clamp);
@ -1467,23 +1466,27 @@ void IHidServer::SetNpadCaptureButtonAssignment(HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_HID, LOG_INFO(Service_HID, "called, npad_styleset={}, applet_resource_user_id={}, button={}",
"(STUBBED) called, npad_styleset={}, applet_resource_user_id={}, button={}", parameters.npad_styleset, parameters.applet_resource_user_id, parameters.button);
parameters.npad_styleset, parameters.applet_resource_user_id, parameters.button);
const auto result = GetResourceManager()->GetNpad()->SetNpadCaptureButtonAssignment(
parameters.applet_resource_user_id, parameters.npad_styleset, parameters.button);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess); rb.Push(result);
} }
void IHidServer::ClearNpadCaptureButtonAssignment(HLERequestContext& ctx) { void IHidServer::ClearNpadCaptureButtonAssignment(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()}; const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
applet_resource_user_id);
const auto result =
GetResourceManager()->GetNpad()->ClearNpadCaptureButtonAssignment(applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess); rb.Push(result);
} }
void IHidServer::GetVibrationDeviceInfo(HLERequestContext& ctx) { void IHidServer::GetVibrationDeviceInfo(HLERequestContext& ctx) {

View File

@ -1,15 +1,14 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // 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/palma.h"
#include "core/hle/service/hid/controllers/touchscreen.h"
#include "core/hle/service/hid/controllers/types/npad_types.h"
#include "core/hle/service/hid/errors.h"
#include "core/hle/service/hid/hid_system_server.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" #include "core/hle/service/ipc_helpers.h"
#include "hid_core/hid_result.h"
#include "hid_core/resource_manager.h"
#include "hid_core/resources/npad/npad.h"
#include "hid_core/resources/npad/npad_types.h"
#include "hid_core/resources/palma/palma.h"
#include "hid_core/resources/touch_screen/touch_screen.h"
namespace Service::HID { namespace Service::HID {
@ -47,7 +46,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{310, &IHidSystemServer::GetMaskedSupportedNpadStyleSet, "GetMaskedSupportedNpadStyleSet"}, {310, &IHidSystemServer::GetMaskedSupportedNpadStyleSet, "GetMaskedSupportedNpadStyleSet"},
{311, nullptr, "SetNpadPlayerLedBlinkingDevice"}, {311, nullptr, "SetNpadPlayerLedBlinkingDevice"},
{312, &IHidSystemServer::SetSupportedNpadStyleSetAll, "SetSupportedNpadStyleSetAll"}, {312, &IHidSystemServer::SetSupportedNpadStyleSetAll, "SetSupportedNpadStyleSetAll"},
{313, nullptr, "GetNpadCaptureButtonAssignment"}, {313, &IHidSystemServer::GetNpadCaptureButtonAssignment, "GetNpadCaptureButtonAssignment"},
{314, nullptr, "GetAppletFooterUiType"}, {314, nullptr, "GetAppletFooterUiType"},
{315, &IHidSystemServer::GetAppletDetailedUiType, "GetAppletDetailedUiType"}, {315, &IHidSystemServer::GetAppletDetailedUiType, "GetAppletDetailedUiType"},
{316, &IHidSystemServer::GetNpadInterfaceType, "GetNpadInterfaceType"}, {316, &IHidSystemServer::GetNpadInterfaceType, "GetNpadInterfaceType"},
@ -55,8 +54,8 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{318, &IHidSystemServer::HasBattery, "HasBattery"}, {318, &IHidSystemServer::HasBattery, "HasBattery"},
{319, &IHidSystemServer::HasLeftRightBattery, "HasLeftRightBattery"}, {319, &IHidSystemServer::HasLeftRightBattery, "HasLeftRightBattery"},
{321, &IHidSystemServer::GetUniquePadsFromNpad, "GetUniquePadsFromNpad"}, {321, &IHidSystemServer::GetUniquePadsFromNpad, "GetUniquePadsFromNpad"},
{322, &IHidSystemServer::GetIrSensorState, "GetIrSensorState"}, {322, &IHidSystemServer::SetNpadSystemExtStateEnabled, "SetNpadSystemExtStateEnabled"},
{323, nullptr, "GetXcdHandleForNpadWithIrSensor"}, {323, nullptr, "GetLastActiveUniquePad"},
{324, nullptr, "GetUniquePadButtonSet"}, {324, nullptr, "GetUniquePadButtonSet"},
{325, nullptr, "GetUniquePadColor"}, {325, nullptr, "GetUniquePadColor"},
{326, nullptr, "GetUniquePadAppletDetailedUiType"}, {326, nullptr, "GetUniquePadAppletDetailedUiType"},
@ -82,7 +81,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{522, nullptr, "SetJoyConRailEnabled"}, {522, nullptr, "SetJoyConRailEnabled"},
{523, nullptr, "IsJoyConRailEnabled"}, {523, nullptr, "IsJoyConRailEnabled"},
{524, nullptr, "IsHandheldHidsEnabled"}, {524, nullptr, "IsHandheldHidsEnabled"},
{525, nullptr, "IsJoyConAttachedOnAllRail"}, {525, &IHidSystemServer::IsJoyConAttachedOnAllRail, "IsJoyConAttachedOnAllRail"},
{540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"}, {540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"},
{541, nullptr, "GetPlayReportControllerUsages"}, {541, nullptr, "GetPlayReportControllerUsages"},
{542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"}, {542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"},
@ -132,7 +131,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{1001, nullptr, "GetFirmwareVersion"}, {1001, nullptr, "GetFirmwareVersion"},
{1002, nullptr, "GetAvailableFirmwareVersion"}, {1002, nullptr, "GetAvailableFirmwareVersion"},
{1003, nullptr, "IsFirmwareUpdateAvailable"}, {1003, nullptr, "IsFirmwareUpdateAvailable"},
{1004, nullptr, "CheckFirmwareUpdateRequired"}, {1004, &IHidSystemServer::CheckFirmwareUpdateRequired, "CheckFirmwareUpdateRequired"},
{1005, nullptr, "StartFirmwareUpdate"}, {1005, nullptr, "StartFirmwareUpdate"},
{1006, nullptr, "AbortFirmwareUpdate"}, {1006, nullptr, "AbortFirmwareUpdate"},
{1007, nullptr, "GetFirmwareUpdateState"}, {1007, nullptr, "GetFirmwareUpdateState"},
@ -145,9 +144,9 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{1052, nullptr, "CancelSixAxisSensorAccurateUserCalibration"}, {1052, nullptr, "CancelSixAxisSensorAccurateUserCalibration"},
{1053, nullptr, "GetSixAxisSensorAccurateUserCalibrationState"}, {1053, nullptr, "GetSixAxisSensorAccurateUserCalibrationState"},
{1100, nullptr, "GetHidbusSystemServiceObject"}, {1100, nullptr, "GetHidbusSystemServiceObject"},
{1120, nullptr, "SetFirmwareHotfixUpdateSkipEnabled"}, {1120, &IHidSystemServer::SetFirmwareHotfixUpdateSkipEnabled, "SetFirmwareHotfixUpdateSkipEnabled"},
{1130, nullptr, "InitializeUsbFirmwareUpdate"}, {1130, &IHidSystemServer::InitializeUsbFirmwareUpdate, "InitializeUsbFirmwareUpdate"},
{1131, nullptr, "FinalizeUsbFirmwareUpdate"}, {1131, &IHidSystemServer::FinalizeUsbFirmwareUpdate, "FinalizeUsbFirmwareUpdate"},
{1132, nullptr, "CheckUsbFirmwareUpdateRequired"}, {1132, nullptr, "CheckUsbFirmwareUpdateRequired"},
{1133, nullptr, "StartUsbFirmwareUpdate"}, {1133, nullptr, "StartUsbFirmwareUpdate"},
{1134, nullptr, "GetUsbFirmwareUpdateState"}, {1134, nullptr, "GetUsbFirmwareUpdateState"},
@ -197,7 +196,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{1268, nullptr, "DeleteButtonConfigStorageFull"}, {1268, nullptr, "DeleteButtonConfigStorageFull"},
{1269, nullptr, "DeleteButtonConfigStorageLeft"}, {1269, nullptr, "DeleteButtonConfigStorageLeft"},
{1270, nullptr, "DeleteButtonConfigStorageRight"}, {1270, nullptr, "DeleteButtonConfigStorageRight"},
{1271, nullptr, "IsUsingCustomButtonConfig"}, {1271, &IHidSystemServer::IsUsingCustomButtonConfig, "IsUsingCustomButtonConfig"},
{1272, nullptr, "IsAnyCustomButtonConfigEnabled"}, {1272, nullptr, "IsAnyCustomButtonConfigEnabled"},
{1273, nullptr, "SetAllCustomButtonConfigEnabled"}, {1273, nullptr, "SetAllCustomButtonConfigEnabled"},
{1274, nullptr, "SetDefaultButtonConfig"}, {1274, nullptr, "SetDefaultButtonConfig"},
@ -252,25 +251,38 @@ void IHidSystemServer::ApplyNpadSystemCommonPolicy(HLERequestContext& ctx) {
} }
void IHidSystemServer::EnableAssigningSingleOnSlSrPress(HLERequestContext& ctx) { void IHidSystemServer::EnableAssigningSingleOnSlSrPress(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called"); IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
GetResourceManager()->GetNpad()->AssigningSingleOnSlSrPress(applet_resource_user_id, true);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
} }
void IHidSystemServer::DisableAssigningSingleOnSlSrPress(HLERequestContext& ctx) { void IHidSystemServer::DisableAssigningSingleOnSlSrPress(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called"); IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
GetResourceManager()->GetNpad()->AssigningSingleOnSlSrPress(applet_resource_user_id, false);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
} }
void IHidSystemServer::GetLastActiveNpad(HLERequestContext& ctx) { void IHidSystemServer::GetLastActiveNpad(HLERequestContext& ctx) {
LOG_DEBUG(Service_HID, "(STUBBED) called"); // Spams a lot when controller applet is running Core::HID::NpadIdType npad_id{};
const Result result = GetResourceManager()->GetNpad()->GetLastActiveNpad(npad_id);
LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id);
IPC::ResponseBuilder rb{ctx, 3}; IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess); rb.Push(result);
rb.PushEnum(system.HIDCore().GetLastActiveController()); rb.PushEnum(npad_id);
} }
void IHidSystemServer::ApplyNpadSystemCommonPolicyFull(HLERequestContext& ctx) { void IHidSystemServer::ApplyNpadSystemCommonPolicyFull(HLERequestContext& ctx) {
@ -332,6 +344,27 @@ void IHidSystemServer::SetSupportedNpadStyleSetAll(HLERequestContext& ctx) {
rb.Push(result); rb.Push(result);
} }
void IHidSystemServer::GetNpadCaptureButtonAssignment(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
const auto capture_button_list_size{ctx.GetWriteBufferNumElements<Core::HID::NpadButton>()};
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
std::vector<Core::HID::NpadButton> capture_button_list(capture_button_list_size);
const auto& npad = GetResourceManager()->GetNpad();
const u64 list_size =
npad->GetNpadCaptureButtonAssignment(capture_button_list, applet_resource_user_id);
if (list_size != 0) {
ctx.WriteBuffer(capture_button_list);
}
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(list_size);
}
void IHidSystemServer::GetAppletDetailedUiType(HLERequestContext& ctx) { void IHidSystemServer::GetAppletDetailedUiType(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()}; const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
@ -424,13 +457,25 @@ void IHidSystemServer::GetUniquePadsFromNpad(HLERequestContext& ctx) {
rb.Push(static_cast<u32>(unique_pads.size())); rb.Push(static_cast<u32>(unique_pads.size()));
} }
void IHidSystemServer::GetIrSensorState(HLERequestContext& ctx) { void IHidSystemServer::SetNpadSystemExtStateEnabled(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters {
bool is_enabled;
INSERT_PADDING_BYTES_NOINIT(7);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
LOG_WARNING(Service_HID, "(STUBBED) called"); const auto parameters{rp.PopRaw<Parameters>()};
LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}",
parameters.is_enabled, parameters.applet_resource_user_id);
const auto result = GetResourceManager()->GetNpad()->SetNpadSystemExtStateEnabled(
parameters.applet_resource_user_id, parameters.is_enabled);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess); rb.Push(result);
} }
void IHidSystemServer::RegisterAppletResourceUserId(HLERequestContext& ctx) { void IHidSystemServer::RegisterAppletResourceUserId(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
@ -556,6 +601,16 @@ void IHidSystemServer::EnableAppletToGetTouchScreen(HLERequestContext& ctx) {
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
} }
void IHidSystemServer::IsJoyConAttachedOnAllRail(HLERequestContext& ctx) {
const bool is_attached = true;
LOG_DEBUG(Service_HID, "(STUBBED) called, is_attached={}", is_attached);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(is_attached);
}
void IHidSystemServer::AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx) { void IHidSystemServer::AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx) {
LOG_INFO(Service_AM, "(STUBBED) called"); LOG_INFO(Service_AM, "(STUBBED) called");
@ -642,6 +697,34 @@ void IHidSystemServer::InitializeFirmwareUpdate(HLERequestContext& ctx) {
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
} }
void IHidSystemServer::CheckFirmwareUpdateRequired(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IHidSystemServer::SetFirmwareHotfixUpdateSkipEnabled(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IHidSystemServer::InitializeUsbFirmwareUpdate(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IHidSystemServer::FinalizeUsbFirmwareUpdate(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx) { void IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called"); LOG_WARNING(Service_HID, "(STUBBED) called");
@ -666,6 +749,16 @@ void IHidSystemServer::GetTouchScreenDefaultConfiguration(HLERequestContext& ctx
rb.PushRaw(touchscreen_config); rb.PushRaw(touchscreen_config);
} }
void IHidSystemServer::IsUsingCustomButtonConfig(HLERequestContext& ctx) {
const bool is_enabled = false;
LOG_DEBUG(Service_HID, "(STUBBED) called, is_enabled={}", is_enabled);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(is_enabled);
}
std::shared_ptr<ResourceManager> IHidSystemServer::GetResourceManager() { std::shared_ptr<ResourceManager> IHidSystemServer::GetResourceManager() {
resource_manager->Initialize(); resource_manager->Initialize();
return resource_manager; return resource_manager;

View File

@ -31,19 +31,21 @@ private:
void GetNpadFullKeyGripColor(HLERequestContext& ctx); void GetNpadFullKeyGripColor(HLERequestContext& ctx);
void GetMaskedSupportedNpadStyleSet(HLERequestContext& ctx); void GetMaskedSupportedNpadStyleSet(HLERequestContext& ctx);
void SetSupportedNpadStyleSetAll(HLERequestContext& ctx); void SetSupportedNpadStyleSetAll(HLERequestContext& ctx);
void GetNpadCaptureButtonAssignment(HLERequestContext& ctx);
void GetAppletDetailedUiType(HLERequestContext& ctx); void GetAppletDetailedUiType(HLERequestContext& ctx);
void GetNpadInterfaceType(HLERequestContext& ctx); void GetNpadInterfaceType(HLERequestContext& ctx);
void GetNpadLeftRightInterfaceType(HLERequestContext& ctx); void GetNpadLeftRightInterfaceType(HLERequestContext& ctx);
void HasBattery(HLERequestContext& ctx); void HasBattery(HLERequestContext& ctx);
void HasLeftRightBattery(HLERequestContext& ctx); void HasLeftRightBattery(HLERequestContext& ctx);
void GetUniquePadsFromNpad(HLERequestContext& ctx); void GetUniquePadsFromNpad(HLERequestContext& ctx);
void GetIrSensorState(HLERequestContext& ctx); void SetNpadSystemExtStateEnabled(HLERequestContext& ctx);
void RegisterAppletResourceUserId(HLERequestContext& ctx); void RegisterAppletResourceUserId(HLERequestContext& ctx);
void UnregisterAppletResourceUserId(HLERequestContext& ctx); void UnregisterAppletResourceUserId(HLERequestContext& ctx);
void EnableAppletToGetInput(HLERequestContext& ctx); void EnableAppletToGetInput(HLERequestContext& ctx);
void EnableAppletToGetSixAxisSensor(HLERequestContext& ctx); void EnableAppletToGetSixAxisSensor(HLERequestContext& ctx);
void EnableAppletToGetPadInput(HLERequestContext& ctx); void EnableAppletToGetPadInput(HLERequestContext& ctx);
void EnableAppletToGetTouchScreen(HLERequestContext& ctx); void EnableAppletToGetTouchScreen(HLERequestContext& ctx);
void IsJoyConAttachedOnAllRail(HLERequestContext& ctx);
void AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx); void AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx);
void AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx); void AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx);
void GetRegisteredDevices(HLERequestContext& ctx); void GetRegisteredDevices(HLERequestContext& ctx);
@ -53,8 +55,13 @@ private:
void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx); void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx);
void IsHandheldButtonPressedOnConsoleMode(HLERequestContext& ctx); void IsHandheldButtonPressedOnConsoleMode(HLERequestContext& ctx);
void InitializeFirmwareUpdate(HLERequestContext& ctx); void InitializeFirmwareUpdate(HLERequestContext& ctx);
void CheckFirmwareUpdateRequired(HLERequestContext& ctx);
void SetFirmwareHotfixUpdateSkipEnabled(HLERequestContext& ctx);
void InitializeUsbFirmwareUpdate(HLERequestContext& ctx);
void FinalizeUsbFirmwareUpdate(HLERequestContext& ctx);
void InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx); void InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx);
void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx); void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx);
void IsUsingCustomButtonConfig(HLERequestContext& ctx);
std::shared_ptr<ResourceManager> GetResourceManager(); std::shared_ptr<ResourceManager> GetResourceManager();

View File

@ -5,18 +5,18 @@
#include "common/settings.h" #include "common/settings.h"
#include "core/core.h" #include "core/core.h"
#include "core/core_timing.h" #include "core/core_timing.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_readable_event.h" #include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/service/hid/hidbus.h" #include "core/hle/service/hid/hidbus.h"
#include "core/hle/service/hid/hidbus/ringcon.h"
#include "core/hle/service/hid/hidbus/starlink.h"
#include "core/hle/service/hid/hidbus/stubbed.h"
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#include "core/memory.h" #include "core/memory.h"
#include "hid_core/hid_types.h"
#include "hid_core/hidbus/ringcon.h"
#include "hid_core/hidbus/starlink.h"
#include "hid_core/hidbus/stubbed.h"
namespace Service::HID { namespace Service::HID {
// (15ms, 66Hz) // (15ms, 66Hz)
@ -67,7 +67,7 @@ HidBus::~HidBus() {
void HidBus::UpdateHidbus(std::chrono::nanoseconds ns_late) { void HidBus::UpdateHidbus(std::chrono::nanoseconds ns_late) {
if (is_hidbus_enabled) { if (is_hidbus_enabled) {
for (std::size_t i = 0; i < devices.size(); ++i) { for (std::size_t i = 0; i < devices.size(); ++i) {
if (!devices[i].is_device_initializated) { if (!devices[i].is_device_initialized) {
continue; continue;
} }
auto& device = devices[i].device; auto& device = devices[i].device;
@ -213,7 +213,7 @@ void HidBus::Initialize(HLERequestContext& ctx) {
if (bus_handle_.internal_index == 0 && Settings::values.enable_ring_controller) { if (bus_handle_.internal_index == 0 && Settings::values.enable_ring_controller) {
MakeDevice<RingController>(bus_handle_); MakeDevice<RingController>(bus_handle_);
devices[device_index.value()].is_device_initializated = true; devices[device_index.value()].is_device_initialized = true;
devices[device_index.value()].device->ActivateDevice(); devices[device_index.value()].device->ActivateDevice();
cur_entry.is_in_focus = true; cur_entry.is_in_focus = true;
cur_entry.is_connected = true; cur_entry.is_connected = true;
@ -222,7 +222,7 @@ void HidBus::Initialize(HLERequestContext& ctx) {
cur_entry.is_polling_mode = false; cur_entry.is_polling_mode = false;
} else { } else {
MakeDevice<HidbusStubbed>(bus_handle_); MakeDevice<HidbusStubbed>(bus_handle_);
devices[device_index.value()].is_device_initializated = true; devices[device_index.value()].is_device_initialized = true;
cur_entry.is_in_focus = true; cur_entry.is_in_focus = true;
cur_entry.is_connected = false; cur_entry.is_connected = false;
cur_entry.is_connected_result = ResultSuccess; cur_entry.is_connected_result = ResultSuccess;
@ -261,7 +261,7 @@ void HidBus::Finalize(HLERequestContext& ctx) {
const auto entry_index = devices[device_index.value()].handle.internal_index; const auto entry_index = devices[device_index.value()].handle.internal_index;
auto& cur_entry = hidbus_status.entries[entry_index]; auto& cur_entry = hidbus_status.entries[entry_index];
auto& device = devices[device_index.value()].device; auto& device = devices[device_index.value()].device;
devices[device_index.value()].is_device_initializated = false; devices[device_index.value()].is_device_initialized = false;
device->DeactivateDevice(); device->DeactivateDevice();
cur_entry.is_in_focus = true; cur_entry.is_in_focus = true;

View File

@ -5,9 +5,9 @@
#include <functional> #include <functional>
#include "core/hle/service/hid/hidbus/hidbus_base.h"
#include "core/hle/service/kernel_helpers.h" #include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#include "hid_core/hidbus/hidbus_base.h"
namespace Core::Timing { namespace Core::Timing {
struct EventType; struct EventType;
@ -89,7 +89,7 @@ private:
static_assert(sizeof(HidbusStatusManager) <= 0x1000, "HidbusStatusManager is an invalid size"); static_assert(sizeof(HidbusStatusManager) <= 0x1000, "HidbusStatusManager is an invalid size");
struct HidbusDevice { struct HidbusDevice {
bool is_device_initializated{}; bool is_device_initialized{};
BusHandle handle{}; BusHandle handle{};
std::unique_ptr<HidbusBase> device{nullptr}; std::unique_ptr<HidbusBase> device{nullptr};
}; };

View File

@ -6,22 +6,22 @@
#include "core/core.h" #include "core/core.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/kernel.h"
#include "core/hle/service/hid/errors.h"
#include "core/hle/service/hid/hid_util.h"
#include "core/hle/service/hid/irs.h" #include "core/hle/service/hid/irs.h"
#include "core/hle/service/hid/irsensor/clustering_processor.h"
#include "core/hle/service/hid/irsensor/image_transfer_processor.h"
#include "core/hle/service/hid/irsensor/ir_led_processor.h"
#include "core/hle/service/hid/irsensor/moment_processor.h"
#include "core/hle/service/hid/irsensor/pointing_processor.h"
#include "core/hle/service/hid/irsensor/tera_plugin_processor.h"
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
#include "core/memory.h" #include "core/memory.h"
#include "hid_core/frontend/emulated_controller.h"
#include "hid_core/hid_core.h"
#include "hid_core/hid_result.h"
#include "hid_core/hid_util.h"
#include "hid_core/irsensor/clustering_processor.h"
#include "hid_core/irsensor/image_transfer_processor.h"
#include "hid_core/irsensor/ir_led_processor.h"
#include "hid_core/irsensor/moment_processor.h"
#include "hid_core/irsensor/pointing_processor.h"
#include "hid_core/irsensor/tera_plugin_processor.h"
namespace Service::IRS { namespace Service::IRS {

View File

@ -4,10 +4,10 @@
#pragma once #pragma once
#include "core/core.h" #include "core/core.h"
#include "core/hid/hid_types.h"
#include "core/hid/irs_types.h"
#include "core/hle/service/hid/irsensor/processor_base.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#include "hid_core/hid_types.h"
#include "hid_core/irsensor/irs_types.h"
#include "hid_core/irsensor/processor_base.h"
namespace Core::HID { namespace Core::HID {
class EmulatedController; class EmulatedController;

View File

@ -12,6 +12,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/scratch_buffer.h" #include "common/scratch_buffer.h"
#include "core/guest_memory.h"
#include "core/hle/kernel/k_auto_object.h" #include "core/hle/kernel/k_auto_object.h"
#include "core/hle/kernel/k_handle_table.h" #include "core/hle/kernel/k_handle_table.h"
#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_process.h"
@ -181,22 +182,22 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
} }
} }
buffer_x_desciptors.reserve(command_header->num_buf_x_descriptors); buffer_x_descriptors.reserve(command_header->num_buf_x_descriptors);
buffer_a_desciptors.reserve(command_header->num_buf_a_descriptors); buffer_a_descriptors.reserve(command_header->num_buf_a_descriptors);
buffer_b_desciptors.reserve(command_header->num_buf_b_descriptors); buffer_b_descriptors.reserve(command_header->num_buf_b_descriptors);
buffer_w_desciptors.reserve(command_header->num_buf_w_descriptors); buffer_w_descriptors.reserve(command_header->num_buf_w_descriptors);
for (u32 i = 0; i < command_header->num_buf_x_descriptors; ++i) { for (u32 i = 0; i < command_header->num_buf_x_descriptors; ++i) {
buffer_x_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>()); buffer_x_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>());
} }
for (u32 i = 0; i < command_header->num_buf_a_descriptors; ++i) { for (u32 i = 0; i < command_header->num_buf_a_descriptors; ++i) {
buffer_a_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); buffer_a_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
} }
for (u32 i = 0; i < command_header->num_buf_b_descriptors; ++i) { for (u32 i = 0; i < command_header->num_buf_b_descriptors; ++i) {
buffer_b_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); buffer_b_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
} }
for (u32 i = 0; i < command_header->num_buf_w_descriptors; ++i) { for (u32 i = 0; i < command_header->num_buf_w_descriptors; ++i) {
buffer_w_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); buffer_w_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
} }
const auto buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size; const auto buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size;
@ -246,7 +247,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
IPC::CommandHeader::BufferDescriptorCFlag::InlineDescriptor) { IPC::CommandHeader::BufferDescriptorCFlag::InlineDescriptor) {
if (command_header->buf_c_descriptor_flags == if (command_header->buf_c_descriptor_flags ==
IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) { IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) {
buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); buffer_c_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>());
} else { } else {
u32 num_buf_c_descriptors = u32 num_buf_c_descriptors =
static_cast<u32>(command_header->buf_c_descriptor_flags.Value()) - 2; static_cast<u32>(command_header->buf_c_descriptor_flags.Value()) - 2;
@ -256,7 +257,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
ASSERT(num_buf_c_descriptors < 14); ASSERT(num_buf_c_descriptors < 14);
for (u32 i = 0; i < num_buf_c_descriptors; ++i) { for (u32 i = 0; i < num_buf_c_descriptors; ++i) {
buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); buffer_c_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>());
} }
} }
} }
@ -344,9 +345,9 @@ std::vector<u8> HLERequestContext::ReadBufferCopy(std::size_t buffer_index) cons
std::span<const u8> HLERequestContext::ReadBufferA(std::size_t buffer_index) const { std::span<const u8> HLERequestContext::ReadBufferA(std::size_t buffer_index) const {
static thread_local std::array read_buffer_a{ static thread_local std::array read_buffer_a{
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead>(memory, 0, 0),
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead>(memory, 0, 0),
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead>(memory, 0, 0),
}; };
ASSERT_OR_EXECUTE_MSG( ASSERT_OR_EXECUTE_MSG(
@ -360,9 +361,9 @@ std::span<const u8> HLERequestContext::ReadBufferA(std::size_t buffer_index) con
std::span<const u8> HLERequestContext::ReadBufferX(std::size_t buffer_index) const { std::span<const u8> HLERequestContext::ReadBufferX(std::size_t buffer_index) const {
static thread_local std::array read_buffer_x{ static thread_local std::array read_buffer_x{
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead>(memory, 0, 0),
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead>(memory, 0, 0),
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead>(memory, 0, 0),
}; };
ASSERT_OR_EXECUTE_MSG( ASSERT_OR_EXECUTE_MSG(
@ -376,14 +377,14 @@ std::span<const u8> HLERequestContext::ReadBufferX(std::size_t buffer_index) con
std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const { std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
static thread_local std::array read_buffer_a{ static thread_local std::array read_buffer_a{
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead>(memory, 0, 0),
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead>(memory, 0, 0),
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead>(memory, 0, 0),
}; };
static thread_local std::array read_buffer_x{ static thread_local std::array read_buffer_x{
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead>(memory, 0, 0),
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead>(memory, 0, 0),
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead>(memory, 0, 0),
}; };
const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&

View File

@ -41,6 +41,8 @@ class KernelCore;
class KHandleTable; class KHandleTable;
class KProcess; class KProcess;
class KServerSession; class KServerSession;
template <typename T>
class KScopedAutoObject;
class KThread; class KThread;
} // namespace Kernel } // namespace Kernel
@ -232,19 +234,19 @@ public:
} }
[[nodiscard]] const std::vector<IPC::BufferDescriptorX>& BufferDescriptorX() const { [[nodiscard]] const std::vector<IPC::BufferDescriptorX>& BufferDescriptorX() const {
return buffer_x_desciptors; return buffer_x_descriptors;
} }
[[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorA() const { [[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorA() const {
return buffer_a_desciptors; return buffer_a_descriptors;
} }
[[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorB() const { [[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorB() const {
return buffer_b_desciptors; return buffer_b_descriptors;
} }
[[nodiscard]] const std::vector<IPC::BufferDescriptorC>& BufferDescriptorC() const { [[nodiscard]] const std::vector<IPC::BufferDescriptorC>& BufferDescriptorC() const {
return buffer_c_desciptors; return buffer_c_descriptors;
} }
[[nodiscard]] const IPC::DomainMessageHeader& GetDomainMessageHeader() const { [[nodiscard]] const IPC::DomainMessageHeader& GetDomainMessageHeader() const {
@ -406,11 +408,11 @@ private:
std::optional<IPC::HandleDescriptorHeader> handle_descriptor_header; std::optional<IPC::HandleDescriptorHeader> handle_descriptor_header;
std::optional<IPC::DataPayloadHeader> data_payload_header; std::optional<IPC::DataPayloadHeader> data_payload_header;
std::optional<IPC::DomainMessageHeader> domain_message_header; std::optional<IPC::DomainMessageHeader> domain_message_header;
std::vector<IPC::BufferDescriptorX> buffer_x_desciptors; std::vector<IPC::BufferDescriptorX> buffer_x_descriptors;
std::vector<IPC::BufferDescriptorABW> buffer_a_desciptors; std::vector<IPC::BufferDescriptorABW> buffer_a_descriptors;
std::vector<IPC::BufferDescriptorABW> buffer_b_desciptors; std::vector<IPC::BufferDescriptorABW> buffer_b_descriptors;
std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors; std::vector<IPC::BufferDescriptorABW> buffer_w_descriptors;
std::vector<IPC::BufferDescriptorC> buffer_c_desciptors; std::vector<IPC::BufferDescriptorC> buffer_c_descriptors;
u32_le command{}; u32_le command{};
u64 pid{}; u64 pid{};

View File

@ -19,7 +19,7 @@ namespace Service::NFP::AmiiboCrypto {
bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) { bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) {
const auto& amiibo_data = ntag_file.user_memory; const auto& amiibo_data = ntag_file.user_memory;
LOG_DEBUG(Service_NFP, "uuid_lock=0x{0:x}", ntag_file.static_lock); LOG_DEBUG(Service_NFP, "uuid_lock=0x{0:x}", ntag_file.static_lock);
LOG_DEBUG(Service_NFP, "compability_container=0x{0:x}", ntag_file.compability_container); LOG_DEBUG(Service_NFP, "compatibility_container=0x{0:x}", ntag_file.compatibility_container);
LOG_DEBUG(Service_NFP, "write_count={}", static_cast<u16>(amiibo_data.write_counter)); LOG_DEBUG(Service_NFP, "write_count={}", static_cast<u16>(amiibo_data.write_counter));
LOG_DEBUG(Service_NFP, "character_id=0x{0:x}", amiibo_data.model_info.character_id); LOG_DEBUG(Service_NFP, "character_id=0x{0:x}", amiibo_data.model_info.character_id);
@ -49,7 +49,7 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) {
if (ntag_file.static_lock != 0xE00F) { if (ntag_file.static_lock != 0xE00F) {
return false; return false;
} }
if (ntag_file.compability_container != 0xEEFF10F1U) { if (ntag_file.compatibility_container != 0xEEFF10F1U) {
return false; return false;
} }
if (amiibo_data.model_info.tag_type != NFC::PackedTagType::Type2) { if (amiibo_data.model_info.tag_type != NFC::PackedTagType::Type2) {
@ -78,7 +78,7 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) {
encoded_data.uid_crc_check2 = nfc_data.uuid_crc_check2; encoded_data.uid_crc_check2 = nfc_data.uuid_crc_check2;
encoded_data.internal_number = nfc_data.internal_number; encoded_data.internal_number = nfc_data.internal_number;
encoded_data.static_lock = nfc_data.static_lock; encoded_data.static_lock = nfc_data.static_lock;
encoded_data.compability_container = nfc_data.compability_container; encoded_data.compatibility_container = nfc_data.compatibility_container;
encoded_data.hmac_data = nfc_data.user_memory.hmac_data; encoded_data.hmac_data = nfc_data.user_memory.hmac_data;
encoded_data.constant_value = nfc_data.user_memory.constant_value; encoded_data.constant_value = nfc_data.user_memory.constant_value;
encoded_data.write_counter = nfc_data.user_memory.write_counter; encoded_data.write_counter = nfc_data.user_memory.write_counter;
@ -112,7 +112,7 @@ EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) {
nfc_data.uuid_crc_check2 = encoded_data.uid_crc_check2; nfc_data.uuid_crc_check2 = encoded_data.uid_crc_check2;
nfc_data.internal_number = encoded_data.internal_number; nfc_data.internal_number = encoded_data.internal_number;
nfc_data.static_lock = encoded_data.static_lock; nfc_data.static_lock = encoded_data.static_lock;
nfc_data.compability_container = encoded_data.compability_container; nfc_data.compatibility_container = encoded_data.compatibility_container;
nfc_data.user_memory.hmac_data = encoded_data.hmac_data; nfc_data.user_memory.hmac_data = encoded_data.hmac_data;
nfc_data.user_memory.constant_value = encoded_data.constant_value; nfc_data.user_memory.constant_value = encoded_data.constant_value;
nfc_data.user_memory.write_counter = encoded_data.write_counter; nfc_data.user_memory.write_counter = encoded_data.write_counter;
@ -257,7 +257,7 @@ void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& ou
out_data.uid_crc_check2 = in_data.uid_crc_check2; out_data.uid_crc_check2 = in_data.uid_crc_check2;
out_data.internal_number = in_data.internal_number; out_data.internal_number = in_data.internal_number;
out_data.static_lock = in_data.static_lock; out_data.static_lock = in_data.static_lock;
out_data.compability_container = in_data.compability_container; out_data.compatibility_container = in_data.compatibility_container;
out_data.constant_value = in_data.constant_value; out_data.constant_value = in_data.constant_value;
out_data.write_counter = in_data.write_counter; out_data.write_counter = in_data.write_counter;

View File

@ -22,9 +22,6 @@
#include "common/string_util.h" #include "common/string_util.h"
#include "common/tiny_mt.h" #include "common/tiny_mt.h"
#include "core/core.h" #include "core/core.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hid/hid_types.h"
#include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_event.h"
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/mii/mii_manager.h" #include "core/hle/service/mii/mii_manager.h"
@ -33,6 +30,9 @@
#include "core/hle/service/nfc/mifare_result.h" #include "core/hle/service/nfc/mifare_result.h"
#include "core/hle/service/nfc/nfc_result.h" #include "core/hle/service/nfc/nfc_result.h"
#include "core/hle/service/time/time_manager.h" #include "core/hle/service/time/time_manager.h"
#include "hid_core/frontend/emulated_controller.h"
#include "hid_core/hid_core.h"
#include "hid_core/hid_types.h"
namespace Service::NFC { namespace Service::NFC {
NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_, NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
@ -75,7 +75,7 @@ void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
return; return;
} }
if (!is_initalized) { if (!is_initialized) {
return; return;
} }
@ -207,7 +207,7 @@ void NfcDevice::Initialize() {
return; return;
} }
is_initalized = npad_device->AddNfcHandle(); is_initialized = npad_device->AddNfcHandle();
} }
void NfcDevice::Finalize() { void NfcDevice::Finalize() {
@ -226,7 +226,7 @@ void NfcDevice::Finalize() {
} }
device_state = DeviceState::Unavailable; device_state = DeviceState::Unavailable;
is_initalized = false; is_initialized = false;
} }
Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) { Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) {

View File

@ -126,7 +126,7 @@ private:
Kernel::KEvent* deactivate_event = nullptr; Kernel::KEvent* deactivate_event = nullptr;
Kernel::KEvent* availability_change_event = nullptr; Kernel::KEvent* availability_change_event = nullptr;
bool is_initalized{}; bool is_initialized{};
NfcProtocol allowed_protocols{}; NfcProtocol allowed_protocols{};
DeviceState device_state{DeviceState::Unavailable}; DeviceState device_state{DeviceState::Unavailable};

View File

@ -5,15 +5,15 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/core.h" #include "core/core.h"
#include "core/hid/hid_types.h"
#include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_event.h"
#include "core/hle/service/hid/hid_util.h"
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/nfc/common/device.h" #include "core/hle/service/nfc/common/device.h"
#include "core/hle/service/nfc/common/device_manager.h" #include "core/hle/service/nfc/common/device_manager.h"
#include "core/hle/service/nfc/nfc_result.h" #include "core/hle/service/nfc/nfc_result.h"
#include "core/hle/service/time/clock_types.h" #include "core/hle/service/time/clock_types.h"
#include "core/hle/service/time/time_manager.h" #include "core/hle/service/time/time_manager.h"
#include "hid_core/hid_types.h"
#include "hid_core/hid_util.h"
namespace Service::NFC { namespace Service::NFC {

View File

@ -8,13 +8,13 @@
#include <optional> #include <optional>
#include <span> #include <span>
#include "core/hid/hid_types.h"
#include "core/hle/service/kernel_helpers.h" #include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/nfc/mifare_types.h" #include "core/hle/service/nfc/mifare_types.h"
#include "core/hle/service/nfc/nfc_types.h" #include "core/hle/service/nfc/nfc_types.h"
#include "core/hle/service/nfp/nfp_types.h" #include "core/hle/service/nfp/nfp_types.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#include "core/hle/service/time/clock_types.h" #include "core/hle/service/time/clock_types.h"
#include "hid_core/hid_types.h"
namespace Service::NFC { namespace Service::NFC {
class NfcDevice; class NfcDevice;

View File

@ -3,7 +3,6 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/core.h" #include "core/core.h"
#include "core/hid/hid_types.h"
#include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_event.h"
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/nfc/common/device.h" #include "core/hle/service/nfc/common/device.h"
@ -15,6 +14,7 @@
#include "core/hle/service/nfc/nfc_types.h" #include "core/hle/service/nfc/nfc_types.h"
#include "core/hle/service/nfp/nfp_result.h" #include "core/hle/service/nfp/nfp_result.h"
#include "core/hle/service/time/clock_types.h" #include "core/hle/service/time/clock_types.h"
#include "hid_core/hid_types.h"
namespace Service::NFC { namespace Service::NFC {

View File

@ -3,7 +3,6 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/core.h" #include "core/core.h"
#include "core/hid/hid_types.h"
#include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_event.h"
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/nfc/common/device.h" #include "core/hle/service/nfc/common/device.h"
@ -12,6 +11,7 @@
#include "core/hle/service/nfp/nfp_interface.h" #include "core/hle/service/nfp/nfp_interface.h"
#include "core/hle/service/nfp/nfp_result.h" #include "core/hle/service/nfp/nfp_result.h"
#include "core/hle/service/nfp/nfp_types.h" #include "core/hle/service/nfp/nfp_types.h"
#include "hid_core/hid_types.h"
namespace Service::NFP { namespace Service::NFP {

View File

@ -243,12 +243,12 @@ static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid si
struct NTAG215File { struct NTAG215File {
u8 uid_crc_check2; u8 uid_crc_check2;
u8 internal_number; u8 internal_number;
u16 static_lock; // Set defined pages as read only u16 static_lock; // Set defined pages as read only
u32 compability_container; // Defines available memory u32 compatibility_container; // Defines available memory
HashData hmac_data; // Hash HashData hmac_data; // Hash
u8 constant_value; // Must be A5 u8 constant_value; // Must be A5
u16_be write_counter; // Number of times the amiibo has been written? u16_be write_counter; // Number of times the amiibo has been written?
u8 amiibo_version; // Amiibo file version u8 amiibo_version; // Amiibo file version
AmiiboSettings settings; AmiiboSettings settings;
Service::Mii::Ver3StoreData owner_mii; // Mii data Service::Mii::Ver3StoreData owner_mii; // Mii data
u64_be application_id; // Game id u64_be application_id; // Game id
@ -278,7 +278,7 @@ struct EncryptedNTAG215File {
u8 uuid_crc_check2; u8 uuid_crc_check2;
u8 internal_number; u8 internal_number;
u16 static_lock; // Set defined pages as read only u16 static_lock; // Set defined pages as read only
u32 compability_container; // Defines available memory u32 compatibility_container; // Defines available memory
EncryptedAmiiboFile user_memory; // Writable data EncryptedAmiiboFile user_memory; // Writable data
u32 dynamic_lock; // Dynamic lock u32 dynamic_lock; // Dynamic lock
u32 CFG0; // Defines memory protected by password u32 CFG0; // Defines memory protected by password

View File

@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/ns/language.h" #include "core/hle/service/ns/language.h"
#include "core/hle/service/set/set.h" #include "core/hle/service/set/settings_server.h"
namespace Service::NS { namespace Service::NS {

View File

@ -16,7 +16,7 @@
#include "core/hle/service/ns/ns.h" #include "core/hle/service/ns/ns.h"
#include "core/hle/service/ns/pdm_qry.h" #include "core/hle/service/ns/pdm_qry.h"
#include "core/hle/service/server_manager.h" #include "core/hle/service/server_manager.h"
#include "core/hle/service/set/set.h" #include "core/hle/service/set/settings_server.h"
namespace Service::NS { namespace Service::NS {

View File

@ -2,27 +2,134 @@
// SPDX-FileCopyrightText: 2022 Skyline Team and Contributors // SPDX-FileCopyrightText: 2022 Skyline Team and Contributors
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
#include <atomic>
#include <deque>
#include <mutex>
#include "core/hle/kernel/k_process.h"
#include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/core/container.h"
#include "core/hle/service/nvdrv/core/heap_mapper.h"
#include "core/hle/service/nvdrv/core/nvmap.h" #include "core/hle/service/nvdrv/core/nvmap.h"
#include "core/hle/service/nvdrv/core/syncpoint_manager.h" #include "core/hle/service/nvdrv/core/syncpoint_manager.h"
#include "core/memory.h"
#include "video_core/host1x/host1x.h" #include "video_core/host1x/host1x.h"
namespace Service::Nvidia::NvCore { namespace Service::Nvidia::NvCore {
Session::Session(size_t id_, Kernel::KProcess* process_, size_t smmu_id_)
: id{id_}, process{process_}, smmu_id{smmu_id_},
has_preallocated_area{}, mapper{}, is_active{} {}
Session::~Session() = default;
struct ContainerImpl { struct ContainerImpl {
explicit ContainerImpl(Tegra::Host1x::Host1x& host1x_) explicit ContainerImpl(Container& core, Tegra::Host1x::Host1x& host1x_)
: file{host1x_}, manager{host1x_}, device_file_data{} {} : host1x{host1x_}, file{core, host1x_}, manager{host1x_}, device_file_data{} {}
Tegra::Host1x::Host1x& host1x;
NvMap file; NvMap file;
SyncpointManager manager; SyncpointManager manager;
Container::Host1xDeviceFileData device_file_data; Container::Host1xDeviceFileData device_file_data;
std::deque<Session> sessions;
size_t new_ids{};
std::deque<size_t> id_pool;
std::mutex session_guard;
}; };
Container::Container(Tegra::Host1x::Host1x& host1x_) { Container::Container(Tegra::Host1x::Host1x& host1x_) {
impl = std::make_unique<ContainerImpl>(host1x_); impl = std::make_unique<ContainerImpl>(*this, host1x_);
} }
Container::~Container() = default; Container::~Container() = default;
size_t Container::OpenSession(Kernel::KProcess* process) {
std::scoped_lock lk(impl->session_guard);
for (auto& session : impl->sessions) {
if (!session.is_active) {
continue;
}
if (session.process == process) {
return session.id;
}
}
size_t new_id{};
auto* memory_interface = &process->GetMemory();
auto& smmu = impl->host1x.MemoryManager();
auto smmu_id = smmu.RegisterProcess(memory_interface);
if (!impl->id_pool.empty()) {
new_id = impl->id_pool.front();
impl->id_pool.pop_front();
impl->sessions[new_id] = Session{new_id, process, smmu_id};
} else {
new_id = impl->new_ids++;
impl->sessions.emplace_back(new_id, process, smmu_id);
}
auto& session = impl->sessions[new_id];
session.is_active = true;
// Optimization
if (process->IsApplication()) {
auto& page_table = process->GetPageTable().GetBasePageTable();
auto heap_start = page_table.GetHeapRegionStart();
Kernel::KProcessAddress cur_addr = heap_start;
size_t region_size = 0;
VAddr region_start = 0;
while (true) {
Kernel::KMemoryInfo mem_info{};
Kernel::Svc::PageInfo page_info{};
R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info),
cur_addr));
auto svc_mem_info = mem_info.GetSvcMemoryInfo();
// check if this memory block is heap
if (svc_mem_info.state == Kernel::Svc::MemoryState::Normal) {
if (svc_mem_info.size > region_size) {
region_size = svc_mem_info.size;
region_start = svc_mem_info.base_address;
}
}
// Check if we're done.
const uintptr_t next_address = svc_mem_info.base_address + svc_mem_info.size;
if (next_address <= GetInteger(cur_addr)) {
break;
}
cur_addr = next_address;
}
session.has_preallocated_area = false;
auto start_region = (region_size >> 15) >= 1024 ? smmu.Allocate(region_size) : 0;
if (start_region != 0) {
session.mapper = std::make_unique<HeapMapper>(region_start, start_region, region_size,
smmu_id, impl->host1x);
smmu.TrackContinuity(start_region, region_start, region_size, smmu_id);
session.has_preallocated_area = true;
LOG_CRITICAL(Debug, "Preallocation created!");
}
}
return new_id;
}
void Container::CloseSession(size_t id) {
std::scoped_lock lk(impl->session_guard);
auto& session = impl->sessions[id];
auto& smmu = impl->host1x.MemoryManager();
if (session.has_preallocated_area) {
const DAddr region_start = session.mapper->GetRegionStart();
const size_t region_size = session.mapper->GetRegionSize();
session.mapper.reset();
smmu.Free(region_start, region_size);
session.has_preallocated_area = false;
}
session.is_active = false;
smmu.UnregisterProcess(impl->sessions[id].smmu_id);
impl->id_pool.emplace_front(id);
}
Session* Container::GetSession(size_t id) {
std::atomic_thread_fence(std::memory_order_acquire);
return &impl->sessions[id];
}
NvMap& Container::GetNvMapFile() { NvMap& Container::GetNvMapFile() {
return impl->file; return impl->file;
} }

View File

@ -10,22 +10,49 @@
#include "core/hle/service/nvdrv/nvdata.h" #include "core/hle/service/nvdrv/nvdata.h"
namespace Kernel {
class KProcess;
}
namespace Tegra::Host1x { namespace Tegra::Host1x {
class Host1x; class Host1x;
} // namespace Tegra::Host1x } // namespace Tegra::Host1x
namespace Service::Nvidia::NvCore { namespace Service::Nvidia::NvCore {
class HeapMapper;
class NvMap; class NvMap;
class SyncpointManager; class SyncpointManager;
struct ContainerImpl; struct ContainerImpl;
struct Session {
Session(size_t id_, Kernel::KProcess* process_, size_t smmu_id_);
~Session();
Session(const Session&) = delete;
Session& operator=(const Session&) = delete;
Session(Session&&) = default;
Session& operator=(Session&&) = default;
size_t id;
Kernel::KProcess* process;
size_t smmu_id;
bool has_preallocated_area{};
std::unique_ptr<HeapMapper> mapper{};
bool is_active{};
};
class Container { class Container {
public: public:
explicit Container(Tegra::Host1x::Host1x& host1x); explicit Container(Tegra::Host1x::Host1x& host1x);
~Container(); ~Container();
size_t OpenSession(Kernel::KProcess* process);
void CloseSession(size_t id);
Session* GetSession(size_t id);
NvMap& GetNvMapFile(); NvMap& GetNvMapFile();
const NvMap& GetNvMapFile() const; const NvMap& GetNvMapFile() const;

View File

@ -0,0 +1,175 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <mutex>
#include <boost/container/small_vector.hpp>
#define BOOST_NO_MT
#include <boost/pool/detail/mutex.hpp>
#undef BOOST_NO_MT
#include <boost/icl/interval.hpp>
#include <boost/icl/interval_base_set.hpp>
#include <boost/icl/interval_set.hpp>
#include <boost/icl/split_interval_map.hpp>
#include <boost/pool/pool.hpp>
#include <boost/pool/pool_alloc.hpp>
#include <boost/pool/poolfwd.hpp>
#include "core/hle/service/nvdrv/core/heap_mapper.h"
#include "video_core/host1x/host1x.h"
namespace boost {
template <typename T>
class fast_pool_allocator<T, default_user_allocator_new_delete, details::pool::null_mutex, 4096, 0>;
}
namespace Service::Nvidia::NvCore {
using IntervalCompare = std::less<DAddr>;
using IntervalInstance = boost::icl::interval_type_default<DAddr, std::less>;
using IntervalAllocator = boost::fast_pool_allocator<DAddr>;
using IntervalSet = boost::icl::interval_set<DAddr>;
using IntervalType = typename IntervalSet::interval_type;
template <typename Type>
struct counter_add_functor : public boost::icl::identity_based_inplace_combine<Type> {
// types
typedef counter_add_functor<Type> type;
typedef boost::icl::identity_based_inplace_combine<Type> base_type;
// public member functions
void operator()(Type& current, const Type& added) const {
current += added;
if (current < base_type::identity_element()) {
current = base_type::identity_element();
}
}
// public static functions
static void version(Type&){};
};
using OverlapCombine = counter_add_functor<int>;
using OverlapSection = boost::icl::inter_section<int>;
using OverlapCounter = boost::icl::split_interval_map<DAddr, int>;
struct HeapMapper::HeapMapperInternal {
HeapMapperInternal(Tegra::Host1x::Host1x& host1x) : device_memory{host1x.MemoryManager()} {}
~HeapMapperInternal() = default;
template <typename Func>
void ForEachInOverlapCounter(OverlapCounter& current_range, VAddr cpu_addr, u64 size,
Func&& func) {
const DAddr start_address = cpu_addr;
const DAddr end_address = start_address + size;
const IntervalType search_interval{start_address, end_address};
auto it = current_range.lower_bound(search_interval);
if (it == current_range.end()) {
return;
}
auto end_it = current_range.upper_bound(search_interval);
for (; it != end_it; it++) {
auto& inter = it->first;
DAddr inter_addr_end = inter.upper();
DAddr inter_addr = inter.lower();
if (inter_addr_end > end_address) {
inter_addr_end = end_address;
}
if (inter_addr < start_address) {
inter_addr = start_address;
}
func(inter_addr, inter_addr_end, it->second);
}
}
void RemoveEachInOverlapCounter(OverlapCounter& current_range,
const IntervalType search_interval, int subtract_value) {
bool any_removals = false;
current_range.add(std::make_pair(search_interval, subtract_value));
do {
any_removals = false;
auto it = current_range.lower_bound(search_interval);
if (it == current_range.end()) {
return;
}
auto end_it = current_range.upper_bound(search_interval);
for (; it != end_it; it++) {
if (it->second <= 0) {
any_removals = true;
current_range.erase(it);
break;
}
}
} while (any_removals);
}
IntervalSet base_set;
OverlapCounter mapping_overlaps;
Tegra::MaxwellDeviceMemoryManager& device_memory;
std::mutex guard;
};
HeapMapper::HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size, size_t smmu_id,
Tegra::Host1x::Host1x& host1x)
: m_vaddress{start_vaddress}, m_daddress{start_daddress}, m_size{size}, m_smmu_id{smmu_id} {
m_internal = std::make_unique<HeapMapperInternal>(host1x);
}
HeapMapper::~HeapMapper() {
m_internal->device_memory.Unmap(m_daddress, m_size);
}
DAddr HeapMapper::Map(VAddr start, size_t size) {
std::scoped_lock lk(m_internal->guard);
m_internal->base_set.clear();
const IntervalType interval{start, start + size};
m_internal->base_set.insert(interval);
m_internal->ForEachInOverlapCounter(m_internal->mapping_overlaps, start, size,
[this](VAddr start_addr, VAddr end_addr, int) {
const IntervalType other{start_addr, end_addr};
m_internal->base_set.subtract(other);
});
if (!m_internal->base_set.empty()) {
auto it = m_internal->base_set.begin();
auto end_it = m_internal->base_set.end();
for (; it != end_it; it++) {
const VAddr inter_addr_end = it->upper();
const VAddr inter_addr = it->lower();
const size_t offset = inter_addr - m_vaddress;
const size_t sub_size = inter_addr_end - inter_addr;
m_internal->device_memory.Map(m_daddress + offset, m_vaddress + offset, sub_size,
m_smmu_id);
}
}
m_internal->mapping_overlaps += std::make_pair(interval, 1);
m_internal->base_set.clear();
return m_daddress + (start - m_vaddress);
}
void HeapMapper::Unmap(VAddr start, size_t size) {
std::scoped_lock lk(m_internal->guard);
m_internal->base_set.clear();
m_internal->ForEachInOverlapCounter(m_internal->mapping_overlaps, start, size,
[this](VAddr start_addr, VAddr end_addr, int value) {
if (value <= 1) {
const IntervalType other{start_addr, end_addr};
m_internal->base_set.insert(other);
}
});
if (!m_internal->base_set.empty()) {
auto it = m_internal->base_set.begin();
auto end_it = m_internal->base_set.end();
for (; it != end_it; it++) {
const VAddr inter_addr_end = it->upper();
const VAddr inter_addr = it->lower();
const size_t offset = inter_addr - m_vaddress;
const size_t sub_size = inter_addr_end - inter_addr;
m_internal->device_memory.Unmap(m_daddress + offset, sub_size);
}
}
const IntervalType to_remove{start, start + size};
m_internal->RemoveEachInOverlapCounter(m_internal->mapping_overlaps, to_remove, -1);
m_internal->base_set.clear();
}
} // namespace Service::Nvidia::NvCore

View File

@ -0,0 +1,48 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <memory>
#include "common/common_types.h"
namespace Tegra::Host1x {
class Host1x;
} // namespace Tegra::Host1x
namespace Service::Nvidia::NvCore {
class HeapMapper {
public:
HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size, size_t smmu_id,
Tegra::Host1x::Host1x& host1x);
~HeapMapper();
bool IsInBounds(VAddr start, size_t size) const {
VAddr end = start + size;
return start >= m_vaddress && end <= (m_vaddress + m_size);
}
DAddr Map(VAddr start, size_t size);
void Unmap(VAddr start, size_t size);
DAddr GetRegionStart() const {
return m_daddress;
}
size_t GetRegionSize() const {
return m_size;
}
private:
struct HeapMapperInternal;
VAddr m_vaddress;
DAddr m_daddress;
size_t m_size;
size_t m_smmu_id;
std::unique_ptr<HeapMapperInternal> m_internal;
};
} // namespace Service::Nvidia::NvCore

View File

@ -2,14 +2,19 @@
// SPDX-FileCopyrightText: 2022 Skyline Team and Contributors // SPDX-FileCopyrightText: 2022 Skyline Team and Contributors
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
#include <functional>
#include "common/alignment.h" #include "common/alignment.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/hle/service/nvdrv/core/container.h"
#include "core/hle/service/nvdrv/core/heap_mapper.h"
#include "core/hle/service/nvdrv/core/nvmap.h" #include "core/hle/service/nvdrv/core/nvmap.h"
#include "core/memory.h" #include "core/memory.h"
#include "video_core/host1x/host1x.h" #include "video_core/host1x/host1x.h"
using Core::Memory::YUZU_PAGESIZE; using Core::Memory::YUZU_PAGESIZE;
constexpr size_t BIG_PAGE_SIZE = YUZU_PAGESIZE * 16;
namespace Service::Nvidia::NvCore { namespace Service::Nvidia::NvCore {
NvMap::Handle::Handle(u64 size_, Id id_) NvMap::Handle::Handle(u64 size_, Id id_)
@ -17,9 +22,8 @@ NvMap::Handle::Handle(u64 size_, Id id_)
flags.raw = 0; flags.raw = 0;
} }
NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress) { NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress, size_t pSessionId) {
std::scoped_lock lock(mutex); std::scoped_lock lock(mutex);
// Handles cannot be allocated twice // Handles cannot be allocated twice
if (allocated) { if (allocated) {
return NvResult::AccessDenied; return NvResult::AccessDenied;
@ -28,6 +32,7 @@ NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress)
flags = pFlags; flags = pFlags;
kind = pKind; kind = pKind;
align = pAlign < YUZU_PAGESIZE ? YUZU_PAGESIZE : pAlign; align = pAlign < YUZU_PAGESIZE ? YUZU_PAGESIZE : pAlign;
session_id = pSessionId;
// This flag is only applicable for handles with an address passed // This flag is only applicable for handles with an address passed
if (pAddress) { if (pAddress) {
@ -63,7 +68,7 @@ NvResult NvMap::Handle::Duplicate(bool internal_session) {
return NvResult::Success; return NvResult::Success;
} }
NvMap::NvMap(Tegra::Host1x::Host1x& host1x_) : host1x{host1x_} {} NvMap::NvMap(Container& core_, Tegra::Host1x::Host1x& host1x_) : host1x{host1x_}, core{core_} {}
void NvMap::AddHandle(std::shared_ptr<Handle> handle_description) { void NvMap::AddHandle(std::shared_ptr<Handle> handle_description) {
std::scoped_lock lock(handles_lock); std::scoped_lock lock(handles_lock);
@ -78,12 +83,30 @@ void NvMap::UnmapHandle(Handle& handle_description) {
handle_description.unmap_queue_entry.reset(); handle_description.unmap_queue_entry.reset();
} }
// Free and unmap the handle from Host1x GMMU
if (handle_description.pin_virt_address) {
host1x.GMMU().Unmap(static_cast<GPUVAddr>(handle_description.pin_virt_address),
handle_description.aligned_size);
host1x.Allocator().Free(handle_description.pin_virt_address,
static_cast<u32>(handle_description.aligned_size));
handle_description.pin_virt_address = 0;
}
// Free and unmap the handle from the SMMU // Free and unmap the handle from the SMMU
host1x.MemoryManager().Unmap(static_cast<GPUVAddr>(handle_description.pin_virt_address), const size_t map_size = handle_description.aligned_size;
handle_description.aligned_size); if (!handle_description.in_heap) {
host1x.Allocator().Free(handle_description.pin_virt_address, auto& smmu = host1x.MemoryManager();
static_cast<u32>(handle_description.aligned_size)); size_t aligned_up = Common::AlignUp(map_size, BIG_PAGE_SIZE);
handle_description.pin_virt_address = 0; smmu.Unmap(handle_description.d_address, map_size);
smmu.Free(handle_description.d_address, static_cast<size_t>(aligned_up));
handle_description.d_address = 0;
return;
}
const VAddr vaddress = handle_description.address;
auto* session = core.GetSession(handle_description.session_id);
session->mapper->Unmap(vaddress, map_size);
handle_description.d_address = 0;
handle_description.in_heap = false;
} }
bool NvMap::TryRemoveHandle(const Handle& handle_description) { bool NvMap::TryRemoveHandle(const Handle& handle_description) {
@ -124,22 +147,33 @@ std::shared_ptr<NvMap::Handle> NvMap::GetHandle(Handle::Id handle) {
} }
} }
VAddr NvMap::GetHandleAddress(Handle::Id handle) { DAddr NvMap::GetHandleAddress(Handle::Id handle) {
std::scoped_lock lock(handles_lock); std::scoped_lock lock(handles_lock);
try { try {
return handles.at(handle)->address; return handles.at(handle)->d_address;
} catch (std::out_of_range&) { } catch (std::out_of_range&) {
return 0; return 0;
} }
} }
u32 NvMap::PinHandle(NvMap::Handle::Id handle) { DAddr NvMap::PinHandle(NvMap::Handle::Id handle, bool low_area_pin) {
auto handle_description{GetHandle(handle)}; auto handle_description{GetHandle(handle)};
if (!handle_description) [[unlikely]] { if (!handle_description) [[unlikely]] {
return 0; return 0;
} }
std::scoped_lock lock(handle_description->mutex); std::scoped_lock lock(handle_description->mutex);
const auto map_low_area = [&] {
if (handle_description->pin_virt_address == 0) {
auto& gmmu_allocator = host1x.Allocator();
auto& gmmu = host1x.GMMU();
u32 address =
gmmu_allocator.Allocate(static_cast<u32>(handle_description->aligned_size));
gmmu.Map(static_cast<GPUVAddr>(address), handle_description->d_address,
handle_description->aligned_size);
handle_description->pin_virt_address = address;
}
};
if (!handle_description->pins) { if (!handle_description->pins) {
// If we're in the unmap queue we can just remove ourselves and return since we're already // If we're in the unmap queue we can just remove ourselves and return since we're already
// mapped // mapped
@ -151,37 +185,58 @@ u32 NvMap::PinHandle(NvMap::Handle::Id handle) {
unmap_queue.erase(*handle_description->unmap_queue_entry); unmap_queue.erase(*handle_description->unmap_queue_entry);
handle_description->unmap_queue_entry.reset(); handle_description->unmap_queue_entry.reset();
if (low_area_pin) {
map_low_area();
handle_description->pins++;
return static_cast<DAddr>(handle_description->pin_virt_address);
}
handle_description->pins++; handle_description->pins++;
return handle_description->pin_virt_address; return handle_description->d_address;
} }
} }
using namespace std::placeholders;
// If not then allocate some space and map it // If not then allocate some space and map it
u32 address{}; DAddr address{};
auto& smmu_allocator = host1x.Allocator(); auto& smmu = host1x.MemoryManager();
auto& smmu_memory_manager = host1x.MemoryManager(); auto* session = core.GetSession(handle_description->session_id);
while ((address = smmu_allocator.Allocate( const VAddr vaddress = handle_description->address;
static_cast<u32>(handle_description->aligned_size))) == 0) { const size_t map_size = handle_description->aligned_size;
// Free handles until the allocation succeeds if (session->has_preallocated_area && session->mapper->IsInBounds(vaddress, map_size)) {
std::scoped_lock queueLock(unmap_queue_lock); handle_description->d_address = session->mapper->Map(vaddress, map_size);
if (auto freeHandleDesc{unmap_queue.front()}) { handle_description->in_heap = true;
// Handles in the unmap queue are guaranteed not to be pinned so don't bother } else {
// checking if they are before unmapping size_t aligned_up = Common::AlignUp(map_size, BIG_PAGE_SIZE);
std::scoped_lock freeLock(freeHandleDesc->mutex); while ((address = smmu.Allocate(aligned_up)) == 0) {
if (handle_description->pin_virt_address) // Free handles until the allocation succeeds
UnmapHandle(*freeHandleDesc); std::scoped_lock queueLock(unmap_queue_lock);
} else { if (auto freeHandleDesc{unmap_queue.front()}) {
LOG_CRITICAL(Service_NVDRV, "Ran out of SMMU address space!"); // Handles in the unmap queue are guaranteed not to be pinned so don't bother
// checking if they are before unmapping
std::scoped_lock freeLock(freeHandleDesc->mutex);
if (handle_description->d_address)
UnmapHandle(*freeHandleDesc);
} else {
LOG_CRITICAL(Service_NVDRV, "Ran out of SMMU address space!");
}
} }
}
smmu_memory_manager.Map(static_cast<GPUVAddr>(address), handle_description->address, handle_description->d_address = address;
handle_description->aligned_size); smmu.Map(address, vaddress, map_size, session->smmu_id, true);
handle_description->pin_virt_address = address; handle_description->in_heap = false;
}
}
if (low_area_pin) {
map_low_area();
} }
handle_description->pins++; handle_description->pins++;
return handle_description->pin_virt_address; if (low_area_pin) {
return static_cast<DAddr>(handle_description->pin_virt_address);
}
return handle_description->d_address;
} }
void NvMap::UnpinHandle(Handle::Id handle) { void NvMap::UnpinHandle(Handle::Id handle) {
@ -232,7 +287,7 @@ std::optional<NvMap::FreeInfo> NvMap::FreeHandle(Handle::Id handle, bool interna
LOG_WARNING(Service_NVDRV, "User duplicate count imbalance detected!"); LOG_WARNING(Service_NVDRV, "User duplicate count imbalance detected!");
} else if (handle_description->dupes == 0) { } else if (handle_description->dupes == 0) {
// Force unmap the handle // Force unmap the handle
if (handle_description->pin_virt_address) { if (handle_description->d_address) {
std::scoped_lock queueLock(unmap_queue_lock); std::scoped_lock queueLock(unmap_queue_lock);
UnmapHandle(*handle_description); UnmapHandle(*handle_description);
} }

View File

@ -25,6 +25,8 @@ class Host1x;
} // namespace Tegra } // namespace Tegra
namespace Service::Nvidia::NvCore { namespace Service::Nvidia::NvCore {
class Container;
/** /**
* @brief The nvmap core class holds the global state for nvmap and provides methods to manage * @brief The nvmap core class holds the global state for nvmap and provides methods to manage
* handles * handles
@ -48,7 +50,7 @@ public:
using Id = u32; using Id = u32;
Id id; //!< A globally unique identifier for this handle Id id; //!< A globally unique identifier for this handle
s32 pins{}; s64 pins{};
u32 pin_virt_address{}; u32 pin_virt_address{};
std::optional<typename std::list<std::shared_ptr<Handle>>::iterator> unmap_queue_entry{}; std::optional<typename std::list<std::shared_ptr<Handle>>::iterator> unmap_queue_entry{};
@ -61,15 +63,18 @@ public:
} flags{}; } flags{};
static_assert(sizeof(Flags) == sizeof(u32)); static_assert(sizeof(Flags) == sizeof(u32));
u64 address{}; //!< The memory location in the guest's AS that this handle corresponds to, VAddr address{}; //!< The memory location in the guest's AS that this handle corresponds to,
//!< this can also be in the nvdrv tmem //!< this can also be in the nvdrv tmem
bool is_shared_mem_mapped{}; //!< If this nvmap has been mapped with the MapSharedMem IPC bool is_shared_mem_mapped{}; //!< If this nvmap has been mapped with the MapSharedMem IPC
//!< call //!< call
u8 kind{}; //!< Used for memory compression u8 kind{}; //!< Used for memory compression
bool allocated{}; //!< If the handle has been allocated with `Alloc` bool allocated{}; //!< If the handle has been allocated with `Alloc`
bool in_heap{};
size_t session_id{};
u64 dma_map_addr{}; //! remove me after implementing pinning. DAddr d_address{}; //!< The memory location in the device's AS that this handle corresponds
//!< to, this can also be in the nvdrv tmem
Handle(u64 size, Id id); Handle(u64 size, Id id);
@ -77,7 +82,8 @@ public:
* @brief Sets up the handle with the given memory config, can allocate memory from the tmem * @brief Sets up the handle with the given memory config, can allocate memory from the tmem
* if a 0 address is passed * if a 0 address is passed
*/ */
[[nodiscard]] NvResult Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress); [[nodiscard]] NvResult Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress,
size_t pSessionId);
/** /**
* @brief Increases the dupe counter of the handle for the given session * @brief Increases the dupe counter of the handle for the given session
@ -108,7 +114,7 @@ public:
bool can_unlock; //!< If the address region is ready to be unlocked bool can_unlock; //!< If the address region is ready to be unlocked
}; };
explicit NvMap(Tegra::Host1x::Host1x& host1x); explicit NvMap(Container& core, Tegra::Host1x::Host1x& host1x);
/** /**
* @brief Creates an unallocated handle of the given size * @brief Creates an unallocated handle of the given size
@ -117,7 +123,7 @@ public:
std::shared_ptr<Handle> GetHandle(Handle::Id handle); std::shared_ptr<Handle> GetHandle(Handle::Id handle);
VAddr GetHandleAddress(Handle::Id handle); DAddr GetHandleAddress(Handle::Id handle);
/** /**
* @brief Maps a handle into the SMMU address space * @brief Maps a handle into the SMMU address space
@ -125,7 +131,7 @@ public:
* number of calls to `UnpinHandle` * number of calls to `UnpinHandle`
* @return The SMMU virtual address that the handle has been mapped to * @return The SMMU virtual address that the handle has been mapped to
*/ */
u32 PinHandle(Handle::Id handle); DAddr PinHandle(Handle::Id handle, bool low_area_pin);
/** /**
* @brief When this has been called an equal number of times to `PinHandle` for the supplied * @brief When this has been called an equal number of times to `PinHandle` for the supplied
@ -172,5 +178,7 @@ private:
* @return If the handle was removed from the map * @return If the handle was removed from the map
*/ */
bool TryRemoveHandle(const Handle& handle_description); bool TryRemoveHandle(const Handle& handle_description);
Container& core;
}; };
} // namespace Service::Nvidia::NvCore } // namespace Service::Nvidia::NvCore

View File

@ -62,7 +62,7 @@ public:
* Called once a device is opened * Called once a device is opened
* @param fd The device fd * @param fd The device fd
*/ */
virtual void OnOpen(DeviceFD fd) = 0; virtual void OnOpen(size_t session_id, DeviceFD fd) = 0;
/** /**
* Called once a device is closed * Called once a device is closed

View File

@ -35,14 +35,14 @@ NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in
return NvResult::NotImplemented; return NvResult::NotImplemented;
} }
void nvdisp_disp0::OnOpen(DeviceFD fd) {} void nvdisp_disp0::OnOpen(size_t session_id, DeviceFD fd) {}
void nvdisp_disp0::OnClose(DeviceFD fd) {} void nvdisp_disp0::OnClose(DeviceFD fd) {}
void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width, void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width,
u32 height, u32 stride, android::BufferTransformFlags transform, u32 height, u32 stride, android::BufferTransformFlags transform,
const Common::Rectangle<int>& crop_rect, const Common::Rectangle<int>& crop_rect,
std::array<Service::Nvidia::NvFence, 4>& fences, u32 num_fences) { std::array<Service::Nvidia::NvFence, 4>& fences, u32 num_fences) {
const VAddr addr = nvmap.GetHandleAddress(buffer_handle); const DAddr addr = nvmap.GetHandleAddress(buffer_handle);
LOG_TRACE(Service, LOG_TRACE(Service,
"Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}", "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}",
addr, offset, width, height, stride, format); addr, offset, width, height, stride, format);

View File

@ -32,7 +32,7 @@ public:
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
std::span<u8> inline_output) override; std::span<u8> inline_output) override;
void OnOpen(DeviceFD fd) override; void OnOpen(size_t session_id, DeviceFD fd) override;
void OnClose(DeviceFD fd) override; void OnClose(DeviceFD fd) override;
/// Performs a screen flip, drawing the buffer pointed to by the handle. /// Performs a screen flip, drawing the buffer pointed to by the handle.

View File

@ -86,7 +86,7 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> i
return NvResult::NotImplemented; return NvResult::NotImplemented;
} }
void nvhost_as_gpu::OnOpen(DeviceFD fd) {} void nvhost_as_gpu::OnOpen(size_t session_id, DeviceFD fd) {}
void nvhost_as_gpu::OnClose(DeviceFD fd) {} void nvhost_as_gpu::OnClose(DeviceFD fd) {}
NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) { NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) {
@ -206,6 +206,8 @@ void nvhost_as_gpu::FreeMappingLocked(u64 offset) {
static_cast<u32>(aligned_size >> page_size_bits)); static_cast<u32>(aligned_size >> page_size_bits));
} }
nvmap.UnpinHandle(mapping->handle);
// Sparse mappings shouldn't be fully unmapped, just returned to their sparse state // Sparse mappings shouldn't be fully unmapped, just returned to their sparse state
// Only FreeSpace can unmap them fully // Only FreeSpace can unmap them fully
if (mapping->sparse_alloc) { if (mapping->sparse_alloc) {
@ -293,12 +295,12 @@ NvResult nvhost_as_gpu::Remap(std::span<IoctlRemapEntry> entries) {
return NvResult::BadValue; return NvResult::BadValue;
} }
VAddr cpu_address{static_cast<VAddr>( DAddr base = nvmap.PinHandle(entry.handle, false);
handle->address + DAddr device_address{static_cast<DAddr>(
(static_cast<u64>(entry.handle_offset_big_pages) << vm.big_page_size_bits))}; base + (static_cast<u64>(entry.handle_offset_big_pages) << vm.big_page_size_bits))};
gmmu->Map(virtual_address, cpu_address, size, static_cast<Tegra::PTEKind>(entry.kind), gmmu->Map(virtual_address, device_address, size,
use_big_pages); static_cast<Tegra::PTEKind>(entry.kind), use_big_pages);
} }
} }
@ -331,9 +333,9 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) {
} }
u64 gpu_address{static_cast<u64>(params.offset + params.buffer_offset)}; u64 gpu_address{static_cast<u64>(params.offset + params.buffer_offset)};
VAddr cpu_address{mapping->ptr + params.buffer_offset}; VAddr device_address{mapping->ptr + params.buffer_offset};
gmmu->Map(gpu_address, cpu_address, params.mapping_size, gmmu->Map(gpu_address, device_address, params.mapping_size,
static_cast<Tegra::PTEKind>(params.kind), mapping->big_page); static_cast<Tegra::PTEKind>(params.kind), mapping->big_page);
return NvResult::Success; return NvResult::Success;
@ -349,7 +351,8 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) {
return NvResult::BadValue; return NvResult::BadValue;
} }
VAddr cpu_address{static_cast<VAddr>(handle->address + params.buffer_offset)}; DAddr device_address{
static_cast<DAddr>(nvmap.PinHandle(params.handle, false) + params.buffer_offset)};
u64 size{params.mapping_size ? params.mapping_size : handle->orig_size}; u64 size{params.mapping_size ? params.mapping_size : handle->orig_size};
bool big_page{[&]() { bool big_page{[&]() {
@ -373,15 +376,14 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) {
} }
const bool use_big_pages = alloc->second.big_pages && big_page; const bool use_big_pages = alloc->second.big_pages && big_page;
gmmu->Map(params.offset, cpu_address, size, static_cast<Tegra::PTEKind>(params.kind), gmmu->Map(params.offset, device_address, size, static_cast<Tegra::PTEKind>(params.kind),
use_big_pages); use_big_pages);
auto mapping{std::make_shared<Mapping>(cpu_address, params.offset, size, true, auto mapping{std::make_shared<Mapping>(params.handle, device_address, params.offset, size,
use_big_pages, alloc->second.sparse)}; true, use_big_pages, alloc->second.sparse)};
alloc->second.mappings.push_back(mapping); alloc->second.mappings.push_back(mapping);
mapping_map[params.offset] = mapping; mapping_map[params.offset] = mapping;
} else { } else {
auto& allocator{big_page ? *vm.big_page_allocator : *vm.small_page_allocator}; auto& allocator{big_page ? *vm.big_page_allocator : *vm.small_page_allocator};
u32 page_size{big_page ? vm.big_page_size : VM::YUZU_PAGESIZE}; u32 page_size{big_page ? vm.big_page_size : VM::YUZU_PAGESIZE};
u32 page_size_bits{big_page ? vm.big_page_size_bits : VM::PAGE_SIZE_BITS}; u32 page_size_bits{big_page ? vm.big_page_size_bits : VM::PAGE_SIZE_BITS};
@ -394,11 +396,11 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) {
return NvResult::InsufficientMemory; return NvResult::InsufficientMemory;
} }
gmmu->Map(params.offset, cpu_address, Common::AlignUp(size, page_size), gmmu->Map(params.offset, device_address, Common::AlignUp(size, page_size),
static_cast<Tegra::PTEKind>(params.kind), big_page); static_cast<Tegra::PTEKind>(params.kind), big_page);
auto mapping{ auto mapping{std::make_shared<Mapping>(params.handle, device_address, params.offset, size,
std::make_shared<Mapping>(cpu_address, params.offset, size, false, big_page, false)}; false, big_page, false)};
mapping_map[params.offset] = mapping; mapping_map[params.offset] = mapping;
} }
@ -433,6 +435,8 @@ NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params) {
gmmu->Unmap(params.offset, mapping->size); gmmu->Unmap(params.offset, mapping->size);
} }
nvmap.UnpinHandle(mapping->handle);
mapping_map.erase(params.offset); mapping_map.erase(params.offset);
} catch (const std::out_of_range&) { } catch (const std::out_of_range&) {
LOG_WARNING(Service_NVDRV, "Couldn't find region to unmap at 0x{:X}", params.offset); LOG_WARNING(Service_NVDRV, "Couldn't find region to unmap at 0x{:X}", params.offset);

View File

@ -55,7 +55,7 @@ public:
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
std::span<u8> inline_output) override; std::span<u8> inline_output) override;
void OnOpen(DeviceFD fd) override; void OnOpen(size_t session_id, DeviceFD fd) override;
void OnClose(DeviceFD fd) override; void OnClose(DeviceFD fd) override;
Kernel::KEvent* QueryEvent(u32 event_id) override; Kernel::KEvent* QueryEvent(u32 event_id) override;
@ -90,7 +90,7 @@ private:
u64_le align; u64_le align;
}; };
}; };
static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size"); static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitializeEx is incorrect size");
struct IoctlFreeSpace { struct IoctlFreeSpace {
u64_le offset{}; u64_le offset{};
@ -159,16 +159,18 @@ private:
NvCore::NvMap& nvmap; NvCore::NvMap& nvmap;
struct Mapping { struct Mapping {
VAddr ptr; NvCore::NvMap::Handle::Id handle;
DAddr ptr;
u64 offset; u64 offset;
u64 size; u64 size;
bool fixed; bool fixed;
bool big_page; // Only valid if fixed == false bool big_page; // Only valid if fixed == false
bool sparse_alloc; bool sparse_alloc;
Mapping(VAddr ptr_, u64 offset_, u64 size_, bool fixed_, bool big_page_, bool sparse_alloc_) Mapping(NvCore::NvMap::Handle::Id handle_, DAddr ptr_, u64 offset_, u64 size_, bool fixed_,
: ptr(ptr_), offset(offset_), size(size_), fixed(fixed_), big_page(big_page_), bool big_page_, bool sparse_alloc_)
sparse_alloc(sparse_alloc_) {} : handle(handle_), ptr(ptr_), offset(offset_), size(size_), fixed(fixed_),
big_page(big_page_), sparse_alloc(sparse_alloc_) {}
}; };
struct Allocation { struct Allocation {
@ -212,9 +214,6 @@ private:
bool initialised{}; bool initialised{};
} vm; } vm;
std::shared_ptr<Tegra::MemoryManager> gmmu; std::shared_ptr<Tegra::MemoryManager> gmmu;
// s32 channel{};
// u32 big_page_size{VM::DEFAULT_BIG_PAGE_SIZE};
}; };
} // namespace Service::Nvidia::Devices } // namespace Service::Nvidia::Devices

View File

@ -76,7 +76,7 @@ NvResult nvhost_ctrl::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inp
return NvResult::NotImplemented; return NvResult::NotImplemented;
} }
void nvhost_ctrl::OnOpen(DeviceFD fd) {} void nvhost_ctrl::OnOpen(size_t session_id, DeviceFD fd) {}
void nvhost_ctrl::OnClose(DeviceFD fd) {} void nvhost_ctrl::OnClose(DeviceFD fd) {}

View File

@ -32,7 +32,7 @@ public:
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
std::span<u8> inline_output) override; std::span<u8> inline_output) override;
void OnOpen(DeviceFD fd) override; void OnOpen(size_t session_id, DeviceFD fd) override;
void OnClose(DeviceFD fd) override; void OnClose(DeviceFD fd) override;
Kernel::KEvent* QueryEvent(u32 event_id) override; Kernel::KEvent* QueryEvent(u32 event_id) override;

View File

@ -15,7 +15,7 @@ namespace Service::Nvidia::Devices {
nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_) nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_)
: nvdevice{system_}, events_interface{events_interface_} { : nvdevice{system_}, events_interface{events_interface_} {
error_notifier_event = events_interface.CreateEvent("CtrlGpuErrorNotifier"); error_notifier_event = events_interface.CreateEvent("CtrlGpuErrorNotifier");
unknown_event = events_interface.CreateEvent("CtrlGpuUknownEvent"); unknown_event = events_interface.CreateEvent("CtrlGpuUnknownEvent");
} }
nvhost_ctrl_gpu::~nvhost_ctrl_gpu() { nvhost_ctrl_gpu::~nvhost_ctrl_gpu() {
events_interface.FreeEvent(error_notifier_event); events_interface.FreeEvent(error_notifier_event);
@ -82,7 +82,7 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8>
return NvResult::NotImplemented; return NvResult::NotImplemented;
} }
void nvhost_ctrl_gpu::OnOpen(DeviceFD fd) {} void nvhost_ctrl_gpu::OnOpen(size_t session_id, DeviceFD fd) {}
void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {} void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {}
NvResult nvhost_ctrl_gpu::GetCharacteristics1(IoctlCharacteristics& params) { NvResult nvhost_ctrl_gpu::GetCharacteristics1(IoctlCharacteristics& params) {

View File

@ -28,7 +28,7 @@ public:
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
std::span<u8> inline_output) override; std::span<u8> inline_output) override;
void OnOpen(DeviceFD fd) override; void OnOpen(size_t session_id, DeviceFD fd) override;
void OnClose(DeviceFD fd) override; void OnClose(DeviceFD fd) override;
Kernel::KEvent* QueryEvent(u32 event_id) override; Kernel::KEvent* QueryEvent(u32 event_id) override;

View File

@ -120,7 +120,7 @@ NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inpu
return NvResult::NotImplemented; return NvResult::NotImplemented;
} }
void nvhost_gpu::OnOpen(DeviceFD fd) {} void nvhost_gpu::OnOpen(size_t session_id, DeviceFD fd) {}
void nvhost_gpu::OnClose(DeviceFD fd) {} void nvhost_gpu::OnClose(DeviceFD fd) {}
NvResult nvhost_gpu::SetNVMAPfd(IoctlSetNvmapFD& params) { NvResult nvhost_gpu::SetNVMAPfd(IoctlSetNvmapFD& params) {

View File

@ -47,7 +47,7 @@ public:
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
std::span<u8> inline_output) override; std::span<u8> inline_output) override;
void OnOpen(DeviceFD fd) override; void OnOpen(size_t session_id, DeviceFD fd) override;
void OnClose(DeviceFD fd) override; void OnClose(DeviceFD fd) override;
Kernel::KEvent* QueryEvent(u32 event_id) override; Kernel::KEvent* QueryEvent(u32 event_id) override;

View File

@ -35,7 +35,7 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in
case 0x7: case 0x7:
return WrapFixed(this, &nvhost_nvdec::SetSubmitTimeout, input, output); return WrapFixed(this, &nvhost_nvdec::SetSubmitTimeout, input, output);
case 0x9: case 0x9:
return WrapFixedVariable(this, &nvhost_nvdec::MapBuffer, input, output); return WrapFixedVariable(this, &nvhost_nvdec::MapBuffer, input, output, fd);
case 0xa: case 0xa:
return WrapFixedVariable(this, &nvhost_nvdec::UnmapBuffer, input, output); return WrapFixedVariable(this, &nvhost_nvdec::UnmapBuffer, input, output);
default: default:
@ -68,9 +68,10 @@ NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in
return NvResult::NotImplemented; return NvResult::NotImplemented;
} }
void nvhost_nvdec::OnOpen(DeviceFD fd) { void nvhost_nvdec::OnOpen(size_t session_id, DeviceFD fd) {
LOG_INFO(Service_NVDRV, "NVDEC video stream started"); LOG_INFO(Service_NVDRV, "NVDEC video stream started");
system.SetNVDECActive(true); system.SetNVDECActive(true);
sessions[fd] = session_id;
} }
void nvhost_nvdec::OnClose(DeviceFD fd) { void nvhost_nvdec::OnClose(DeviceFD fd) {
@ -81,6 +82,10 @@ void nvhost_nvdec::OnClose(DeviceFD fd) {
system.GPU().ClearCdmaInstance(iter->second); system.GPU().ClearCdmaInstance(iter->second);
} }
system.SetNVDECActive(false); system.SetNVDECActive(false);
auto it = sessions.find(fd);
if (it != sessions.end()) {
sessions.erase(it);
}
} }
} // namespace Service::Nvidia::Devices } // namespace Service::Nvidia::Devices

View File

@ -20,7 +20,7 @@ public:
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
std::span<u8> inline_output) override; std::span<u8> inline_output) override;
void OnOpen(DeviceFD fd) override; void OnOpen(size_t session_id, DeviceFD fd) override;
void OnClose(DeviceFD fd) override; void OnClose(DeviceFD fd) override;
}; };

View File

@ -8,6 +8,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/core.h" #include "core/core.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/core/container.h"
#include "core/hle/service/nvdrv/core/nvmap.h" #include "core/hle/service/nvdrv/core/nvmap.h"
#include "core/hle/service/nvdrv/core/syncpoint_manager.h" #include "core/hle/service/nvdrv/core/syncpoint_manager.h"
@ -95,6 +96,8 @@ NvResult nvhost_nvdec_common::Submit(IoctlSubmit& params, std::span<u8> data, De
offset += SliceVectors(data, fence_thresholds, params.fence_count, offset); offset += SliceVectors(data, fence_thresholds, params.fence_count, offset);
auto& gpu = system.GPU(); auto& gpu = system.GPU();
auto* session = core.GetSession(sessions[fd]);
if (gpu.UseNvdec()) { if (gpu.UseNvdec()) {
for (std::size_t i = 0; i < syncpt_increments.size(); i++) { for (std::size_t i = 0; i < syncpt_increments.size(); i++) {
const SyncptIncr& syncpt_incr = syncpt_increments[i]; const SyncptIncr& syncpt_incr = syncpt_increments[i];
@ -106,8 +109,8 @@ NvResult nvhost_nvdec_common::Submit(IoctlSubmit& params, std::span<u8> data, De
const auto object = nvmap.GetHandle(cmd_buffer.memory_id); const auto object = nvmap.GetHandle(cmd_buffer.memory_id);
ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;); ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;);
Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count); Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count);
system.ApplicationMemory().ReadBlock(object->address + cmd_buffer.offset, cmdlist.data(), session->process->GetMemory().ReadBlock(object->address + cmd_buffer.offset, cmdlist.data(),
cmdlist.size() * sizeof(u32)); cmdlist.size() * sizeof(u32));
gpu.PushCommandBuffer(core.Host1xDeviceFile().fd_to_id[fd], cmdlist); gpu.PushCommandBuffer(core.Host1xDeviceFile().fd_to_id[fd], cmdlist);
} }
// Some games expect command_buffers to be written back // Some games expect command_buffers to be written back
@ -133,10 +136,12 @@ NvResult nvhost_nvdec_common::GetWaitbase(IoctlGetWaitbase& params) {
return NvResult::Success; return NvResult::Success;
} }
NvResult nvhost_nvdec_common::MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries) { NvResult nvhost_nvdec_common::MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries,
DeviceFD fd) {
const size_t num_entries = std::min(params.num_entries, static_cast<u32>(entries.size())); const size_t num_entries = std::min(params.num_entries, static_cast<u32>(entries.size()));
for (size_t i = 0; i < num_entries; i++) { for (size_t i = 0; i < num_entries; i++) {
entries[i].map_address = nvmap.PinHandle(entries[i].map_handle); DAddr pin_address = nvmap.PinHandle(entries[i].map_handle, true);
entries[i].map_address = static_cast<u32>(pin_address);
} }
return NvResult::Success; return NvResult::Success;

View File

@ -4,7 +4,9 @@
#pragma once #pragma once
#include <deque> #include <deque>
#include <unordered_map>
#include <vector> #include <vector>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/swap.h" #include "common/swap.h"
#include "core/hle/service/nvdrv/core/syncpoint_manager.h" #include "core/hle/service/nvdrv/core/syncpoint_manager.h"
@ -111,7 +113,7 @@ protected:
NvResult Submit(IoctlSubmit& params, std::span<u8> input, DeviceFD fd); NvResult Submit(IoctlSubmit& params, std::span<u8> input, DeviceFD fd);
NvResult GetSyncpoint(IoctlGetSyncpoint& params); NvResult GetSyncpoint(IoctlGetSyncpoint& params);
NvResult GetWaitbase(IoctlGetWaitbase& params); NvResult GetWaitbase(IoctlGetWaitbase& params);
NvResult MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries); NvResult MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries, DeviceFD fd);
NvResult UnmapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries); NvResult UnmapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries);
NvResult SetSubmitTimeout(u32 timeout); NvResult SetSubmitTimeout(u32 timeout);
@ -125,6 +127,7 @@ protected:
NvCore::NvMap& nvmap; NvCore::NvMap& nvmap;
NvCore::ChannelType channel_type; NvCore::ChannelType channel_type;
std::array<u32, MaxSyncPoints> device_syncpoints{}; std::array<u32, MaxSyncPoints> device_syncpoints{};
std::unordered_map<DeviceFD, size_t> sessions;
}; };
}; // namespace Devices }; // namespace Devices
} // namespace Service::Nvidia } // namespace Service::Nvidia

View File

@ -44,7 +44,7 @@ NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in
return NvResult::NotImplemented; return NvResult::NotImplemented;
} }
void nvhost_nvjpg::OnOpen(DeviceFD fd) {} void nvhost_nvjpg::OnOpen(size_t session_id, DeviceFD fd) {}
void nvhost_nvjpg::OnClose(DeviceFD fd) {} void nvhost_nvjpg::OnClose(DeviceFD fd) {}
NvResult nvhost_nvjpg::SetNVMAPfd(IoctlSetNvmapFD& params) { NvResult nvhost_nvjpg::SetNVMAPfd(IoctlSetNvmapFD& params) {

View File

@ -22,7 +22,7 @@ public:
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
std::span<u8> inline_output) override; std::span<u8> inline_output) override;
void OnOpen(DeviceFD fd) override; void OnOpen(size_t session_id, DeviceFD fd) override;
void OnClose(DeviceFD fd) override; void OnClose(DeviceFD fd) override;
private: private:

View File

@ -33,7 +33,7 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
case 0x3: case 0x3:
return WrapFixed(this, &nvhost_vic::GetWaitbase, input, output); return WrapFixed(this, &nvhost_vic::GetWaitbase, input, output);
case 0x9: case 0x9:
return WrapFixedVariable(this, &nvhost_vic::MapBuffer, input, output); return WrapFixedVariable(this, &nvhost_vic::MapBuffer, input, output, fd);
case 0xa: case 0xa:
return WrapFixedVariable(this, &nvhost_vic::UnmapBuffer, input, output); return WrapFixedVariable(this, &nvhost_vic::UnmapBuffer, input, output);
default: default:
@ -68,7 +68,9 @@ NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inpu
return NvResult::NotImplemented; return NvResult::NotImplemented;
} }
void nvhost_vic::OnOpen(DeviceFD fd) {} void nvhost_vic::OnOpen(size_t session_id, DeviceFD fd) {
sessions[fd] = session_id;
}
void nvhost_vic::OnClose(DeviceFD fd) { void nvhost_vic::OnClose(DeviceFD fd) {
auto& host1x_file = core.Host1xDeviceFile(); auto& host1x_file = core.Host1xDeviceFile();
@ -76,6 +78,10 @@ void nvhost_vic::OnClose(DeviceFD fd) {
if (iter != host1x_file.fd_to_id.end()) { if (iter != host1x_file.fd_to_id.end()) {
system.GPU().ClearCdmaInstance(iter->second); system.GPU().ClearCdmaInstance(iter->second);
} }
auto it = sessions.find(fd);
if (it != sessions.end()) {
sessions.erase(it);
}
} }
} // namespace Service::Nvidia::Devices } // namespace Service::Nvidia::Devices

View File

@ -19,7 +19,7 @@ public:
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
std::span<u8> inline_output) override; std::span<u8> inline_output) override;
void OnOpen(DeviceFD fd) override; void OnOpen(size_t session_id, DeviceFD fd) override;
void OnClose(DeviceFD fd) override; void OnClose(DeviceFD fd) override;
}; };
} // namespace Service::Nvidia::Devices } // namespace Service::Nvidia::Devices

View File

@ -36,9 +36,9 @@ NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
case 0x3: case 0x3:
return WrapFixed(this, &nvmap::IocFromId, input, output); return WrapFixed(this, &nvmap::IocFromId, input, output);
case 0x4: case 0x4:
return WrapFixed(this, &nvmap::IocAlloc, input, output); return WrapFixed(this, &nvmap::IocAlloc, input, output, fd);
case 0x5: case 0x5:
return WrapFixed(this, &nvmap::IocFree, input, output); return WrapFixed(this, &nvmap::IocFree, input, output, fd);
case 0x9: case 0x9:
return WrapFixed(this, &nvmap::IocParam, input, output); return WrapFixed(this, &nvmap::IocParam, input, output);
case 0xe: case 0xe:
@ -67,8 +67,15 @@ NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, st
return NvResult::NotImplemented; return NvResult::NotImplemented;
} }
void nvmap::OnOpen(DeviceFD fd) {} void nvmap::OnOpen(size_t session_id, DeviceFD fd) {
void nvmap::OnClose(DeviceFD fd) {} sessions[fd] = session_id;
}
void nvmap::OnClose(DeviceFD fd) {
auto it = sessions.find(fd);
if (it != sessions.end()) {
sessions.erase(it);
}
}
NvResult nvmap::IocCreate(IocCreateParams& params) { NvResult nvmap::IocCreate(IocCreateParams& params) {
LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size); LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size);
@ -87,7 +94,7 @@ NvResult nvmap::IocCreate(IocCreateParams& params) {
return NvResult::Success; return NvResult::Success;
} }
NvResult nvmap::IocAlloc(IocAllocParams& params) { NvResult nvmap::IocAlloc(IocAllocParams& params, DeviceFD fd) {
LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.address); LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.address);
if (!params.handle) { if (!params.handle) {
@ -116,15 +123,15 @@ NvResult nvmap::IocAlloc(IocAllocParams& params) {
return NvResult::InsufficientMemory; return NvResult::InsufficientMemory;
} }
const auto result = const auto result = handle_description->Alloc(params.flags, params.align, params.kind,
handle_description->Alloc(params.flags, params.align, params.kind, params.address); params.address, sessions[fd]);
if (result != NvResult::Success) { if (result != NvResult::Success) {
LOG_CRITICAL(Service_NVDRV, "Object failed to allocate, handle={:08X}", params.handle); LOG_CRITICAL(Service_NVDRV, "Object failed to allocate, handle={:08X}", params.handle);
return result; return result;
} }
bool is_out_io{}; bool is_out_io{};
ASSERT(system.ApplicationProcess() auto process = container.GetSession(sessions[fd])->process;
->GetPageTable() ASSERT(process->GetPageTable()
.LockForMapDeviceAddressSpace(&is_out_io, handle_description->address, .LockForMapDeviceAddressSpace(&is_out_io, handle_description->address,
handle_description->size, handle_description->size,
Kernel::KMemoryPermission::None, true, false) Kernel::KMemoryPermission::None, true, false)
@ -224,7 +231,7 @@ NvResult nvmap::IocParam(IocParamParams& params) {
return NvResult::Success; return NvResult::Success;
} }
NvResult nvmap::IocFree(IocFreeParams& params) { NvResult nvmap::IocFree(IocFreeParams& params, DeviceFD fd) {
LOG_DEBUG(Service_NVDRV, "called"); LOG_DEBUG(Service_NVDRV, "called");
if (!params.handle) { if (!params.handle) {
@ -233,9 +240,9 @@ NvResult nvmap::IocFree(IocFreeParams& params) {
} }
if (auto freeInfo{file.FreeHandle(params.handle, false)}) { if (auto freeInfo{file.FreeHandle(params.handle, false)}) {
auto process = container.GetSession(sessions[fd])->process;
if (freeInfo->can_unlock) { if (freeInfo->can_unlock) {
ASSERT(system.ApplicationProcess() ASSERT(process->GetPageTable()
->GetPageTable()
.UnlockForDeviceAddressSpace(freeInfo->address, freeInfo->size) .UnlockForDeviceAddressSpace(freeInfo->address, freeInfo->size)
.IsSuccess()); .IsSuccess());
} }

View File

@ -33,7 +33,7 @@ public:
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
std::span<u8> inline_output) override; std::span<u8> inline_output) override;
void OnOpen(DeviceFD fd) override; void OnOpen(size_t session_id, DeviceFD fd) override;
void OnClose(DeviceFD fd) override; void OnClose(DeviceFD fd) override;
enum class HandleParameterType : u32_le { enum class HandleParameterType : u32_le {
@ -100,11 +100,11 @@ public:
static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
NvResult IocCreate(IocCreateParams& params); NvResult IocCreate(IocCreateParams& params);
NvResult IocAlloc(IocAllocParams& params); NvResult IocAlloc(IocAllocParams& params, DeviceFD fd);
NvResult IocGetId(IocGetIdParams& params); NvResult IocGetId(IocGetIdParams& params);
NvResult IocFromId(IocFromIdParams& params); NvResult IocFromId(IocFromIdParams& params);
NvResult IocParam(IocParamParams& params); NvResult IocParam(IocParamParams& params);
NvResult IocFree(IocFreeParams& params); NvResult IocFree(IocFreeParams& params, DeviceFD fd);
private: private:
/// Id to use for the next handle that is created. /// Id to use for the next handle that is created.
@ -115,6 +115,7 @@ private:
NvCore::Container& container; NvCore::Container& container;
NvCore::NvMap& file; NvCore::NvMap& file;
std::unordered_map<DeviceFD, size_t> sessions;
}; };
} // namespace Service::Nvidia::Devices } // namespace Service::Nvidia::Devices

View File

@ -51,7 +51,7 @@ enum class NvResult : u32 {
DispNoDisplaysAttached = 0x20003, DispNoDisplaysAttached = 0x20003,
DispModeNotSupported = 0x20004, DispModeNotSupported = 0x20004,
DispNotFound = 0x20005, DispNotFound = 0x20005,
DispAttachDissallowed = 0x20006, DispAttachDisallowed = 0x20006,
DispTypeNotSupported = 0x20007, DispTypeNotSupported = 0x20007,
DispAuthenticationFailed = 0x20008, DispAuthenticationFailed = 0x20008,
DispNotAttached = 0x20009, DispNotAttached = 0x20009,

Some files were not shown because too many files have changed in this diff Show More