Compare commits

..

180 Commits

Author SHA1 Message Date
Tobias
f9d7a6bec6 citra_qt/main.ui: remove unused actions "Load Symbol Map..." and...
..."Select Game Directory..."

Co-authored-by: vvanelslande <vvanelslandedev@gmail.com>
2019-11-19 16:39:58 +01:00
bunnei
376f1a4432 Merge pull request #2869 from ReinUsesLisp/suld
shader/image: Implement SULD and fix SUATOM
2019-09-23 21:47:03 -04:00
James Rowe
2f5545f8de Merge pull request #2901 from DarkLordZach/mainline-title-bar
ci: Properly parse Azure CI details in title bar
2019-09-22 18:14:08 -06:00
Zach Hilman
921dae5e83 ci: Correct GitHub Release name 2019-09-22 19:06:48 -04:00
Zach Hilman
15805f4e01 ci: Determine build date via bash 2019-09-22 18:39:29 -04:00
Zach Hilman
851c5d67ae ci: Update to use date as build number 2019-09-22 17:23:47 -04:00
Zach Hilman
14248685af cmake: Add SCM detection for Azure 2019-09-22 17:23:10 -04:00
Zach Hilman
cc3db2aa43 ci: Split mainline pipeline and add support for GitHub releases (#2900)
* ci: Add mock build alternative for fast testing

* ci: Always cache build

* ci: Extract steps to download build stage artifacts

* ci: Add template to release to GitHub

* ci: Add template to release to Azure Universal Artifacts

* ci: Split mainline to two pipelines
2019-09-22 20:01:29 +00:00
David
aaec1562f8 Merge pull request #2683 from DarkLordZach/lock-exit
am: Implement exit locking and self exit commands
2019-09-23 00:37:12 +10:00
David
a9abf4e7f8 Merge pull request #2889 from FearlessTobi/adwsawdawd
Add missing include
2019-09-23 00:30:12 +10:00
Zach Hilman
b835d76311 Merge pull request #2876 from ogniK5377/AcquireNpadStyleSetUpdateEventHandle-fix
AcquireNpadStyleSetUpdateEventHandle should have a separate event for each controller type
2019-09-22 10:06:48 -04:00
Zach Hilman
b7725812ac Merge pull request #2877 from ogniK5377/framecount-rev7
Added frame_count for REV5 audio renderer
2019-09-22 10:05:44 -04:00
Zach Hilman
9f3bf6d157 main: Use const on all variable initializations 2019-09-22 10:02:07 -04:00
David
e31c15606b Merge pull request #2895 from FearlessTobi/debug-logs
service/acc: Lower log severity from INFO to DEBUG
2019-09-22 23:50:49 +10:00
FearlessTobi
e22e0eb8d7 Add missing include 2019-09-22 15:47:21 +02:00
Fernando Sahmkow
a755f24369 Merge pull request #2873 from ogniK5377/new-ioctls
Initial implementation of Ioctl2 & Ioctl3
2019-09-22 09:45:29 -04:00
David Marcec
59fd910355 removed comment 2019-09-22 23:42:52 +10:00
David Marcec
654427d4d0 Rebased 2019-09-22 23:42:41 +10:00
Fernando Sahmkow
4ace69de9c Merge pull request #2884 from ogniK5377/deglobal-sys-services
Remove usage of System::CurrentInterface() from most services
2019-09-22 09:38:13 -04:00
FearlessTobi
82979296d2 service/acc: Lower log severity from INFO to DEBUG
According to ogniK, this should have always been Debug and not Info.
2019-09-22 15:15:07 +02:00
David
9d69206cd0 Merge pull request #2870 from FernandoS27/multi-draw
Implement a MME Draw commands Inliner and correct host instance drawing
2019-09-22 23:13:02 +10:00
Fernando Sahmkow
822ca65d69 Merge pull request #2891 from FearlessTobi/rod-tex
video_core: Implement RGBX16F and lower Surface Copy log severity
2019-09-22 09:11:28 -04:00
David
3bfba23362 Merge pull request #2867 from ReinUsesLisp/configure-framebuffers-clean
gl_rasterizer: Remove unused code paths from ConfigureFramebuffers
2019-09-22 23:10:07 +10:00
Fernando Sahmkow
68f5aff64f Maxwell3D: Corrections and refactors to MME instance refactor 2019-09-22 07:23:13 -04:00
David Marcec
9513abbb0a removed unneeded semicolon 2019-09-22 18:50:34 +10:00
David
cf1e4770f9 Merge pull request #2893 from ogniK5377/revert-dlz
Revert "Merge pull request #2709 from DarkLordZach/oss-ext-fonts-1"
2019-09-22 18:09:55 +10:00
David Marcec
d961d5479e Revert "Merge pull request #2709 from DarkLordZach/oss-ext-fonts-1"
This reverts commit fa1c60c33e, reversing
changes made to e34899067b.
2019-09-22 17:47:25 +10:00
David Marcec
e73ac40eaa Removed reference to core timing to nvflinger and used system instead 2019-09-22 16:55:15 +10:00
David Marcec
aed884d121 marked controller constructors as explicit 2019-09-22 16:41:38 +10:00
David Marcec
bd1c4ec9a0 Rebase 2019-09-22 16:41:34 +10:00
David Marcec
fcdbf0bc53 Rebase 2019-09-22 16:40:58 +10:00
David Marcec
4d220964df Deglobalize System: Vi 2019-09-22 16:38:03 +10:00
David Marcec
2c6e4ce0ad Deglobalize System: Time 2019-09-22 16:38:02 +10:00
David Marcec
36a97dd8a2 Rebase 2019-09-22 16:37:59 +10:00
David Marcec
d6e830d877 Deglobalize System: NvFlinger 2019-09-22 16:35:51 +10:00
David Marcec
f21ab654db Rebase 2019-09-22 16:35:43 +10:00
David Marcec
8d3ff2b127 Deglobalize System: Nim 2019-09-22 16:30:34 +10:00
David Marcec
ad53dc0106 Deglobalize System: Nifm 2019-09-22 16:30:33 +10:00
David Marcec
8df2a98f75 Deglobalize System: NFP 2019-09-22 16:30:32 +10:00
David Marcec
482a03f8a5 Deglobalize System: LDR 2019-09-22 16:30:31 +10:00
David Marcec
07823b61a1 Deglobalize System: IRS 2019-09-22 16:30:30 +10:00
David Marcec
28181919a6 Deglobalize System: Hid 2019-09-22 16:30:29 +10:00
David Marcec
a9e9570d84 Deglobalize System: Friend 2019-09-22 16:30:27 +10:00
David Marcec
a40e5b2def Deglobalize System: Fatal 2019-09-22 16:30:25 +10:00
David Marcec
c33faabb27 Deglobalize System: Btm 2019-09-22 16:30:24 +10:00
David Marcec
f2b61ff073 Deglobalize System: Btdrv 2019-09-22 16:30:20 +10:00
David Marcec
7da8e3f812 Deglobalize System: Aoc 2019-09-22 16:30:17 +10:00
David Marcec
2dbfac652e Deglobalize System: Am 2019-09-22 16:30:14 +10:00
David
9187350b32 Merge pull request #2535 from DarkLordZach/cheat-v2
cheat_engine: Use Atmosphere's Cheat VM and fix cheat crash
2019-09-22 16:24:42 +10:00
David
fa1c60c33e Merge pull request #2709 from DarkLordZach/oss-ext-fonts-1
system_archive: Move shared font data to system_archive and fix extended font data
2019-09-22 16:09:22 +10:00
Zach Hilman
2a4730cbee pl_u: Use kernel physical memory 2019-09-21 23:00:22 -04:00
Zach Hilman
60c2e9e675 qt: Prompt user for confirmation if exit lock is active 2019-09-21 22:46:57 -04:00
Zach Hilman
2bddc03468 dmnt_cheat_vm: Default initialize structure values 2019-09-21 22:43:49 -04:00
David
e34899067b Merge pull request #2886 from MysticExile/dynarmic
externals: Update dynarmic to master
2019-09-22 12:41:50 +10:00
David Marcec
6325c3044c server side clang format fix2 2019-09-22 12:26:03 +10:00
Zach Hilman
e58e3719d8 am: Implement ISelfController ExitLock commands 2019-09-21 22:25:18 -04:00
Zach Hilman
a7fda84902 am: Implement ISelfController Exit
Closes the current application.
2019-09-21 22:25:18 -04:00
Zach Hilman
4c1c8801a5 am: Add RequestExit event to AppletMessageQueue
Tested against libnx, signals to games to begin cleanup.
2019-09-21 22:24:10 -04:00
Zach Hilman
bbc1437188 core: Track system exit lock status
Used to determine if yuzu should confirm before pausing or stopping a game.
2019-09-21 22:23:44 -04:00
David Marcec
d3783fcc52 Use clang-format provided by build server 2019-09-22 12:21:07 +10:00
Zach Hilman
885ea2de2a pl_u: Remove excess static qualifier 2019-09-21 22:17:30 -04:00
Zach Hilman
94afffe9e5 pl_u: Use OSS system archives if real archives don't exist 2019-09-21 21:50:41 -04:00
David
a1b8e5d09a Merge pull request #2612 from DarkLordZach/prepo-new
prepo: Implement New, System, and Non-User variants of SaveReport
2019-09-22 11:49:36 +10:00
Zach Hilman
682174b112 dmnt_cheat_vm: Make Cheat VM compliant to code style 2019-09-21 21:45:05 -04:00
Zach Hilman
3e729c13cc core: Initialize cheats after load to avoid VMManager crash
This used to occur due to the VMManager being nullptr at the time cheats were registered (during load, but before it was done). This is bypassed by not accessing the VMManager for offset data until load is complete,
2019-09-21 21:45:05 -04:00
Zach Hilman
37850eeee5 core: Update RegisterCheatList for new VM 2019-09-21 21:45:05 -04:00
Zach Hilman
a0055192fe patch_manager: Update cheat parsing for new VM 2019-09-21 21:45:05 -04:00
Zach Hilman
c6becfc9f5 nso: Pass build ID directly
As opposed to converting to string and then back to hex array
2019-09-21 21:44:22 -04:00
Zach Hilman
7d41c1f523 cheat_engine: Move to memory and strip VM
This is to go with the Atmosphere VM port, now it just contains the callbacks needed for the interface between DmntCheatVm and yuzu, along with the cheat parsers.
2019-09-21 21:44:22 -04:00
Zach Hilman
12aa127df3 memory: Port Atmosphere's DmntCheatVm
This was done because the current VM contained many inaccuracies and this also allows cheats to have identical behavior between hardware and yuzu.
2019-09-21 21:44:22 -04:00
Zach Hilman
470466b31b log: Add logging class for Cheat Engine
This is better than just using something like Common.Filesystem or Common.Memory
2019-09-21 21:44:22 -04:00
David
c9ccdfbeac Merge pull request #2430 from DarkLordZach/fs-controller
core: Implement FileSystemController to deglobalize FS services
2019-09-22 11:42:34 +10:00
Zach Hilman
7979ccd956 Merge pull request #2883 from ogniK5377/log-game
Log the current title id and game name which is booting
2019-09-21 21:34:19 -04:00
FearlessTobi
01fc969a5f Fix clang-format 2019-09-22 02:21:56 +02:00
FearlessTobi
366e900376 fermi_2d: Lower surface copy log severity to DEBUG 2019-09-22 02:18:57 +02:00
FearlessTobi
55d272efe6 video_core: Implement RGBX16F PixelFormat 2019-09-22 02:16:44 +02:00
Zach Hilman
8b857fc7c2 system_archive: Synthesize shared fonts system archives 2019-09-21 19:21:58 -04:00
Zach Hilman
ae9604faba pl_u: Expose method to encrypt TTF to BFTTF 2019-09-21 19:21:58 -04:00
Zach Hilman
361a8fa318 externals: Move OSS font data to file_sys in core 2019-09-21 19:21:22 -04:00
Zach Hilman
8dd2e91427 prepo: Remove system global accessors 2019-09-21 19:17:45 -04:00
Zach Hilman
daf9cd9358 prepo: Implement SaveReport New and System variants 2019-09-21 19:17:08 -04:00
Zach Hilman
787b191abf reporter: Differentiate between Old, New, and System play reports 2019-09-21 19:17:08 -04:00
Zach Hilman
038bcec111 configure_debug: Move reporting option to logging 2019-09-21 18:43:20 -04:00
MysticExile
2b514275ad Update README.md (#2871)
* Update README.md

* Adress feedback

* Add link to our compatability page

* Address feedback

Co-Authored-By: Morph <39850852+Morph1984@users.noreply.github.com>

* Fix spelling

Co-Authored-By: Morph <39850852+Morph1984@users.noreply.github.com>

* Small fix

* Removed the mention of a specific game

* fix
2019-09-21 17:37:21 -04:00
Rodrigo Locatti
9286976948 Merge pull request #2878 from FernandoS27/icmp
shader_ir: Implement ICMP
2019-09-21 18:06:07 -03:00
Zach Hilman
ccd70819c2 config: Remove Dump options from configure_debug 2019-09-21 16:50:39 -04:00
Zach Hilman
a49169e819 filesystem: Add const qualification to various accessors 2019-09-21 16:50:39 -04:00
Zach Hilman
d4d38dd44d yuzu: Add UI to manage filesystem paths and sizes 2019-09-21 16:50:39 -04:00
Zach Hilman
c182688ad6 core: Store FileSystemController in core 2019-09-21 16:50:39 -04:00
Zach Hilman
2590b5a9ea settings: Add options for managing gamecard emulation 2019-09-21 16:43:10 -04:00
Zach Hilman
918119ae1b settings: Add options for setting storage sizes 2019-09-21 16:43:10 -04:00
Zach Hilman
c6ff4a6f4d yuzu: Port old usages of Filesystem namespace to FilesystemController 2019-09-21 16:43:10 -04:00
Zach Hilman
faf628ad8d settings: Update LogSettings to show NAND/SDMC paths from FileUtil 2019-09-21 16:43:10 -04:00
Zach Hilman
ccaafaccfc card_image: Add accessors for gamecard certificate
Used by fsp-srv/IDeviceOperator
2019-09-21 16:43:10 -04:00
Zach Hilman
77f9ecd32b card_image: Add functions to query gamecard update partition
Includes version and meta title ID, used by fsp-srv/IDeviceOperator
2019-09-21 16:43:10 -04:00
Zach Hilman
e018a48460 content_archive: Add accessors for Rights ID and SDK Version 2019-09-21 16:43:10 -04:00
Zach Hilman
b4164d295b partition_data_manager: Add accessor for decrypted PRODINFO partition 2019-09-21 16:43:10 -04:00
Zach Hilman
4b91057688 services: Pass FileSystemController as reference to services that need it 2019-09-21 16:43:10 -04:00
Zach Hilman
1b04b72653 am: Unstub IApplicationFunctions EnsureSaveData (20)
Creates a default save data for the application given a user ID.
2019-09-21 16:43:10 -04:00
Zach Hilman
43af31836e filesystem: Pass Size Getter functions to IFileSystem for sizes 2019-09-21 16:43:10 -04:00
Zach Hilman
721a92775d sdmc_factory: Add SD Card size getters 2019-09-21 16:43:10 -04:00
Zach Hilman
e47b57a90f bis_factory: Add getters for NAND partition sizes 2019-09-21 16:43:10 -04:00
Zach Hilman
8abbc619a1 filesystem: Add FileSystemController to deglobalize FS services 2019-09-21 16:43:10 -04:00
Zach Hilman
0a8e540681 submisson_package: Fix edge case with improperly sized filenames
Prevents a crash if the filename is less than 9 characters long.
2019-09-21 16:43:10 -04:00
Zach Hilman
08c0783d34 sdmc_factory: Add accessor for SDMC Album directory 2019-09-21 16:43:10 -04:00
Zach Hilman
0084cceb20 sdmc_factory: Add accessor for SDMC PlaceholderCache 2019-09-21 16:43:10 -04:00
Zach Hilman
02b36b0eb5 sdmc_factory: Add accessor for content directory 2019-09-21 16:43:10 -04:00
Zach Hilman
49c44e3fae savedata_factory: Implement savedata creation and don't create dir on open
Matches hardware behavior and eliminates some nasty behavior we were doing that wasn't hw-accurate at all.
2019-09-21 16:43:10 -04:00
Zach Hilman
62d772eaed patch_manager: Add short-circuit edge-case to GetPatchVersionNames
If title ID is 0, there are no add ons, prevents wasting time looking for them.
2019-09-21 16:43:10 -04:00
Zach Hilman
06db4d94fd patch_manager: Add error checking to load dir to prevent crashes
Prevents a crash if the load dir would be nullptr, instead logs an error and returns appropriately.
2019-09-21 16:43:10 -04:00
Zach Hilman
9d9fc8a675 registered_cache: Process *.cnmt.nca files
Needed to use the RegisteredCache/PlaceholderCache on gamecards.
2019-09-21 16:43:10 -04:00
Zach Hilman
8500ca797f registered_cache: Implement PlaceholderCache to manage placeholder and installing content 2019-09-21 16:43:10 -04:00
Zach Hilman
256a50ad15 bis_factory: Fix mod loader edge-case with homebrew title IDs
Fixes a bug where homebrew that has a title ID with the update bit set can cause issues with the PatchManager
2019-09-21 16:43:10 -04:00
Zach Hilman
b71bda45ae bis_factory: Add accessors for BIS placeholder caches 2019-09-21 16:43:10 -04:00
Zach Hilman
9bee885282 bis_factory: Add accessor for NAND Image Directory 2019-09-21 16:43:10 -04:00
Zach Hilman
4dae5a52a8 bis_factory: Add accessors for BIS content directories 2019-09-21 16:43:10 -04:00
Zach Hilman
3a1899d143 bis_factory: Add accessors for BIS partitions 2019-09-21 16:43:10 -04:00
ReinUsesLisp
44000971e2 gl_shader_decompiler: Use uint for images and fix SUATOM
In the process remove implementation of SUATOM.MIN and SUATOM.MAX as
these require a distinction between U32 and S32. These have to be
implemented with imageCompSwap loop.
2019-09-21 17:33:52 -03:00
ReinUsesLisp
675f23aedc shader/image: Implement SULD and remove irrelevant code
* Implement SULD as float.
* Remove conditional declaration of GL_ARB_shader_viewport_layer_array.
2019-09-21 17:32:48 -03:00
ReinUsesLisp
4de0f1e1c8 shader_bytecode: Add SULD encoding 2019-09-21 17:31:46 -03:00
Fernando Sahmkow
527b841c15 Shader_IR: ICMP corrections and fixes 2019-09-21 14:28:03 -04:00
Ethan
8b76444916 externals: Update dynarmic to master 2019-09-21 16:54:06 +02:00
David
97b8c9d2c3 Merge pull request #2885 from Hexagon12/port-4944
Port citra-emu/citra#4944: "Added Host CPU and OS to log"
2019-09-21 23:46:58 +10:00
pbarilla
8fd266a7c4 Added Host CPU and OS to log 2019-09-21 16:11:46 +03:00
David
183c445c30 Merge pull request #2806 from FearlessTobi/port-4882
Port citra-emu/citra#4882: "Add frametime logging for tracking performance over time"
2019-09-21 20:09:55 +10:00
David
c7c8ffbc13 Merge pull request #2872 from FernandoS27/mem-gpu-opt
Core/Memory: Only FlushAndInvalidate GPU if the page is marked as RasterizerCachedMemory
2019-09-21 20:07:25 +10:00
David
25383b9ff2 Merge pull request #2576 from DarkLordZach/nsp-fix-1
nsp: Fix various errors with loading and processing of extracted NSPs
2019-09-21 20:05:24 +10:00
David
c41365a56f Merge pull request #2866 from Morph1984/checkbox_fix
configure_input: Uncheck "Joycons Docked" when "Use Docked Mode" is checked
2019-09-21 19:58:22 +10:00
David
9ad42fb0cf Merge pull request #2868 from ReinUsesLisp/fix-mipmaps
maxwell_to_gl: Fix mipmap filtering
2019-09-21 19:57:09 +10:00
David Marcec
b4db662053 Swapped TID and Game name to make it easier to parse 2019-09-21 17:43:18 +10:00
David Marcec
934ce530f6 Log the current title id and game name which is booting
Spit out a LOG_INFO of the current game name and it's title id in the log. This helps to read log files and figure out which games have which issues
2019-09-21 17:34:46 +10:00
David Marcec
e9d19add7d Used revision 5 instead of 7, marked constexpr as static 2019-09-21 16:24:56 +10:00
David
b9fd1e2bed Merge pull request #2879 from ogniK5377/trace-submitgpfifo
Mark KickOffPb & SubmitGPFIFO as trace
2019-09-21 16:22:39 +10:00
David
41836f3a17 Merge pull request #2880 from ogniK5377/drawarrays-trace
Mark DrawArrays as LOG_TRACE
2019-09-21 16:11:54 +10:00
David Marcec
01a4afee42 Mark DrawArrays as LOG_TRACE
There's no reason to clog logs with DrawArray.
2019-09-21 15:43:58 +10:00
David Marcec
c2f966dbc1 Mark KickOffPb & SubmitGPFIFO as trace
These functions are not stubbed and are called fairly often. Due to the nature of how often they're called, we should keep them marked as LOG_TRACE instead of LOG_DEBUG or LOG_WARNING
2019-09-21 15:41:11 +10:00
bunnei
bbe82d62b0 Merge pull request #2846 from ReinUsesLisp/fixup-viewport-index
gl_shader_decompiler: Avoid writing output attribute when unimplemented
2019-09-20 17:11:20 -04:00
bunnei
88d857499b Merge pull request #2855 from ReinUsesLisp/shfl
shader_ir/warp: Implement SHFL for Nvidia devices
2019-09-20 17:10:42 -04:00
Fernando Sahmkow
433e764bb0 Rasterizer: Correct introduced bug where a conditional render wouldn't stop a draw call from executing 2019-09-20 15:44:28 -04:00
Fernando Sahmkow
4b81d19a1a Shader_IR: Implement ICMP. 2019-09-19 20:56:29 -04:00
David Marcec
b54cdeb284 Added frame_count for REV7 audio renderer
Added framecount
2019-09-20 10:42:09 +10:00
David Marcec
0740758b25 disable clang-format temp 2019-09-20 10:25:12 +10:00
Fernando Sahmkow
7761e44d18 Rasterizer: Refactor and simplify DrawBatch Interface. 2019-09-19 11:41:33 -04:00
Fernando Sahmkow
d2ea592ddb Rasterizer: Address Feedback and conscerns. 2019-09-19 11:41:32 -04:00
Fernando Sahmkow
c17655ce74 Rasterizer: Refactor draw calls, remove deadcode and clean up. 2019-09-19 11:41:31 -04:00
Fernando Sahmkow
7606da5611 VideoCore: Corrections to the MME Inliner and removal of hacky instance management. 2019-09-19 11:41:29 -04:00
Fernando Sahmkow
ba02d564f8 Video Core: initial Implementation of InstanceDraw Packaging 2019-09-19 11:41:27 -04:00
David Marcec
f9259c0383 Initial implementation of Ioctl2 & Ioctl3
Purpose of Ioctl2 and Ioctl3 is to prevent the passing of raw pointers through ioctls
2019-09-19 15:37:25 +10:00
Fernando Sahmkow
50259d7bdc Core/Memory: Only FlushAndInvalidate GPU if the page is marked as RasterizerCachedMemory
This commit avoids Invalidating and Flushing the GPU if the page is not
marked as a RasterizerCache Page.
2019-09-18 22:47:22 -04:00
bunnei
b31880dc5e Merge pull request #2784 from ReinUsesLisp/smem
shader_ir: Implement shared memory
2019-09-18 16:26:05 -04:00
ReinUsesLisp
0526bf1895 shader_ir/warp: Implement SHFL 2019-09-17 17:44:07 -03:00
ReinUsesLisp
2dd6411753 maxwell_to_gl: Fix mipmap filtering
OpenGL texture filters follow GL_<texture_filter>_MIPMAP_<mipmap_filter>
but we were using them in the opposite way.
2019-09-17 03:32:24 -03:00
ReinUsesLisp
af809b491e gl_rasterizer: Remove unused code paths from ConfigureFramebuffers 2019-09-17 02:50:42 -03:00
Morph
8d778c90e2 When docked mode is checked, uncheck "joycons docked" 2019-09-16 23:26:32 -04:00
Fernando Sahmkow
393cc3ef2f Merge pull request #2851 from ReinUsesLisp/srgb
renderer_opengl: Fix sRGB blits
2019-09-15 10:38:10 -04:00
Fernando Sahmkow
b8b1747704 Merge pull request #2824 from ReinUsesLisp/mme
Revert "Revert #2466" and stub FirmwareCall 4
2019-09-15 06:17:04 -04:00
Rodrigo Locatti
193bfefce4 maxwell_3d: Update firmware 4 call stub commentary 2019-09-14 22:51:18 -03:00
Fernando Sahmkow
daae327e86 Merge pull request #2857 from ReinUsesLisp/surface-srgb
video_core/surface: Add function to detect sRGB surfaces
2019-09-14 03:53:21 -04:00
Fernando Sahmkow
18fac59050 Merge pull request #2858 from ReinUsesLisp/vk-device
vk_device: Add miscellaneous features and minor style changes
2019-09-14 03:52:06 -04:00
bunnei
ddfdeea3af Merge pull request #2667 from DarkLordZach/profile-editor
acc: Implement IProfileEditor interface and 'Store'/'StoreWithImage' commands
2019-09-14 00:46:18 -04:00
bunnei
3cc27e4dda Merge pull request #2757 from ReinUsesLisp/suatom
shader/image: Implement SUATOM and fix SUST
2019-09-14 00:45:51 -04:00
ReinUsesLisp
01d96e1136 vk_device: Add miscellaneous features and minor style changes
* Increase minimum Vulkan requirements
* Require VK_EXT_vertex_attribute_divisor
* Require depthClamp, samplerAnisotropy and largePoints features
* Search and expose VK_KHR_uniform_buffer_standard_layout
* Search and expose VK_EXT_index_type_uint8
* Search and expose native float16 arithmetics
* Track current driver with VK_KHR_driver_properties
* Query and expose SSBO alignment
* Query more image formats
* Improve logging overall
* Minor style changes
* Minor rephrasing of commentaries
2019-09-13 02:10:07 -03:00
ReinUsesLisp
78d078e183 externals: Update Vulkan headers 2019-09-13 01:54:00 -03:00
ReinUsesLisp
6b997c8f7f renderer_opengl: Fix rebase mistake 2019-09-11 00:09:37 -03:00
ReinUsesLisp
36abf67e79 shader/image: Implement SUATOM and fix SUST 2019-09-10 20:22:31 -03:00
Fernando Sahmkow
e60d281a01 gl_rasterizer: Correct sRGB Fix regression 2019-09-10 19:31:42 -03:00
ReinUsesLisp
78574746bd renderer_opengl: Fix sRGB blits
Removes the sRGB hack of tracking if a frame used an sRGB rendertarget
to apply at least once to blit the final texture as sRGB. Instead of
doing this apply sRGB if the presented image has sRGB.

Also enable sRGB by default on Maxwell3D registers as some games seem to
assume this.
2019-09-10 19:31:42 -03:00
FearlessTobi
d36a7a43c5 Address review comments 2019-09-10 12:57:45 +02:00
fearlessTobi
684b616f0d Add frametime logging for tracking performance over time
Co-Authored-By: jroweboy <jroweboy@gmail.com>
2019-09-10 12:44:19 +02:00
ReinUsesLisp
17a9b0178d gl_shader_decompiler: Avoid writing output attribute when unimplemented 2019-09-06 15:02:12 -03:00
ReinUsesLisp
0f7b813d65 gl_shader_decompiler: Implement shared memory 2019-09-05 01:40:24 -03:00
ReinUsesLisp
4de04eba39 shader_ir: Implement LD_S
Loads from shared memory.
2019-09-05 01:38:37 -03:00
ReinUsesLisp
f17415d431 shader_ir: Implement ST_S
This instruction writes to a memory buffer shared with threads within
the same work group. It is known as "shared" memory in GLSL.
2019-09-05 01:38:37 -03:00
ReinUsesLisp
5f309b88db Revert "Revert #2466" and stub FirmwareCall 4 2019-09-04 01:55:45 -03:00
Zach Hilman
471b2a4211 acc_su: Implement GetProfileEditor (205)
Takes a UUID of a user and provides and interface that allows RW access to user data/settings.
2019-07-03 07:57:41 -05:00
Zach Hilman
812fb30821 acc: Implement IProfileEditor-specific commands 'Store' and 'StoreWithImage'
Verified with IDA
2019-07-03 07:57:03 -05:00
Zach Hilman
02560d6482 profile_manager: Add setter for ProfileBase and ProfileData
Needed by IProfileEditor 'Store' and 'StoreWithImage'
2019-07-03 07:56:28 -05:00
Zach Hilman
39f6d57c34 acc: Add IProfileCommon for IProfile and IProfileEditor
Since 2/3 of the commands are shared, this is likely how its done on HW.
2019-07-03 07:55:54 -05:00
Zach Hilman
b957a4862f nsp: Correct status codes for extracted NSPs
Avoids all extracted NSPs being marked as error file type because they don't have program NCAs.
2019-06-10 00:21:41 -04:00
Zach Hilman
1c75945dc4 nsp: Use title ID from NPDM metadata for extracted type NSPs
Avoids 0 being used as title ID for all extracted NSPs.
2019-06-10 00:19:23 -04:00
214 changed files with 6159 additions and 1958 deletions

View File

@@ -0,0 +1,5 @@
steps:
- script: mkdir artifacts || echo 'X' > artifacts/T1.txt
- publish: artifacts
artifact: 'yuzu-$(BuildName)-$(BuildSuffix)'
displayName: 'Upload Artifacts'

View File

@@ -3,17 +3,18 @@ parameters:
cache: 'false'
steps:
- script: export DATE=`date '+%Y.%m.%d'` && export CI=true && AZURE_REPO_NAME=yuzu-emu/yuzu-$(BuildName) && AZURE_REPO_TAG=$(BuildName)-$DATE
displayName: 'Determine Build Name'
- task: DockerInstaller@0
displayName: 'Prepare Environment'
inputs:
dockerVersion: '17.09.0-ce'
- ${{ if eq(parameters.cache, 'true') }}:
- task: CacheBeta@0
displayName: 'Cache Build System'
inputs:
key: yuzu-v1-$(BuildName)-$(BuildSuffix)-$(CacheSuffix)
path: $(System.DefaultWorkingDirectory)/ccache
cacheHitVar: CACHE_RESTORED
- task: CacheBeta@0
displayName: 'Cache Build System'
inputs:
key: yuzu-v1-$(BuildName)-$(BuildSuffix)-$(CacheSuffix)
path: $(System.DefaultWorkingDirectory)/ccache
cacheHitVar: CACHE_RESTORED
- script: chmod a+x ./.ci/scripts/$(ScriptFolder)/exec.sh && ./.ci/scripts/$(ScriptFolder)/exec.sh
displayName: 'Build'
- script: chmod a+x ./.ci/scripts/$(ScriptFolder)/upload.sh && RELEASE_NAME=$(BuildName) ./.ci/scripts/$(ScriptFolder)/upload.sh

View File

@@ -0,0 +1,13 @@
steps:
- task: DownloadPipelineArtifact@2
displayName: 'Download Windows Release'
inputs:
artifactName: 'yuzu-$(BuildName)-windows-mingw'
buildType: 'current'
targetPath: '$(Build.ArtifactStagingDirectory)'
- task: DownloadPipelineArtifact@2
displayName: 'Download Linux Release'
inputs:
artifactName: 'yuzu-$(BuildName)-linux'
buildType: 'current'
targetPath: '$(Build.ArtifactStagingDirectory)'

View File

@@ -0,0 +1,11 @@
steps:
- template: ./release-download.yml
- task: GitHubRelease@0
inputs:
action: 'create'
title: 'yuzu $(BuildName) #$(Build.BuildId)'
assets: '$(Build.ArtifactStagingDirectory)/*'
gitHubConnection: $(GitHubReleaseConnectionName)
repositoryName: '$(Build.Repository.Name)'
target: '$(Build.SourceVersion)'
tagSource: 'auto'

View File

@@ -0,0 +1,10 @@
steps:
- template: ./release-download.yml
- task: UniversalPackages@0
displayName: Publish Artifacts
inputs:
command: publish
publishDirectory: '$(Build.ArtifactStagingDirectory)'
vstsFeedPublish: 'yuzu-$(BuildName)'
vstsFeedPackagePublish: 'main'
packagePublishDescription: 'Yuzu Windows and Linux Executable Packages'

View File

@@ -0,0 +1,8 @@
trigger:
- master
stages:
- stage: merge
displayName: 'merge'
jobs:
- template: ./templates/merge.yml

View File

@@ -2,12 +2,7 @@ trigger:
- master
stages:
- stage: merge
displayName: 'merge'
jobs:
- template: ./templates/merge.yml
- stage: format
dependsOn: merge
displayName: 'format'
jobs:
- job: format
@@ -17,9 +12,17 @@ stages:
steps:
- template: ./templates/format-check.yml
- stage: build
displayName: 'build'
dependsOn: format
displayName: 'build'
jobs:
- template: ./templates/build-standard.yml
parameters:
cache: 'true'
- stage: release
displayName: 'Release'
dependsOn: build
jobs:
- job: github
displayName: 'GitHub Release'
steps:
- template: ./templates/release-github.yml

View File

@@ -6,9 +6,11 @@ yuzu emulator
yuzu is an experimental open-source emulator for the Nintendo Switch from the creators of [Citra](https://citra-emu.org/).
It is written in C++ with portability in mind, with builds actively maintained for Windows, Linux and macOS. The emulator is currently only useful for homebrew development and research purposes.
It is written in C++ with portability in mind, with builds actively maintained for Windows and Linux. The emulator is capable of running several commercial games.
yuzu only emulates a subset of Switch hardware and therefore is generally only useful for running/debugging homebrew applications. yuzu can boot some games, to varying degrees of success.
yuzu only emulates a subset of Switch hardware and therefore most commercial games **do not** run at full speed or are not fully functional.
Do you want to check which games are compatible and which ones are not? Please visit our [Compatibility page](https://yuzu-emu.org/game/)!
yuzu is licensed under the GPLv2 (or any later version). Refer to the license.txt file included.

View File

@@ -107,6 +107,11 @@ Stream::State AudioRenderer::GetStreamState() const {
return stream->GetState();
}
static constexpr u32 VersionFromRevision(u32_le rev) {
// "REV7" -> 7
return ((rev >> 24) & 0xff) - 0x30;
}
std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params) {
// Copy UpdateDataHeader struct
UpdateDataHeader config{};
@@ -166,6 +171,11 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
// Copy output header
UpdateDataHeader response_data{worker_params};
std::vector<u8> output_params(response_data.total_size);
const auto audren_revision = VersionFromRevision(config.revision);
if (audren_revision >= 5) {
response_data.frame_count = 0x10;
response_data.total_size += 0x10;
}
std::memcpy(output_params.data(), &response_data, sizeof(UpdateDataHeader));
// Copy output memory pool entries

View File

@@ -194,21 +194,24 @@ struct UpdateDataHeader {
mixes_size = 0x0;
sinks_size = config.sink_count * 0x20;
performance_manager_size = 0x10;
frame_count = 0;
total_size = sizeof(UpdateDataHeader) + behavior_size + memory_pools_size + voices_size +
effects_size + sinks_size + performance_manager_size;
}
u32_le revision;
u32_le behavior_size;
u32_le memory_pools_size;
u32_le voices_size;
u32_le voice_resource_size;
u32_le effects_size;
u32_le mixes_size;
u32_le sinks_size;
u32_le performance_manager_size;
INSERT_PADDING_WORDS(6);
u32_le total_size;
u32_le revision{};
u32_le behavior_size{};
u32_le memory_pools_size{};
u32_le voices_size{};
u32_le voice_resource_size{};
u32_le effects_size{};
u32_le mixes_size{};
u32_le sinks_size{};
u32_le performance_manager_size{};
INSERT_PADDING_WORDS(1);
u32_le frame_count{};
INSERT_PADDING_WORDS(4);
u32_le total_size{};
};
static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size");

View File

@@ -10,6 +10,9 @@ if (DEFINED ENV{CI})
elseif(DEFINED ENV{APPVEYOR})
set(BUILD_REPOSITORY $ENV{APPVEYOR_REPO_NAME})
set(BUILD_TAG $ENV{APPVEYOR_REPO_TAG_NAME})
elseif(DEFINED ENV{AZURE})
set(BUILD_REPOSITORY $ENV{AZURE_REPO_NAME})
set(BUILD_TAG $ENV{AZURE_REPO_TAG})
endif()
endif()
add_custom_command(OUTPUT scm_rev.cpp

View File

@@ -255,6 +255,7 @@ void DebuggerBackend::Write(const Entry& entry) {
CLS(Input) \
CLS(Network) \
CLS(Loader) \
CLS(CheatEngine) \
CLS(Crypto) \
CLS(WebService)

View File

@@ -117,6 +117,7 @@ enum class Class : ClassType {
Audio_DSP, ///< The HLE implementation of the DSP
Audio_Sink, ///< Emulator audio output backend
Loader, ///< ROM loader
CheatEngine, ///< Memory manipulation and engine VM functions
Crypto, ///< Cryptographic engine/functions
Input, ///< Input emulation
Network, ///< Network emulation

View File

@@ -33,8 +33,6 @@ add_library(core STATIC
file_sys/bis_factory.h
file_sys/card_image.cpp
file_sys/card_image.h
file_sys/cheat_engine.cpp
file_sys/cheat_engine.h
file_sys/content_archive.cpp
file_sys/content_archive.h
file_sys/control_metadata.cpp
@@ -477,6 +475,11 @@ add_library(core STATIC
loader/nsp.h
loader/xci.cpp
loader/xci.h
memory/cheat_engine.cpp
memory/cheat_engine.h
memory/dmnt_cheat_types.h
memory/dmnt_cheat_vm.cpp
memory/dmnt_cheat_vm.h
memory.cpp
memory.h
memory_setup.h

View File

@@ -14,8 +14,14 @@
#include "core/core_cpu.h"
#include "core/core_timing.h"
#include "core/cpu_core_manager.h"
#include "core/file_sys/bis_factory.h"
#include "core/file_sys/card_image.h"
#include "core/file_sys/mode.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/romfs_factory.h"
#include "core/file_sys/savedata_factory.h"
#include "core/file_sys/sdmc_factory.h"
#include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_real.h"
#include "core/gdbstub/gdbstub.h"
@@ -27,17 +33,17 @@
#include "core/hle/kernel/thread.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/apm/controller.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/glue/manager.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
#include "core/loader/loader.h"
#include "core/memory/cheat_engine.h"
#include "core/perf_stats.h"
#include "core/reporter.h"
#include "core/settings.h"
#include "core/telemetry_session.h"
#include "core/tools/freezer.h"
#include "file_sys/cheat_engine.h"
#include "file_sys/patch_manager.h"
#include "video_core/debug_utils/debug_utils.h"
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
@@ -157,13 +163,10 @@ struct System::Impl {
gpu_core = VideoCore::CreateGPU(system);
is_powered_on = true;
exit_lock = false;
LOG_DEBUG(Core, "Initialized OK");
// Reset counters and set time origin to current frame
GetAndResetPerfStats();
perf_stats.BeginSystemFrame();
return ResultStatus::Success;
}
@@ -202,10 +205,34 @@ struct System::Impl {
gpu_core->Start();
cpu_core_manager.StartThreads();
// Initialize cheat engine
if (cheat_engine) {
cheat_engine->Initialize();
}
// All threads are started, begin main process execution, now that we're in the clear.
main_process->Run(load_parameters->main_thread_priority,
load_parameters->main_thread_stack_size);
if (Settings::values.gamecard_inserted) {
if (Settings::values.gamecard_current_game) {
fs_controller.SetGameCard(GetGameFileFromPath(virtual_filesystem, filepath));
} else if (!Settings::values.gamecard_path.empty()) {
fs_controller.SetGameCard(
GetGameFileFromPath(virtual_filesystem, Settings::values.gamecard_path));
}
}
u64 title_id{0};
if (app_loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) {
LOG_ERROR(Core, "Failed to find title id for ROM (Error {})",
static_cast<u32>(load_result));
}
perf_stats = std::make_unique<PerfStats>(title_id);
// Reset counters and set time origin to current frame
GetAndResetPerfStats();
perf_stats->BeginSystemFrame();
status = ResultStatus::Success;
return status;
}
@@ -219,8 +246,11 @@ struct System::Impl {
perf_results.game_fps);
telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime",
perf_results.frametime * 1000.0);
telemetry_session->AddField(Telemetry::FieldType::Performance, "Mean_Frametime_MS",
perf_stats->GetMeanFrametime());
is_powered_on = false;
exit_lock = false;
// Shutdown emulation session
renderer.reset();
@@ -229,6 +259,7 @@ struct System::Impl {
service_manager.reset();
cheat_engine.reset();
telemetry_session.reset();
perf_stats.reset();
gpu_core.reset();
// Close all CPU/threading state
@@ -286,7 +317,7 @@ struct System::Impl {
}
PerfStatsResults GetAndResetPerfStats() {
return perf_stats.GetAndResetStats(core_timing.GetGlobalTimeUs());
return perf_stats->GetAndResetStats(core_timing.GetGlobalTimeUs());
}
Timing::CoreTiming core_timing;
@@ -295,6 +326,7 @@ struct System::Impl {
FileSys::VirtualFilesystem virtual_filesystem;
/// ContentProviderUnion instance
std::unique_ptr<FileSys::ContentProviderUnion> content_provider;
Service::FileSystem::FileSystemController fs_controller;
/// AppLoader used to load the current executing application
std::unique_ptr<Loader::AppLoader> app_loader;
std::unique_ptr<VideoCore::RendererBase> renderer;
@@ -303,8 +335,9 @@ struct System::Impl {
std::unique_ptr<Core::Hardware::InterruptManager> interrupt_manager;
CpuCoreManager cpu_core_manager;
bool is_powered_on = false;
bool exit_lock = false;
std::unique_ptr<FileSys::CheatEngine> cheat_engine;
std::unique_ptr<Memory::CheatEngine> cheat_engine;
std::unique_ptr<Tools::Freezer> memory_freezer;
/// Frontend applets
@@ -327,7 +360,7 @@ struct System::Impl {
ResultStatus status = ResultStatus::Success;
std::string status_details = "";
Core::PerfStats perf_stats;
std::unique_ptr<Core::PerfStats> perf_stats;
Core::FrameLimiter frame_limiter;
};
@@ -480,11 +513,11 @@ const Timing::CoreTiming& System::CoreTiming() const {
}
Core::PerfStats& System::GetPerfStats() {
return impl->perf_stats;
return *impl->perf_stats;
}
const Core::PerfStats& System::GetPerfStats() const {
return impl->perf_stats;
return *impl->perf_stats;
}
Core::FrameLimiter& System::FrameLimiter() {
@@ -519,13 +552,6 @@ Tegra::DebugContext* System::GetGPUDebugContext() const {
return impl->debug_context.get();
}
void System::RegisterCheatList(const std::vector<FileSys::CheatList>& list,
const std::string& build_id, VAddr code_region_start,
VAddr code_region_end) {
impl->cheat_engine = std::make_unique<FileSys::CheatEngine>(*this, list, build_id,
code_region_start, code_region_end);
}
void System::SetFilesystem(std::shared_ptr<FileSys::VfsFilesystem> vfs) {
impl->virtual_filesystem = std::move(vfs);
}
@@ -534,6 +560,13 @@ std::shared_ptr<FileSys::VfsFilesystem> System::GetFilesystem() const {
return impl->virtual_filesystem;
}
void System::RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
const std::array<u8, 32>& build_id, VAddr main_region_begin,
u64 main_region_size) {
impl->cheat_engine = std::make_unique<Memory::CheatEngine>(*this, list, build_id);
impl->cheat_engine->SetMainMemoryParameters(main_region_begin, main_region_size);
}
void System::SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set) {
impl->applet_manager.SetAppletFrontendSet(std::move(set));
}
@@ -562,6 +595,14 @@ const FileSys::ContentProvider& System::GetContentProvider() const {
return *impl->content_provider;
}
Service::FileSystem::FileSystemController& System::GetFileSystemController() {
return impl->fs_controller;
}
const Service::FileSystem::FileSystemController& System::GetFileSystemController() const {
return impl->fs_controller;
}
void System::RegisterContentProvider(FileSys::ContentProviderUnionSlot slot,
FileSys::ContentProvider* provider) {
impl->content_provider->SetSlot(slot, provider);
@@ -591,6 +632,14 @@ const Service::APM::Controller& System::GetAPMController() const {
return impl->apm_controller;
}
void System::SetExitLock(bool locked) {
impl->exit_lock = locked;
}
bool System::GetExitLock() const {
return impl->exit_lock;
}
System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
return impl->Init(*this, emu_window);
}

View File

@@ -18,7 +18,6 @@ class EmuWindow;
} // namespace Core::Frontend
namespace FileSys {
class CheatList;
class ContentProvider;
class ContentProviderUnion;
enum class ContentProviderUnionSlot;
@@ -36,6 +35,10 @@ class AppLoader;
enum class ResultStatus : u16;
} // namespace Loader
namespace Memory {
struct CheatEntry;
} // namespace Memory
namespace Service {
namespace AM::Applets {
@@ -47,6 +50,10 @@ namespace APM {
class Controller;
}
namespace FileSystem {
class FileSystemController;
} // namespace FileSystem
namespace Glue {
class ARPManager;
}
@@ -282,8 +289,9 @@ public:
std::shared_ptr<FileSys::VfsFilesystem> GetFilesystem() const;
void RegisterCheatList(const std::vector<FileSys::CheatList>& list, const std::string& build_id,
VAddr code_region_start, VAddr code_region_end);
void RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
const std::array<u8, 0x20>& build_id, VAddr main_region_begin,
u64 main_region_size);
void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set);
@@ -299,6 +307,10 @@ public:
const FileSys::ContentProvider& GetContentProvider() const;
Service::FileSystem::FileSystemController& GetFileSystemController();
const Service::FileSystem::FileSystemController& GetFileSystemController() const;
void RegisterContentProvider(FileSys::ContentProviderUnionSlot slot,
FileSys::ContentProvider* provider);
@@ -314,6 +326,10 @@ public:
const Service::APM::Controller& GetAPMController() const;
void SetExitLock(bool locked);
bool GetExitLock() const;
private:
System();

View File

@@ -480,6 +480,10 @@ void PartitionDataManager::DecryptProdInfo(std::array<u8, 0x20> bis_key) {
prodinfo_decrypted = std::make_shared<XTSEncryptionLayer>(prodinfo, bis_key);
}
FileSys::VirtualFile PartitionDataManager::GetDecryptedProdInfo() const {
return prodinfo_decrypted;
}
std::array<u8, 576> PartitionDataManager::GetETicketExtendedKek() const {
std::array<u8, 0x240> out{};
if (prodinfo_decrypted != nullptr)

View File

@@ -84,6 +84,7 @@ public:
bool HasProdInfo() const;
FileSys::VirtualFile GetProdInfoRaw() const;
void DecryptProdInfo(std::array<u8, 0x20> bis_key);
FileSys::VirtualFile GetDecryptedProdInfo() const;
std::array<u8, 0x240> GetETicketExtendedKek() const;
private:

View File

@@ -3,8 +3,12 @@
// Refer to the license.txt file included.
#include <fmt/format.h>
#include "common/file_util.h"
#include "core/core.h"
#include "core/file_sys/bis_factory.h"
#include "core/file_sys/mode.h"
#include "core/file_sys/registered_cache.h"
#include "core/settings.h"
namespace FileSys {
@@ -14,10 +18,22 @@ BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_, VirtualDir
sysnand_cache(std::make_unique<RegisteredCache>(
GetOrCreateDirectoryRelative(nand_root, "/system/Contents/registered"))),
usrnand_cache(std::make_unique<RegisteredCache>(
GetOrCreateDirectoryRelative(nand_root, "/user/Contents/registered"))) {}
GetOrCreateDirectoryRelative(nand_root, "/user/Contents/registered"))),
sysnand_placeholder(std::make_unique<PlaceholderCache>(
GetOrCreateDirectoryRelative(nand_root, "/system/Contents/placehld"))),
usrnand_placeholder(std::make_unique<PlaceholderCache>(
GetOrCreateDirectoryRelative(nand_root, "/user/Contents/placehld"))) {}
BISFactory::~BISFactory() = default;
VirtualDir BISFactory::GetSystemNANDContentDirectory() const {
return GetOrCreateDirectoryRelative(nand_root, "/system/Contents");
}
VirtualDir BISFactory::GetUserNANDContentDirectory() const {
return GetOrCreateDirectoryRelative(nand_root, "/user/Contents");
}
RegisteredCache* BISFactory::GetSystemNANDContents() const {
return sysnand_cache.get();
}
@@ -26,9 +42,17 @@ RegisteredCache* BISFactory::GetUserNANDContents() const {
return usrnand_cache.get();
}
PlaceholderCache* BISFactory::GetSystemNANDPlaceholder() const {
return sysnand_placeholder.get();
}
PlaceholderCache* BISFactory::GetUserNANDPlaceholder() const {
return usrnand_placeholder.get();
}
VirtualDir BISFactory::GetModificationLoadRoot(u64 title_id) const {
// LayeredFS doesn't work on updates and title id-less homebrew
if (title_id == 0 || (title_id & 0x800) > 0)
if (title_id == 0 || (title_id & 0xFFF) == 0x800)
return nullptr;
return GetOrCreateDirectoryRelative(load_root, fmt::format("/{:016X}", title_id));
}
@@ -39,4 +63,77 @@ VirtualDir BISFactory::GetModificationDumpRoot(u64 title_id) const {
return GetOrCreateDirectoryRelative(dump_root, fmt::format("/{:016X}", title_id));
}
VirtualDir BISFactory::OpenPartition(BisPartitionId id) const {
switch (id) {
case BisPartitionId::CalibrationFile:
return GetOrCreateDirectoryRelative(nand_root, "/prodinfof");
case BisPartitionId::SafeMode:
return GetOrCreateDirectoryRelative(nand_root, "/safe");
case BisPartitionId::System:
return GetOrCreateDirectoryRelative(nand_root, "/system");
case BisPartitionId::User:
return GetOrCreateDirectoryRelative(nand_root, "/user");
default:
return nullptr;
}
}
VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id) const {
Core::Crypto::KeyManager keys;
Core::Crypto::PartitionDataManager pdm{
Core::System::GetInstance().GetFilesystem()->OpenDirectory(
FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir), Mode::Read)};
keys.PopulateFromPartitionData(pdm);
switch (id) {
case BisPartitionId::CalibrationBinary:
return pdm.GetDecryptedProdInfo();
case BisPartitionId::BootConfigAndPackage2Part1:
case BisPartitionId::BootConfigAndPackage2Part2:
case BisPartitionId::BootConfigAndPackage2Part3:
case BisPartitionId::BootConfigAndPackage2Part4:
case BisPartitionId::BootConfigAndPackage2Part5:
case BisPartitionId::BootConfigAndPackage2Part6: {
const auto new_id = static_cast<u8>(id) -
static_cast<u8>(BisPartitionId::BootConfigAndPackage2Part1) +
static_cast<u8>(Core::Crypto::Package2Type::NormalMain);
return pdm.GetPackage2Raw(static_cast<Core::Crypto::Package2Type>(new_id));
}
default:
return nullptr;
}
}
VirtualDir BISFactory::GetImageDirectory() const {
return GetOrCreateDirectoryRelative(nand_root, "/user/Album");
}
u64 BISFactory::GetSystemNANDFreeSpace() const {
const auto sys_dir = GetOrCreateDirectoryRelative(nand_root, "/system");
if (sys_dir == nullptr)
return 0;
return GetSystemNANDTotalSpace() - sys_dir->GetSize();
}
u64 BISFactory::GetSystemNANDTotalSpace() const {
return static_cast<u64>(Settings::values.nand_system_size);
}
u64 BISFactory::GetUserNANDFreeSpace() const {
const auto usr_dir = GetOrCreateDirectoryRelative(nand_root, "/user");
if (usr_dir == nullptr)
return 0;
return GetUserNANDTotalSpace() - usr_dir->GetSize();
}
u64 BISFactory::GetUserNANDTotalSpace() const {
return static_cast<u64>(Settings::values.nand_user_size);
}
u64 BISFactory::GetFullNANDTotalSpace() const {
return static_cast<u64>(Settings::values.nand_total_size);
}
} // namespace FileSys

View File

@@ -10,7 +10,25 @@
namespace FileSys {
enum class BisPartitionId : u32 {
UserDataRoot = 20,
CalibrationBinary = 27,
CalibrationFile = 28,
BootConfigAndPackage2Part1 = 21,
BootConfigAndPackage2Part2 = 22,
BootConfigAndPackage2Part3 = 23,
BootConfigAndPackage2Part4 = 24,
BootConfigAndPackage2Part5 = 25,
BootConfigAndPackage2Part6 = 26,
SafeMode = 29,
System = 31,
SystemProperEncryption = 32,
SystemProperPartition = 33,
User = 30,
};
class RegisteredCache;
class PlaceholderCache;
/// File system interface to the Built-In Storage
/// This is currently missing accessors to BIS partitions, but seemed like a good place for the NAND
@@ -20,12 +38,29 @@ public:
explicit BISFactory(VirtualDir nand_root, VirtualDir load_root, VirtualDir dump_root);
~BISFactory();
VirtualDir GetSystemNANDContentDirectory() const;
VirtualDir GetUserNANDContentDirectory() const;
RegisteredCache* GetSystemNANDContents() const;
RegisteredCache* GetUserNANDContents() const;
PlaceholderCache* GetSystemNANDPlaceholder() const;
PlaceholderCache* GetUserNANDPlaceholder() const;
VirtualDir GetModificationLoadRoot(u64 title_id) const;
VirtualDir GetModificationDumpRoot(u64 title_id) const;
VirtualDir OpenPartition(BisPartitionId id) const;
VirtualFile OpenPartitionStorage(BisPartitionId id) const;
VirtualDir GetImageDirectory() const;
u64 GetSystemNANDFreeSpace() const;
u64 GetSystemNANDTotalSpace() const;
u64 GetUserNANDFreeSpace() const;
u64 GetUserNANDTotalSpace() const;
u64 GetFullNANDTotalSpace() const;
private:
VirtualDir nand_root;
VirtualDir load_root;
@@ -33,6 +68,9 @@ private:
std::unique_ptr<RegisteredCache> sysnand_cache;
std::unique_ptr<RegisteredCache> usrnand_cache;
std::unique_ptr<PlaceholderCache> sysnand_placeholder;
std::unique_ptr<PlaceholderCache> usrnand_placeholder;
};
} // namespace FileSys

View File

@@ -12,12 +12,16 @@
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/partition_filesystem.h"
#include "core/file_sys/romfs.h"
#include "core/file_sys/submission_package.h"
#include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_offset.h"
#include "core/file_sys/vfs_vector.h"
#include "core/loader/loader.h"
namespace FileSys {
constexpr u64 GAMECARD_CERTIFICATE_OFFSET = 0x7000;
constexpr std::array partition_names{
"update",
"normal",
@@ -175,6 +179,26 @@ VirtualDir XCI::GetParentDirectory() const {
return file->GetContainingDirectory();
}
VirtualDir XCI::ConcatenatedPseudoDirectory() {
const auto out = std::make_shared<VectorVfsDirectory>();
for (const auto& part_id : {XCIPartition::Normal, XCIPartition::Logo, XCIPartition::Secure}) {
const auto& part = GetPartition(part_id);
if (part == nullptr)
continue;
for (const auto& file : part->GetFiles())
out->AddFile(file);
}
return out;
}
std::array<u8, 0x200> XCI::GetCertificate() const {
std::array<u8, 0x200> out;
file->Read(out.data(), out.size(), GAMECARD_CERTIFICATE_OFFSET);
return out;
}
Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) {
const auto partition_index = static_cast<std::size_t>(part);
const auto& partition = partitions[partition_index];

View File

@@ -91,6 +91,8 @@ public:
VirtualDir GetLogoPartition() const;
u64 GetProgramTitleID() const;
u32 GetSystemUpdateVersion();
u64 GetSystemUpdateTitleID() const;
bool HasProgramNCA() const;
VirtualFile GetProgramNCAFile() const;
@@ -106,6 +108,11 @@ public:
VirtualDir GetParentDirectory() const override;
// Creates a directory that contains all the NCAs in the gamecard
VirtualDir ConcatenatedPseudoDirectory();
std::array<u8, 0x200> GetCertificate() const;
private:
Loader::ResultStatus AddNCAFromPartition(XCIPartition part);
@@ -120,6 +127,8 @@ private:
std::shared_ptr<NCA> program;
std::vector<std::shared_ptr<NCA>> ncas;
u64 update_normal_partition_end;
Core::Crypto::KeyManager keys;
};
} // namespace FileSys

View File

@@ -1,492 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <locale>
#include "common/hex_util.h"
#include "common/microprofile.h"
#include "common/swap.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
#include "core/file_sys/cheat_engine.h"
#include "core/hle/kernel/process.h"
#include "core/hle/service/hid/controllers/npad.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/sm/sm.h"
namespace FileSys {
constexpr s64 CHEAT_ENGINE_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60);
constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF;
u64 Cheat::Address() const {
u64 out;
std::memcpy(&out, raw.data(), sizeof(u64));
return Common::swap64(out) & 0xFFFFFFFFFF;
}
u64 Cheat::ValueWidth(u64 offset) const {
return Value(offset, width);
}
u64 Cheat::Value(u64 offset, u64 width) const {
u64 out;
std::memcpy(&out, raw.data() + offset, sizeof(u64));
out = Common::swap64(out);
if (width == 8)
return out;
return out & ((1ull << (width * CHAR_BIT)) - 1);
}
u32 Cheat::KeypadValue() const {
u32 out;
std::memcpy(&out, raw.data(), sizeof(u32));
return Common::swap32(out) & 0x0FFFFFFF;
}
void CheatList::SetMemoryParameters(VAddr main_begin, VAddr heap_begin, VAddr main_end,
VAddr heap_end, MemoryWriter writer, MemoryReader reader) {
this->main_region_begin = main_begin;
this->main_region_end = main_end;
this->heap_region_begin = heap_begin;
this->heap_region_end = heap_end;
this->writer = writer;
this->reader = reader;
}
MICROPROFILE_DEFINE(Cheat_Engine, "Add-Ons", "Cheat Engine", MP_RGB(70, 200, 70));
void CheatList::Execute() {
MICROPROFILE_SCOPE(Cheat_Engine);
std::fill(scratch.begin(), scratch.end(), 0);
in_standard = false;
for (std::size_t i = 0; i < master_list.size(); ++i) {
LOG_DEBUG(Common_Filesystem, "Executing block #{:08X} ({})", i, master_list[i].first);
current_block = i;
ExecuteBlock(master_list[i].second);
}
in_standard = true;
for (std::size_t i = 0; i < standard_list.size(); ++i) {
LOG_DEBUG(Common_Filesystem, "Executing block #{:08X} ({})", i, standard_list[i].first);
current_block = i;
ExecuteBlock(standard_list[i].second);
}
}
CheatList::CheatList(const Core::System& system_, ProgramSegment master, ProgramSegment standard)
: master_list{std::move(master)}, standard_list{std::move(standard)}, system{&system_} {}
bool CheatList::EvaluateConditional(const Cheat& cheat) const {
using ComparisonFunction = bool (*)(u64, u64);
constexpr std::array<ComparisonFunction, 6> comparison_functions{
[](u64 a, u64 b) { return a > b; }, [](u64 a, u64 b) { return a >= b; },
[](u64 a, u64 b) { return a < b; }, [](u64 a, u64 b) { return a <= b; },
[](u64 a, u64 b) { return a == b; }, [](u64 a, u64 b) { return a != b; },
};
if (cheat.type == CodeType::ConditionalInput) {
const auto applet_resource =
system->ServiceManager().GetService<Service::HID::Hid>("hid")->GetAppletResource();
if (applet_resource == nullptr) {
LOG_WARNING(
Common_Filesystem,
"Attempted to evaluate input conditional, but applet resource is not initialized!");
return false;
}
const auto press_state =
applet_resource
->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)
.GetAndResetPressState();
return ((press_state & cheat.KeypadValue()) & KEYPAD_BITMASK) != 0;
}
ASSERT(cheat.type == CodeType::Conditional);
const auto offset =
cheat.memory_type == MemoryType::MainNSO ? main_region_begin : heap_region_begin;
ASSERT(static_cast<u8>(cheat.comparison_op.Value()) < 6);
auto* function = comparison_functions[static_cast<u8>(cheat.comparison_op.Value())];
const auto addr = cheat.Address() + offset;
return function(reader(cheat.width, SanitizeAddress(addr)), cheat.ValueWidth(8));
}
void CheatList::ProcessBlockPairs(const Block& block) {
block_pairs.clear();
u64 scope = 0;
std::map<u64, u64> pairs;
for (std::size_t i = 0; i < block.size(); ++i) {
const auto& cheat = block[i];
switch (cheat.type) {
case CodeType::Conditional:
case CodeType::ConditionalInput:
pairs.insert_or_assign(scope, i);
++scope;
break;
case CodeType::EndConditional: {
--scope;
const auto idx = pairs.at(scope);
block_pairs.insert_or_assign(idx, i);
break;
}
case CodeType::Loop: {
if (cheat.end_of_loop) {
--scope;
const auto idx = pairs.at(scope);
block_pairs.insert_or_assign(idx, i);
} else {
pairs.insert_or_assign(scope, i);
++scope;
}
break;
}
}
}
}
void CheatList::WriteImmediate(const Cheat& cheat) {
const auto offset =
cheat.memory_type == MemoryType::MainNSO ? main_region_begin : heap_region_begin;
const auto& register_3 = scratch.at(cheat.register_3);
const auto addr = cheat.Address() + offset + register_3;
LOG_DEBUG(Common_Filesystem, "writing value={:016X} to addr={:016X}", addr,
cheat.Value(8, cheat.width));
writer(cheat.width, SanitizeAddress(addr), cheat.ValueWidth(8));
}
void CheatList::BeginConditional(const Cheat& cheat) {
if (EvaluateConditional(cheat)) {
return;
}
const auto iter = block_pairs.find(current_index);
ASSERT(iter != block_pairs.end());
current_index = iter->second - 1;
}
void CheatList::EndConditional(const Cheat& cheat) {
LOG_DEBUG(Common_Filesystem, "Ending conditional block.");
}
void CheatList::Loop(const Cheat& cheat) {
if (cheat.end_of_loop.Value())
ASSERT(!cheat.end_of_loop.Value());
auto& register_3 = scratch.at(cheat.register_3);
const auto iter = block_pairs.find(current_index);
ASSERT(iter != block_pairs.end());
ASSERT(iter->first < iter->second);
const s32 initial_value = static_cast<s32>(cheat.Value(4, sizeof(s32)));
for (s32 i = initial_value; i >= 0; --i) {
register_3 = static_cast<u64>(i);
for (std::size_t c = iter->first + 1; c < iter->second; ++c) {
current_index = c;
ExecuteSingleCheat(
(in_standard ? standard_list : master_list)[current_block].second[c]);
}
}
current_index = iter->second;
}
void CheatList::LoadImmediate(const Cheat& cheat) {
auto& register_3 = scratch.at(cheat.register_3);
LOG_DEBUG(Common_Filesystem, "setting register={:01X} equal to value={:016X}", cheat.register_3,
cheat.Value(4, 8));
register_3 = cheat.Value(4, 8);
}
void CheatList::LoadIndexed(const Cheat& cheat) {
const auto offset =
cheat.memory_type == MemoryType::MainNSO ? main_region_begin : heap_region_begin;
auto& register_3 = scratch.at(cheat.register_3);
const auto addr = (cheat.load_from_register.Value() ? register_3 : offset) + cheat.Address();
LOG_DEBUG(Common_Filesystem, "writing indexed value to register={:01X}, addr={:016X}",
cheat.register_3, addr);
register_3 = reader(cheat.width, SanitizeAddress(addr));
}
void CheatList::StoreIndexed(const Cheat& cheat) {
const auto& register_3 = scratch.at(cheat.register_3);
const auto addr =
register_3 + (cheat.add_additional_register.Value() ? scratch.at(cheat.register_6) : 0);
LOG_DEBUG(Common_Filesystem, "writing value={:016X} to addr={:016X}",
cheat.Value(4, cheat.width), addr);
writer(cheat.width, SanitizeAddress(addr), cheat.ValueWidth(4));
}
void CheatList::RegisterArithmetic(const Cheat& cheat) {
using ArithmeticFunction = u64 (*)(u64, u64);
constexpr std::array<ArithmeticFunction, 5> arithmetic_functions{
[](u64 a, u64 b) { return a + b; }, [](u64 a, u64 b) { return a - b; },
[](u64 a, u64 b) { return a * b; }, [](u64 a, u64 b) { return a << b; },
[](u64 a, u64 b) { return a >> b; },
};
using ArithmeticOverflowCheck = bool (*)(u64, u64);
constexpr std::array<ArithmeticOverflowCheck, 5> arithmetic_overflow_checks{
[](u64 a, u64 b) { return a > (std::numeric_limits<u64>::max() - b); }, // a + b
[](u64 a, u64 b) { return a > (std::numeric_limits<u64>::max() + b); }, // a - b
[](u64 a, u64 b) { return a > (std::numeric_limits<u64>::max() / b); }, // a * b
[](u64 a, u64 b) { return b >= 64 || (a & ~((1ull << (64 - b)) - 1)) != 0; }, // a << b
[](u64 a, u64 b) { return b >= 64 || (a & ((1ull << b) - 1)) != 0; }, // a >> b
};
static_assert(sizeof(arithmetic_functions) == sizeof(arithmetic_overflow_checks),
"Missing or have extra arithmetic overflow checks compared to functions!");
auto& register_3 = scratch.at(cheat.register_3);
ASSERT(static_cast<u8>(cheat.arithmetic_op.Value()) < 5);
auto* function = arithmetic_functions[static_cast<u8>(cheat.arithmetic_op.Value())];
auto* overflow_function =
arithmetic_overflow_checks[static_cast<u8>(cheat.arithmetic_op.Value())];
LOG_DEBUG(Common_Filesystem, "performing arithmetic with register={:01X}, value={:016X}",
cheat.register_3, cheat.ValueWidth(4));
if (overflow_function(register_3, cheat.ValueWidth(4))) {
LOG_WARNING(Common_Filesystem,
"overflow will occur when performing arithmetic operation={:02X} with operands "
"a={:016X}, b={:016X}!",
static_cast<u8>(cheat.arithmetic_op.Value()), register_3, cheat.ValueWidth(4));
}
register_3 = function(register_3, cheat.ValueWidth(4));
}
void CheatList::BeginConditionalInput(const Cheat& cheat) {
if (EvaluateConditional(cheat))
return;
const auto iter = block_pairs.find(current_index);
ASSERT(iter != block_pairs.end());
current_index = iter->second - 1;
}
VAddr CheatList::SanitizeAddress(VAddr in) const {
if ((in < main_region_begin || in >= main_region_end) &&
(in < heap_region_begin || in >= heap_region_end)) {
LOG_ERROR(Common_Filesystem,
"Cheat attempting to access memory at invalid address={:016X}, if this persists, "
"the cheat may be incorrect. However, this may be normal early in execution if "
"the game has not properly set up yet.",
in);
return 0; ///< Invalid addresses will hard crash
}
return in;
}
void CheatList::ExecuteSingleCheat(const Cheat& cheat) {
using CheatOperationFunction = void (CheatList::*)(const Cheat&);
constexpr std::array<CheatOperationFunction, 9> cheat_operation_functions{
&CheatList::WriteImmediate, &CheatList::BeginConditional,
&CheatList::EndConditional, &CheatList::Loop,
&CheatList::LoadImmediate, &CheatList::LoadIndexed,
&CheatList::StoreIndexed, &CheatList::RegisterArithmetic,
&CheatList::BeginConditionalInput,
};
const auto index = static_cast<u8>(cheat.type.Value());
ASSERT(index < sizeof(cheat_operation_functions));
const auto op = cheat_operation_functions[index];
(this->*op)(cheat);
}
void CheatList::ExecuteBlock(const Block& block) {
encountered_loops.clear();
ProcessBlockPairs(block);
for (std::size_t i = 0; i < block.size(); ++i) {
current_index = i;
ExecuteSingleCheat(block[i]);
i = current_index;
}
}
CheatParser::~CheatParser() = default;
CheatList CheatParser::MakeCheatList(const Core::System& system, CheatList::ProgramSegment master,
CheatList::ProgramSegment standard) const {
return {system, std::move(master), std::move(standard)};
}
TextCheatParser::~TextCheatParser() = default;
CheatList TextCheatParser::Parse(const Core::System& system, const std::vector<u8>& data) const {
std::stringstream ss;
ss.write(reinterpret_cast<const char*>(data.data()), data.size());
std::vector<std::string> lines;
std::string stream_line;
while (std::getline(ss, stream_line)) {
// Remove a trailing \r
if (!stream_line.empty() && stream_line.back() == '\r')
stream_line.pop_back();
lines.push_back(std::move(stream_line));
}
CheatList::ProgramSegment master_list;
CheatList::ProgramSegment standard_list;
for (std::size_t i = 0; i < lines.size(); ++i) {
auto line = lines[i];
if (!line.empty() && (line[0] == '[' || line[0] == '{')) {
const auto master = line[0] == '{';
const auto begin = master ? line.find('{') : line.find('[');
const auto end = master ? line.rfind('}') : line.rfind(']');
ASSERT(begin != std::string::npos && end != std::string::npos);
const std::string patch_name{line.begin() + begin + 1, line.begin() + end};
CheatList::Block block{};
while (i < lines.size() - 1) {
line = lines[++i];
if (!line.empty() && (line[0] == '[' || line[0] == '{')) {
--i;
break;
}
if (line.size() < 8)
continue;
Cheat out{};
out.raw = ParseSingleLineCheat(line);
block.push_back(out);
}
(master ? master_list : standard_list).emplace_back(patch_name, block);
}
}
return MakeCheatList(system, master_list, standard_list);
}
std::array<u8, 16> TextCheatParser::ParseSingleLineCheat(const std::string& line) const {
std::array<u8, 16> out{};
if (line.size() < 8)
return out;
const auto word1 = Common::HexStringToArray<sizeof(u32)>(std::string_view{line.data(), 8});
std::memcpy(out.data(), word1.data(), sizeof(u32));
if (line.size() < 17 || line[8] != ' ')
return out;
const auto word2 = Common::HexStringToArray<sizeof(u32)>(std::string_view{line.data() + 9, 8});
std::memcpy(out.data() + sizeof(u32), word2.data(), sizeof(u32));
if (line.size() < 26 || line[17] != ' ') {
// Perform shifting in case value is truncated early.
const auto type = static_cast<CodeType>((out[0] & 0xF0) >> 4);
if (type == CodeType::Loop || type == CodeType::LoadImmediate ||
type == CodeType::StoreIndexed || type == CodeType::RegisterArithmetic) {
std::memcpy(out.data() + 8, out.data() + 4, sizeof(u32));
std::memset(out.data() + 4, 0, sizeof(u32));
}
return out;
}
const auto word3 = Common::HexStringToArray<sizeof(u32)>(std::string_view{line.data() + 18, 8});
std::memcpy(out.data() + 2 * sizeof(u32), word3.data(), sizeof(u32));
if (line.size() < 35 || line[26] != ' ') {
// Perform shifting in case value is truncated early.
const auto type = static_cast<CodeType>((out[0] & 0xF0) >> 4);
if (type == CodeType::WriteImmediate || type == CodeType::Conditional) {
std::memcpy(out.data() + 12, out.data() + 8, sizeof(u32));
std::memset(out.data() + 8, 0, sizeof(u32));
}
return out;
}
const auto word4 = Common::HexStringToArray<sizeof(u32)>(std::string_view{line.data() + 27, 8});
std::memcpy(out.data() + 3 * sizeof(u32), word4.data(), sizeof(u32));
return out;
}
namespace {
u64 MemoryReadImpl(u32 width, VAddr addr) {
switch (width) {
case 1:
return Memory::Read8(addr);
case 2:
return Memory::Read16(addr);
case 4:
return Memory::Read32(addr);
case 8:
return Memory::Read64(addr);
default:
UNREACHABLE();
return 0;
}
}
void MemoryWriteImpl(u32 width, VAddr addr, u64 value) {
switch (width) {
case 1:
Memory::Write8(addr, static_cast<u8>(value));
break;
case 2:
Memory::Write16(addr, static_cast<u16>(value));
break;
case 4:
Memory::Write32(addr, static_cast<u32>(value));
break;
case 8:
Memory::Write64(addr, value);
break;
default:
UNREACHABLE();
}
}
} // Anonymous namespace
CheatEngine::CheatEngine(Core::System& system, std::vector<CheatList> cheats_,
const std::string& build_id, VAddr code_region_start,
VAddr code_region_end)
: cheats{std::move(cheats_)}, core_timing{system.CoreTiming()} {
event = core_timing.RegisterEvent(
"CheatEngine::FrameCallback::" + build_id,
[this](u64 userdata, s64 cycles_late) { FrameCallback(userdata, cycles_late); });
core_timing.ScheduleEvent(CHEAT_ENGINE_TICKS, event);
const auto& vm_manager = system.CurrentProcess()->VMManager();
for (auto& list : this->cheats) {
list.SetMemoryParameters(code_region_start, vm_manager.GetHeapRegionBaseAddress(),
code_region_end, vm_manager.GetHeapRegionEndAddress(),
&MemoryWriteImpl, &MemoryReadImpl);
}
}
CheatEngine::~CheatEngine() {
core_timing.UnscheduleEvent(event, 0);
}
void CheatEngine::FrameCallback(u64 userdata, s64 cycles_late) {
for (auto& list : cheats) {
list.Execute();
}
core_timing.ScheduleEvent(CHEAT_ENGINE_TICKS - cycles_late, event);
}
} // namespace FileSys

View File

@@ -1,234 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <map>
#include <set>
#include <vector>
#include "common/bit_field.h"
#include "common/common_types.h"
namespace Core {
class System;
}
namespace Core::Timing {
class CoreTiming;
struct EventType;
} // namespace Core::Timing
namespace FileSys {
enum class CodeType : u32 {
// 0TMR00AA AAAAAAAA YYYYYYYY YYYYYYYY
// Writes a T sized value Y to the address A added to the value of register R in memory domain M
WriteImmediate = 0,
// 1TMC00AA AAAAAAAA YYYYYYYY YYYYYYYY
// Compares the T sized value Y to the value at address A in memory domain M using the
// conditional function C. If success, continues execution. If failure, jumps to the matching
// EndConditional statement.
Conditional = 1,
// 20000000
// Terminates a Conditional or ConditionalInput block.
EndConditional = 2,
// 300R0000 VVVVVVVV
// Starts looping V times, storing the current count in register R.
// Loop block is terminated with a matching 310R0000.
Loop = 3,
// 400R0000 VVVVVVVV VVVVVVVV
// Sets the value of register R to the value V.
LoadImmediate = 4,
// 5TMRI0AA AAAAAAAA
// Sets the value of register R to the value of width T at address A in memory domain M, with
// the current value of R added to the address if I == 1.
LoadIndexed = 5,
// 6T0RIFG0 VVVVVVVV VVVVVVVV
// Writes the value V of width T to the memory address stored in register R. Adds the value of
// register G to the final calculation if F is nonzero. Increments the value of register R by T
// after operation if I is nonzero.
StoreIndexed = 6,
// 7T0RA000 VVVVVVVV
// Performs the arithmetic operation A on the value in register R and the value V of width T,
// storing the result in register R.
RegisterArithmetic = 7,
// 8KKKKKKK
// Checks to see if any of the buttons defined by the bitmask K are pressed. If any are,
// execution continues. If none are, execution skips to the next EndConditional command.
ConditionalInput = 8,
};
enum class MemoryType : u32 {
// Addressed relative to start of main NSO
MainNSO = 0,
// Addressed relative to start of heap
Heap = 1,
};
enum class ArithmeticOp : u32 {
Add = 0,
Sub = 1,
Mult = 2,
LShift = 3,
RShift = 4,
};
enum class ComparisonOp : u32 {
GreaterThan = 1,
GreaterThanEqual = 2,
LessThan = 3,
LessThanEqual = 4,
Equal = 5,
Inequal = 6,
};
union Cheat {
std::array<u8, 16> raw;
BitField<4, 4, CodeType> type;
BitField<0, 4, u32> width; // Can be 1, 2, 4, or 8. Measured in bytes.
BitField<0, 4, u32> end_of_loop;
BitField<12, 4, MemoryType> memory_type;
BitField<8, 4, u32> register_3;
BitField<8, 4, ComparisonOp> comparison_op;
BitField<20, 4, u32> load_from_register;
BitField<20, 4, u32> increment_register;
BitField<20, 4, ArithmeticOp> arithmetic_op;
BitField<16, 4, u32> add_additional_register;
BitField<28, 4, u32> register_6;
u64 Address() const;
u64 ValueWidth(u64 offset) const;
u64 Value(u64 offset, u64 width) const;
u32 KeypadValue() const;
};
class CheatParser;
// Represents a full collection of cheats for a game. The Execute function should be called every
// interval that all cheats should be executed. Clients should not directly instantiate this class
// (hence private constructor), they should instead receive an instance from CheatParser, which
// guarantees the list is always in an acceptable state.
class CheatList {
public:
friend class CheatParser;
using Block = std::vector<Cheat>;
using ProgramSegment = std::vector<std::pair<std::string, Block>>;
// (width in bytes, address, value)
using MemoryWriter = void (*)(u32, VAddr, u64);
// (width in bytes, address) -> value
using MemoryReader = u64 (*)(u32, VAddr);
void SetMemoryParameters(VAddr main_begin, VAddr heap_begin, VAddr main_end, VAddr heap_end,
MemoryWriter writer, MemoryReader reader);
void Execute();
private:
CheatList(const Core::System& system_, ProgramSegment master, ProgramSegment standard);
void ProcessBlockPairs(const Block& block);
void ExecuteSingleCheat(const Cheat& cheat);
void ExecuteBlock(const Block& block);
bool EvaluateConditional(const Cheat& cheat) const;
// Individual cheat operations
void WriteImmediate(const Cheat& cheat);
void BeginConditional(const Cheat& cheat);
void EndConditional(const Cheat& cheat);
void Loop(const Cheat& cheat);
void LoadImmediate(const Cheat& cheat);
void LoadIndexed(const Cheat& cheat);
void StoreIndexed(const Cheat& cheat);
void RegisterArithmetic(const Cheat& cheat);
void BeginConditionalInput(const Cheat& cheat);
VAddr SanitizeAddress(VAddr in) const;
// Master Codes are defined as codes that cannot be disabled and are run prior to all
// others.
ProgramSegment master_list;
// All other codes
ProgramSegment standard_list;
bool in_standard = false;
// 16 (0x0-0xF) scratch registers that can be used by cheats
std::array<u64, 16> scratch{};
MemoryWriter writer = nullptr;
MemoryReader reader = nullptr;
u64 main_region_begin{};
u64 heap_region_begin{};
u64 main_region_end{};
u64 heap_region_end{};
u64 current_block{};
// The current index of the cheat within the current Block
u64 current_index{};
// The 'stack' of the program. When a conditional or loop statement is encountered, its index is
// pushed onto this queue. When a end block is encountered, the condition is checked.
std::map<u64, u64> block_pairs;
std::set<u64> encountered_loops;
const Core::System* system;
};
// Intermediary class that parses a text file or other disk format for storing cheats into a
// CheatList object, that can be used for execution.
class CheatParser {
public:
virtual ~CheatParser();
virtual CheatList Parse(const Core::System& system, const std::vector<u8>& data) const = 0;
protected:
CheatList MakeCheatList(const Core::System& system_, CheatList::ProgramSegment master,
CheatList::ProgramSegment standard) const;
};
// CheatParser implementation that parses text files
class TextCheatParser final : public CheatParser {
public:
~TextCheatParser() override;
CheatList Parse(const Core::System& system, const std::vector<u8>& data) const override;
private:
std::array<u8, 16> ParseSingleLineCheat(const std::string& line) const;
};
// Class that encapsulates a CheatList and manages its interaction with memory and CoreTiming
class CheatEngine final {
public:
CheatEngine(Core::System& system_, std::vector<CheatList> cheats_, const std::string& build_id,
VAddr code_region_start, VAddr code_region_end);
~CheatEngine();
private:
void FrameCallback(u64 userdata, s64 cycles_late);
std::vector<CheatList> cheats;
Core::Timing::EventType* event;
Core::Timing::CoreTiming& core_timing;
};
} // namespace FileSys

View File

@@ -528,6 +528,14 @@ u64 NCA::GetTitleId() const {
return header.title_id;
}
std::array<u8, 16> NCA::GetRightsId() const {
return header.rights_id;
}
u32 NCA::GetSDKVersion() const {
return header.sdk_version;
}
bool NCA::IsUpdate() const {
return is_update;
}

View File

@@ -112,6 +112,8 @@ public:
NCAContentType GetType() const;
u64 GetTitleId() const;
std::array<u8, 0x10> GetRightsId() const;
u32 GetSDKVersion() const;
bool IsUpdate() const;
VirtualFile GetRomFS() const;

View File

@@ -22,6 +22,7 @@
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h"
#include "core/loader/nso.h"
#include "core/memory/cheat_engine.h"
#include "core/settings.h"
namespace FileSys {
@@ -63,7 +64,8 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
if (Settings::values.dump_exefs) {
LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id);
const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id);
const auto dump_dir =
Core::System::GetInstance().GetFileSystemController().GetModificationDumpRoot(title_id);
if (dump_dir != nullptr) {
const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs");
VfsRawCopyD(exefs, exefs_dir);
@@ -88,7 +90,8 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
}
// LayeredExeFS
const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
const auto load_dir =
Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
if (load_dir != nullptr && load_dir->GetSize() > 0) {
auto patch_dirs = load_dir->GetSubdirectories();
std::sort(
@@ -174,7 +177,8 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st
if (Settings::values.dump_nso) {
LOG_INFO(Loader, "Dumping NSO for name={}, build_id={}, title_id={:016X}", name, build_id,
title_id);
const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id);
const auto dump_dir =
Core::System::GetInstance().GetFileSystemController().GetModificationDumpRoot(title_id);
if (dump_dir != nullptr) {
const auto nso_dir = GetOrCreateDirectoryRelative(dump_dir, "/nso");
const auto file = nso_dir->CreateFile(fmt::format("{}-{}.nso", name, build_id));
@@ -186,7 +190,13 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st
LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id);
const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
const auto load_dir =
Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
if (load_dir == nullptr) {
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
return nso;
}
auto patch_dirs = load_dir->GetSubdirectories();
std::sort(patch_dirs.begin(), patch_dirs.end(),
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
@@ -224,7 +234,13 @@ bool PatchManager::HasNSOPatch(const std::array<u8, 32>& build_id_) const {
LOG_INFO(Loader, "Querying NSO patch existence for build_id={}", build_id);
const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
const auto load_dir =
Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
if (load_dir == nullptr) {
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
return false;
}
auto patch_dirs = load_dir->GetSubdirectories();
std::sort(patch_dirs.begin(), patch_dirs.end(),
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
@@ -232,9 +248,10 @@ bool PatchManager::HasNSOPatch(const std::array<u8, 32>& build_id_) const {
return !CollectPatches(patch_dirs, build_id).empty();
}
static std::optional<CheatList> ReadCheatFileFromFolder(const Core::System& system, u64 title_id,
const std::array<u8, 0x20>& build_id_,
const VirtualDir& base_path, bool upper) {
namespace {
std::optional<std::vector<Memory::CheatEntry>> ReadCheatFileFromFolder(
const Core::System& system, u64 title_id, const std::array<u8, 0x20>& build_id_,
const VirtualDir& base_path, bool upper) {
const auto build_id_raw = Common::HexToString(build_id_, upper);
const auto build_id = build_id_raw.substr(0, sizeof(u64) * 2);
const auto file = base_path->GetFile(fmt::format("{}.txt", build_id));
@@ -252,31 +269,39 @@ static std::optional<CheatList> ReadCheatFileFromFolder(const Core::System& syst
return std::nullopt;
}
TextCheatParser parser;
return parser.Parse(system, data);
Memory::TextCheatParser parser;
return parser.Parse(
system, std::string_view(reinterpret_cast<const char* const>(data.data()), data.size()));
}
std::vector<CheatList> PatchManager::CreateCheatList(const Core::System& system,
const std::array<u8, 32>& build_id_) const {
const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
} // Anonymous namespace
std::vector<Memory::CheatEntry> PatchManager::CreateCheatList(
const Core::System& system, const std::array<u8, 32>& build_id_) const {
const auto load_dir = system.GetFileSystemController().GetModificationLoadRoot(title_id);
if (load_dir == nullptr) {
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
return {};
}
auto patch_dirs = load_dir->GetSubdirectories();
std::sort(patch_dirs.begin(), patch_dirs.end(),
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
std::vector<CheatList> out;
out.reserve(patch_dirs.size());
std::vector<Memory::CheatEntry> out;
for (const auto& subdir : patch_dirs) {
auto cheats_dir = subdir->GetSubdirectory("cheats");
if (cheats_dir != nullptr) {
auto res = ReadCheatFileFromFolder(system, title_id, build_id_, cheats_dir, true);
if (res.has_value()) {
out.push_back(std::move(*res));
std::copy(res->begin(), res->end(), std::back_inserter(out));
continue;
}
res = ReadCheatFileFromFolder(system, title_id, build_id_, cheats_dir, false);
if (res.has_value())
out.push_back(std::move(*res));
if (res.has_value()) {
std::copy(res->begin(), res->end(), std::back_inserter(out));
}
}
}
@@ -284,7 +309,8 @@ std::vector<CheatList> PatchManager::CreateCheatList(const Core::System& system,
}
static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) {
const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
const auto load_dir =
Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
if ((type != ContentRecordType::Program && type != ContentRecordType::Data) ||
load_dir == nullptr || load_dir->GetSize() <= 0) {
return;
@@ -393,6 +419,8 @@ static bool IsDirValidAndNonEmpty(const VirtualDir& dir) {
std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNames(
VirtualFile update_raw) const {
if (title_id == 0)
return {};
std::map<std::string, std::string, std::less<>> out;
const auto& installed = Core::System::GetInstance().GetContentProvider();
const auto& disabled = Settings::values.disabled_addons[title_id];
@@ -423,7 +451,8 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
}
// General Mods (LayeredFS and IPS)
const auto mod_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
const auto mod_dir =
Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
if (mod_dir != nullptr && mod_dir->GetSize() > 0) {
for (const auto& mod : mod_dir->GetSubdirectories()) {
std::string types;

View File

@@ -8,9 +8,9 @@
#include <memory>
#include <string>
#include "common/common_types.h"
#include "core/file_sys/cheat_engine.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/vfs.h"
#include "core/memory/dmnt_cheat_types.h"
namespace Core {
class System;
@@ -51,8 +51,8 @@ public:
bool HasNSOPatch(const std::array<u8, 0x20>& build_id) const;
// Creates a CheatList object with all
std::vector<CheatList> CreateCheatList(const Core::System& system,
const std::array<u8, 0x20>& build_id) const;
std::vector<Memory::CheatEntry> CreateCheatList(const Core::System& system,
const std::array<u8, 0x20>& build_id) const;
// Currently tracked RomFS patches:
// - Game Updates

View File

@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <algorithm>
#include <random>
#include <regex>
#include <mbedtls/sha256.h>
#include "common/assert.h"
@@ -48,18 +49,21 @@ static bool FollowsTwoDigitDirFormat(std::string_view name) {
static bool FollowsNcaIdFormat(std::string_view name) {
static const std::regex nca_id_regex("[0-9A-F]{32}\\.nca", std::regex_constants::ECMAScript |
std::regex_constants::icase);
return name.size() == 36 && std::regex_match(name.begin(), name.end(), nca_id_regex);
static const std::regex nca_id_cnmt_regex(
"[0-9A-F]{32}\\.cnmt.nca", std::regex_constants::ECMAScript | std::regex_constants::icase);
return (name.size() == 36 && std::regex_match(name.begin(), name.end(), nca_id_regex)) ||
(name.size() == 41 && std::regex_match(name.begin(), name.end(), nca_id_cnmt_regex));
}
static std::string GetRelativePathFromNcaID(const std::array<u8, 16>& nca_id, bool second_hex_upper,
bool within_two_digit) {
if (!within_two_digit) {
return fmt::format("/{}.nca", Common::HexToString(nca_id, second_hex_upper));
}
bool within_two_digit, bool cnmt_suffix) {
if (!within_two_digit)
return fmt::format(cnmt_suffix ? "{}.cnmt.nca" : "/{}.nca",
Common::HexToString(nca_id, second_hex_upper));
Core::Crypto::SHA256Hash hash{};
mbedtls_sha256(nca_id.data(), nca_id.size(), hash.data(), 0);
return fmt::format("/000000{:02X}/{}.nca", hash[0],
return fmt::format(cnmt_suffix ? "/000000{:02X}/{}.cnmt.nca" : "/000000{:02X}/{}.nca", hash[0],
Common::HexToString(nca_id, second_hex_upper));
}
@@ -127,6 +131,156 @@ std::vector<ContentProviderEntry> ContentProvider::ListEntries() const {
return ListEntriesFilter(std::nullopt, std::nullopt, std::nullopt);
}
PlaceholderCache::PlaceholderCache(VirtualDir dir_) : dir(std::move(dir_)) {}
bool PlaceholderCache::Create(const NcaID& id, u64 size) const {
const auto path = GetRelativePathFromNcaID(id, false, true, false);
if (dir->GetFileRelative(path) != nullptr) {
return false;
}
Core::Crypto::SHA256Hash hash{};
mbedtls_sha256(id.data(), id.size(), hash.data(), 0);
const auto dirname = fmt::format("000000{:02X}", hash[0]);
const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname);
if (dir2 == nullptr)
return false;
const auto file = dir2->CreateFile(fmt::format("{}.nca", Common::HexToString(id, false)));
if (file == nullptr)
return false;
return file->Resize(size);
}
bool PlaceholderCache::Delete(const NcaID& id) const {
const auto path = GetRelativePathFromNcaID(id, false, true, false);
if (dir->GetFileRelative(path) == nullptr) {
return false;
}
Core::Crypto::SHA256Hash hash{};
mbedtls_sha256(id.data(), id.size(), hash.data(), 0);
const auto dirname = fmt::format("000000{:02X}", hash[0]);
const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname);
const auto res = dir2->DeleteFile(fmt::format("{}.nca", Common::HexToString(id, false)));
return res;
}
bool PlaceholderCache::Exists(const NcaID& id) const {
const auto path = GetRelativePathFromNcaID(id, false, true, false);
return dir->GetFileRelative(path) != nullptr;
}
bool PlaceholderCache::Write(const NcaID& id, u64 offset, const std::vector<u8>& data) const {
const auto path = GetRelativePathFromNcaID(id, false, true, false);
const auto file = dir->GetFileRelative(path);
if (file == nullptr)
return false;
return file->WriteBytes(data, offset) == data.size();
}
bool PlaceholderCache::Register(RegisteredCache* cache, const NcaID& placeholder,
const NcaID& install) const {
const auto path = GetRelativePathFromNcaID(placeholder, false, true, false);
const auto file = dir->GetFileRelative(path);
if (file == nullptr)
return false;
const auto res = cache->RawInstallNCA(NCA{file}, &VfsRawCopy, false, install);
if (res != InstallResult::Success)
return false;
return Delete(placeholder);
}
bool PlaceholderCache::CleanAll() const {
return dir->GetParentDirectory()->CleanSubdirectoryRecursive(dir->GetName());
}
std::optional<std::array<u8, 0x10>> PlaceholderCache::GetRightsID(const NcaID& id) const {
const auto path = GetRelativePathFromNcaID(id, false, true, false);
const auto file = dir->GetFileRelative(path);
if (file == nullptr)
return std::nullopt;
NCA nca{file};
if (nca.GetStatus() != Loader::ResultStatus::Success &&
nca.GetStatus() != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
return std::nullopt;
}
const auto rights_id = nca.GetRightsId();
if (rights_id == NcaID{})
return std::nullopt;
return rights_id;
}
u64 PlaceholderCache::Size(const NcaID& id) const {
const auto path = GetRelativePathFromNcaID(id, false, true, false);
const auto file = dir->GetFileRelative(path);
if (file == nullptr)
return 0;
return file->GetSize();
}
bool PlaceholderCache::SetSize(const NcaID& id, u64 new_size) const {
const auto path = GetRelativePathFromNcaID(id, false, true, false);
const auto file = dir->GetFileRelative(path);
if (file == nullptr)
return false;
return file->Resize(new_size);
}
std::vector<NcaID> PlaceholderCache::List() const {
std::vector<NcaID> out;
for (const auto& sdir : dir->GetSubdirectories()) {
for (const auto& file : sdir->GetFiles()) {
const auto name = file->GetName();
if (name.length() == 36 && name[32] == '.' && name[33] == 'n' && name[34] == 'c' &&
name[35] == 'a') {
out.push_back(Common::HexStringToArray<0x10>(name.substr(0, 32)));
}
}
}
return out;
}
NcaID PlaceholderCache::Generate() {
std::random_device device;
std::mt19937 gen(device());
std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
NcaID out{};
const auto v1 = distribution(gen);
const auto v2 = distribution(gen);
std::memcpy(out.data(), &v1, sizeof(u64));
std::memcpy(out.data() + sizeof(u64), &v2, sizeof(u64));
return out;
}
VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
std::string_view path) const {
const auto file = dir->GetFileRelative(path);
@@ -169,14 +323,18 @@ VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
VirtualFile file;
// Try all four modes of file storage:
// (bit 1 = uppercase/lower, bit 0 = within a two-digit dir)
// 00: /000000**/{:032X}.nca
// 01: /{:032X}.nca
// 10: /000000**/{:032x}.nca
// 11: /{:032x}.nca
for (u8 i = 0; i < 4; ++i) {
const auto path = GetRelativePathFromNcaID(id, (i & 0b10) == 0, (i & 0b01) == 0);
// Try all five relevant modes of file storage:
// (bit 2 = uppercase/lower, bit 1 = within a two-digit dir, bit 0 = .cnmt suffix)
// 000: /000000**/{:032X}.nca
// 010: /{:032X}.nca
// 100: /000000**/{:032x}.nca
// 110: /{:032x}.nca
// 111: /{:032x}.cnmt.nca
for (u8 i = 0; i < 8; ++i) {
if ((i % 2) == 1 && i != 7)
continue;
const auto path =
GetRelativePathFromNcaID(id, (i & 0b100) == 0, (i & 0b010) == 0, (i & 0b001) == 0b001);
file = OpenFileOrDirectoryConcat(dir, path);
if (file != nullptr)
return file;
@@ -472,7 +630,7 @@ InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFuncti
memcpy(id.data(), hash.data(), 16);
}
std::string path = GetRelativePathFromNcaID(id, false, true);
std::string path = GetRelativePathFromNcaID(id, false, true, false);
if (GetFileAtID(id) != nullptr && !overwrite_if_exists) {
LOG_WARNING(Loader, "Attempting to overwrite existing NCA. Skipping...");

View File

@@ -25,6 +25,8 @@ enum class NCAContentType : u8;
enum class TitleType : u8;
struct ContentRecord;
struct MetaRecord;
class RegisteredCache;
using NcaID = std::array<u8, 0x10>;
using ContentProviderParsingFunction = std::function<VirtualFile(const VirtualFile&, const NcaID&)>;
@@ -89,6 +91,27 @@ protected:
Core::Crypto::KeyManager keys;
};
class PlaceholderCache {
public:
explicit PlaceholderCache(VirtualDir dir);
bool Create(const NcaID& id, u64 size) const;
bool Delete(const NcaID& id) const;
bool Exists(const NcaID& id) const;
bool Write(const NcaID& id, u64 offset, const std::vector<u8>& data) const;
bool Register(RegisteredCache* cache, const NcaID& placeholder, const NcaID& install) const;
bool CleanAll() const;
std::optional<std::array<u8, 0x10>> GetRightsID(const NcaID& id) const;
u64 Size(const NcaID& id) const;
bool SetSize(const NcaID& id, u64 new_size) const;
std::vector<NcaID> List() const;
static NcaID Generate();
private:
VirtualDir dir;
};
/*
* A class that catalogues NCAs in the registered directory structure.
* Nintendo's registered format follows this structure:
@@ -103,6 +126,8 @@ protected:
* when 4GB splitting can be ignored.)
*/
class RegisteredCache : public ContentProvider {
friend class PlaceholderCache;
public:
// Parsing function defines the conversion from raw file to NCA. If there are other steps
// besides creating the NCA from the file (e.g. NAX0 on SD Card), that should go in a custom

View File

@@ -7,6 +7,7 @@
#include "common/common_types.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/file_sys/card_image.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/patch_manager.h"
@@ -34,7 +35,7 @@ void RomFSFactory::SetPackedUpdate(VirtualFile update_raw) {
this->update_raw = std::move(update_raw);
}
ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() {
ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() const {
if (!updatable)
return MakeResult<VirtualFile>(file);
@@ -43,7 +44,8 @@ ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() {
patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw));
}
ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, ContentRecordType type) {
ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage,
ContentRecordType type) const {
std::shared_ptr<NCA> res;
switch (storage) {
@@ -51,13 +53,17 @@ ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, Conte
res = Core::System::GetInstance().GetContentProvider().GetEntry(title_id, type);
break;
case StorageId::NandSystem:
res = Service::FileSystem::GetSystemNANDContents()->GetEntry(title_id, type);
res =
Core::System::GetInstance().GetFileSystemController().GetSystemNANDContents()->GetEntry(
title_id, type);
break;
case StorageId::NandUser:
res = Service::FileSystem::GetUserNANDContents()->GetEntry(title_id, type);
res = Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->GetEntry(
title_id, type);
break;
case StorageId::SdCard:
res = Service::FileSystem::GetSDMCContents()->GetEntry(title_id, type);
res = Core::System::GetInstance().GetFileSystemController().GetSDMCContents()->GetEntry(
title_id, type);
break;
default:
UNIMPLEMENTED_MSG("Unimplemented storage_id={:02X}", static_cast<u8>(storage));

View File

@@ -33,8 +33,8 @@ public:
~RomFSFactory();
void SetPackedUpdate(VirtualFile update_raw);
ResultVal<VirtualFile> OpenCurrentProcess();
ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, ContentRecordType type);
ResultVal<VirtualFile> OpenCurrentProcess() const;
ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, ContentRecordType type) const;
private:
VirtualFile file;

View File

@@ -15,22 +15,8 @@ namespace FileSys {
constexpr char SAVE_DATA_SIZE_FILENAME[] = ".yuzu_save_size";
std::string SaveDataDescriptor::DebugInfo() const {
return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, "
"rank={}, index={}]",
static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id,
static_cast<u8>(rank), index);
}
SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {
// Delete all temporary storages
// On hardware, it is expected that temporary storage be empty at first use.
dir->DeleteSubdirectoryRecursive("temp");
}
SaveDataFactory::~SaveDataFactory() = default;
ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataDescriptor& meta) {
namespace {
void PrintSaveDataDescriptorWarnings(SaveDataDescriptor meta) {
if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) {
if (meta.zero_1 != 0) {
LOG_WARNING(Service_FS,
@@ -65,23 +51,51 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, const SaveDat
"non-zero ({:016X}{:016X})",
meta.user_id[1], meta.user_id[0]);
}
}
} // Anonymous namespace
std::string save_directory =
std::string SaveDataDescriptor::DebugInfo() const {
return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, "
"save_id={:016X}, "
"rank={}, index={}]",
static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id,
static_cast<u8>(rank), index);
}
SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {
// Delete all temporary storages
// On hardware, it is expected that temporary storage be empty at first use.
dir->DeleteSubdirectoryRecursive("temp");
}
SaveDataFactory::~SaveDataFactory() = default;
ResultVal<VirtualDir> SaveDataFactory::Create(SaveDataSpaceId space,
const SaveDataDescriptor& meta) const {
PrintSaveDataDescriptorWarnings(meta);
const auto save_directory =
GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id);
// TODO(DarkLordZach): Try to not create when opening, there are dedicated create save methods.
// But, user_ids don't match so this works for now.
auto out = dir->CreateDirectoryRelative(save_directory);
// Return an error if the save data doesn't actually exist.
if (out == nullptr) {
// TODO(DarkLordZach): Find out correct error code.
return ResultCode(-1);
}
return MakeResult<VirtualDir>(std::move(out));
}
ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space,
const SaveDataDescriptor& meta) const {
const auto save_directory =
GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id);
auto out = dir->GetDirectoryRelative(save_directory);
if (out == nullptr) {
// TODO(bunnei): This is a work-around to always create a save data directory if it does not
// already exist. This is a hack, as we do not understand yet how this works on hardware.
// Without a save data directory, many games will assert on boot. This should not have any
// bad side-effects.
out = dir->CreateDirectoryRelative(save_directory);
}
// Return an error if the save data doesn't actually exist.
if (out == nullptr) {
// TODO(Subv): Find out correct error code.
@@ -152,7 +166,7 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
}
void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
SaveDataSize new_value) {
SaveDataSize new_value) const {
const auto path = GetFullPath(SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
const auto dir = GetOrCreateDirectoryRelative(this->dir, path);

View File

@@ -64,7 +64,8 @@ public:
explicit SaveDataFactory(VirtualDir dir);
~SaveDataFactory();
ResultVal<VirtualDir> Open(SaveDataSpaceId space, const SaveDataDescriptor& meta);
ResultVal<VirtualDir> Create(SaveDataSpaceId space, const SaveDataDescriptor& meta) const;
ResultVal<VirtualDir> Open(SaveDataSpaceId space, const SaveDataDescriptor& meta) const;
VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;
@@ -73,7 +74,8 @@ public:
u128 user_id, u64 save_id);
SaveDataSize ReadSaveDataSize(SaveDataType type, u64 title_id, u128 user_id) const;
void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, SaveDataSize new_value);
void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
SaveDataSize new_value) const;
private:
VirtualDir dir;

View File

@@ -6,6 +6,7 @@
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/sdmc_factory.h"
#include "core/file_sys/xts_archive.h"
#include "core/settings.h"
namespace FileSys {
@@ -14,16 +15,38 @@ SDMCFactory::SDMCFactory(VirtualDir dir_)
GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/registered"),
[](const VirtualFile& file, const NcaID& id) {
return NAX{file, id}.GetDecrypted();
})) {}
})),
placeholder(std::make_unique<PlaceholderCache>(
GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/placehld"))) {}
SDMCFactory::~SDMCFactory() = default;
ResultVal<VirtualDir> SDMCFactory::Open() {
ResultVal<VirtualDir> SDMCFactory::Open() const {
return MakeResult<VirtualDir>(dir);
}
VirtualDir SDMCFactory::GetSDMCContentDirectory() const {
return GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents");
}
RegisteredCache* SDMCFactory::GetSDMCContents() const {
return contents.get();
}
PlaceholderCache* SDMCFactory::GetSDMCPlaceholder() const {
return placeholder.get();
}
VirtualDir SDMCFactory::GetImageDirectory() const {
return GetOrCreateDirectoryRelative(dir, "/Nintendo/Album");
}
u64 SDMCFactory::GetSDMCFreeSpace() const {
return GetSDMCTotalSpace() - dir->GetSize();
}
u64 SDMCFactory::GetSDMCTotalSpace() const {
return static_cast<u64>(Settings::values.sdmc_size);
}
} // namespace FileSys

View File

@@ -11,6 +11,7 @@
namespace FileSys {
class RegisteredCache;
class PlaceholderCache;
/// File system interface to the SDCard archive
class SDMCFactory {
@@ -18,13 +19,23 @@ public:
explicit SDMCFactory(VirtualDir dir);
~SDMCFactory();
ResultVal<VirtualDir> Open();
ResultVal<VirtualDir> Open() const;
VirtualDir GetSDMCContentDirectory() const;
RegisteredCache* GetSDMCContents() const;
PlaceholderCache* GetSDMCPlaceholder() const;
VirtualDir GetImageDirectory() const;
u64 GetSDMCFreeSpace() const;
u64 GetSDMCTotalSpace() const;
private:
VirtualDir dir;
std::unique_ptr<RegisteredCache> contents;
std::unique_ptr<PlaceholderCache> placeholder;
};
} // namespace FileSys

View File

@@ -14,6 +14,7 @@
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/partition_filesystem.h"
#include "core/file_sys/program_metadata.h"
#include "core/file_sys/submission_package.h"
#include "core/loader/loader.h"
@@ -78,6 +79,10 @@ Loader::ResultStatus NSP::GetStatus() const {
}
Loader::ResultStatus NSP::GetProgramStatus(u64 title_id) const {
if (IsExtractedType() && GetExeFS() != nullptr && FileSys::IsDirectoryExeFS(GetExeFS())) {
return Loader::ResultStatus::Success;
}
const auto iter = program_status.find(title_id);
if (iter == program_status.end())
return Loader::ResultStatus::ErrorNSPMissingProgramNCA;
@@ -85,12 +90,29 @@ Loader::ResultStatus NSP::GetProgramStatus(u64 title_id) const {
}
u64 NSP::GetFirstTitleID() const {
if (IsExtractedType()) {
return GetProgramTitleID();
}
if (program_status.empty())
return 0;
return program_status.begin()->first;
}
u64 NSP::GetProgramTitleID() const {
if (IsExtractedType()) {
if (GetExeFS() == nullptr || !IsDirectoryExeFS(GetExeFS())) {
return 0;
}
ProgramMetadata meta;
if (meta.Load(GetExeFS()->GetFile("main.npdm")) == Loader::ResultStatus::Success) {
return meta.GetTitleID();
} else {
return 0;
}
}
const auto out = GetFirstTitleID();
if ((out & 0x800) == 0)
return out;
@@ -102,6 +124,10 @@ u64 NSP::GetProgramTitleID() const {
}
std::vector<u64> NSP::GetTitleIDs() const {
if (IsExtractedType()) {
return {GetProgramTitleID()};
}
std::vector<u64> out;
out.reserve(ncas.size());
for (const auto& kv : ncas)
@@ -222,7 +248,8 @@ void NSP::InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files) {
void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
for (const auto& outer_file : files) {
if (outer_file->GetName().substr(outer_file->GetName().size() - 9) != ".cnmt.nca") {
if (outer_file->GetName().size() < 9 ||
outer_file->GetName().substr(outer_file->GetName().size() - 9) != ".cnmt.nca") {
continue;
}

View File

@@ -31,6 +31,9 @@
namespace Service::Account {
constexpr ResultCode ERR_INVALID_BUFFER_SIZE{ErrorModule::Account, 30};
constexpr ResultCode ERR_FAILED_SAVE_DATA{ErrorModule::Account, 100};
static std::string GetImagePath(Common::UUID uuid) {
return FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
"/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg";
@@ -41,22 +44,33 @@ static constexpr u32 SanitizeJPEGSize(std::size_t size) {
return static_cast<u32>(std::min(size, max_jpeg_image_size));
}
class IProfile final : public ServiceFramework<IProfile> {
class IProfileCommon : public ServiceFramework<IProfileCommon> {
public:
explicit IProfile(Common::UUID user_id, ProfileManager& profile_manager)
: ServiceFramework("IProfile"), profile_manager(profile_manager), user_id(user_id) {
explicit IProfileCommon(const char* name, bool editor_commands, Common::UUID user_id,
ProfileManager& profile_manager)
: ServiceFramework(name), profile_manager(profile_manager), user_id(user_id) {
static const FunctionInfo functions[] = {
{0, &IProfile::Get, "Get"},
{1, &IProfile::GetBase, "GetBase"},
{10, &IProfile::GetImageSize, "GetImageSize"},
{11, &IProfile::LoadImage, "LoadImage"},
{0, &IProfileCommon::Get, "Get"},
{1, &IProfileCommon::GetBase, "GetBase"},
{10, &IProfileCommon::GetImageSize, "GetImageSize"},
{11, &IProfileCommon::LoadImage, "LoadImage"},
};
RegisterHandlers(functions);
if (editor_commands) {
static const FunctionInfo editor_functions[] = {
{100, &IProfileCommon::Store, "Store"},
{101, &IProfileCommon::StoreWithImage, "StoreWithImage"},
};
RegisterHandlers(editor_functions);
}
}
private:
protected:
void Get(Kernel::HLERequestContext& ctx) {
LOG_INFO(Service_ACC, "called user_id={}", user_id.Format());
LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
ProfileBase profile_base{};
ProfileData data{};
if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) {
@@ -75,7 +89,7 @@ private:
}
void GetBase(Kernel::HLERequestContext& ctx) {
LOG_INFO(Service_ACC, "called user_id={}", user_id.Format());
LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
ProfileBase profile_base{};
if (profile_manager.GetProfileBase(user_id, profile_base)) {
IPC::ResponseBuilder rb{ctx, 16};
@@ -127,10 +141,91 @@ private:
}
}
const ProfileManager& profile_manager;
void Store(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto base = rp.PopRaw<ProfileBase>();
const auto user_data = ctx.ReadBuffer();
LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid={}",
Common::StringFromFixedZeroTerminatedBuffer(
reinterpret_cast<const char*>(base.username.data()), base.username.size()),
base.timestamp, base.user_uuid.Format());
if (user_data.size() < sizeof(ProfileData)) {
LOG_ERROR(Service_ACC, "ProfileData buffer too small!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_INVALID_BUFFER_SIZE);
return;
}
ProfileData data;
std::memcpy(&data, user_data.data(), sizeof(ProfileData));
if (!profile_manager.SetProfileBaseAndData(user_id, base, data)) {
LOG_ERROR(Service_ACC, "Failed to update profile data and base!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_FAILED_SAVE_DATA);
return;
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void StoreWithImage(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto base = rp.PopRaw<ProfileBase>();
const auto user_data = ctx.ReadBuffer();
const auto image_data = ctx.ReadBuffer(1);
LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid={}",
Common::StringFromFixedZeroTerminatedBuffer(
reinterpret_cast<const char*>(base.username.data()), base.username.size()),
base.timestamp, base.user_uuid.Format());
if (user_data.size() < sizeof(ProfileData)) {
LOG_ERROR(Service_ACC, "ProfileData buffer too small!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_INVALID_BUFFER_SIZE);
return;
}
ProfileData data;
std::memcpy(&data, user_data.data(), sizeof(ProfileData));
FileUtil::IOFile image(GetImagePath(user_id), "wb");
if (!image.IsOpen() || !image.Resize(image_data.size()) ||
image.WriteBytes(image_data.data(), image_data.size()) != image_data.size() ||
!profile_manager.SetProfileBaseAndData(user_id, base, data)) {
LOG_ERROR(Service_ACC, "Failed to update profile data, base, and image!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_FAILED_SAVE_DATA);
return;
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
ProfileManager& profile_manager;
Common::UUID user_id; ///< The user id this profile refers to.
};
class IProfile final : public IProfileCommon {
public:
IProfile(Common::UUID user_id, ProfileManager& profile_manager)
: IProfileCommon("IProfile", false, user_id, profile_manager) {}
};
class IProfileEditor final : public IProfileCommon {
public:
IProfileEditor(Common::UUID user_id, ProfileManager& profile_manager)
: IProfileCommon("IProfileEditor", true, user_id, profile_manager) {}
};
class IManagerForApplication final : public ServiceFramework<IManagerForApplication> {
public:
IManagerForApplication() : ServiceFramework("IManagerForApplication") {
@@ -168,7 +263,7 @@ private:
};
void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) {
LOG_INFO(Service_ACC, "called");
LOG_DEBUG(Service_ACC, "called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(static_cast<u32>(profile_manager->GetUserCount()));
@@ -177,7 +272,7 @@ void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) {
void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
Common::UUID user_id = rp.PopRaw<Common::UUID>();
LOG_INFO(Service_ACC, "called user_id={}", user_id.Format());
LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
@@ -185,21 +280,21 @@ void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) {
}
void Module::Interface::ListAllUsers(Kernel::HLERequestContext& ctx) {
LOG_INFO(Service_ACC, "called");
LOG_DEBUG(Service_ACC, "called");
ctx.WriteBuffer(profile_manager->GetAllUsers());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void Module::Interface::ListOpenUsers(Kernel::HLERequestContext& ctx) {
LOG_INFO(Service_ACC, "called");
LOG_DEBUG(Service_ACC, "called");
ctx.WriteBuffer(profile_manager->GetOpenUsers());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) {
LOG_INFO(Service_ACC, "called");
LOG_DEBUG(Service_ACC, "called");
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(RESULT_SUCCESS);
rb.PushRaw<Common::UUID>(profile_manager->GetLastOpenedUser());
@@ -322,6 +417,17 @@ void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx
rb.Push(is_locked);
}
void Module::Interface::GetProfileEditor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
Common::UUID user_id = rp.PopRaw<Common::UUID>();
LOG_DEBUG(Service_ACC, "called, user_id={}", user_id.Format());
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IProfileEditor>(user_id, *profile_manager);
}
void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
// A u8 is passed into this function which we can safely ignore. It's to determine if we have

View File

@@ -32,6 +32,7 @@ public:
void IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx);
void TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx);
void IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx);
void GetProfileEditor(Kernel::HLERequestContext& ctx);
private:
ResultCode InitializeApplicationInfoBase(u64 process_id);

View File

@@ -41,7 +41,7 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
{202, nullptr, "CancelUserRegistration"},
{203, nullptr, "DeleteUser"},
{204, nullptr, "SetUserPosition"},
{205, nullptr, "GetProfileEditor"},
{205, &ACC_SU::GetProfileEditor, "GetProfileEditor"},
{206, nullptr, "CompleteUserRegistrationForcibly"},
{210, nullptr, "CreateFloatingRegistrationRequest"},
{230, nullptr, "AuthenticateServiceAsync"},

View File

@@ -305,6 +305,17 @@ bool ProfileManager::SetProfileBase(UUID uuid, const ProfileBase& profile_new) {
return true;
}
bool ProfileManager::SetProfileBaseAndData(Common::UUID uuid, const ProfileBase& profile_new,
const ProfileData& data_new) {
const auto index = GetUserIndex(uuid);
if (index.has_value() && SetProfileBase(uuid, profile_new)) {
profiles[*index].data = data_new;
return true;
}
return false;
}
void ProfileManager::ParseUserSaveFile() {
FileUtil::IOFile save(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
ACC_SAVE_AVATORS_BASE_PATH + "profiles.dat",

View File

@@ -91,6 +91,8 @@ public:
bool RemoveUser(Common::UUID uuid);
bool SetProfileBase(Common::UUID uuid, const ProfileBase& profile_new);
bool SetProfileBaseAndData(Common::UUID uuid, const ProfileBase& profile_new,
const ProfileData& data_new);
private:
void ParseUserSaveFile();

View File

@@ -232,12 +232,12 @@ IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} {
IDebugFunctions::~IDebugFunctions() = default;
ISelfController::ISelfController(Core::System& system_,
std::shared_ptr<NVFlinger::NVFlinger> nvflinger_)
: ServiceFramework("ISelfController"), nvflinger(std::move(nvflinger_)) {
ISelfController::ISelfController(Core::System& system,
std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
: ServiceFramework("ISelfController"), system(system), nvflinger(std::move(nvflinger)) {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "Exit"},
{0, &ISelfController::Exit, "Exit"},
{1, &ISelfController::LockExit, "LockExit"},
{2, &ISelfController::UnlockExit, "UnlockExit"},
{3, &ISelfController::EnterFatalSection, "EnterFatalSection"},
@@ -282,7 +282,7 @@ ISelfController::ISelfController(Core::System& system_,
RegisterHandlers(functions);
auto& kernel = system_.Kernel();
auto& kernel = system.Kernel();
launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
"ISelfController:LaunchableEvent");
@@ -298,15 +298,28 @@ ISelfController::ISelfController(Core::System& system_,
ISelfController::~ISelfController() = default;
void ISelfController::Exit(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
system.Shutdown();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void ISelfController::LockExit(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
LOG_DEBUG(Service_AM, "called");
system.SetExitLock(true);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
LOG_DEBUG(Service_AM, "called");
system.SetExitLock(false);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -550,6 +563,10 @@ void AppletMessageQueue::OperationModeChanged() {
on_operation_mode_changed.writable->Signal();
}
void AppletMessageQueue::RequestExit() {
PushMessage(AppletMessage::ExitRequested);
}
ICommonStateGetter::ICommonStateGetter(Core::System& system,
std::shared_ptr<AppletMessageQueue> msg_queue)
: ServiceFramework("ICommonStateGetter"), system(system), msg_queue(std::move(msg_queue)) {
@@ -1066,7 +1083,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
auto& kernel = system.Kernel();
gpu_error_detected_event = Kernel::WritableEvent::CreateEventPair(
kernel, Kernel::ResetType::Manual, "IApplicationFunctions:GpuErrorDetectedSystemEvent");
}
@@ -1143,13 +1160,21 @@ void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(
void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
u128 uid = rp.PopRaw<u128>(); // What does this do?
LOG_WARNING(Service, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]);
u128 user_id = rp.PopRaw<u128>();
LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]);
FileSys::SaveDataDescriptor descriptor{};
descriptor.title_id = Core::CurrentProcess()->GetTitleID();
descriptor.user_id = user_id;
descriptor.type = FileSys::SaveDataType::SaveData;
const auto res = system.GetFileSystemController().CreateSaveData(
FileSys::SaveDataSpaceId::NandUser, descriptor);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push(res.Code());
rb.Push<u64>(0);
} // namespace Service::AM
}
void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) {
// Takes an input u32 Result, no output.
@@ -1261,8 +1286,8 @@ void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) {
"new_journal={:016X}",
static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size);
const auto title_id = system.CurrentProcess()->GetTitleID();
FileSystem::WriteSaveDataSize(type, title_id, user_id, {new_normal_size, new_journal_size});
system.GetFileSystemController().WriteSaveDataSize(
type, system.CurrentProcess()->GetTitleID(), user_id, {new_normal_size, new_journal_size});
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
@@ -1281,8 +1306,8 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", static_cast<u8>(type),
user_id[1], user_id[0]);
const auto title_id = system.CurrentProcess()->GetTitleID();
const auto size = FileSystem::ReadSaveDataSize(type, title_id, user_id);
const auto size = system.GetFileSystemController().ReadSaveDataSize(
type, system.CurrentProcess()->GetTitleID(), user_id);
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(RESULT_SUCCESS);

View File

@@ -45,6 +45,7 @@ class AppletMessageQueue {
public:
enum class AppletMessage : u32 {
NoMessage = 0,
ExitRequested = 4,
FocusStateChanged = 15,
OperationModeChanged = 30,
PerformanceModeChanged = 31,
@@ -59,6 +60,7 @@ public:
AppletMessage PopMessage();
std::size_t GetMessageCount() const;
void OperationModeChanged();
void RequestExit();
private:
std::queue<AppletMessage> messages;
@@ -123,6 +125,7 @@ public:
~ISelfController() override;
private:
void Exit(Kernel::HLERequestContext& ctx);
void LockExit(Kernel::HLERequestContext& ctx);
void UnlockExit(Kernel::HLERequestContext& ctx);
void EnterFatalSection(Kernel::HLERequestContext& ctx);
@@ -151,6 +154,8 @@ private:
u32 idle_time_detection_extension = 0;
u64 num_fatal_sections_entered = 0;
bool is_auto_sleep_disabled = false;
Core::System& system;
};
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {

View File

@@ -9,12 +9,18 @@
#include "core/hle/service/service.h"
namespace Service {
namespace FileSystem {
class FileSystemController;
}
namespace NVFlinger {
class NVFlinger;
}
namespace AM {
class AppletMessageQueue;
class AppletAE final : public ServiceFramework<AppletAE> {
public:
explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,

View File

@@ -9,12 +9,18 @@
#include "core/hle/service/service.h"
namespace Service {
namespace FileSystem {
class FileSystemController;
}
namespace NVFlinger {
class NVFlinger;
}
namespace AM {
class AppletMessageQueue;
class AppletOE final : public ServiceFramework<AppletOE> {
public:
explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,

View File

@@ -29,9 +29,9 @@ static bool CheckAOCTitleIDMatchesBase(u64 title_id, u64 base) {
return (title_id & DLC_BASE_TITLE_ID_MASK) == base;
}
static std::vector<u64> AccumulateAOCTitleIDs() {
static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) {
std::vector<u64> add_on_content;
const auto& rcu = Core::System::GetInstance().GetContentProvider();
const auto& rcu = system.GetContentProvider();
const auto list =
rcu.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
std::transform(list.begin(), list.end(), std::back_inserter(add_on_content),
@@ -47,7 +47,8 @@ static std::vector<u64> AccumulateAOCTitleIDs() {
return add_on_content;
}
AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs()) {
AOC_U::AOC_U(Core::System& system)
: ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs(system)), system(system) {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "CountAddOnContentByApplicationId"},
@@ -65,7 +66,7 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
auto& kernel = system.Kernel();
aoc_change_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
"GetAddOnContentListChanged:Event");
}
@@ -86,7 +87,7 @@ void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID();
const auto current = system.CurrentProcess()->GetTitleID();
const auto& disabled = Settings::values.disabled_addons[current];
if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) {
@@ -113,7 +114,7 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count,
process_id);
const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID();
const auto current = system.CurrentProcess()->GetTitleID();
std::vector<u32> out;
const auto& disabled = Settings::values.disabled_addons[current];
@@ -159,7 +160,7 @@ void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
const auto title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
const auto title_id = system.CurrentProcess()->GetTitleID();
FileSys::PatchManager pm{title_id};
const auto res = pm.GetControlMetadata();
@@ -196,8 +197,8 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) {
rb.PushCopyObjects(aoc_change_event.readable);
}
void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<AOC_U>()->InstallAsService(service_manager);
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
std::make_shared<AOC_U>(system)->InstallAsService(service_manager);
}
} // namespace Service::AOC

View File

@@ -14,7 +14,7 @@ namespace Service::AOC {
class AOC_U final : public ServiceFramework<AOC_U> {
public:
AOC_U();
explicit AOC_U(Core::System& system);
~AOC_U() override;
private:
@@ -26,9 +26,10 @@ private:
std::vector<u64> add_on_content;
Kernel::EventPair aoc_change_event;
Core::System& system;
};
/// Registers all AOC services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
} // namespace Service::AOC

View File

@@ -16,7 +16,7 @@ namespace Service::BtDrv {
class Bt final : public ServiceFramework<Bt> {
public:
explicit Bt() : ServiceFramework{"bt"} {
explicit Bt(Core::System& system) : ServiceFramework{"bt"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "LeClientReadCharacteristic"},
@@ -33,7 +33,7 @@ public:
// clang-format on
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
auto& kernel = system.Kernel();
register_event = Kernel::WritableEvent::CreateEventPair(
kernel, Kernel::ResetType::Automatic, "BT:RegisterEvent");
}
@@ -163,9 +163,9 @@ public:
}
};
void InstallInterfaces(SM::ServiceManager& sm) {
void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
std::make_shared<BtDrv>()->InstallAsService(sm);
std::make_shared<Bt>()->InstallAsService(sm);
std::make_shared<Bt>(system)->InstallAsService(sm);
}
} // namespace Service::BtDrv

View File

@@ -8,9 +8,13 @@ namespace Service::SM {
class ServiceManager;
}
namespace Core {
class System;
}
namespace Service::BtDrv {
/// Registers all BtDrv services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& sm);
void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
} // namespace Service::BtDrv

View File

@@ -17,7 +17,7 @@ namespace Service::BTM {
class IBtmUserCore final : public ServiceFramework<IBtmUserCore> {
public:
explicit IBtmUserCore() : ServiceFramework{"IBtmUserCore"} {
explicit IBtmUserCore(Core::System& system) : ServiceFramework{"IBtmUserCore"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IBtmUserCore::AcquireBleScanEvent, "AcquireBleScanEvent"},
@@ -56,7 +56,7 @@ public:
// clang-format on
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
auto& kernel = system.Kernel();
scan_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
"IBtmUserCore:ScanEvent");
connection_event = Kernel::WritableEvent::CreateEventPair(
@@ -108,7 +108,7 @@ private:
class BTM_USR final : public ServiceFramework<BTM_USR> {
public:
explicit BTM_USR() : ServiceFramework{"btm:u"} {
explicit BTM_USR(Core::System& system) : ServiceFramework{"btm:u"}, system(system) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &BTM_USR::GetCore, "GetCore"},
@@ -123,8 +123,10 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IBtmUserCore>();
rb.PushIpcInterface<IBtmUserCore>(system);
}
Core::System& system;
};
class BTM final : public ServiceFramework<BTM> {
@@ -268,11 +270,11 @@ private:
}
};
void InstallInterfaces(SM::ServiceManager& sm) {
void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
std::make_shared<BTM>()->InstallAsService(sm);
std::make_shared<BTM_DBG>()->InstallAsService(sm);
std::make_shared<BTM_SYS>()->InstallAsService(sm);
std::make_shared<BTM_USR>()->InstallAsService(sm);
std::make_shared<BTM_USR>(system)->InstallAsService(sm);
}
} // namespace Service::BTM

View File

@@ -8,8 +8,12 @@ namespace Service::SM {
class ServiceManager;
}
namespace Core {
class System;
};
namespace Service::BTM {
void InstallInterfaces(SM::ServiceManager& sm);
void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
} // namespace Service::BTM

View File

@@ -20,8 +20,8 @@
namespace Service::Fatal {
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
: ServiceFramework(name), module(std::move(module)) {}
Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name)
: ServiceFramework(name), module(std::move(module)), system(system) {}
Module::Interface::~Interface() = default;
@@ -64,7 +64,8 @@ enum class FatalType : u32 {
ErrorScreen = 2,
};
static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) {
static void GenerateErrorReport(Core::System& system, ResultCode error_code,
const FatalInfo& info) {
const auto title_id = Core::CurrentProcess()->GetTitleID();
std::string crash_report = fmt::format(
"Yuzu {}-{} crash report\n"
@@ -101,18 +102,19 @@ static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) {
LOG_ERROR(Service_Fatal, "{}", crash_report);
Core::System::GetInstance().GetReporter().SaveCrashReport(
system.GetReporter().SaveCrashReport(
title_id, error_code, info.set_flags, info.program_entry_point, info.sp, info.pc,
info.pstate, info.afsr0, info.afsr1, info.esr, info.far, info.registers, info.backtrace,
info.backtrace_size, info.ArchAsString(), info.unk10);
}
static void ThrowFatalError(ResultCode error_code, FatalType fatal_type, const FatalInfo& info) {
static void ThrowFatalError(Core::System& system, ResultCode error_code, FatalType fatal_type,
const FatalInfo& info) {
LOG_ERROR(Service_Fatal, "Threw fatal error type {} with error code 0x{:X}",
static_cast<u32>(fatal_type), error_code.raw);
switch (fatal_type) {
case FatalType::ErrorReportAndScreen:
GenerateErrorReport(error_code, info);
GenerateErrorReport(system, error_code, info);
[[fallthrough]];
case FatalType::ErrorScreen:
// Since we have no fatal:u error screen. We should just kill execution instead
@@ -120,7 +122,7 @@ static void ThrowFatalError(ResultCode error_code, FatalType fatal_type, const F
break;
// Should not throw a fatal screen but should generate an error report
case FatalType::ErrorReport:
GenerateErrorReport(error_code, info);
GenerateErrorReport(system, error_code, info);
break;
}
}
@@ -130,7 +132,7 @@ void Module::Interface::ThrowFatal(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto error_code = rp.Pop<ResultCode>();
ThrowFatalError(error_code, FatalType::ErrorScreen, {});
ThrowFatalError(system, error_code, FatalType::ErrorScreen, {});
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
@@ -141,7 +143,8 @@ void Module::Interface::ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx) {
const auto error_code = rp.Pop<ResultCode>();
const auto fatal_type = rp.PopEnum<FatalType>();
ThrowFatalError(error_code, fatal_type, {}); // No info is passed with ThrowFatalWithPolicy
ThrowFatalError(system, error_code, fatal_type,
{}); // No info is passed with ThrowFatalWithPolicy
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
@@ -157,15 +160,15 @@ void Module::Interface::ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx)
ASSERT_MSG(fatal_info.size() == sizeof(FatalInfo), "Invalid fatal info buffer size!");
std::memcpy(&info, fatal_info.data(), sizeof(FatalInfo));
ThrowFatalError(error_code, fatal_type, info);
ThrowFatalError(system, error_code, fatal_type, info);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void InstallInterfaces(SM::ServiceManager& service_manager) {
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
auto module = std::make_shared<Module>();
std::make_shared<Fatal_P>(module)->InstallAsService(service_manager);
std::make_shared<Fatal_U>(module)->InstallAsService(service_manager);
std::make_shared<Fatal_P>(module, system)->InstallAsService(service_manager);
std::make_shared<Fatal_U>(module, system)->InstallAsService(service_manager);
}
} // namespace Service::Fatal

View File

@@ -6,13 +6,17 @@
#include "core/hle/service/service.h"
namespace Core {
class System;
}
namespace Service::Fatal {
class Module final {
public:
class Interface : public ServiceFramework<Interface> {
public:
explicit Interface(std::shared_ptr<Module> module, const char* name);
explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name);
~Interface() override;
void ThrowFatal(Kernel::HLERequestContext& ctx);
@@ -21,9 +25,10 @@ public:
protected:
std::shared_ptr<Module> module;
Core::System& system;
};
};
void InstallInterfaces(SM::ServiceManager& service_manager);
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
} // namespace Service::Fatal

View File

@@ -6,8 +6,8 @@
namespace Service::Fatal {
Fatal_P::Fatal_P(std::shared_ptr<Module> module)
: Module::Interface(std::move(module), "fatal:p") {}
Fatal_P::Fatal_P(std::shared_ptr<Module> module, Core::System& system)
: Module::Interface(std::move(module), system, "fatal:p") {}
Fatal_P::~Fatal_P() = default;

View File

@@ -10,7 +10,7 @@ namespace Service::Fatal {
class Fatal_P final : public Module::Interface {
public:
explicit Fatal_P(std::shared_ptr<Module> module);
explicit Fatal_P(std::shared_ptr<Module> module, Core::System& system);
~Fatal_P() override;
};

View File

@@ -6,7 +6,8 @@
namespace Service::Fatal {
Fatal_U::Fatal_U(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "fatal:u") {
Fatal_U::Fatal_U(std::shared_ptr<Module> module, Core::System& system)
: Module::Interface(std::move(module), system, "fatal:u") {
static const FunctionInfo functions[] = {
{0, &Fatal_U::ThrowFatal, "ThrowFatal"},
{1, &Fatal_U::ThrowFatalWithPolicy, "ThrowFatalWithPolicy"},

View File

@@ -10,7 +10,7 @@ namespace Service::Fatal {
class Fatal_U final : public Module::Interface {
public:
explicit Fatal_U(std::shared_ptr<Module> module);
explicit Fatal_U(std::shared_ptr<Module> module, Core::System& system);
~Fatal_U() override;
};

View File

@@ -8,6 +8,7 @@
#include "common/file_util.h"
#include "core/core.h"
#include "core/file_sys/bis_factory.h"
#include "core/file_sys/card_image.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/mode.h"
@@ -25,14 +26,10 @@
#include "core/hle/service/filesystem/fsp_pr.h"
#include "core/hle/service/filesystem/fsp_srv.h"
#include "core/loader/loader.h"
#include "core/settings.h"
namespace Service::FileSystem {
// Size of emulated sd card free space, reported in bytes.
// Just using 32GB because thats reasonable
// TODO(DarkLordZach): Eventually make this configurable in settings.
constexpr u64 EMULATED_SD_REPORTED_SIZE = 32000000000;
// A default size for normal/journal save data size if application control metadata cannot be found.
// This should be large enough to satisfy even the most extreme requirements (~4.2GB)
constexpr u64 SUFFICIENT_SAVE_DATA_SIZE = 0xF0000000;
@@ -226,13 +223,6 @@ ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const s
return MakeResult(dir);
}
u64 VfsDirectoryServiceWrapper::GetFreeSpaceSize() const {
if (backing->IsWritable())
return EMULATED_SD_REPORTED_SIZE;
return 0;
}
ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
const std::string& path_) const {
std::string path(FileUtil::SanitizePath(path_));
@@ -251,44 +241,39 @@ ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
return FileSys::ERROR_PATH_NOT_FOUND;
}
/**
* Map of registered file systems, identified by type. Once an file system is registered here, it
* is never removed until UnregisterFileSystems is called.
*/
static std::unique_ptr<FileSys::RomFSFactory> romfs_factory;
static std::unique_ptr<FileSys::SaveDataFactory> save_data_factory;
static std::unique_ptr<FileSys::SDMCFactory> sdmc_factory;
static std::unique_ptr<FileSys::BISFactory> bis_factory;
FileSystemController::FileSystemController() = default;
ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory) {
ASSERT_MSG(romfs_factory == nullptr, "Tried to register a second RomFS");
FileSystemController::~FileSystemController() = default;
ResultCode FileSystemController::RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory) {
romfs_factory = std::move(factory);
LOG_DEBUG(Service_FS, "Registered RomFS");
return RESULT_SUCCESS;
}
ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory) {
ASSERT_MSG(romfs_factory == nullptr, "Tried to register a second save data");
ResultCode FileSystemController::RegisterSaveData(
std::unique_ptr<FileSys::SaveDataFactory>&& factory) {
ASSERT_MSG(save_data_factory == nullptr, "Tried to register a second save data");
save_data_factory = std::move(factory);
LOG_DEBUG(Service_FS, "Registered save data");
return RESULT_SUCCESS;
}
ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory) {
ResultCode FileSystemController::RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory) {
ASSERT_MSG(sdmc_factory == nullptr, "Tried to register a second SDMC");
sdmc_factory = std::move(factory);
LOG_DEBUG(Service_FS, "Registered SDMC");
return RESULT_SUCCESS;
}
ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory) {
ResultCode FileSystemController::RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory) {
ASSERT_MSG(bis_factory == nullptr, "Tried to register a second BIS");
bis_factory = std::move(factory);
LOG_DEBUG(Service_FS, "Registered BIS");
return RESULT_SUCCESS;
}
void SetPackedUpdate(FileSys::VirtualFile update_raw) {
void FileSystemController::SetPackedUpdate(FileSys::VirtualFile update_raw) {
LOG_TRACE(Service_FS, "Setting packed update for romfs");
if (romfs_factory == nullptr)
@@ -297,7 +282,7 @@ void SetPackedUpdate(FileSys::VirtualFile update_raw) {
romfs_factory->SetPackedUpdate(std::move(update_raw));
}
ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() {
ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFSCurrentProcess() const {
LOG_TRACE(Service_FS, "Opening RomFS for current process");
if (romfs_factory == nullptr) {
@@ -308,8 +293,8 @@ ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() {
return romfs_factory->OpenCurrentProcess();
}
ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
FileSys::ContentRecordType type) {
ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFS(
u64 title_id, FileSys::StorageId storage_id, FileSys::ContentRecordType type) const {
LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}, storage_id={:02X}, type={:02X}",
title_id, static_cast<u8>(storage_id), static_cast<u8>(type));
@@ -321,8 +306,20 @@ ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId stora
return romfs_factory->Open(title_id, storage_id, type);
}
ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
const FileSys::SaveDataDescriptor& descriptor) {
ResultVal<FileSys::VirtualDir> FileSystemController::CreateSaveData(
FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& save_struct) const {
LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}",
static_cast<u8>(space), save_struct.DebugInfo());
if (save_data_factory == nullptr) {
return FileSys::ERROR_ENTITY_NOT_FOUND;
}
return save_data_factory->Create(space, save_struct);
}
ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveData(
FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& descriptor) const {
LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}",
static_cast<u8>(space), descriptor.DebugInfo());
@@ -333,7 +330,8 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
return save_data_factory->Open(space, descriptor);
}
ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) {
ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveDataSpace(
FileSys::SaveDataSpaceId space) const {
LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", static_cast<u8>(space));
if (save_data_factory == nullptr) {
@@ -343,7 +341,7 @@ ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space)
return MakeResult(save_data_factory->GetSaveDataSpaceDirectory(space));
}
ResultVal<FileSys::VirtualDir> OpenSDMC() {
ResultVal<FileSys::VirtualDir> FileSystemController::OpenSDMC() const {
LOG_TRACE(Service_FS, "Opening SDMC");
if (sdmc_factory == nullptr) {
@@ -353,7 +351,92 @@ ResultVal<FileSys::VirtualDir> OpenSDMC() {
return sdmc_factory->Open();
}
FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id) {
ResultVal<FileSys::VirtualDir> FileSystemController::OpenBISPartition(
FileSys::BisPartitionId id) const {
LOG_TRACE(Service_FS, "Opening BIS Partition with id={:08X}", static_cast<u32>(id));
if (bis_factory == nullptr) {
return FileSys::ERROR_ENTITY_NOT_FOUND;
}
auto part = bis_factory->OpenPartition(id);
if (part == nullptr) {
return FileSys::ERROR_INVALID_ARGUMENT;
}
return MakeResult<FileSys::VirtualDir>(std::move(part));
}
ResultVal<FileSys::VirtualFile> FileSystemController::OpenBISPartitionStorage(
FileSys::BisPartitionId id) const {
LOG_TRACE(Service_FS, "Opening BIS Partition Storage with id={:08X}", static_cast<u32>(id));
if (bis_factory == nullptr) {
return FileSys::ERROR_ENTITY_NOT_FOUND;
}
auto part = bis_factory->OpenPartitionStorage(id);
if (part == nullptr) {
return FileSys::ERROR_INVALID_ARGUMENT;
}
return MakeResult<FileSys::VirtualFile>(std::move(part));
}
u64 FileSystemController::GetFreeSpaceSize(FileSys::StorageId id) const {
switch (id) {
case FileSys::StorageId::None:
case FileSys::StorageId::GameCard:
return 0;
case FileSys::StorageId::SdCard:
if (sdmc_factory == nullptr)
return 0;
return sdmc_factory->GetSDMCFreeSpace();
case FileSys::StorageId::Host:
if (bis_factory == nullptr)
return 0;
return bis_factory->GetSystemNANDFreeSpace() + bis_factory->GetUserNANDFreeSpace();
case FileSys::StorageId::NandSystem:
if (bis_factory == nullptr)
return 0;
return bis_factory->GetSystemNANDFreeSpace();
case FileSys::StorageId::NandUser:
if (bis_factory == nullptr)
return 0;
return bis_factory->GetUserNANDFreeSpace();
}
return 0;
}
u64 FileSystemController::GetTotalSpaceSize(FileSys::StorageId id) const {
switch (id) {
case FileSys::StorageId::None:
case FileSys::StorageId::GameCard:
return 0;
case FileSys::StorageId::SdCard:
if (sdmc_factory == nullptr)
return 0;
return sdmc_factory->GetSDMCTotalSpace();
case FileSys::StorageId::Host:
if (bis_factory == nullptr)
return 0;
return bis_factory->GetFullNANDTotalSpace();
case FileSys::StorageId::NandSystem:
if (bis_factory == nullptr)
return 0;
return bis_factory->GetSystemNANDTotalSpace();
case FileSys::StorageId::NandUser:
if (bis_factory == nullptr)
return 0;
return bis_factory->GetUserNANDTotalSpace();
}
return 0;
}
FileSys::SaveDataSize FileSystemController::ReadSaveDataSize(FileSys::SaveDataType type,
u64 title_id, u128 user_id) const {
if (save_data_factory == nullptr) {
return {0, 0};
}
@@ -385,13 +468,32 @@ FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id,
return value;
}
void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
FileSys::SaveDataSize new_value) {
void FileSystemController::WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
FileSys::SaveDataSize new_value) const {
if (save_data_factory != nullptr)
save_data_factory->WriteSaveDataSize(type, title_id, user_id, new_value);
}
FileSys::RegisteredCache* GetSystemNANDContents() {
void FileSystemController::SetGameCard(FileSys::VirtualFile file) {
gamecard = std::make_unique<FileSys::XCI>(file);
const auto dir = gamecard->ConcatenatedPseudoDirectory();
gamecard_registered = std::make_unique<FileSys::RegisteredCache>(dir);
gamecard_placeholder = std::make_unique<FileSys::PlaceholderCache>(dir);
}
FileSys::XCI* FileSystemController::GetGameCard() const {
return gamecard.get();
}
FileSys::RegisteredCache* FileSystemController::GetGameCardContents() const {
return gamecard_registered.get();
}
FileSys::PlaceholderCache* FileSystemController::GetGameCardPlaceholder() const {
return gamecard_placeholder.get();
}
FileSys::RegisteredCache* FileSystemController::GetSystemNANDContents() const {
LOG_TRACE(Service_FS, "Opening System NAND Contents");
if (bis_factory == nullptr)
@@ -400,7 +502,7 @@ FileSys::RegisteredCache* GetSystemNANDContents() {
return bis_factory->GetSystemNANDContents();
}
FileSys::RegisteredCache* GetUserNANDContents() {
FileSys::RegisteredCache* FileSystemController::GetUserNANDContents() const {
LOG_TRACE(Service_FS, "Opening User NAND Contents");
if (bis_factory == nullptr)
@@ -409,7 +511,7 @@ FileSys::RegisteredCache* GetUserNANDContents() {
return bis_factory->GetUserNANDContents();
}
FileSys::RegisteredCache* GetSDMCContents() {
FileSys::RegisteredCache* FileSystemController::GetSDMCContents() const {
LOG_TRACE(Service_FS, "Opening SDMC Contents");
if (sdmc_factory == nullptr)
@@ -418,7 +520,143 @@ FileSys::RegisteredCache* GetSDMCContents() {
return sdmc_factory->GetSDMCContents();
}
FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) {
FileSys::PlaceholderCache* FileSystemController::GetSystemNANDPlaceholder() const {
LOG_TRACE(Service_FS, "Opening System NAND Placeholder");
if (bis_factory == nullptr)
return nullptr;
return bis_factory->GetSystemNANDPlaceholder();
}
FileSys::PlaceholderCache* FileSystemController::GetUserNANDPlaceholder() const {
LOG_TRACE(Service_FS, "Opening User NAND Placeholder");
if (bis_factory == nullptr)
return nullptr;
return bis_factory->GetUserNANDPlaceholder();
}
FileSys::PlaceholderCache* FileSystemController::GetSDMCPlaceholder() const {
LOG_TRACE(Service_FS, "Opening SDMC Placeholder");
if (sdmc_factory == nullptr)
return nullptr;
return sdmc_factory->GetSDMCPlaceholder();
}
FileSys::RegisteredCache* FileSystemController::GetRegisteredCacheForStorage(
FileSys::StorageId id) const {
switch (id) {
case FileSys::StorageId::None:
case FileSys::StorageId::Host:
UNIMPLEMENTED();
return nullptr;
case FileSys::StorageId::GameCard:
return GetGameCardContents();
case FileSys::StorageId::NandSystem:
return GetSystemNANDContents();
case FileSys::StorageId::NandUser:
return GetUserNANDContents();
case FileSys::StorageId::SdCard:
return GetSDMCContents();
}
return nullptr;
}
FileSys::PlaceholderCache* FileSystemController::GetPlaceholderCacheForStorage(
FileSys::StorageId id) const {
switch (id) {
case FileSys::StorageId::None:
case FileSys::StorageId::Host:
UNIMPLEMENTED();
return nullptr;
case FileSys::StorageId::GameCard:
return GetGameCardPlaceholder();
case FileSys::StorageId::NandSystem:
return GetSystemNANDPlaceholder();
case FileSys::StorageId::NandUser:
return GetUserNANDPlaceholder();
case FileSys::StorageId::SdCard:
return GetSDMCPlaceholder();
}
return nullptr;
}
FileSys::VirtualDir FileSystemController::GetSystemNANDContentDirectory() const {
LOG_TRACE(Service_FS, "Opening system NAND content directory");
if (bis_factory == nullptr)
return nullptr;
return bis_factory->GetSystemNANDContentDirectory();
}
FileSys::VirtualDir FileSystemController::GetUserNANDContentDirectory() const {
LOG_TRACE(Service_FS, "Opening user NAND content directory");
if (bis_factory == nullptr)
return nullptr;
return bis_factory->GetUserNANDContentDirectory();
}
FileSys::VirtualDir FileSystemController::GetSDMCContentDirectory() const {
LOG_TRACE(Service_FS, "Opening SDMC content directory");
if (sdmc_factory == nullptr)
return nullptr;
return sdmc_factory->GetSDMCContentDirectory();
}
FileSys::VirtualDir FileSystemController::GetNANDImageDirectory() const {
LOG_TRACE(Service_FS, "Opening NAND image directory");
if (bis_factory == nullptr)
return nullptr;
return bis_factory->GetImageDirectory();
}
FileSys::VirtualDir FileSystemController::GetSDMCImageDirectory() const {
LOG_TRACE(Service_FS, "Opening SDMC image directory");
if (sdmc_factory == nullptr)
return nullptr;
return sdmc_factory->GetImageDirectory();
}
FileSys::VirtualDir FileSystemController::GetContentDirectory(ContentStorageId id) const {
switch (id) {
case ContentStorageId::System:
return GetSystemNANDContentDirectory();
case ContentStorageId::User:
return GetUserNANDContentDirectory();
case ContentStorageId::SdCard:
return GetSDMCContentDirectory();
}
return nullptr;
}
FileSys::VirtualDir FileSystemController::GetImageDirectory(ImageDirectoryId id) const {
switch (id) {
case ImageDirectoryId::NAND:
return GetNANDImageDirectory();
case ImageDirectoryId::SdCard:
return GetSDMCImageDirectory();
}
return nullptr;
}
FileSys::VirtualDir FileSystemController::GetModificationLoadRoot(u64 title_id) const {
LOG_TRACE(Service_FS, "Opening mod load root for tid={:016X}", title_id);
if (bis_factory == nullptr)
@@ -427,7 +665,7 @@ FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) {
return bis_factory->GetModificationLoadRoot(title_id);
}
FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) {
FileSys::VirtualDir FileSystemController::GetModificationDumpRoot(u64 title_id) const {
LOG_TRACE(Service_FS, "Opening mod dump root for tid={:016X}", title_id);
if (bis_factory == nullptr)
@@ -436,7 +674,7 @@ FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) {
return bis_factory->GetModificationDumpRoot(title_id);
}
void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
if (overwrite) {
bis_factory = nullptr;
save_data_factory = nullptr;
@@ -473,11 +711,10 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
}
void InstallInterfaces(Core::System& system) {
romfs_factory = nullptr;
CreateFactories(*system.GetFilesystem(), false);
std::make_shared<FSP_LDR>()->InstallAsService(system.ServiceManager());
std::make_shared<FSP_PR>()->InstallAsService(system.ServiceManager());
std::make_shared<FSP_SRV>(system.GetReporter())->InstallAsService(system.ServiceManager());
std::make_shared<FSP_SRV>(system.GetFileSystemController(), system.GetReporter())
->InstallAsService(system.ServiceManager());
}
} // namespace Service::FileSystem

View File

@@ -14,10 +14,13 @@ namespace FileSys {
class BISFactory;
class RegisteredCache;
class RegisteredCacheUnion;
class PlaceholderCache;
class RomFSFactory;
class SaveDataFactory;
class SDMCFactory;
class XCI;
enum class BisPartitionId : u32;
enum class ContentRecordType : u8;
enum class Mode : u32;
enum class SaveDataSpaceId : u8;
@@ -36,34 +39,91 @@ class ServiceManager;
namespace FileSystem {
ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory);
ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory);
ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory);
ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory);
enum class ContentStorageId : u32 {
System,
User,
SdCard,
};
void SetPackedUpdate(FileSys::VirtualFile update_raw);
ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess();
ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
FileSys::ContentRecordType type);
ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
const FileSys::SaveDataDescriptor& descriptor);
ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space);
ResultVal<FileSys::VirtualDir> OpenSDMC();
enum class ImageDirectoryId : u32 {
NAND,
SdCard,
};
FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id);
void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
FileSys::SaveDataSize new_value);
class FileSystemController {
public:
FileSystemController();
~FileSystemController();
FileSys::RegisteredCache* GetSystemNANDContents();
FileSys::RegisteredCache* GetUserNANDContents();
FileSys::RegisteredCache* GetSDMCContents();
ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory);
ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory);
ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory);
ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory);
FileSys::VirtualDir GetModificationLoadRoot(u64 title_id);
FileSys::VirtualDir GetModificationDumpRoot(u64 title_id);
void SetPackedUpdate(FileSys::VirtualFile update_raw);
ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() const;
ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
FileSys::ContentRecordType type) const;
ResultVal<FileSys::VirtualDir> CreateSaveData(
FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& save_struct) const;
ResultVal<FileSys::VirtualDir> OpenSaveData(
FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& save_struct) const;
ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) const;
ResultVal<FileSys::VirtualDir> OpenSDMC() const;
ResultVal<FileSys::VirtualDir> OpenBISPartition(FileSys::BisPartitionId id) const;
ResultVal<FileSys::VirtualFile> OpenBISPartitionStorage(FileSys::BisPartitionId id) const;
// Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function
// above is called.
void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true);
u64 GetFreeSpaceSize(FileSys::StorageId id) const;
u64 GetTotalSpaceSize(FileSys::StorageId id) const;
FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id,
u128 user_id) const;
void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
FileSys::SaveDataSize new_value) const;
void SetGameCard(FileSys::VirtualFile file);
FileSys::XCI* GetGameCard() const;
FileSys::RegisteredCache* GetSystemNANDContents() const;
FileSys::RegisteredCache* GetUserNANDContents() const;
FileSys::RegisteredCache* GetSDMCContents() const;
FileSys::RegisteredCache* GetGameCardContents() const;
FileSys::PlaceholderCache* GetSystemNANDPlaceholder() const;
FileSys::PlaceholderCache* GetUserNANDPlaceholder() const;
FileSys::PlaceholderCache* GetSDMCPlaceholder() const;
FileSys::PlaceholderCache* GetGameCardPlaceholder() const;
FileSys::RegisteredCache* GetRegisteredCacheForStorage(FileSys::StorageId id) const;
FileSys::PlaceholderCache* GetPlaceholderCacheForStorage(FileSys::StorageId id) const;
FileSys::VirtualDir GetSystemNANDContentDirectory() const;
FileSys::VirtualDir GetUserNANDContentDirectory() const;
FileSys::VirtualDir GetSDMCContentDirectory() const;
FileSys::VirtualDir GetNANDImageDirectory() const;
FileSys::VirtualDir GetSDMCImageDirectory() const;
FileSys::VirtualDir GetContentDirectory(ContentStorageId id) const;
FileSys::VirtualDir GetImageDirectory(ImageDirectoryId id) const;
FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) const;
FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) const;
// Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function
// above is called.
void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true);
private:
std::unique_ptr<FileSys::RomFSFactory> romfs_factory;
std::unique_ptr<FileSys::SaveDataFactory> save_data_factory;
std::unique_ptr<FileSys::SDMCFactory> sdmc_factory;
std::unique_ptr<FileSys::BISFactory> bis_factory;
std::unique_ptr<FileSys::XCI> gamecard;
std::unique_ptr<FileSys::RegisteredCache> gamecard_registered;
std::unique_ptr<FileSys::PlaceholderCache> gamecard_placeholder;
};
void InstallInterfaces(Core::System& system);
@@ -159,12 +219,6 @@ public:
*/
ResultVal<FileSys::VirtualDir> OpenDirectory(const std::string& path);
/**
* Get the free space
* @return The number of free bytes in the archive
*/
u64 GetFreeSpaceSize() const;
/**
* Get the type of the specified path
* @return The type of the specified path or error code

View File

@@ -19,6 +19,7 @@
#include "core/file_sys/mode.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/romfs_factory.h"
#include "core/file_sys/savedata_factory.h"
#include "core/file_sys/system_archive/system_archive.h"
#include "core/file_sys/vfs.h"
@@ -30,6 +31,18 @@
namespace Service::FileSystem {
struct SizeGetter {
std::function<u64()> get_free_size;
std::function<u64()> get_total_size;
static SizeGetter FromStorageId(const FileSystemController& fsc, FileSys::StorageId id) {
return {
[&fsc, id] { return fsc.GetFreeSpaceSize(id); },
[&fsc, id] { return fsc.GetTotalSpaceSize(id); },
};
}
};
enum class FileSystemType : u8 {
Invalid0 = 0,
Invalid1 = 1,
@@ -289,8 +302,8 @@ private:
class IFileSystem final : public ServiceFramework<IFileSystem> {
public:
explicit IFileSystem(FileSys::VirtualDir backend)
: ServiceFramework("IFileSystem"), backend(std::move(backend)) {
explicit IFileSystem(FileSys::VirtualDir backend, SizeGetter size)
: ServiceFramework("IFileSystem"), backend(std::move(backend)), size(std::move(size)) {
static const FunctionInfo functions[] = {
{0, &IFileSystem::CreateFile, "CreateFile"},
{1, &IFileSystem::DeleteFile, "DeleteFile"},
@@ -467,14 +480,31 @@ public:
rb.Push(RESULT_SUCCESS);
}
void GetFreeSpaceSize(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push(size.get_free_size());
}
void GetTotalSpaceSize(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push(size.get_total_size());
}
private:
VfsDirectoryServiceWrapper backend;
SizeGetter size;
};
class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
public:
explicit ISaveDataInfoReader(FileSys::SaveDataSpaceId space)
: ServiceFramework("ISaveDataInfoReader") {
explicit ISaveDataInfoReader(FileSys::SaveDataSpaceId space, FileSystemController& fsc)
: ServiceFramework("ISaveDataInfoReader"), fsc(fsc) {
static const FunctionInfo functions[] = {
{0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
};
@@ -520,8 +550,13 @@ private:
}
void FindAllSaves(FileSys::SaveDataSpaceId space) {
const auto save_root = OpenSaveDataSpace(space);
ASSERT(save_root.Succeeded());
const auto save_root = fsc.OpenSaveDataSpace(space);
if (save_root.Failed() || *save_root == nullptr) {
LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!",
static_cast<u8>(space));
return;
}
for (const auto& type : (*save_root)->GetSubdirectories()) {
if (type->GetName() == "save") {
@@ -610,11 +645,13 @@ private:
};
static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
FileSystemController& fsc;
std::vector<SaveDataInfo> info;
u64 next_entry_index = 0;
};
FSP_SRV::FSP_SRV(const Core::Reporter& reporter) : ServiceFramework("fsp-srv"), reporter(reporter) {
FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter)
: ServiceFramework("fsp-srv"), fsc(fsc), reporter(reporter) {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "OpenFileSystem"},
@@ -754,7 +791,8 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) {
void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
IFileSystem filesystem(OpenSDMC().Unwrap());
IFileSystem filesystem(fsc.OpenSDMC().Unwrap(),
SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -768,8 +806,10 @@ void FSP_SRV::CreateSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
u128 uid = rp.PopRaw<u128>();
LOG_WARNING(Service_FS, "(STUBBED) called save_struct = {}, uid = {:016X}{:016X}",
save_struct.DebugInfo(), uid[1], uid[0]);
LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(),
uid[1], uid[0]);
fsc.CreateSaveData(FileSys::SaveDataSpaceId::NandUser, save_struct);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -786,14 +826,24 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto parameters = rp.PopRaw<Parameters>();
auto dir = OpenSaveData(parameters.save_data_space_id, parameters.descriptor);
auto dir = fsc.OpenSaveData(parameters.save_data_space_id, parameters.descriptor);
if (dir.Failed()) {
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
return;
}
IFileSystem filesystem(std::move(dir.Unwrap()));
FileSys::StorageId id;
if (parameters.save_data_space_id == FileSys::SaveDataSpaceId::NandUser) {
id = FileSys::StorageId::NandUser;
} else if (parameters.save_data_space_id == FileSys::SaveDataSpaceId::SdCardSystem ||
parameters.save_data_space_id == FileSys::SaveDataSpaceId::SdCardUser) {
id = FileSys::StorageId::SdCard;
} else {
id = FileSys::StorageId::NandSystem;
}
IFileSystem filesystem(std::move(dir.Unwrap()), SizeGetter::FromStorageId(fsc, id));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -812,7 +862,7 @@ void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext&
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space));
rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space, fsc));
}
void FSP_SRV::SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
@@ -836,7 +886,7 @@ void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
auto romfs = OpenRomFSCurrentProcess();
auto romfs = fsc.OpenRomFSCurrentProcess();
if (romfs.Failed()) {
// TODO (bunnei): Find the right error code to use here
LOG_CRITICAL(Service_FS, "no file system interface available!");
@@ -861,7 +911,7 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}",
static_cast<u8>(storage_id), unknown, title_id);
auto data = OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
auto data = fsc.OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
if (data.Failed()) {
const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);

View File

@@ -32,7 +32,7 @@ enum class LogMode : u32 {
class FSP_SRV final : public ServiceFramework<FSP_SRV> {
public:
explicit FSP_SRV(const Core::Reporter& reporter);
explicit FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter);
~FSP_SRV() override;
private:
@@ -51,6 +51,8 @@ private:
void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx);
void GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx);
FileSystemController& fsc;
FileSys::VirtualFile romfs;
u64 current_process_id = 0;
u32 access_log_program_index = 0;

View File

@@ -149,7 +149,8 @@ private:
class INotificationService final : public ServiceFramework<INotificationService> {
public:
INotificationService(Common::UUID uuid) : ServiceFramework("INotificationService"), uuid(uuid) {
INotificationService(Common::UUID uuid, Core::System& system)
: ServiceFramework("INotificationService"), uuid(uuid) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &INotificationService::GetEvent, "GetEvent"},
@@ -159,6 +160,9 @@ public:
// clang-format on
RegisterHandlers(functions);
notification_event = Kernel::WritableEvent::CreateEventPair(
system.Kernel(), Kernel::ResetType::Manual, "INotificationService:NotifyEvent");
}
private:
@@ -167,13 +171,6 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
if (!is_event_created) {
auto& kernel = Core::System::GetInstance().Kernel();
notification_event = Kernel::WritableEvent::CreateEventPair(
kernel, Kernel::ResetType::Manual, "INotificationService:NotifyEvent");
is_event_created = true;
}
rb.PushCopyObjects(notification_event.readable);
}
@@ -261,21 +258,21 @@ void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<INotificationService>(uuid);
rb.PushIpcInterface<INotificationService>(uuid, system);
}
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
: ServiceFramework(name), module(std::move(module)) {}
Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name)
: ServiceFramework(name), module(std::move(module)), system(system) {}
Module::Interface::~Interface() = default;
void InstallInterfaces(SM::ServiceManager& service_manager) {
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
auto module = std::make_shared<Module>();
std::make_shared<Friend>(module, "friend:a")->InstallAsService(service_manager);
std::make_shared<Friend>(module, "friend:m")->InstallAsService(service_manager);
std::make_shared<Friend>(module, "friend:s")->InstallAsService(service_manager);
std::make_shared<Friend>(module, "friend:u")->InstallAsService(service_manager);
std::make_shared<Friend>(module, "friend:v")->InstallAsService(service_manager);
std::make_shared<Friend>(module, system, "friend:a")->InstallAsService(service_manager);
std::make_shared<Friend>(module, system, "friend:m")->InstallAsService(service_manager);
std::make_shared<Friend>(module, system, "friend:s")->InstallAsService(service_manager);
std::make_shared<Friend>(module, system, "friend:u")->InstallAsService(service_manager);
std::make_shared<Friend>(module, system, "friend:v")->InstallAsService(service_manager);
}
} // namespace Service::Friend

View File

@@ -6,13 +6,17 @@
#include "core/hle/service/service.h"
namespace Core {
class System;
}
namespace Service::Friend {
class Module final {
public:
class Interface : public ServiceFramework<Interface> {
public:
explicit Interface(std::shared_ptr<Module> module, const char* name);
explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name);
~Interface() override;
void CreateFriendService(Kernel::HLERequestContext& ctx);
@@ -20,10 +24,11 @@ public:
protected:
std::shared_ptr<Module> module;
Core::System& system;
};
};
/// Registers all Friend services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
} // namespace Service::Friend

View File

@@ -6,8 +6,8 @@
namespace Service::Friend {
Friend::Friend(std::shared_ptr<Module> module, const char* name)
: Interface(std::move(module), name) {
Friend::Friend(std::shared_ptr<Module> module, Core::System& system, const char* name)
: Interface(std::move(module), system, name) {
static const FunctionInfo functions[] = {
{0, &Friend::CreateFriendService, "CreateFriendService"},
{1, &Friend::CreateNotificationService, "CreateNotificationService"},

View File

@@ -10,7 +10,7 @@ namespace Service::Friend {
class Friend final : public Module::Interface {
public:
explicit Friend(std::shared_ptr<Module> module, const char* name);
explicit Friend(std::shared_ptr<Module> module, Core::System& system, const char* name);
~Friend() override;
};

View File

@@ -6,7 +6,7 @@
namespace Service::HID {
ControllerBase::ControllerBase() = default;
ControllerBase::ControllerBase(Core::System& system) : system(system) {}
ControllerBase::~ControllerBase() = default;
void ControllerBase::ActivateController() {

View File

@@ -11,10 +11,14 @@ namespace Core::Timing {
class CoreTiming;
}
namespace Core {
class System;
}
namespace Service::HID {
class ControllerBase {
public:
ControllerBase();
explicit ControllerBase(Core::System& system);
virtual ~ControllerBase();
// Called when the controller is initialized
@@ -46,5 +50,7 @@ protected:
s64_le entry_count;
};
static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
Core::System& system;
};
} // namespace Service::HID

View File

@@ -14,7 +14,8 @@ constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right };
Controller_DebugPad::Controller_DebugPad() = default;
Controller_DebugPad::Controller_DebugPad(Core::System& system)
: ControllerBase(system), system(system) {}
Controller_DebugPad::~Controller_DebugPad() = default;
void Controller_DebugPad::OnInit() {}

View File

@@ -16,7 +16,7 @@
namespace Service::HID {
class Controller_DebugPad final : public ControllerBase {
public:
Controller_DebugPad();
explicit Controller_DebugPad(Core::System& system);
~Controller_DebugPad() override;
// Called when the controller is initialized
@@ -89,5 +89,6 @@ private:
buttons;
std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>
analogs;
Core::System& system;
};
} // namespace Service::HID

View File

@@ -10,7 +10,8 @@
namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00;
Controller_Gesture::Controller_Gesture() = default;
Controller_Gesture::Controller_Gesture(Core::System& system)
: ControllerBase(system), system(system) {}
Controller_Gesture::~Controller_Gesture() = default;
void Controller_Gesture::OnInit() {}

View File

@@ -12,7 +12,7 @@
namespace Service::HID {
class Controller_Gesture final : public ControllerBase {
public:
Controller_Gesture();
explicit Controller_Gesture(Core::System& system);
~Controller_Gesture() override;
// Called when the controller is initialized
@@ -59,5 +59,6 @@ private:
std::array<GestureState, 17> gesture_states;
};
SharedMemory shared_memory{};
Core::System& system;
};
} // namespace Service::HID

View File

@@ -12,7 +12,8 @@ namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800;
constexpr u8 KEYS_PER_BYTE = 8;
Controller_Keyboard::Controller_Keyboard() = default;
Controller_Keyboard::Controller_Keyboard(Core::System& system)
: ControllerBase(system), system(system) {}
Controller_Keyboard::~Controller_Keyboard() = default;
void Controller_Keyboard::OnInit() {}

View File

@@ -15,7 +15,7 @@
namespace Service::HID {
class Controller_Keyboard final : public ControllerBase {
public:
Controller_Keyboard();
explicit Controller_Keyboard(Core::System& system);
~Controller_Keyboard() override;
// Called when the controller is initialized
@@ -53,5 +53,6 @@ private:
keyboard_keys;
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardMods>
keyboard_mods;
Core::System& system;
};
} // namespace Service::HID

View File

@@ -11,7 +11,7 @@
namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400;
Controller_Mouse::Controller_Mouse() = default;
Controller_Mouse::Controller_Mouse(Core::System& system) : ControllerBase(system), system(system) {}
Controller_Mouse::~Controller_Mouse() = default;
void Controller_Mouse::OnInit() {}

View File

@@ -14,7 +14,7 @@
namespace Service::HID {
class Controller_Mouse final : public ControllerBase {
public:
Controller_Mouse();
explicit Controller_Mouse(Core::System& system);
~Controller_Mouse() override;
// Called when the controller is initialized
@@ -53,5 +53,6 @@ private:
std::unique_ptr<Input::MouseDevice> mouse_device;
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeMouseButton::NumMouseButtons>
mouse_button_devices;
Core::System& system;
};
} // namespace Service::HID

View File

@@ -93,7 +93,7 @@ u32 Controller_NPad::IndexToNPad(std::size_t index) {
};
}
Controller_NPad::Controller_NPad() = default;
Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {}
Controller_NPad::~Controller_NPad() = default;
void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
@@ -168,9 +168,11 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
}
void Controller_NPad::OnInit() {
auto& kernel = Core::System::GetInstance().Kernel();
styleset_changed_event = Kernel::WritableEvent::CreateEventPair(
kernel, Kernel::ResetType::Automatic, "npad:NpadStyleSetChanged");
auto& kernel = system.Kernel();
for (std::size_t i = 0; i < styleset_changed_events.size(); i++) {
styleset_changed_events[i] = Kernel::WritableEvent::CreateEventPair(
kernel, Kernel::ResetType::Automatic, fmt::format("npad:NpadStyleSetChanged_{}", i));
}
if (!IsControllerActivated()) {
return;
@@ -453,7 +455,7 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) {
had_controller_update = true;
}
if (had_controller_update) {
styleset_changed_event.writable->Signal();
styleset_changed_events[i].writable->Signal();
}
}
}
@@ -468,7 +470,6 @@ std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const {
}
void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) {
styleset_changed_event.writable->Signal();
hold_type = joy_hold_type;
}
@@ -479,7 +480,10 @@ Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const {
void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) {
const std::size_t npad_index = NPadIdToIndex(npad_id);
ASSERT(npad_index < shared_memory_entries.size());
shared_memory_entries[npad_index].pad_assignment = assignment_mode;
if (shared_memory_entries[npad_index].pad_assignment != assignment_mode) {
styleset_changed_events[npad_index].writable->Signal();
shared_memory_entries[npad_index].pad_assignment = assignment_mode;
}
}
void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
@@ -498,11 +502,13 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
last_processed_vibration = vibrations.back();
}
Kernel::SharedPtr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent() const {
Kernel::SharedPtr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(
u32 npad_id) const {
// TODO(ogniK): Figure out the best time to signal this event. This event seems that it should
// be signalled at least once, and signaled after a new controller is connected?
styleset_changed_event.writable->Signal();
return styleset_changed_event.readable;
const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)];
styleset_event.writable->Signal();
return styleset_event.readable;
}
Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {

View File

@@ -20,7 +20,7 @@ constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this?
class Controller_NPad final : public ControllerBase {
public:
Controller_NPad();
explicit Controller_NPad(Core::System& system);
~Controller_NPad() override;
// Called when the controller is initialized
@@ -109,7 +109,7 @@ public:
void VibrateController(const std::vector<u32>& controller_ids,
const std::vector<Vibration>& vibrations);
Kernel::SharedPtr<Kernel::ReadableEvent> GetStyleSetChangedEvent() const;
Kernel::SharedPtr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
Vibration GetLastVibration() const;
void AddNewController(NPadControllerType controller);
@@ -315,7 +315,8 @@ private:
sticks;
std::vector<u32> supported_npad_id_types{};
NpadHoldType hold_type{NpadHoldType::Vertical};
Kernel::EventPair styleset_changed_event;
// Each controller should have their own styleset changed event
std::array<Kernel::EventPair, 10> styleset_changed_events;
Vibration last_processed_vibration{};
std::array<ControllerHolder, 10> connected_controllers{};
bool can_controllers_vibrate{true};
@@ -327,5 +328,6 @@ private:
std::array<ControllerPad, 10> npad_pad_states{};
bool IsControllerSupported(NPadControllerType controller);
bool is_in_lr_assignment_mode{false};
Core::System& system;
};
} // namespace Service::HID

View File

@@ -9,7 +9,8 @@
namespace Service::HID {
Controller_Stubbed::Controller_Stubbed() = default;
Controller_Stubbed::Controller_Stubbed(Core::System& system)
: ControllerBase(system), system(system) {}
Controller_Stubbed::~Controller_Stubbed() = default;
void Controller_Stubbed::OnInit() {}

View File

@@ -10,7 +10,7 @@
namespace Service::HID {
class Controller_Stubbed final : public ControllerBase {
public:
Controller_Stubbed();
explicit Controller_Stubbed(Core::System& system);
~Controller_Stubbed() override;
// Called when the controller is initialized
@@ -30,5 +30,6 @@ public:
private:
bool smart_update{};
std::size_t common_offset{};
Core::System& system;
};
} // namespace Service::HID

View File

@@ -13,7 +13,8 @@
namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400;
Controller_Touchscreen::Controller_Touchscreen() = default;
Controller_Touchscreen::Controller_Touchscreen(Core::System& system)
: ControllerBase(system), system(system) {}
Controller_Touchscreen::~Controller_Touchscreen() = default;
void Controller_Touchscreen::OnInit() {}

View File

@@ -14,7 +14,7 @@
namespace Service::HID {
class Controller_Touchscreen final : public ControllerBase {
public:
Controller_Touchscreen();
explicit Controller_Touchscreen(Core::System& system);
~Controller_Touchscreen() override;
// Called when the controller is initialized
@@ -69,5 +69,6 @@ private:
TouchScreenSharedMemory shared_memory{};
std::unique_ptr<Input::TouchDevice> touch_device;
s64_le last_touch{};
Core::System& system;
};
} // namespace Service::HID

View File

@@ -10,7 +10,7 @@
namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00;
Controller_XPad::Controller_XPad() = default;
Controller_XPad::Controller_XPad(Core::System& system) : ControllerBase(system), system(system) {}
Controller_XPad::~Controller_XPad() = default;
void Controller_XPad::OnInit() {}

View File

@@ -12,7 +12,7 @@
namespace Service::HID {
class Controller_XPad final : public ControllerBase {
public:
Controller_XPad();
explicit Controller_XPad(Core::System& system);
~Controller_XPad() override;
// Called when the controller is initialized
@@ -56,5 +56,6 @@ private:
};
static_assert(sizeof(SharedMemory) == 0x1000, "SharedMemory is an invalid size");
SharedMemory shared_memory{};
Core::System& system;
};
} // namespace Service::HID

View File

@@ -42,13 +42,14 @@ constexpr s64 accelerometer_update_ticks = static_cast<s64>(Core::Timing::BASE_C
constexpr s64 gyroscope_update_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100);
constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
IAppletResource::IAppletResource() : ServiceFramework("IAppletResource") {
IAppletResource::IAppletResource(Core::System& system)
: ServiceFramework("IAppletResource"), system(system) {
static const FunctionInfo functions[] = {
{0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
};
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
auto& kernel = system.Kernel();
shared_mem = Kernel::SharedMemory::Create(
kernel, nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite,
Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory");
@@ -74,7 +75,7 @@ IAppletResource::IAppletResource() : ServiceFramework("IAppletResource") {
GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000);
// Register update callbacks
auto& core_timing = Core::System::GetInstance().CoreTiming();
auto& core_timing = system.CoreTiming();
pad_update_event =
core_timing.RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 cycles_late) {
UpdateControllers(userdata, cycles_late);
@@ -96,7 +97,7 @@ void IAppletResource::DeactivateController(HidController controller) {
}
IAppletResource ::~IAppletResource() {
Core::System::GetInstance().CoreTiming().UnscheduleEvent(pad_update_event, 0);
system.CoreTiming().UnscheduleEvent(pad_update_event, 0);
}
void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
@@ -108,7 +109,7 @@ void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
}
void IAppletResource::UpdateControllers(u64 userdata, s64 cycles_late) {
auto& core_timing = Core::System::GetInstance().CoreTiming();
auto& core_timing = system.CoreTiming();
const bool should_reload = Settings::values.is_device_reload_pending.exchange(false);
for (const auto& controller : controllers) {
@@ -141,13 +142,13 @@ private:
std::shared_ptr<IAppletResource> Hid::GetAppletResource() {
if (applet_resource == nullptr) {
applet_resource = std::make_shared<IAppletResource>();
applet_resource = std::make_shared<IAppletResource>(system);
}
return applet_resource;
}
Hid::Hid() : ServiceFramework("hid") {
Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &Hid::CreateAppletResource, "CreateAppletResource"},
@@ -286,7 +287,7 @@ void Hid::CreateAppletResource(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
if (applet_resource == nullptr) {
applet_resource = std::make_shared<IAppletResource>();
applet_resource = std::make_shared<IAppletResource>(system);
}
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -479,7 +480,7 @@ void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad)
.GetStyleSetChangedEvent());
.GetStyleSetChangedEvent(npad_id));
}
void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) {
@@ -1053,14 +1054,14 @@ void ReloadInputDevices() {
Settings::values.is_device_reload_pending.store(true);
}
void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<Hid>()->InstallAsService(service_manager);
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
std::make_shared<Hid>(system)->InstallAsService(service_manager);
std::make_shared<HidBus>()->InstallAsService(service_manager);
std::make_shared<HidDbg>()->InstallAsService(service_manager);
std::make_shared<HidSys>()->InstallAsService(service_manager);
std::make_shared<HidTmp>()->InstallAsService(service_manager);
std::make_shared<IRS>()->InstallAsService(service_manager);
std::make_shared<IRS>(system)->InstallAsService(service_manager);
std::make_shared<IRS_SYS>()->InstallAsService(service_manager);
std::make_shared<XCD_SYS>()->InstallAsService(service_manager);

View File

@@ -42,7 +42,7 @@ enum class HidController : std::size_t {
class IAppletResource final : public ServiceFramework<IAppletResource> {
public:
IAppletResource();
explicit IAppletResource(Core::System& system);
~IAppletResource() override;
void ActivateController(HidController controller);
@@ -61,7 +61,7 @@ public:
private:
template <typename T>
void MakeController(HidController controller) {
controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>();
controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(system);
}
void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
@@ -70,6 +70,7 @@ private:
Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
Core::Timing::EventType* pad_update_event;
Core::System& system;
std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
controllers{};
@@ -77,7 +78,7 @@ private:
class Hid final : public ServiceFramework<Hid> {
public:
Hid();
explicit Hid(Core::System& system);
~Hid() override;
std::shared_ptr<IAppletResource> GetAppletResource();
@@ -126,12 +127,13 @@ private:
void SwapNpadAssignment(Kernel::HLERequestContext& ctx);
std::shared_ptr<IAppletResource> applet_resource;
Core::System& system;
};
/// Reload input devices. Used when input configuration changed
void ReloadInputDevices();
/// Registers all HID services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
} // namespace Service::HID

View File

@@ -11,7 +11,7 @@
namespace Service::HID {
IRS::IRS() : ServiceFramework{"irs"} {
IRS::IRS(Core::System& system) : ServiceFramework{"irs"}, system(system) {
// clang-format off
static const FunctionInfo functions[] = {
{302, &IRS::ActivateIrsensor, "ActivateIrsensor"},
@@ -37,7 +37,7 @@ IRS::IRS() : ServiceFramework{"irs"} {
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
auto& kernel = system.Kernel();
shared_mem = Kernel::SharedMemory::Create(
kernel, nullptr, 0x8000, Kernel::MemoryPermission::ReadWrite,
Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "IRS:SharedMemory");
@@ -98,7 +98,7 @@ void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 5};
rb.Push(RESULT_SUCCESS);
rb.PushRaw<u64>(Core::System::GetInstance().CoreTiming().GetTicks());
rb.PushRaw<u64>(system.CoreTiming().GetTicks());
rb.PushRaw<u32>(0);
}

View File

@@ -15,7 +15,7 @@ namespace Service::HID {
class IRS final : public ServiceFramework<IRS> {
public:
explicit IRS();
explicit IRS(Core::System& system);
~IRS() override;
private:
@@ -39,6 +39,7 @@ private:
void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx);
Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
const u32 device_handle{0xABCD};
Core::System& system;
};
class IRS_SYS final : public ServiceFramework<IRS_SYS> {

View File

@@ -78,7 +78,7 @@ public:
class RelocatableObject final : public ServiceFramework<RelocatableObject> {
public:
explicit RelocatableObject() : ServiceFramework{"ldr:ro"} {
explicit RelocatableObject(Core::System& system) : ServiceFramework{"ldr:ro"}, system(system) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &RelocatableObject::LoadNro, "LoadNro"},
@@ -364,7 +364,7 @@ public:
vm_manager.ReprotectRange(*map_address + header.rw_offset, header.rw_size,
Kernel::VMAPermission::ReadWrite);
Core::System::GetInstance().InvalidateCpuInstructionCaches();
system.InvalidateCpuInstructionCaches();
nro.insert_or_assign(*map_address,
NROInfo{hash, nro_address, nro_size, bss_address, bss_size});
@@ -430,7 +430,7 @@ public:
.IsSuccess());
}
Core::System::GetInstance().InvalidateCpuInstructionCaches();
system.InvalidateCpuInstructionCaches();
nro.erase(iter);
IPC::ResponseBuilder rb{ctx, 2};
@@ -516,13 +516,14 @@ private:
Common::Is4KBAligned(header.text_size) && Common::Is4KBAligned(header.ro_size) &&
Common::Is4KBAligned(header.rw_size);
}
Core::System& system;
};
void InstallInterfaces(SM::ServiceManager& sm) {
void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
std::make_shared<DebugMonitor>()->InstallAsService(sm);
std::make_shared<ProcessManager>()->InstallAsService(sm);
std::make_shared<Shell>()->InstallAsService(sm);
std::make_shared<RelocatableObject>()->InstallAsService(sm);
std::make_shared<RelocatableObject>(system)->InstallAsService(sm);
}
} // namespace Service::LDR

View File

@@ -11,6 +11,6 @@ class ServiceManager;
namespace Service::LDR {
/// Registers all LDR services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& sm);
void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
} // namespace Service::LDR

View File

@@ -23,9 +23,9 @@ constexpr ResultCode ERR_TAG_FAILED(ErrorModule::NFP,
constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152);
} // namespace ErrCodes
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
: ServiceFramework(name), module(std::move(module)) {
auto& kernel = Core::System::GetInstance().Kernel();
Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name)
: ServiceFramework(name), module(std::move(module)), system(system) {
auto& kernel = system.Kernel();
nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
"IUser:NFCTagDetected");
}
@@ -34,8 +34,8 @@ Module::Interface::~Interface() = default;
class IUser final : public ServiceFramework<IUser> {
public:
IUser(Module::Interface& nfp_interface)
: ServiceFramework("NFP::IUser"), nfp_interface(nfp_interface) {
IUser(Module::Interface& nfp_interface, Core::System& system)
: ServiceFramework("NFP::IUser"), nfp_interface(nfp_interface), system(system) {
static const FunctionInfo functions[] = {
{0, &IUser::Initialize, "Initialize"},
{1, &IUser::Finalize, "Finalize"},
@@ -65,7 +65,7 @@ public:
};
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
auto& kernel = system.Kernel();
deactivate_event = Kernel::WritableEvent::CreateEventPair(
kernel, Kernel::ResetType::Automatic, "IUser:DeactivateEvent");
availability_change_event = Kernel::WritableEvent::CreateEventPair(
@@ -324,6 +324,7 @@ private:
Kernel::EventPair deactivate_event;
Kernel::EventPair availability_change_event;
const Module::Interface& nfp_interface;
Core::System& system;
};
void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
@@ -331,7 +332,7 @@ void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IUser>(*this);
rb.PushIpcInterface<IUser>(*this, system);
}
bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
@@ -353,9 +354,9 @@ const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const
return amiibo;
}
void InstallInterfaces(SM::ServiceManager& service_manager) {
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
auto module = std::make_shared<Module>();
std::make_shared<NFP_User>(module)->InstallAsService(service_manager);
std::make_shared<NFP_User>(module, system)->InstallAsService(service_manager);
}
} // namespace Service::NFP

View File

@@ -16,7 +16,7 @@ class Module final {
public:
class Interface : public ServiceFramework<Interface> {
public:
explicit Interface(std::shared_ptr<Module> module, const char* name);
explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name);
~Interface() override;
struct ModelInfo {
@@ -43,9 +43,10 @@ public:
protected:
std::shared_ptr<Module> module;
Core::System& system;
};
};
void InstallInterfaces(SM::ServiceManager& service_manager);
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
} // namespace Service::NFP

View File

@@ -6,8 +6,8 @@
namespace Service::NFP {
NFP_User::NFP_User(std::shared_ptr<Module> module)
: Module::Interface(std::move(module), "nfp:user") {
NFP_User::NFP_User(std::shared_ptr<Module> module, Core::System& system)
: Module::Interface(std::move(module), system, "nfp:user") {
static const FunctionInfo functions[] = {
{0, &NFP_User::CreateUserInterface, "CreateUserInterface"},
};

View File

@@ -10,7 +10,7 @@ namespace Service::NFP {
class NFP_User final : public Module::Interface {
public:
explicit NFP_User(std::shared_ptr<Module> module);
explicit NFP_User(std::shared_ptr<Module> module, Core::System& system);
~NFP_User() override;
};

View File

@@ -31,7 +31,7 @@ public:
class IRequest final : public ServiceFramework<IRequest> {
public:
explicit IRequest() : ServiceFramework("IRequest") {
explicit IRequest(Core::System& system) : ServiceFramework("IRequest") {
static const FunctionInfo functions[] = {
{0, &IRequest::GetRequestState, "GetRequestState"},
{1, &IRequest::GetResult, "GetResult"},
@@ -61,7 +61,7 @@ public:
};
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
auto& kernel = system.Kernel();
event1 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
"IRequest:Event1");
event2 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
@@ -130,7 +130,7 @@ public:
class IGeneralService final : public ServiceFramework<IGeneralService> {
public:
IGeneralService();
IGeneralService(Core::System& system);
private:
void GetClientId(Kernel::HLERequestContext& ctx) {
@@ -155,7 +155,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IRequest>();
rb.PushIpcInterface<IRequest>(system);
}
void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
@@ -198,9 +198,11 @@ private:
rb.Push(RESULT_SUCCESS);
rb.Push<u8>(0);
}
Core::System& system;
};
IGeneralService::IGeneralService() : ServiceFramework("IGeneralService") {
IGeneralService::IGeneralService(Core::System& system)
: ServiceFramework("IGeneralService"), system(system) {
static const FunctionInfo functions[] = {
{1, &IGeneralService::GetClientId, "GetClientId"},
{2, &IGeneralService::CreateScanRequest, "CreateScanRequest"},
@@ -245,7 +247,8 @@ IGeneralService::IGeneralService() : ServiceFramework("IGeneralService") {
class NetworkInterface final : public ServiceFramework<NetworkInterface> {
public:
explicit NetworkInterface(const char* name) : ServiceFramework{name} {
explicit NetworkInterface(const char* name, Core::System& system)
: ServiceFramework{name}, system(system) {
static const FunctionInfo functions[] = {
{4, &NetworkInterface::CreateGeneralServiceOld, "CreateGeneralServiceOld"},
{5, &NetworkInterface::CreateGeneralService, "CreateGeneralService"},
@@ -258,7 +261,7 @@ public:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IGeneralService>();
rb.PushIpcInterface<IGeneralService>(system);
}
void CreateGeneralService(Kernel::HLERequestContext& ctx) {
@@ -266,14 +269,17 @@ public:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IGeneralService>();
rb.PushIpcInterface<IGeneralService>(system);
}
private:
Core::System& system;
};
void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<NetworkInterface>("nifm:a")->InstallAsService(service_manager);
std::make_shared<NetworkInterface>("nifm:s")->InstallAsService(service_manager);
std::make_shared<NetworkInterface>("nifm:u")->InstallAsService(service_manager);
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
std::make_shared<NetworkInterface>("nifm:a", system)->InstallAsService(service_manager);
std::make_shared<NetworkInterface>("nifm:s", system)->InstallAsService(service_manager);
std::make_shared<NetworkInterface>("nifm:u", system)->InstallAsService(service_manager);
}
} // namespace Service::NIFM

View File

@@ -8,9 +8,13 @@ namespace Service::SM {
class ServiceManager;
}
namespace Core {
class System;
}
namespace Service::NIFM {
/// Registers all NIFM services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
} // namespace Service::NIFM

View File

@@ -126,7 +126,7 @@ public:
class IEnsureNetworkClockAvailabilityService final
: public ServiceFramework<IEnsureNetworkClockAvailabilityService> {
public:
IEnsureNetworkClockAvailabilityService()
explicit IEnsureNetworkClockAvailabilityService(Core::System& system)
: ServiceFramework("IEnsureNetworkClockAvailabilityService") {
static const FunctionInfo functions[] = {
{0, &IEnsureNetworkClockAvailabilityService::StartTask, "StartTask"},
@@ -139,7 +139,7 @@ public:
};
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
auto& kernel = system.Kernel();
finished_event = Kernel::WritableEvent::CreateEventPair(
kernel, Kernel::ResetType::Automatic,
"IEnsureNetworkClockAvailabilityService:FinishEvent");
@@ -200,7 +200,7 @@ private:
class NTC final : public ServiceFramework<NTC> {
public:
explicit NTC() : ServiceFramework{"ntc"} {
explicit NTC(Core::System& system) : ServiceFramework{"ntc"}, system(system) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &NTC::OpenEnsureNetworkClockAvailabilityService, "OpenEnsureNetworkClockAvailabilityService"},
@@ -218,7 +218,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>();
rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>(system);
}
// TODO(ogniK): Do we need these?
@@ -235,13 +235,14 @@ private:
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
Core::System& system;
};
void InstallInterfaces(SM::ServiceManager& sm) {
void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
std::make_shared<NIM>()->InstallAsService(sm);
std::make_shared<NIM_ECA>()->InstallAsService(sm);
std::make_shared<NIM_SHP>()->InstallAsService(sm);
std::make_shared<NTC>()->InstallAsService(sm);
std::make_shared<NTC>(system)->InstallAsService(sm);
}
} // namespace Service::NIM

View File

@@ -8,8 +8,12 @@ namespace Service::SM {
class ServiceManager;
}
namespace Core {
class System;
}
namespace Service::NIM {
void InstallInterfaces(SM::ServiceManager& sm);
void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
} // namespace Service::NIM

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