Compare commits

...

367 Commits

Author SHA1 Message Date
bunnei
03c2d049d4 settings: Turn docked mode off by default. 2018-07-17 22:52:25 -04:00
bunnei
49e5de9f03 vi: Change TransactionId::CancelBuffer to LOG_CRITICAL. 2018-07-17 22:47:35 -04:00
bunnei
0d1a99edf6 vi: Fix size for ListDisplays default display. 2018-07-17 22:18:14 -04:00
bunnei
c3dd456d51 vi: Partially implement buffer crop parameters. 2018-07-17 20:13:17 -04:00
bunnei
8e28af6f89 Merge pull request #675 from Subv/stencil
GPU: Added register definitions for the stencil parameters.
2018-07-17 15:53:00 -07:00
Subv
3d3b10adc7 GPU: Added register definitions for the stencil parameters. 2018-07-17 15:00:21 -05:00
Zach Hilman
69bfe075b5 General Filesystem and Save Data Fixes (#670) 2018-07-17 12:42:15 -07:00
bunnei
88a3140c9b Merge pull request #671 from MerryMage/clear-exclusive-state
scheduler: Clear exclusive state when switching contexts
2018-07-17 07:33:32 -07:00
bunnei
519035db3d Merge pull request #672 from SciresM/to_address_fix
svc:: Fix bug in svcWaitForAddress
2018-07-17 07:32:42 -07:00
bunnei
5f119bed56 Merge pull request #673 from bunnei/fix-buffer-queue-evt
nvflinger: Fix for BufferQueue event handling.
2018-07-17 07:07:57 -07:00
bunnei
170e19d4ea nvflinger: Fix for BufferQueue event handling. 2018-07-17 00:26:23 -04:00
Michael Scire
3b885691a1 Kernel/Arbiter: Fix bug in WaitIfLessThan 2018-07-16 20:55:53 -06:00
MerryMage
56cc1c11ec scheduler: Clear exclusive state when switching contexts 2018-07-16 11:24:00 +01:00
bunnei
f00ca69a81 Merge pull request #669 from lioncash/dynarmic
externals: Update dynarmic to dfdec79
2018-07-15 18:36:32 -07:00
Lioncash
0722adb471 externals: Update dynarmic to dfdec79 2018-07-15 16:11:45 -04:00
bunnei
068668780c Merge pull request #668 from jroweboy/controller-lag
HID: Update controllers less often
2018-07-15 13:06:28 -07:00
bunnei
04b9cde4f5 Merge pull request #664 from jroweboy/logging-stuff
Minor logging improvements
2018-07-15 12:58:52 -07:00
James Rowe
7d209b3c9f HID: Update controllers less often 2018-07-15 13:47:41 -06:00
James Rowe
497b81558e Logging: Dump all logs in the queue on close in debug mode 2018-07-15 13:02:09 -06:00
bunnei
98762e9601 Merge pull request #666 from bunnei/g8r8
gl_rasterizer_cache: Implement texture format G8R8.
2018-07-15 10:09:36 -07:00
bunnei
3a96670f2d gl_rasterizer_cache: Implement texture format G8R8. 2018-07-15 01:33:42 -04:00
bunnei
aaec0b7e70 Merge pull request #665 from bunnei/fix-z24-s8
gl_rasterizer_cache: Fix incorrect offset in ConvertS8Z24ToZ24S8.
2018-07-14 22:18:55 -07:00
bunnei
f8ab956189 Merge pull request #659 from bunnei/depth16
gl_rasterizer_cache: Implement depth format Z16_UNORM.
2018-07-14 21:39:23 -07:00
bunnei
3145114190 gl_rasterizer_cache: Fix incorrect offset in ConvertS8Z24ToZ24S8. 2018-07-15 00:02:05 -04:00
bunnei
e21190f47f gl_rasterizer_cache: Implement depth format Z16_UNORM. 2018-07-14 23:43:28 -04:00
bunnei
2cb3fdca86 Merge pull request #598 from bunnei/makedonecurrent
OpenGL: Use MakeCurrent/DoneCurrent for multithreaded rendering.
2018-07-14 20:18:11 -07:00
bunnei
c324a378ac Merge pull request #663 from Subv/bsd
Services/BSD: Corrected the return for StartMonitoring according to SwIPC
2018-07-14 19:40:34 -07:00
bunnei
fd1f5c5414 Merge pull request #662 from Subv/delete_file
FileSys: Append the requested path to the filesystem base path in DeleteFile
2018-07-14 13:11:58 -07:00
James Rowe
6daebaaa57 Logging: Don't lock the queue for the duration of the write 2018-07-14 11:57:13 -06:00
Subv
b07f4d6afb Services/BSD: Corrected the return for StartMonitoring according to SwIPC. 2018-07-14 12:34:07 -05:00
bunnei
ad0166a982 Merge pull request #661 from ogniK5377/assert-nit
No need to use ASSERT_MSG with an empty assert message
2018-07-14 09:12:21 -07:00
Subv
7e5e4f8d7a FileSys: Append the requested path to the filesystem base path in DeleteFile.
We were trying to delete things in the current directory instead of the actual filesystem directory. This may fix some savedata issues in some games.
2018-07-14 10:57:22 -05:00
David Marcec
a7d6c0d6ea No need to use ASSERT_MSG with an empty message 2018-07-14 23:13:16 +10:00
bunnei
81739a5448 Merge pull request #660 from Subv/depth_write
GPU: Always enable the depth write when clearing the depth buffer.
2018-07-14 00:38:12 -07:00
bunnei
05cb10530f OpenGL: Use MakeCurrent/DoneCurrent for multithreaded rendering. 2018-07-14 02:50:35 -04:00
Subv
b37354cca8 GPU: Always enable the depth write when clearing the depth buffer.
The GPU ignores that register when clearing, but OpenGL obeys the glDepthMask parameter, so we set the depth mask to GL_TRUE when clearing the depth buffer. It will be restored to the correct value automatically on the next draw call.
2018-07-14 00:52:23 -05:00
bunnei
9fc0d1d701 Merge pull request #657 from bunnei/dual-vs
gl_shader_gen: Implement dual vertex shader mode.
2018-07-13 07:08:54 -07:00
Hedges
e066bc75b9 More improvements to GDBStub (#653)
* More improvements to GDBStub
- Debugging of threads should work correctly with source and assembly level stepping and modifying registers and memory, meaning threads and callstacks are fully clickable in VS.
- List of modules is available to the client, with assumption that .nro and .nso are backed up by an .elf with symbols, while deconstructed ROMs keep N names.
- Initial support for floating point registers.

* Tidy up as requested in PR feedback

* Tidy up as requested in PR feedback
2018-07-12 20:22:59 -07:00
bunnei
8aeff9cf8e gl_rasterizer: Fix check for if a shader stage is enabled. 2018-07-12 22:57:57 -04:00
bunnei
c4015cd93a gl_shader_gen: Implement dual vertex shader mode.
- When VertexA shader stage is enabled, we combine with VertexB program to make a single Vertex Shader stage.
2018-07-12 22:25:36 -04:00
bunnei
ce23ae3ede Merge pull request #656 from ogniK5377/audren-mem-init
Initialized memory for RequestUpdateAudioRenderer and fixed MemoryPoolSection to be more accurate
2018-07-12 19:12:47 -07:00
bunnei
64b5e5d5d9 Merge pull request #655 from bunnei/pred-lt-nan
gl_shader_decompiler: Implement PredCondition::LessThanWithNan.
2018-07-12 18:59:15 -07:00
bunnei
52636f67cc Merge pull request #654 from bunnei/cond-exit
gl_shader_decompiler: Use FlowCondition field in EXIT instruction.
2018-07-12 18:59:05 -07:00
David Marcec
8bd8d1e3da We only need to alert for memory pool changes 2018-07-13 10:36:28 +10:00
David Marcec
6642011706 initialized voice status and unused sizes in the update data header 2018-07-13 10:35:44 +10:00
bunnei
49c0c081c4 gl_shader_decompiler: Implement PredCondition::LessThanWithNan. 2018-07-12 20:04:35 -04:00
bunnei
4757ffdcce gl_shader_decompiler: Use FlowCondition field in EXIT instruction. 2018-07-12 20:00:37 -04:00
Sebastian Valle
274d1fb0fc Merge pull request #652 from Subv/fadd32i
GPU: Implement the FADD32I shader instruction.
2018-07-12 17:36:51 -05:00
bunnei
3ff21345b4 Merge pull request #651 from Subv/ffma_decode
GPU: Corrected the decoding of FFMA for immediate operands.
2018-07-12 12:42:58 -07:00
Subv
c1ae841f47 GPU: Implement the FADD32I shader instruction. 2018-07-12 12:00:31 -05:00
Tobias
316b933a31 Port #3335 and #3373 from Citra: "Small SDL fixes" and "Print the actual error preventing SDL from working" (#637)
* Port #3335 and #3373 from Citra

* Fixup: Use the new logging placeholders
2018-07-12 09:26:27 -07:00
Subv
0cad310e12 GPU: Corrected the decoding of FFMA for immediate operands. 2018-07-12 10:15:48 -05:00
bunnei
4f41ffdd41 Merge pull request #648 from ogniK5377/no-net
Let games/application know that we're offline
2018-07-12 06:44:15 -07:00
bunnei
7c7b2b8285 Merge pull request #649 from ogniK5377/audout-auto
Audout "Auto" functions
2018-07-12 06:43:37 -07:00
bunnei
b89fb430c7 Merge pull request #650 from jroweboy/logging-stuff
Minor logging fixes
2018-07-12 06:42:46 -07:00
James Rowe
b30c5370b1 yuzu - Fix duplicate logs 2018-07-12 01:11:43 -06:00
James Rowe
020d005d8c yuzu-cmd Apply the filter string from settings 2018-07-12 01:09:03 -06:00
David Marcec
706892de7d Audout "Auto" functions
Audout autos are identical to their counterpart except for the buffer type which yuzu already handles for us.
2018-07-12 16:57:31 +10:00
David Marcec
3d68f6ba6c Added IsWirelessCommunicationEnabled, IsEthernetCommunicationEnabled, IsAnyInternetRequestAccepted
Since we have no socket implementation we should be returning 0 to indicate we're currently offline.
2018-07-12 16:40:17 +10:00
bunnei
7230ceb584 Merge pull request #559 from Subv/mount_savedata
Services/FS: Return the correct error code when trying to mount a nonexistent savedata.
2018-07-11 20:21:52 -07:00
bunnei
afb26b190f Merge pull request #585 from janisozaur/patch-11
Improve directory creation in WindowsCopyFiles.cmake
2018-07-11 20:21:17 -07:00
bunnei
e2037821b6 Merge pull request #646 from bunnei/fix-hid-smo
hid: Fix timestamps and controller type.
2018-07-11 06:30:56 -07:00
bunnei
12a6996262 hid: Fix timestamps and controller type.
- This fixes user input in SMO.
2018-07-10 22:55:13 -04:00
bunnei
379a935016 Merge pull request #644 from ogniK5377/getconfig-err
NvOsGetConfigU32 production impl
2018-07-10 15:44:23 -07:00
bunnei
04524e76c2 Merge pull request #633 from FearlessTobi/port-defines
Port #3579 from Citra: Clean up architecture-specific defines
2018-07-10 09:12:52 -07:00
bunnei
3e966be6fc Merge pull request #642 from bunnei/create-save-dir
savedata_factory: Always create a save directory for games.
2018-07-10 09:09:58 -07:00
David Marcec
0944bfe3cb NvOsGetConfigU32 production impl
Settings are only  used when RMOS_SET_PRODUCTION_MODE is set to 0.
If production mode is set, the error code 0x30006 is returned instead
2018-07-10 14:10:17 +10:00
bunnei
aec90ca506 Merge pull request #636 from FearlessTobi/add-gitignore
Port #3513 (partly) from Citra: .gitignore: Add CMakeLists.txt.user to Project/editor files
2018-07-09 17:09:57 -07:00
bunnei
ef2c955db5 Merge pull request #635 from FearlessTobi/port-crashfix
Port #3474 from Citra: Do not crash on unimplemented code in debug build
2018-07-09 17:08:25 -07:00
bunnei
dacc89b38b Merge pull request #634 from FearlessTobi/port-viewport-fix
Port #3505 from Citra: Fix QGLWidget viewport resize on macOS
2018-07-09 17:07:30 -07:00
bunnei
51a3e93f8e Merge pull request #640 from bunnei/flip-tris-viewport
gl_rasterizer: Flip triangles when regs.viewport_transform[0].scale_y is negative.
2018-07-09 14:32:35 -07:00
bunnei
0d51cfe2f5 Merge pull request #641 from bunnei/nvhost-ctrl-fix
nvhost_ctrl: Fix NvOsGetConfigU32 for Snipper Clips.
2018-07-09 14:32:22 -07:00
bunnei
eb6cbfdbd8 savedata_factory: Always create a save directory for games. 2018-07-08 17:05:13 -04:00
bunnei
1b3dd30ba8 nvhost_ctrl: Fix NvOsGetConfigU32 for Snipper Clips. 2018-07-08 17:01:46 -04:00
bunnei
854f474f52 gl_rasterizer: Flip triangles when regs.viewport_transform[0].scale_y is negative.
- Fixes a regression with Binding of Isaac.
2018-07-08 16:16:24 -04:00
bunnei
639346bcfb Merge pull request #625 from Subv/imnmx
GPU: Implemented the IMNMX shader instruction.
2018-07-07 19:33:50 -07:00
bunnei
d990f2355b Merge pull request #627 from Subv/bc7u
GPU: Implemented the BC7U texture format.
2018-07-07 19:33:18 -07:00
bunnei
f89b47fdf7 Merge pull request #639 from bunnei/revert-vfs
Revert "Virtual Filesystem (#597)"
2018-07-07 19:30:58 -07:00
bunnei
913896cbd9 Revert "Virtual Filesystem (#597)"
This reverts commit 77c684c114.
2018-07-07 20:24:51 -07:00
bunnei
3417f46dd5 Merge pull request #632 from FearlessTobi/add-discord-link
Port #3466 from Citra: Add link to Discord
2018-07-07 07:56:26 -07:00
Subv
4633dd9505 GPU: Implemented the BC7U texture format.
Note: Our version of glad exports GL_COMPRESSED_RGBA_BPTC_UNORM as GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, maybe it's time we update it.
2018-07-07 09:17:48 -05:00
fearlessTobi
f2c2383c8b Port #3513 (partly) from Citra 2018-07-07 14:23:11 +02:00
fearlessTobi
476e0fae4c Port #3474 from Citra 2018-07-07 14:17:44 +02:00
fearlessTobi
b8384c0c91 Port #3505 from CItra 2018-07-07 14:11:49 +02:00
Tobias
9df698fa9c Port #3466 from Citra 2018-07-07 14:00:20 +02:00
fearlessTobi
70a6691e3b Port #3579 from Citra 2018-07-07 13:59:18 +02:00
bunnei
e197476344 Merge pull request #631 from lioncash/dynarmic
externals: Update dynarmic to f7d11baa1
2018-07-06 19:35:02 -07:00
Lioncash
650c89bbbc externals: Update dynarmic to f7d11baa1 2018-07-06 20:54:04 -04:00
bunnei
bebe09a1aa Merge pull request #630 from FearlessTobi/remove-citra-references
Remove some references to Citra
2018-07-06 11:13:50 -04:00
Zach Hilman
77c684c114 Virtual Filesystem (#597)
* Add VfsFile and VfsDirectory classes

* Finish abstract Vfs classes

* Implement RealVfsFile (computer fs backend)

* Finish RealVfsFile and RealVfsDirectory

* Finished OffsetVfsFile

* More changes

* Fix import paths

* Major refactor

* Remove double const

* Use experimental/filesystem or filesystem depending on compiler

* Port partition_filesystem

* More changes

* More Overhaul

* FSP_SRV fixes

* Fixes and testing

* Try to get filesystem to compile

* Filesystem on linux

* Remove std::filesystem and document/test

* Compile fixes

* Missing include

* Bug fixes

* Fixes

* Rename v_file and v_dir

* clang-format fix

* Rename NGLOG_* to LOG_*

* Most review changes

* Fix TODO

* Guess 'main' to be Directory by filename
2018-07-06 10:51:32 -04:00
fearlessTobi
c9aadff9a9 Remove some references to Citra 2018-07-06 15:47:06 +02:00
bunnei
51bd76a5fd Merge pull request #629 from Subv/depth_test
GPU: Allow using the old NV04 values for the depth test function.
2018-07-05 16:43:10 -04:00
Subv
9f6a5660e8 GPU: Allow using the old NV04 values for the depth test function.
These seem to be just a valid as the GL token values. Thanks @ReinUsesLisp

This restores graphical output to Disgaea 5
2018-07-05 13:01:31 -05:00
bunnei
762bf6a522 Merge pull request #626 from Subv/shader_sync
GPU: Stub the shader SYNC and DEPBAR instructions.
2018-07-05 12:54:19 -04:00
bunnei
637f9d780a Merge pull request #624 from Subv/f2f_round
GPU: Implemented the F2F 'round' rounding mode.
2018-07-05 11:30:29 -04:00
bunnei
956b5db52e Merge pull request #623 from Subv/vertex_types
GPU: Implement the Size_16_16 and Size_10_10_10_2 vertex attribute types
2018-07-05 11:30:01 -04:00
bunnei
8b815877a6 Merge pull request #622 from Subv/unused_tex
GPU: Ignore unused textures and corrected the TEX shader instruction decoding.
2018-07-05 11:29:17 -04:00
bunnei
1b0a74e23f Merge pull request #621 from Subv/psetp_
GPU: Implemented the PSETP shader instruction.
2018-07-05 11:28:50 -04:00
bunnei
9a3c0b161e Merge pull request #620 from Subv/depth_z32f
GPU: Implemented the 32 bit float depth buffer format.
2018-07-05 11:09:15 -04:00
Subv
b0c92b80b1 GPU: Implemented the IMNMX shader instruction.
It's similar to the FMNMX instruction but it works on integers.
2018-07-04 15:44:37 -05:00
Subv
d800a02b4b GPU: Implemented the F2F 'round' rounding mode.
It's implemented via the GLSL 'roundEven()' function.
2018-07-04 15:43:21 -05:00
Subv
77cfe4f027 GPU: Stub the shader SYNC and DEPBAR instructions.
It is unknown at this moment if we actually need to do something with these instructions or if the GLSL compiler takes care of that for us.
2018-07-04 15:29:51 -05:00
Subv
ce39ae3e57 GPU: Implement the Size_16_16 and Size_10_10_10_2 vertex attribute types.
Both signed and unsigned variants.
2018-07-04 15:22:34 -05:00
Subv
4bda9693be GPU: Ignore textures that the GLSL compiler deemed unused when binding textures to the shaders. 2018-07-04 15:20:12 -05:00
Subv
c42b818cf9 GPU: Corrected the decoding for the TEX shader instruction. 2018-07-04 15:19:20 -05:00
Subv
53a55bd751 GPU: Implemented the PSETP shader instruction.
It's similar to the isetp and fsetp instructions but it works on predicates instead.
2018-07-04 15:15:03 -05:00
bunnei
2355460d7c Merge pull request #619 from Subv/flip_cull
GPU: Flip the triangle front face winding if the GPU is configured to not flip the triangles.
2018-07-04 12:13:38 -04:00
Subv
016e357c75 GPU: Implemented the 32 bit float depth buffer format. 2018-07-04 10:42:33 -05:00
Subv
c1bebdef5e GPU: Flip the triangle front face winding if the GPU is configured to not flip the triangles.
OpenGL's default behavior is already correct when the GPU is configured to flip the triangles.

This fixes 1-2 Switch's splash screen.
2018-07-04 10:26:46 -05:00
bunnei
81a44d38ee Merge pull request #618 from Subv/clear_used_buffers
GPU: Only configure the used framebuffers during clear.
2018-07-04 00:12:46 -04:00
Subv
5a9df3c675 GPU: Only configure the used framebuffers during clear.
Don't try to configure the color buffer if it is not being cleared, it may not be completely valid at this point.
2018-07-03 22:32:59 -05:00
bunnei
c996787d84 Merge pull request #609 from Subv/clear_buffers
GPU: Implemented the CLEAR_BUFFERS register.
2018-07-03 19:34:34 -04:00
bunnei
4030f600dc Merge pull request #616 from bunnei/s8z24
gl_rasterizer_cache: Implement PixelFormat S8Z24.
2018-07-03 18:26:31 -04:00
Subv
78443a7f29 GPU: Factor out the framebuffer configuration code for both Clear and Draw commands. 2018-07-03 16:56:47 -05:00
Subv
c1811ed3d1 GPU: Support clears that don't clear the color buffer. 2018-07-03 16:56:47 -05:00
Subv
be51120d23 GPU: Bind and clear the render target when the CLEAR_BUFFERS register is written to. 2018-07-03 16:56:44 -05:00
Subv
827bb08c91 GPU: Added registers for the CLEAR_BUFFERS and CLEAR_COLOR methods. 2018-07-03 16:56:31 -05:00
bunnei
c164f02c48 Merge pull request #613 from jroweboy/qt-style
Add qt windowsvistastyle dll to the build
2018-07-03 17:48:29 -04:00
bunnei
9da1552417 gl_rasterizer_cache: Implement PixelFormat S8Z24. 2018-07-03 14:58:13 -04:00
James Rowe
6ff20dc6a7 Add qt windowsvistastyle dll to the build 2018-07-03 14:44:13 -04:00
David
3dab0e284b Update AudioRenderer Voice Sections (#614)
* voice section updating

* fixed slight offset miscalculation

* fixed overflow
2018-07-03 13:09:10 -04:00
bunnei
15e68cdbaa Merge pull request #607 from jroweboy/logging
Logging - Customizable backends
2018-07-03 00:26:45 -04:00
bunnei
e3ca561ea0 Merge pull request #612 from bunnei/fix-cull
gl_rasterizer: Only set cull mode and front face if enabled.
2018-07-02 23:48:52 -04:00
bunnei
ddb767f1b6 Merge pull request #611 from Subv/enabled_depth_test
GPU: Don't try to parse the depth test function if the depth test is disabled and use only the least significant 3 bits in the depth test func
2018-07-02 23:47:11 -04:00
bunnei
5410b4659d Merge pull request #610 from Subv/mufu_8
GPU: Implemented MUFU suboperation 8, sqrt.
2018-07-02 22:26:42 -04:00
bunnei
a9cacd03f6 gl_rasterizer: Only set cull mode and front face if enabled. 2018-07-02 22:22:25 -04:00
Subv
6e0eba9917 GPU: Use only the least significant 3 bits when reading the depth test func.
Some games set the full GL define value here (including nouveau), but others just seem to set those last 3 bits.
2018-07-02 21:06:36 -05:00
Subv
65c664560c GPU: Don't try to parse the depth test function if the depth test is disabled. 2018-07-02 21:02:46 -05:00
bunnei
76b475faf7 Fix build and address review feedback 2018-07-02 21:45:48 -04:00
James Rowe
6269a01b4e Add configurable logging backends 2018-07-02 21:45:47 -04:00
James Rowe
0d46f0df12 Update clang format 2018-07-02 21:45:47 -04:00
James Rowe
638956aa81 Rename logging macro back to LOG_* 2018-07-02 21:45:47 -04:00
bunnei
92c7135065 Merge pull request #608 from Subv/depth
GPU: Implemented the depth buffer and depth test + culling
2018-07-02 21:24:43 -04:00
Subv
a6d4903aaf GPU: Set up the culling configuration on each draw. 2018-07-02 19:51:29 -05:00
Subv
6e4e0b2b41 GPU: Implemented MUFU suboperation 8, sqrt. 2018-07-02 19:48:15 -05:00
Sebastian Valle
055f1546d7 Merge pull request #606 from Subv/base_vertex
GPU: Fixed the index offset and implement BaseVertex when doing indexed rendering.
2018-07-02 14:07:38 -05:00
Sebastian Valle
79167fc989 Merge pull request #603 from Subv/nvmap_free
GPU: Remove unmapped surfaces from the rasterizer cache and fix our nvmap::Free behavior.
2018-07-02 14:07:17 -05:00
Sebastian Valle
9685dd5840 Merge pull request #605 from Subv/dma_copy
GPU: Directly copy the pixels when performing a same-layout DMA.
2018-07-02 14:06:56 -05:00
Subv
18c8ae7750 GPU: Set up the depth test state on every draw. 2018-07-02 13:33:06 -05:00
Subv
d480b63e0d MaxwellToGL: Added conversion functions for depth test and cull mode. 2018-07-02 13:31:49 -05:00
Subv
c1f55c32c8 GPU: Added registers for depth test and cull mode. 2018-07-02 13:31:20 -05:00
Subv
0f929762b3 GPU: Implemented the Z24S8 depth format and load the depth framebuffer. 2018-07-02 12:42:04 -05:00
Subv
4c59105adf GPU: Implement offsetted rendering when using non-indexed drawing. 2018-07-02 11:23:36 -05:00
Subv
fca3d1cc65 GPU: Fixed the index offset rendering, and implemented the base vertex functionality.
This fixes Stardew Valley.
2018-07-02 11:22:17 -05:00
Subv
cc73bad293 GPU: Added register definitions for the vertex buffer base element. 2018-07-02 11:21:23 -05:00
bunnei
3d41fdfbba Merge pull request #604 from Subv/invalid_textures
GPU: Ignore invalid and disabled textures when drawing.
2018-07-02 11:48:18 -04:00
Subv
ca633a5a3c GPU: Directly copy the pixels when performing a same-layout DMA. 2018-07-02 09:46:33 -05:00
Subv
80c5e8ae99 GPU: Ignore disabled textures and textures with an invalid address. 2018-07-02 09:43:38 -05:00
Subv
e9d147349b GPU: Allow GpuToCpuAddress to return boost::none for unmapped addresses. 2018-07-02 09:42:48 -05:00
Subv
6c0c81dfdc GPU: Remove a surface from the cache when its backing memory is being unmapped from the GPU's MMU. 2018-07-01 10:50:06 -05:00
Subv
a093feca62 nvmap: Return the address of the nvmap object when Freeing it for the last time.
This behavior is confirmed by reverse engineering.
2018-07-01 10:48:50 -05:00
bunnei
066d6184d4 Merge pull request #602 from Subv/mufu_subop
GPU: Corrected the size of the MUFU subop field, and removed incorrect "min" operation.
2018-07-01 11:06:04 -04:00
bunnei
b611d852db Merge pull request #601 from Subv/rgba32_ui
GPU: Implement the RGBA32_UINT rendertarget format.
2018-07-01 03:22:38 -04:00
bunnei
85a60e2044 Merge pull request #600 from bunnei/pred-not-eq-nan
gl_shader_decompiler: Implement predicate NotEqualWithNan.
2018-07-01 03:22:11 -04:00
Subv
f33e406ff2 GPU: Corrected the size of the MUFU subop field, and removed incorrect "min" operation. 2018-06-30 14:48:25 -05:00
Subv
c0e2d52758 GPU: Implemented the RGBA32_UINT rendertarget format. 2018-06-30 14:23:13 -05:00
Subv
b11072d54a GLCache: Specify the component type along the texture type in the format tuple. 2018-06-30 14:08:51 -05:00
bunnei
c96da97630 gl_shader_decompiler: Implement predicate NotEqualWithNan. 2018-06-30 03:01:25 -04:00
bunnei
50ef2beb58 Merge pull request #595 from bunnei/raster-cache
Rewrite the OpenGL rasterizer cache
2018-06-29 14:07:28 -04:00
bunnei
c18425ef98 gl_rasterizer_cache: Only dereference color_surface/depth_surface if valid. 2018-06-29 13:08:08 -04:00
bunnei
da2bdbc0d7 Merge pull request #588 from mailwl/hwopus
Service/Audio: add hwopus service, stub GetWorkBufferSize function
2018-06-27 21:57:21 -04:00
bunnei
7fa9177830 gl_shader_decompiler: Add a return path for unknown instructions. 2018-06-27 01:14:34 -04:00
bunnei
1dd754590f gl_rasterizer_cache: Implement caching for texture and framebuffer surfaces.
gl_rasterizer_cache: Improved cache management based on Citra's implementation.

gl_surface_cache: Add some docstrings.
2018-06-27 00:15:44 -04:00
bunnei
8af1ae46aa gl_rasterizer_cache: Various fixes for ASTC handling. 2018-06-27 00:08:04 -04:00
bunnei
c7c379bd19 gl_rasterizer_cache: Use SurfaceParams as a key for surface caching. 2018-06-27 00:08:04 -04:00
bunnei
6a28a66832 maxwell_3d: Add a struct for RenderTargetConfig. 2018-06-27 00:08:04 -04:00
bunnei
1bbbd26563 settings: Add a configuration for use_accurate_framebuffers. 2018-06-27 00:08:04 -04:00
bunnei
3f9f047375 gl_rasterizer: Implement AccelerateDisplay to forward textures to framebuffers. 2018-06-27 00:08:03 -04:00
bunnei
ff6785f3e8 gl_rasterizer_cache: Cache size_in_bytes as a const per surface. 2018-06-27 00:08:03 -04:00
bunnei
9f2f819bb6 gl_rasterizer_cache: Refactor to make SurfaceParams members const. 2018-06-27 00:08:03 -04:00
bunnei
5f57ab1b2a gl_rasterizer_cache: Remove Citra's rasterizer cache, always load/flush surfaces. 2018-06-27 00:08:03 -04:00
bunnei
84cadf9918 Merge pull request #594 from bunnei/max-constbuff
gl_rasterizer: Workaround for when exceeding max UBO size.
2018-06-27 00:06:23 -04:00
bunnei
10422f3c18 gl_rasterizer: Workaround for when exceeding max UBO size. 2018-06-26 23:07:34 -04:00
bunnei
dfac394e60 Merge pull request #593 from bunnei/fix-swizzle
gl_state: Fix state management for texture swizzle.
2018-06-26 22:05:49 -04:00
bunnei
73de9bab1a Merge pull request #592 from bunnei/cleanup-gl-state
gl_state: Remove unused state management from 3DS.
2018-06-26 22:05:03 -04:00
bunnei
0399d98cd9 Merge pull request #591 from bunnei/fix-rgb565
gl_rasterizer_cache: Fix inverted B5G6R5 format.
2018-06-26 22:04:42 -04:00
bunnei
8447d20a11 gl_state: Fix state management for texture swizzle. 2018-06-26 17:15:58 -04:00
bunnei
20b58bab9c gl_state: Remove unused state management from 3DS. 2018-06-26 17:09:25 -04:00
bunnei
41b3725d28 gl_rasterizer_cache: Fix inverted B5G6R5 format. 2018-06-26 17:07:36 -04:00
bunnei
2981408722 Merge pull request #590 from bunnei/rm-ssbo-check
yuzu: Remove SSBOs check from Qt frontend.
2018-06-26 14:28:56 -04:00
bunnei
1669911b1d yuzu: Remove SSBOs check from Qt frontend. 2018-06-26 11:28:56 -04:00
bunnei
36dedae842 Merge pull request #554 from Subv/constbuffer_ubo
Rasterizer: Use UBOs instead of SSBOs for uploading const buffers.
2018-06-26 10:25:56 -04:00
bunnei
1da0ee57fd Merge pull request #589 from mailwl/fix-crash
Fix crash at exit
2018-06-26 01:01:10 -04:00
mailwl
ad39bab271 Fix crash at exit 2018-06-25 18:01:08 +03:00
David
c9e821e93e Send the correct RequestUpdateAudioRenderer revision in the output header (#587)
* We should be returning our revision instead of what is requested.

Hardware test on a 5.1.0 console

* Added sysversion comment
2018-06-25 10:34:41 -04:00
mailwl
11fb17054e Service/Audio: add hwopus service, stub GetWorkBufferSize function 2018-06-25 16:44:17 +03:00
Michał Janiszewski
23dc36ed71 Improve directory creation in WindowsCopyFiles.cmake 2018-06-24 21:27:00 +02:00
David
838724c588 Removed duplicate structs, changed AudioRendererResponse -> UpdateDataHeader (#583)
* Removed duplicate structs, changed AudioRendererResponse -> UpdateDataHeader

According to game symbols(SMO), there's references to UpdateDataHeader which seems to be what AudioRendererResponse actually is

* oops

* AudioRendererParameters should be AudioRendererParameter according to SMO
2018-06-23 20:46:29 -04:00
bunnei
0b831dd2ba Revert "Use Ninja for MSVC AppVeyor builds" (#584) 2018-06-23 03:17:32 -04:00
David
81f24f5685 Fixed RequestUpdateAudioRenderer deadlocks and calculated section sizes properly (#580)
* Fixed RequestUpdateAudioRenderer deadlocks and calculated section sizes properly

This fixes RequestUpdateAudioRenderer deadlocks in games like Puyo Puyo Tetris and games which require a proper section size in games such as Retro City Rampage. This fixes causes various games to start rendering or trying to render
2018-06-22 22:22:33 -04:00
bunnei
ea1880f47c Merge pull request #526 from janisozaur/appveyor-ninja
Use Ninja for MSVC AppVeyor builds
2018-06-22 14:28:26 -04:00
bunnei
6d7941042b Merge pull request #579 from SciresM/master
svc: Fully implement svcSignalToAddress and svcWaitForAddress
2018-06-22 12:08:39 -04:00
bunnei
52a78228dd Merge pull request #581 from mailwl/empty-buf-skip
IPC: skip empty buffer write
2018-06-22 10:26:09 -04:00
mailwl
a27befe456 IPC: skip empty buffer write
prevent yuzu crash, if games, like Axiom Verge, trying to read 0 bytes from file
2018-06-22 11:28:10 +03:00
Michael Scire
067ac434ba Kernel/Arbiters: Fix casts, cleanup comments/magic numbers 2018-06-22 00:47:59 -06:00
Michael Scire
5f8aa02584 Add additional missing format. 2018-06-21 21:09:51 -06:00
Michael Scire
08d454e30d Run clang-format on PR. 2018-06-21 21:05:34 -06:00
bunnei
b7162c32a4 Merge pull request #577 from mailwl/audren-update
Service/Audio: update audren:u service
2018-06-21 22:40:37 -04:00
Michael Scire
dc70a87af1 Kernel/Arbiters: HLE is atomic, adjust code to reflect that. 2018-06-21 20:25:57 -06:00
Zach Hilman
63f26d5c40 Add support for decrypted NCA files (#567)
* Start to add NCA support in loader

* More nca stuff

* More changes to nca.cpp

* Now identifies decrypted NCA cont.

* Game list fixes and more structs and stuff

* More updates to Nca class

* Now reads ExeFs (i think)

* ACTUALLY LOADS EXEFS!

* RomFS loads and games execute

* Cleanup and Finalize

* plumbing, cleanup and testing

* fix some things that i didnt think of before

* Preliminary Review Changes

* Review changes for bunnei and subv
2018-06-21 11:16:23 -04:00
Michael Scire
8f8fe62a19 Kernel/Arbiters: Initialize arb_wait_address in thread struct. 2018-06-21 05:13:06 -06:00
Michael Scire
62bd1299ea Kernel/Arbiters: Clear WaitAddress in SignalToAddress 2018-06-21 04:20:39 -06:00
Michael Scire
4f81bc4e1b Kernel/Arbiters: Mostly implement SignalToAddress 2018-06-21 04:10:11 -06:00
Michael Scire
9d71ce88ce Kernel/Arbiters: Implement WaitForAddress 2018-06-21 01:40:29 -06:00
mailwl
c06d6b27f3 Service/Audio: update audren:u service 2018-06-21 10:26:24 +03:00
Michael Scire
7e191dccc1 Kernel/Arbiters: Add stubs for 4.x SignalToAddress/WaitForAddres SVCs. 2018-06-21 00:49:43 -06:00
bunnei
c3e95086b6 Merge pull request #576 from Subv/warnings1
Build: Fixed some MSVC warnings in various parts of the code.
2018-06-20 16:46:14 -04:00
Subv
a3d82ef5d9 Build: Fixed some MSVC warnings in various parts of the code. 2018-06-20 11:39:10 -05:00
greggameplayer
be1f5dedfb Implement GetAvailableLanguageCodes2 (#575)
* Implement GetAvailableLanguageCodes2

* Revert "Implement GetAvailableLanguageCodes2"

This reverts commit caadd9eea3.

* Implement GetAvailableLanguageCodes2

* Implement GetAvailableLanguageCodes2
2018-06-19 11:29:04 -04:00
bunnei
7a0bb406d5 Merge pull request #574 from Subv/shader_abs_neg
GPU: Perform negation after absolute value in the float shader instructions.
2018-06-18 22:24:57 -04:00
bunnei
0d8ae773f1 Merge pull request #561 from DarkLordZach/fix-odyssey-input-crash
Avoid initializing single-joycon layouts with handheld controller
2018-06-18 22:06:11 -04:00
bunnei
1ab133d7fa Merge pull request #573 from Subv/shader_imm
GPU: Don't mark uniform buffers and registers as used for instructions which don't have them.
2018-06-18 21:52:56 -04:00
Subv
38989bef43 GPU: Perform negation after absolute value in the float shader instructions. 2018-06-18 19:56:29 -05:00
Subv
eab7457c00 GPU: Don't mark uniform buffers and registers as used for instructions which don't have them.
Like the MOV32I and FMUL32I instructions.
This fixes a potential crash when using these instructions.
2018-06-18 19:50:35 -05:00
Subv
5f57a70a7d Services/FS: Return the correct error code when trying to mount a nonexistent savedata. 2018-06-18 19:26:01 -05:00
bunnei
0e13d9cb7b Merge pull request #570 from bunnei/astc
gl_rasterizer: Implement texture format ASTC_2D_4X4.
2018-06-18 19:08:49 -04:00
bunnei
c11cfaa705 Merge pull request #562 from DarkLordZach/extracted-ncas-ui
Add UI support for extracted NCA folders
2018-06-18 16:09:46 -04:00
bunnei
4ac4b308e4 Merge pull request #572 from Armada651/user-except-stub
svc: Add a stub for UserExceptionContextAddr.
2018-06-18 11:37:13 -04:00
bunnei
ea080501fb Merge pull request #571 from Armada651/loose-blend
gl_rasterizer: Get loose on independent blending.
2018-06-18 11:36:50 -04:00
Jules Blok
bf4e2b2f0b svc: Add a stub for UserExceptionContextAddr. 2018-06-18 09:29:11 +02:00
Jules Blok
7c7f4a9be2 gl_rasterizer: Get loose on independent blending. 2018-06-18 09:27:06 +02:00
bunnei
61779fa072 gl_rasterizer: Implement texture format ASTC_2D_4X4. 2018-06-18 01:56:59 -04:00
bunnei
d2277b825e Merge pull request #569 from bunnei/fix-cache
gl_rasterizer_cache: Loosen things up a bit.
2018-06-18 01:32:12 -04:00
bunnei
fe906fff36 gl_rasterizer_cache: Loosen things up a bit. 2018-06-18 00:55:59 -04:00
bunnei
f9af74201c Merge pull request #568 from bunnei/lop
gl_shader_decompiler: Implement LOP instructions.
2018-06-17 17:44:38 -04:00
bunnei
afdd657d30 gl_shader_decompiler: Implement LOP instructions. 2018-06-17 15:27:48 -04:00
bunnei
5673ce39c7 gl_shader_decompiler: Refactor LOP32I instruction a bit in support of LOP. 2018-06-17 13:31:39 -04:00
bunnei
3c43ea5c68 Merge pull request #565 from bunnei/shader_conversions
gl_shader_decompiler: Implement register size conversions for I2I and I2F.
2018-06-16 08:50:29 -04:00
bunnei
d383043e07 gl_shader_decompiler: Implement integer size conversions for I2I/I2F/F2I. 2018-06-15 22:42:02 -04:00
bunnei
fb5bd0920d Merge pull request #564 from bunnei/lop32i_passb
gl_shader_decompiler: Implement LOP32I LogicOperation PassB.
2018-06-15 22:04:03 -04:00
bunnei
46cbb6b090 Merge pull request #566 from bunnei/set_pos_w
gl_shader_gen: Set position.w to 1.
2018-06-15 22:03:48 -04:00
bunnei
55c49d5bf4 gl_shader_gen: Set position.w to 1. 2018-06-15 20:47:04 -04:00
bunnei
61f9d9c4ab gl_shader_decompiler: Implement LOP32I LogicOperation PassB. 2018-06-15 20:43:33 -04:00
Zach Hilman
acc8fe5a2a Bug fixes, testing, and review changes 2018-06-14 17:25:40 -04:00
Zach Hilman
f969ddb54e Add 'Load Folder' menu option 2018-06-14 12:27:29 -04:00
Zach Hilman
9f8fbce35b Add support for main files in file picker 2018-06-14 12:16:56 -04:00
Zach Hilman
94d27b1717 Recognize main files in game list 2018-06-14 12:02:32 -04:00
Zach Hilman
ac88d3e89f Narrow down filter of layout configs 2018-06-13 20:03:12 -04:00
Zach Hilman
a353322b58 Move loop condition to free function 2018-06-13 13:44:46 -04:00
Zach Hilman
50153a1cb2 Avoid initializing single-joycon layouts with handheld controller 2018-06-13 13:01:05 -04:00
bunnei
17f3590d59 Merge pull request #560 from Subv/crash_widget
Qt: Removed the Registers widget.
2018-06-13 10:15:00 -04:00
Subv
7786f41cc0 Qt: Removed the Registers widget.
It was crashing and nobody actually uses this.
2018-06-12 20:33:32 -05:00
bunnei
019d7208c8 Merge pull request #556 from Subv/dma_engine
GPU: Partially implemented the Maxwell DMA engine.
2018-06-12 14:25:17 -04:00
bunnei
2015a1b180 Merge pull request #558 from Subv/iadd32i
GPU: Implemented the iadd32i shader instruction.
2018-06-12 14:19:25 -04:00
Subv
db0497b808 GPU: Implemented the iadd32i shader instruction. 2018-06-12 11:46:45 -05:00
Subv
987a170665 GPU: Partially implemented the Maxwell DMA engine.
Only tiled->linear and linear->tiled copies that aren't offsetted are supported for now. Queries are not supported. Swizzled copies are not supported.
2018-06-12 11:27:36 -05:00
bunnei
33dbf24b56 Merge pull request #557 from shinyquagsire23/libnx-hid-fix
hid: Update all layouts and only show handheld as connected, fixes libnx input for P1_AUTO
2018-06-12 09:07:38 -04:00
bunnei
2dc8b5c224 Merge pull request #552 from bunnei/sat-fmul
gl_shader_decompiler: Implement saturate for float instructions.
2018-06-11 23:19:37 -04:00
bunnei
5f3d6c85db gl_shader_decompiler: Implement saturate for float instructions. 2018-06-11 21:46:34 -04:00
shinyquagsire23
2f9c0e7c7e hid: Update all layouts and only show handheld as connected, fixes libnx input for P1_AUTO 2018-06-11 19:41:29 -06:00
bunnei
09b8a16414 Merge pull request #555 from Subv/gpu_sysregs
GPU: Convert the gl_InstanceId and gl_VertexID variables to floats when reading from them.
2018-06-10 20:55:27 -04:00
Subv
004b1b3830 GPU: Convert the gl_InstanceId and gl_VertexID variables to floats when reading from them.
This corrects the invalid position values in some games when doing attribute-less rendering.
2018-06-10 13:50:19 -05:00
bunnei
281fd881a0 Merge pull request #553 from Subv/iset
GPU: Implement the ISET family of shader instructions.
2018-06-10 10:50:38 -04:00
Subv
2a7653142d Rasterizer: Use UBOs instead of SSBOs for uploading const buffers.
This should help a bit with GPU performance once we're GPU-bound.
2018-06-09 18:02:05 -05:00
Subv
b366b885a1 GPU: Implement the iset family of shader instructions. 2018-06-09 16:19:13 -05:00
Subv
3cb753eeb1 GPU: Added decodings for the ISET family of instructions. 2018-06-09 15:56:50 -05:00
bunnei
d81aaa3ed3 Merge pull request #550 from Subv/ssy
GPU: Stub the SSY shader instruction.
2018-06-09 00:42:53 -04:00
bunnei
e2176dc7ce Merge pull request #551 from bunnei/shr
gl_shader_decompiler: Implement SHR instruction.
2018-06-09 00:42:44 -04:00
bunnei
174c22e5f6 Merge pull request #549 from bunnei/iadd
gl_shader_decompiler: Implement IADD instruction.
2018-06-09 00:34:03 -04:00
bunnei
5440b9c634 gl_shader_decompiler: Implement SHR instruction. 2018-06-09 00:01:17 -04:00
Subv
abec5f82e2 GPU: Stub the SSY shader instruction.
This instruction tells the GPU where the flow reconverges in a non-uniform control flow scenario, we can ignore this when generating GLSL code.
2018-06-08 22:46:10 -05:00
bunnei
bbc4f369ed gl_shader_decompiler: Implement IADD instruction. 2018-06-08 23:25:22 -04:00
bunnei
79e9c2e237 gl_shader_decompiler: Add missing asserts for saturate_a instructions. 2018-06-08 23:24:10 -04:00
bunnei
83517cb53a Merge pull request #505 from janisozaur/ccache-travis
Enable ccache usage on Travis
2018-06-08 18:51:59 -04:00
bunnei
9949e4d508 Merge pull request #533 from mailwl/array-to-buffer
Common/string_util: add StringFromBuffer() function
2018-06-08 18:51:00 -04:00
bunnei
c116b220e9 Merge pull request #548 from Subv/blend
GPU: Fixed ghosting when drawing with blending disabled
2018-06-08 18:48:12 -04:00
Subv
c011b6f67e GPU: Synchronize the blend state on every draw call.
Only independent blending on render target 0 is implemented for now.

This fixes the elongated squids in Splatoon 2's boot screen.
2018-06-08 17:05:52 -05:00
Subv
c712dafaee GPU: Added registers for normal and independent blending. 2018-06-08 17:04:41 -05:00
bunnei
a931cf9e8b Merge pull request #547 from Subv/compressed_alignment
GLCache: Align compressed texture sizes to their compression ratio, and then align that compressed size to the block height for tiled textures.
2018-06-08 16:40:49 -04:00
bunnei
a941a94148 Merge pull request #546 from Subv/flush_ubo_buffer
Rasterizer: Flush the written region when writing shader uniform data before copying it to the uniform buffers.
2018-06-08 16:39:55 -04:00
Subv
8d9534d830 GLCache: Align compressed texture sizes to their compression ratio, and then align that compressed size to the block height for tiled textures.
This fixes issues with retrieving non-block-aligned tiled compressed textures from the cache.
2018-06-08 12:27:19 -05:00
Subv
47dc5e0dab Rasterizer: Flush the written region when writing shader uniform data before copying it to the uniform buffers.
This fixes the flip_viewport uniform having invalid values when drawing.
2018-06-08 12:22:39 -05:00
Michał Janiszewski
f3885845fc Cache ccache on Travis 2018-06-07 21:43:33 +02:00
Michał Janiszewski
c0d3e2da4e Add ccache support for macOS on Travis 2018-06-07 21:43:33 +02:00
Michał Janiszewski
517112f549 Add ccache support for Linux on Travis 2018-06-07 21:43:32 +02:00
Michał Janiszewski
6324d86c71 Install cmake from repositories for Ubuntu
Ubuntu 18.04 already has cmake 3.10.2
2018-06-07 21:42:12 +02:00
bunnei
5aff2d38a9 Merge pull request #478 from janisozaur/patch-1
Use Ninja for Travis builds
2018-06-07 11:45:50 -04:00
bunnei
ee318d4015 Merge pull request #543 from Subv/uniforms
GLRenderer: Write the shader stage configuration UBO data *before* copying it to the GPU.
2018-06-07 11:21:36 -04:00
Subv
86146ef819 GLRenderer: Write the shader stage configuration UBO data *before* copying it to the GPU.
This should fix the bug with the vs_config UBO being uninitialized during shader execution.
2018-06-07 08:33:23 -05:00
mailwl
a2efb1dd48 Common/string_util: add StringFromBuffer function
convert input buffer (std::vector<u8>) to string, stripping zero chars
2018-06-07 09:59:47 +03:00
bunnei
ee1eb8cfdf Merge pull request #522 from mailwl/mm-u
Service/MM: add service and stub some functions
2018-06-07 02:00:04 -04:00
bunnei
0639e03055 Merge pull request #542 from bunnei/bfe_imm
gl_shader_decompiler: Implement BFE_IMM instruction.
2018-06-07 01:49:45 -04:00
bunnei
930487c7fb Merge pull request #541 from Subv/blittextures
GLCache: Fixed copying compressed textures in the rasterizer cache.
2018-06-07 01:35:01 -04:00
bunnei
92209f905f gl_shader_decompiler: Implement BFE_IMM instruction. 2018-06-07 00:58:12 -04:00
Subv
f22e090b86 GLCache: Use the full uncompressed size when blitting from one texture to another.
This avoids the problem of only copying a tiny piece of the textures when they are compressed.
2018-06-06 23:26:36 -05:00
Subv
218a08df93 GLCache: Simplify the logic to copy from one texture to another in BlitTextures.
We now use glCopyImageSubData, this should avoid errors with trying to attach a compressed texture as a framebuffer's color attachment and then blitting to it.

Maybe in the future we can change this to glCopyTextureSubImage which only requires GL_ARB_direct_state_access.
2018-06-06 23:25:24 -05:00
bunnei
0cb7ce71e0 Merge pull request #539 from bunnei/f2f-rounding
gl_shader_decompiler: F2F: Implement rounding modes.
2018-06-07 00:10:09 -04:00
bunnei
9f21f20d7c Merge pull request #503 from mailwl/nfp-stubs
Service/nfp:user : stub some functions.
2018-06-06 22:36:53 -04:00
bunnei
128aeba0f3 gl_shader_decompiler: F2F: Implement rounding modes. 2018-06-06 22:21:29 -04:00
bunnei
03f877919d Merge pull request #537 from bunnei/misc-shader
gl_shader_decompiler: Additional decodings, remove unused stuff from TEX
2018-06-06 21:44:37 -04:00
bunnei
37f50c8773 Merge pull request #535 from Subv/gpu_swizzle
GPU: Support changing the texture swizzles for Maxwell textures.
2018-06-06 21:39:47 -04:00
bunnei
4732e1f064 Merge pull request #536 from bunnei/isetp_imm
gl_shader_decompiler: Implement ISETP_IMM instruction.
2018-06-06 21:38:22 -04:00
bunnei
00c830405b gl_shader_decompiler: Remove some attribute stuff that has nothing to do with TEX/TEXS. 2018-06-06 19:47:41 -04:00
bunnei
4b114e1b8a shader_bytecode: Add instruction decodings for BFE, IMNMX, and XMAD. 2018-06-06 19:47:34 -04:00
bunnei
0a49c46353 gl_shader_decompiler: Implement ISETP_IMM instruction. 2018-06-06 19:45:58 -04:00
Subv
47629c89a8 GPU: Support changing the texture swizzles for Maxwell textures. 2018-06-06 18:36:15 -05:00
Subv
89e81a9be2 GLState: Support changing the GL_TEXTURE_SWIZZLE parameter of each texture unit. 2018-06-06 18:36:13 -05:00
bunnei
0ff2929644 Merge pull request #534 from Subv/multitexturing
GPU: Implement sampling multiple textures in the generated glsl shaders.
2018-06-06 19:12:52 -04:00
bunnei
cfc9effa6c Merge pull request #532 from bunnei/ld_c
gl_shader_decompiler: Implement LD_C instruction.
2018-06-06 18:56:55 -04:00
bunnei
4669f15f8b gl_shader_decompiler: Implement LD_C instruction. 2018-06-06 18:09:06 -04:00
bunnei
4112aa68a6 gl_shader_gen: Add uniform handling for indirect const buffer access. 2018-06-06 18:09:05 -04:00
bunnei
6e386a334b gl_shader_decompiler: Refactor uniform handling to allow different decodings. 2018-06-06 17:57:15 -04:00
Subv
dbfc39d214 GPU: Implement sampling multiple textures in the generated glsl shaders.
All tested games that use a single texture show no regression.

Only Texture2D textures are supported right now, each shader gets its own "tex_fs/vs/gs" sampler array to maintain independent textures between shader stages, the textures themselves are reused if possible.
2018-06-06 12:58:16 -05:00
mailwl
61fbf5c8e6 Stub IUser::AttachAvailabilityChangeEvent 2018-06-06 19:05:11 +03:00
greggameplayer
be09dfeed9 nvdrv/devices/nvidia_ctrl_gpu : add IoctlCommands with their params (#524)
* add IoctlCommands with their params in nvidia_ctrl_gpu.h

* add function related to the changes done previously

* fix clang-format

* delete trailing whitespace

* correct mistake
2018-06-06 08:31:17 -05:00
Sebastian Valle
2f842a86fe Merge pull request #529 from bunnei/am-nifm-stubs
Stub SetConnectionConfirmationOption, GetPseudoDeviceId
2018-06-06 08:29:12 -05:00
Sebastian Valle
ce026332a5 Merge pull request #531 from bunnei/fix-shl
gl_shader_decompiler: Fix un/signed mismatch with SHL.
2018-06-06 08:28:42 -05:00
Sebastian Valle
fa220dd709 Merge pull request #530 from bunnei/wrap-mirror
maxwell_to_gl: Implement WrapMode Mirror.
2018-06-06 08:28:27 -05:00
mailwl
a776464a55 Remove unused header files 2018-06-06 09:10:48 +03:00
bunnei
9a85277d83 Merge pull request #527 from Subv/rgba32f_texcopy
GPU: Allow the usage of RGBA32_FLOAT and RGBA16_FLOAT in the texture copy engine.
2018-06-06 00:24:13 -04:00
bunnei
05dc93399b Merge pull request #528 from Subv/rg11b10f
GPU: Implemented the R11FG11FB10F texture and rendertarget formats.
2018-06-06 00:22:54 -04:00
Hedges
39fb3e362c GDB Stub Improvements (#508)
* GDB Stub should work now.

* Applied clang-format.

* Replaced htonll with swap64.

* Tidy up.
2018-06-06 00:20:47 -04:00
bunnei
566f97b580 gl_shader_decompiler: Fix un/signed mismatch with SHL. 2018-06-05 23:58:06 -04:00
bunnei
bf0543af23 maxwell_to_gl: Implement WrapMode Mirror. 2018-06-05 23:56:45 -04:00
bunnei
c5684411a0 nifm: Stub out IRequest::SetConnectionConfirmationOption. 2018-06-05 23:54:13 -04:00
bunnei
2abe5e39fc am: Stub out IApplicationFunctions::GetPseudoDeviceId. 2018-06-05 23:54:02 -04:00
Subv
adf47cd59a GPU: Allow the usage of RGBA16_FLOAT in the texture copy engine. 2018-06-05 22:01:20 -05:00
Subv
c531a92eda GPU: Implemented the R11FG11FB10F texture and rendertarget formats. 2018-06-05 21:57:16 -05:00
Subv
14afc704d4 GPU: Fixed the compression factor for RGBA16F textures.
They're not compressed.
2018-06-05 21:55:17 -05:00
Subv
8d70d1ea45 GPU: Allow the usage of RGBA32_FLOAT in the texture copy engine. 2018-06-05 21:07:40 -05:00
bunnei
5fb99e6a16 Merge pull request #516 from Subv/f2i_r
GPU: Implemented the F2I_R shader instruction.
2018-06-05 22:01:29 -04:00
Michał Janiszewski
5c3d5d0849 Use Ninja for MSVC AppVeyor builds 2018-06-05 22:46:54 +02:00
Michał Janiszewski
79de0f8fe8 Drop /std:c++latest from MSVC command line
CMake already sets it to version 17 in all cases
2018-06-05 22:41:28 +02:00
James Rowe
6e8e1a4110 Merge pull request #523 from yuzu-emu/revert-507-3616
Revert "Port citra #3616"
2018-06-05 10:49:59 -06:00
bunnei
9232fbdf34 Revert "Port citra #3616" 2018-06-05 10:52:52 -04:00
bunnei
38eb33f150 Merge pull request #521 from Subv/bra
GPU: Corrected the branch targets for the shader bra instruction.
2018-06-05 10:09:35 -04:00
bunnei
b54a72afc0 Merge pull request #520 from bunnei/shader-shl
gl_shader_decompiler: Implement SHL instruction.
2018-06-05 10:08:42 -04:00
mailwl
62cd19e4ae Small fixes 2018-06-05 15:34:01 +03:00
mailwl
7e3d746b06 Service/MM: add service and stub some functions 2018-06-05 12:19:29 +03:00
Subv
e7dfcdde74 GPU: Corrected the branch targets for the shader bra instruction. 2018-06-04 22:56:28 -05:00
Subv
4b89348c00 GPU: Implemented the F2I_R shader instruction. 2018-06-04 22:06:50 -05:00
bunnei
8c99dd055c Merge pull request #518 from Subv/incomplete_shaders
GPU: Implemented predicated exit instructions in the shader programs.
2018-06-04 22:43:46 -04:00
bunnei
799e632ccb gl_shader_decompiler: Fix typo with ISCADD instruction. 2018-06-04 22:41:10 -04:00
bunnei
c23c30c76f gl_shader_decompiler: Implement SHL instruction. 2018-06-04 22:36:49 -04:00
bunnei
00749f5ab3 Merge pull request #519 from bunnei/pred-not-equal
gl_shader_decompiler: Implement PredCondition::NotEqual.
2018-06-04 22:18:22 -04:00
bunnei
6ea1576513 gl_shader_decompiler: Implement PredCondition::NotEqual. 2018-06-04 22:00:47 -04:00
bunnei
81a16c073a Merge pull request #517 from Subv/iscadd
GPU: Implement the ISCADD shader instruction.
2018-06-04 21:59:55 -04:00
Subv
23b1e6eded GPU: Implement the ISCADD shader instructions. 2018-06-04 20:17:41 -05:00
Subv
438a9b70cc GPU: Added decodings for the ISCADD instructions. 2018-06-04 20:17:39 -05:00
bunnei
e8bfff7b4b Merge pull request #514 from Subv/lop32i
GPU: Implemented the LOP32I instruction.
2018-06-04 20:48:15 -04:00
bunnei
f564822e78 Merge pull request #510 from Subv/isetp
GPU: Implemented the ISETP_R and ISETP_C instructions
2018-06-04 20:47:11 -04:00
Subv
6cf6fa2842 GPU: Implement predicated exit instructions in the shader programs. 2018-06-04 19:18:11 -05:00
Subv
d27279092f GPU: Take into account predicated exits when performing shader control flow analysis. 2018-06-04 19:14:23 -05:00
bunnei
37fd4e6d9b Merge pull request #512 from Subv/fset
GPU: Corrected the FSET and I2F instructions.
2018-06-04 19:04:20 -04:00
bunnei
cdd92dc692 Merge pull request #501 from Subv/shader_bra
GPU: Partially implemented the bra shader instruction
2018-06-04 18:31:07 -04:00
bunnei
38d25a4cb2 Merge pull request #515 from Subv/viewport_fix
GPU: Calculate the correct viewport dimensions based on the scale and translate registers.
2018-06-04 18:11:36 -04:00
Subv
5d55403f94 GPU: Calculate the correct viewport dimensions based on the scale and translate registers.
This is how nouveau calculates the viewport width and height. For some reason some games set 0xFFFF in the VIEWPORT_HORIZ and VIEWPORT_VERT registers, maybe those are a misnomer and actually refer to something else?
2018-06-04 16:36:54 -05:00
bunnei
0a0233f39f Merge pull request #490 from BreadFish64/extension-check
Add checks for OpenGL extension support
2018-06-04 16:13:55 -04:00
bunnei
9936d1b9e2 Merge pull request #513 from Subv/cache_alignment
GLCache: Corrected a mismatch between storing compressed sizes and verifying the uncompressed alignment in GetSurface.
2018-06-04 16:12:55 -04:00
greggameplayer
4fad069870 Nvdrv/devices/nvhost_gpu : Add some IoctlCommands with their params (#511)
* Add some IoctlCommand with their params to nvhost_gpu

* fix clang-format

* delete trailing whitespace

* fix some clang-format

* delete one other trailing whitespace

* last clang-format fix
2018-06-04 16:12:02 -04:00
Subv
0c688b421c GPU: Implemented the LOP32I instruction. 2018-06-04 13:56:31 -05:00
Subv
cb47abecc6 GLCache: Corrected a mismatch between storing compressed sizes and verifying the uncompressed alignment in GetSurface. 2018-06-04 13:01:53 -05:00
BreadFish64
fbef849c04 sdl: add check for GL extension support 2018-06-04 12:26:41 -05:00
BreadFish64
0641950f9a qt: add check for GL extension support 2018-06-04 12:26:30 -05:00
bunnei
b7c64f0ded Merge pull request #502 from bunnei/more-am-stuff
am: Implement PopOutData, and various fixes.
2018-06-04 13:23:19 -04:00
Subv
90cddf1996 GPU: Use explicit types when retrieving the uniform values for fsetp/fset and isetp instead of the type of an invalid output register. 2018-06-04 11:22:26 -05:00
Subv
7c181fd4f4 GPU: Implemented the ISETP_R and ISETP_C shader instructions. 2018-06-04 11:12:03 -05:00
James Rowe
d16f83fda3 Merge pull request #507 from valentinvanelslande/3616
Port citra #3616
2018-06-04 10:04:18 -06:00
Valentin Vanelslande
5c82400ef8 Port citra #3616 2018-06-04 10:57:18 -05:00
mailwl
bb081dd1d2 Correct function results 2018-06-04 14:43:02 +03:00
mailwl
019778707d Service/nfp:user : stub some functions.
Used by Zelda: BoTW
2018-06-04 12:39:43 +03:00
bunnei
afdd2f4cad am: Implement ILibraryAppletAccessor::PopOutData. 2018-06-03 23:44:23 -04:00
bunnei
df4336a85e am: ISelfController:LaunchableEvent should be sticky. 2018-06-03 23:44:22 -04:00
bunnei
51d8a2c322 am: Stub out ILibraryAppletAccessor Start and GetResult methods. 2018-06-03 23:44:22 -04:00
Subv
b481d8a00d GPU: Partially implemented the shader BRA instruction. 2018-06-03 22:26:36 -05:00
Subv
06c72b4fcf GPU: Added decoding for the BRA instruction. 2018-06-03 22:14:00 -05:00
Michał Janiszewski
2abf39ea4a Use Ninja for Travis builds 2018-05-28 11:34:47 +02:00
205 changed files with 8080 additions and 3671 deletions

1
.gitignore vendored
View File

@@ -11,6 +11,7 @@ src/common/scm_rev.cpp
.idea/
.vs/
.vscode/
CMakeLists.txt.user
# *nix related
# Common convention for backup or temporary files

View File

@@ -42,3 +42,7 @@ notifications:
webhooks:
urls:
- https://api.yuzu-emu.org/code/travis/notify
cache:
directories:
- $HOME/.ccache

View File

@@ -1,3 +1,3 @@
#!/bin/bash -ex
docker run -v $(pwd):/yuzu ubuntu:18.04 /bin/bash /yuzu/.travis/linux/docker.sh
docker run -e CCACHE_DIR=/ccache -v $HOME/.ccache:/ccache -v $(pwd):/yuzu ubuntu:18.04 /bin/bash /yuzu/.travis/linux/docker.sh

View File

@@ -1,16 +1,18 @@
#!/bin/bash -ex
apt-get update
apt-get install -y build-essential git libqt5opengl5-dev libsdl2-dev libssl-dev python qtbase5-dev wget
# Get a recent version of CMake
wget https://cmake.org/files/v3.10/cmake-3.10.1-Linux-x86_64.sh
sh cmake-3.10.1-Linux-x86_64.sh --exclude-subdir --prefix=/ --skip-license
apt-get install --no-install-recommends -y build-essential git libqt5opengl5-dev libsdl2-dev libssl-dev python qtbase5-dev wget cmake ninja-build ccache
cd /yuzu
export PATH=/usr/lib/ccache:$PATH
ln -sf /usr/bin/ccache /usr/lib/ccache/cc
ln -sf /usr/bin/ccache /usr/lib/ccache/c++
mkdir build && cd build
cmake .. -DYUZU_BUILD_UNICORN=ON -DCMAKE_BUILD_TYPE=Release
make -j4
ccache --show-stats > ccache_before
cmake .. -DYUZU_BUILD_UNICORN=ON -DCMAKE_BUILD_TYPE=Release -G Ninja
ninja
ccache --show-stats > ccache_after
diff -U100 ccache_before ccache_after || true
ctest -VV -C Release

View File

@@ -7,8 +7,12 @@ export Qt5_DIR=$(brew --prefix)/opt/qt5
export UNICORNDIR=$(pwd)/externals/unicorn
mkdir build && cd build
export PATH=/usr/local/opt/ccache/libexec:$PATH
ccache --show-stats > ccache_before
cmake --version
cmake .. -DYUZU_BUILD_UNICORN=ON -DCMAKE_BUILD_TYPE=Release
make -j4
ccache --show-stats > ccache_after
diff -U100 ccache_before ccache_after || true
ctest -VV -C Release

View File

@@ -1,5 +1,5 @@
#!/bin/sh -ex
brew update
brew install dylibbundler p7zip qt5 sdl2
brew install dylibbundler p7zip qt5 sdl2 ccache
brew outdated cmake || brew upgrade cmake

View File

@@ -3,7 +3,9 @@ function(copy_yuzu_Qt5_deps target_dir)
set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
set(Qt5_DLL_DIR "${Qt5_DIR}/../../../bin")
set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/")
set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/")
set(PLATFORMS ${DLL_DEST}platforms/)
set(STYLES ${DLL_DEST}styles/)
windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST}
icudt*.dll
icuin*.dll
@@ -14,4 +16,5 @@ function(copy_yuzu_Qt5_deps target_dir)
Qt5Widgets$<$<CONFIG:Debug>:d>.*
)
windows_copy_files(yuzu ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*)
windows_copy_files(yuzu ${Qt5_STYLES_DIR} ${STYLES} qwindowsvistastyle$<$<CONFIG:Debug>:d>.*)
endfunction(copy_yuzu_Qt5_deps)

View File

@@ -1,6 +1,6 @@
# Reporting Issues
**The issue tracker is not a support forum.** Unless you can provide precise *technical information* regarding an issue, you *should not post in it*. If you need support, first read the [FAQ](https://github.com/yuzu-emu/yuzu/wiki/FAQ) and then either visit our Discord server, [our forum](https://community.citra-emu.org) or ask in a general emulation forum such as [/r/emulation](https://www.reddit.com/r/emulation/). If you post support questions, generic messages to the developers or vague reports without technical details, they will be closed and locked.
**The issue tracker is not a support forum.** Unless you can provide precise *technical information* regarding an issue, you *should not post in it*. If you need support, first read the [FAQ](https://github.com/yuzu-emu/yuzu/wiki/FAQ) and then either visit our [Discord server](https://discordapp.com/invite/u77vRWY), [our forum](https://community.citra-emu.org) or ask in a general emulation forum such as [/r/emulation](https://www.reddit.com/r/emulation/). If you post support questions, generic messages to the developers or vague reports without technical details, they will be closed and locked.
If you believe you have a valid issue report, please post text or a screenshot from the log (the console window that opens alongside yuzu) and build version (hex string visible in the titlebar and zip filename), as well as your hardware and software information if applicable.

View File

@@ -116,6 +116,7 @@ after_build:
mkdir $RELEASE_DIST
mkdir $RELEASE_DIST/platforms
mkdir $RELEASE_DIST/styles
# copy the compiled binaries and other release files to the release folder
Get-ChildItem "$CMAKE_BINARY_DIR" -Filter "yuzu*.exe" | Copy-Item -destination $RELEASE_DIST
@@ -136,6 +137,9 @@ after_build:
# copy the qt windows plugin dll to platforms
Copy-Item -path "C:/msys64/mingw64/share/qt5/plugins/platforms/qwindows.dll" -force -destination "$RELEASE_DIST/platforms"
# copy the qt windows vista style dll to platforms
Copy-Item -path "C:/msys64/mingw64/share/qt5/plugins/styles/qwindowsvistastyle.dll" -force -destination "$RELEASE_DIST/styles"
7z a -tzip $MINGW_BUILD_ZIP $RELEASE_DIST\*
7z a $MINGW_SEVENZIP $RELEASE_DIST
}

View File

@@ -1,4 +1,4 @@
# Copyright 2016 Citra Emulator Project
# Copyright 2018 Yuzu Emulator Project
# Licensed under GPLv2 or any later version
# Refer to the license.txt file included.
@@ -22,7 +22,7 @@ function(windows_copy_files TARGET SOURCE_DIR DEST_DIR)
# cmake adds an extra check for command success which doesn't work too well with robocopy
# so trick it into thinking the command was successful with the || cmd /c "exit /b 0"
add_custom_command(TARGET ${TARGET} POST_BUILD
COMMAND if not exist ${DEST_DIR} mkdir ${DEST_DIR} 2> nul
COMMAND ${CMAKE_COMMAND} -E make_directory ${DEST_DIR}
COMMAND robocopy ${SOURCE_DIR} ${DEST_DIR} ${ARGN} /NJH /NJS /NDL /NFL /NC /NS /NP || cmd /c "exit /b 0"
)
endfunction()
endfunction()

View File

@@ -30,15 +30,14 @@ __declspec(noinline, noreturn)
#define ASSERT(_a_) \
do \
if (!(_a_)) { \
assert_noinline_call([] { NGLOG_CRITICAL(Debug, "Assertion Failed!"); }); \
assert_noinline_call([] { LOG_CRITICAL(Debug, "Assertion Failed!"); }); \
} \
while (0)
#define ASSERT_MSG(_a_, ...) \
do \
if (!(_a_)) { \
assert_noinline_call( \
[&] { NGLOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); }); \
assert_noinline_call([&] { LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); }); \
} \
while (0)
@@ -53,5 +52,5 @@ __declspec(noinline, noreturn)
#define DEBUG_ASSERT_MSG(_a_, _desc_, ...)
#endif
#define UNIMPLEMENTED() DEBUG_ASSERT_MSG(false, "Unimplemented code!")
#define UNIMPLEMENTED() LOG_CRITICAL(Debug, "Unimplemented code!")
#define UNIMPLEMENTED_MSG(...) ASSERT_MSG(false, __VA_ARGS__)

View File

@@ -4,7 +4,7 @@
#pragma once
#if !defined(ARCHITECTURE_x86_64) && !defined(_M_ARM)
#if !defined(ARCHITECTURE_x86_64) && !defined(ARCHITECTURE_ARM)
#include <cstdlib> // for exit
#endif
#include "common/common_types.h"
@@ -30,7 +30,7 @@
#ifdef ARCHITECTURE_x86_64
#define Crash() __asm__ __volatile__("int $3")
#elif defined(_M_ARM)
#elif defined(ARCHITECTURE_ARM)
#define Crash() __asm__ __volatile__("trap")
#else
#define Crash() exit(1)

View File

@@ -32,12 +32,15 @@
#define SDMC_DIR "sdmc"
#define NAND_DIR "nand"
#define SYSDATA_DIR "sysdata"
#define LOG_DIR "log"
// Filenames
// Files in the directory returned by GetUserPath(D_CONFIG_IDX)
#define EMU_CONFIG "emu.ini"
#define DEBUGGER_CONFIG "debugger.ini"
#define LOGGER_CONFIG "logger.ini"
// Files in the directory returned by GetUserPath(D_LOGS_IDX)
#define LOG_FILE "yuzu_log.txt"
// Sys files
#define SHARED_FONT "shared_font.bin"

View File

@@ -118,7 +118,7 @@ bool IsDirectory(const std::string& filename) {
#endif
if (result < 0) {
NGLOG_DEBUG(Common_Filesystem, "stat failed on {}: {}", filename, GetLastErrorMsg());
LOG_DEBUG(Common_Filesystem, "stat failed on {}: {}", filename, GetLastErrorMsg());
return false;
}
@@ -128,29 +128,29 @@ bool IsDirectory(const std::string& filename) {
// Deletes a given filename, return true on success
// Doesn't supports deleting a directory
bool Delete(const std::string& filename) {
NGLOG_TRACE(Common_Filesystem, "file {}", filename);
LOG_TRACE(Common_Filesystem, "file {}", filename);
// Return true because we care about the file no
// being there, not the actual delete.
if (!Exists(filename)) {
NGLOG_DEBUG(Common_Filesystem, "{} does not exist", filename);
LOG_DEBUG(Common_Filesystem, "{} does not exist", filename);
return true;
}
// We can't delete a directory
if (IsDirectory(filename)) {
NGLOG_ERROR(Common_Filesystem, "Failed: {} is a directory", filename);
LOG_ERROR(Common_Filesystem, "Failed: {} is a directory", filename);
return false;
}
#ifdef _WIN32
if (!DeleteFileW(Common::UTF8ToUTF16W(filename).c_str())) {
NGLOG_ERROR(Common_Filesystem, "DeleteFile failed on {}: {}", filename, GetLastErrorMsg());
LOG_ERROR(Common_Filesystem, "DeleteFile failed on {}: {}", filename, GetLastErrorMsg());
return false;
}
#else
if (unlink(filename.c_str()) == -1) {
NGLOG_ERROR(Common_Filesystem, "unlink failed on {}: {}", filename, GetLastErrorMsg());
LOG_ERROR(Common_Filesystem, "unlink failed on {}: {}", filename, GetLastErrorMsg());
return false;
}
#endif
@@ -160,16 +160,16 @@ bool Delete(const std::string& filename) {
// Returns true if successful, or path already exists.
bool CreateDir(const std::string& path) {
NGLOG_TRACE(Common_Filesystem, "directory {}", path);
LOG_TRACE(Common_Filesystem, "directory {}", path);
#ifdef _WIN32
if (::CreateDirectoryW(Common::UTF8ToUTF16W(path).c_str(), nullptr))
return true;
DWORD error = GetLastError();
if (error == ERROR_ALREADY_EXISTS) {
NGLOG_DEBUG(Common_Filesystem, "CreateDirectory failed on {}: already exists", path);
LOG_DEBUG(Common_Filesystem, "CreateDirectory failed on {}: already exists", path);
return true;
}
NGLOG_ERROR(Common_Filesystem, "CreateDirectory failed on {}: {}", path, error);
LOG_ERROR(Common_Filesystem, "CreateDirectory failed on {}: {}", path, error);
return false;
#else
if (mkdir(path.c_str(), 0755) == 0)
@@ -178,11 +178,11 @@ bool CreateDir(const std::string& path) {
int err = errno;
if (err == EEXIST) {
NGLOG_DEBUG(Common_Filesystem, "mkdir failed on {}: already exists", path);
LOG_DEBUG(Common_Filesystem, "mkdir failed on {}: already exists", path);
return true;
}
NGLOG_ERROR(Common_Filesystem, "mkdir failed on {}: {}", path, strerror(err));
LOG_ERROR(Common_Filesystem, "mkdir failed on {}: {}", path, strerror(err));
return false;
#endif
}
@@ -190,10 +190,10 @@ bool CreateDir(const std::string& path) {
// Creates the full path of fullPath returns true on success
bool CreateFullPath(const std::string& fullPath) {
int panicCounter = 100;
NGLOG_TRACE(Common_Filesystem, "path {}", fullPath);
LOG_TRACE(Common_Filesystem, "path {}", fullPath);
if (FileUtil::Exists(fullPath)) {
NGLOG_DEBUG(Common_Filesystem, "path exists {}", fullPath);
LOG_DEBUG(Common_Filesystem, "path exists {}", fullPath);
return true;
}
@@ -209,14 +209,14 @@ bool CreateFullPath(const std::string& fullPath) {
// Include the '/' so the first call is CreateDir("/") rather than CreateDir("")
std::string const subPath(fullPath.substr(0, position + 1));
if (!FileUtil::IsDirectory(subPath) && !FileUtil::CreateDir(subPath)) {
NGLOG_ERROR(Common, "CreateFullPath: directory creation failed");
LOG_ERROR(Common, "CreateFullPath: directory creation failed");
return false;
}
// A safety check
panicCounter--;
if (panicCounter <= 0) {
NGLOG_ERROR(Common, "CreateFullPath: directory structure is too deep");
LOG_ERROR(Common, "CreateFullPath: directory structure is too deep");
return false;
}
position++;
@@ -225,11 +225,11 @@ bool CreateFullPath(const std::string& fullPath) {
// Deletes a directory filename, returns true on success
bool DeleteDir(const std::string& filename) {
NGLOG_TRACE(Common_Filesystem, "directory {}", filename);
LOG_TRACE(Common_Filesystem, "directory {}", filename);
// check if a directory
if (!FileUtil::IsDirectory(filename)) {
NGLOG_ERROR(Common_Filesystem, "Not a directory {}", filename);
LOG_ERROR(Common_Filesystem, "Not a directory {}", filename);
return false;
}
@@ -240,14 +240,14 @@ bool DeleteDir(const std::string& filename) {
if (rmdir(filename.c_str()) == 0)
return true;
#endif
NGLOG_ERROR(Common_Filesystem, "failed {}: {}", filename, GetLastErrorMsg());
LOG_ERROR(Common_Filesystem, "failed {}: {}", filename, GetLastErrorMsg());
return false;
}
// renames file srcFilename to destFilename, returns true on success
bool Rename(const std::string& srcFilename, const std::string& destFilename) {
NGLOG_TRACE(Common_Filesystem, "{} --> {}", srcFilename, destFilename);
LOG_TRACE(Common_Filesystem, "{} --> {}", srcFilename, destFilename);
#ifdef _WIN32
if (_wrename(Common::UTF8ToUTF16W(srcFilename).c_str(),
Common::UTF8ToUTF16W(destFilename).c_str()) == 0)
@@ -256,21 +256,21 @@ bool Rename(const std::string& srcFilename, const std::string& destFilename) {
if (rename(srcFilename.c_str(), destFilename.c_str()) == 0)
return true;
#endif
NGLOG_ERROR(Common_Filesystem, "failed {} --> {}: {}", srcFilename, destFilename,
GetLastErrorMsg());
LOG_ERROR(Common_Filesystem, "failed {} --> {}: {}", srcFilename, destFilename,
GetLastErrorMsg());
return false;
}
// copies file srcFilename to destFilename, returns true on success
bool Copy(const std::string& srcFilename, const std::string& destFilename) {
NGLOG_TRACE(Common_Filesystem, "{} --> {}", srcFilename, destFilename);
LOG_TRACE(Common_Filesystem, "{} --> {}", srcFilename, destFilename);
#ifdef _WIN32
if (CopyFileW(Common::UTF8ToUTF16W(srcFilename).c_str(),
Common::UTF8ToUTF16W(destFilename).c_str(), FALSE))
return true;
NGLOG_ERROR(Common_Filesystem, "failed {} --> {}: {}", srcFilename, destFilename,
GetLastErrorMsg());
LOG_ERROR(Common_Filesystem, "failed {} --> {}: {}", srcFilename, destFilename,
GetLastErrorMsg());
return false;
#else
@@ -282,8 +282,8 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) {
// Open input file
FILE* input = fopen(srcFilename.c_str(), "rb");
if (!input) {
NGLOG_ERROR(Common_Filesystem, "opening input failed {} --> {}: {}", srcFilename,
destFilename, GetLastErrorMsg());
LOG_ERROR(Common_Filesystem, "opening input failed {} --> {}: {}", srcFilename,
destFilename, GetLastErrorMsg());
return false;
}
@@ -291,8 +291,8 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) {
FILE* output = fopen(destFilename.c_str(), "wb");
if (!output) {
fclose(input);
NGLOG_ERROR(Common_Filesystem, "opening output failed {} --> {}: {}", srcFilename,
destFilename, GetLastErrorMsg());
LOG_ERROR(Common_Filesystem, "opening output failed {} --> {}: {}", srcFilename,
destFilename, GetLastErrorMsg());
return false;
}
@@ -302,8 +302,8 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) {
size_t rnum = fread(buffer, sizeof(char), BSIZE, input);
if (rnum != BSIZE) {
if (ferror(input) != 0) {
NGLOG_ERROR(Common_Filesystem, "failed reading from source, {} --> {}: {}",
srcFilename, destFilename, GetLastErrorMsg());
LOG_ERROR(Common_Filesystem, "failed reading from source, {} --> {}: {}",
srcFilename, destFilename, GetLastErrorMsg());
goto bail;
}
}
@@ -311,8 +311,8 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) {
// write output
size_t wnum = fwrite(buffer, sizeof(char), rnum, output);
if (wnum != rnum) {
NGLOG_ERROR(Common_Filesystem, "failed writing to output, {} --> {}: {}", srcFilename,
destFilename, GetLastErrorMsg());
LOG_ERROR(Common_Filesystem, "failed writing to output, {} --> {}: {}", srcFilename,
destFilename, GetLastErrorMsg());
goto bail;
}
}
@@ -332,12 +332,12 @@ bail:
// Returns the size of filename (64bit)
u64 GetSize(const std::string& filename) {
if (!Exists(filename)) {
NGLOG_ERROR(Common_Filesystem, "failed {}: No such file", filename);
LOG_ERROR(Common_Filesystem, "failed {}: No such file", filename);
return 0;
}
if (IsDirectory(filename)) {
NGLOG_ERROR(Common_Filesystem, "failed {}: is a directory", filename);
LOG_ERROR(Common_Filesystem, "failed {}: is a directory", filename);
return 0;
}
@@ -348,11 +348,11 @@ u64 GetSize(const std::string& filename) {
if (stat(filename.c_str(), &buf) == 0)
#endif
{
NGLOG_TRACE(Common_Filesystem, "{}: {}", filename, buf.st_size);
LOG_TRACE(Common_Filesystem, "{}: {}", filename, buf.st_size);
return buf.st_size;
}
NGLOG_ERROR(Common_Filesystem, "Stat failed {}: {}", filename, GetLastErrorMsg());
LOG_ERROR(Common_Filesystem, "Stat failed {}: {}", filename, GetLastErrorMsg());
return 0;
}
@@ -360,7 +360,7 @@ u64 GetSize(const std::string& filename) {
u64 GetSize(const int fd) {
struct stat buf;
if (fstat(fd, &buf) != 0) {
NGLOG_ERROR(Common_Filesystem, "GetSize: stat failed {}: {}", fd, GetLastErrorMsg());
LOG_ERROR(Common_Filesystem, "GetSize: stat failed {}: {}", fd, GetLastErrorMsg());
return 0;
}
return buf.st_size;
@@ -371,14 +371,12 @@ u64 GetSize(FILE* f) {
// can't use off_t here because it can be 32-bit
u64 pos = ftello(f);
if (fseeko(f, 0, SEEK_END) != 0) {
NGLOG_ERROR(Common_Filesystem, "GetSize: seek failed {}: {}", fmt::ptr(f),
GetLastErrorMsg());
LOG_ERROR(Common_Filesystem, "GetSize: seek failed {}: {}", fmt::ptr(f), GetLastErrorMsg());
return 0;
}
u64 size = ftello(f);
if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) {
NGLOG_ERROR(Common_Filesystem, "GetSize: seek failed {}: {}", fmt::ptr(f),
GetLastErrorMsg());
LOG_ERROR(Common_Filesystem, "GetSize: seek failed {}: {}", fmt::ptr(f), GetLastErrorMsg());
return 0;
}
return size;
@@ -386,10 +384,10 @@ u64 GetSize(FILE* f) {
// creates an empty file filename, returns true on success
bool CreateEmptyFile(const std::string& filename) {
NGLOG_TRACE(Common_Filesystem, "{}", filename);
LOG_TRACE(Common_Filesystem, "{}", filename);
if (!FileUtil::IOFile(filename, "wb")) {
NGLOG_ERROR(Common_Filesystem, "failed {}: {}", filename, GetLastErrorMsg());
LOG_ERROR(Common_Filesystem, "failed {}: {}", filename, GetLastErrorMsg());
return false;
}
@@ -398,7 +396,7 @@ bool CreateEmptyFile(const std::string& filename) {
bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string& directory,
DirectoryEntryCallable callback) {
NGLOG_TRACE(Common_Filesystem, "directory {}", directory);
LOG_TRACE(Common_Filesystem, "directory {}", directory);
// How many files + directories we found
unsigned found_entries = 0;
@@ -556,7 +554,7 @@ std::string GetCurrentDir() {
char* dir;
if (!(dir = getcwd(nullptr, 0))) {
#endif
NGLOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: {}", GetLastErrorMsg());
LOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: {}", GetLastErrorMsg());
return nullptr;
}
#ifdef _WIN32
@@ -676,11 +674,11 @@ std::string GetSysDirectory() {
#endif
sysDir += DIR_SEP;
NGLOG_DEBUG(Common_Filesystem, "Setting to {}:", sysDir);
LOG_DEBUG(Common_Filesystem, "Setting to {}:", sysDir);
return sysDir;
}
// Returns a string with a Citra data dir or file in the user's home
// Returns a string with a yuzu data dir or file in the user's home
// directory. To be used in "multi-user" mode (that is, installed).
const std::string& GetUserPath(const unsigned int DirIDX, const std::string& newPath) {
static std::string paths[NUM_PATH_INDICES];
@@ -692,7 +690,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string& new
if (!FileUtil::IsDirectory(paths[D_USER_IDX])) {
paths[D_USER_IDX] = AppDataRoamingDirectory() + DIR_SEP EMU_DATA_DIR DIR_SEP;
} else {
NGLOG_INFO(Common_Filesystem, "Using the local user directory");
LOG_INFO(Common_Filesystem, "Using the local user directory");
}
paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
@@ -715,11 +713,13 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string& new
paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
paths[D_NAND_IDX] = paths[D_USER_IDX] + NAND_DIR DIR_SEP;
paths[D_SYSDATA_IDX] = paths[D_USER_IDX] + SYSDATA_DIR DIR_SEP;
// TODO: Put the logs in a better location for each OS
paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOG_DIR DIR_SEP;
}
if (!newPath.empty()) {
if (!FileUtil::IsDirectory(newPath)) {
NGLOG_ERROR(Common_Filesystem, "Invalid path specified {}", newPath);
LOG_ERROR(Common_Filesystem, "Invalid path specified {}", newPath);
return paths[DirIDX];
} else {
paths[DirIDX] = newPath;
@@ -801,8 +801,8 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
IOFile::IOFile() {}
IOFile::IOFile(const std::string& filename, const char openmode[]) {
Open(filename, openmode);
IOFile::IOFile(const std::string& filename, const char openmode[], int flags) {
Open(filename, openmode, flags);
}
IOFile::~IOFile() {
@@ -823,11 +823,16 @@ void IOFile::Swap(IOFile& other) noexcept {
std::swap(m_good, other.m_good);
}
bool IOFile::Open(const std::string& filename, const char openmode[]) {
bool IOFile::Open(const std::string& filename, const char openmode[], int flags) {
Close();
#ifdef _WIN32
_wfopen_s(&m_file, Common::UTF8ToUTF16W(filename).c_str(),
Common::UTF8ToUTF16W(openmode).c_str());
if (flags != 0) {
m_file = _wfsopen(Common::UTF8ToUTF16W(filename).c_str(),
Common::UTF8ToUTF16W(openmode).c_str(), flags);
} else {
_wfopen_s(&m_file, Common::UTF8ToUTF16W(filename).c_str(),
Common::UTF8ToUTF16W(openmode).c_str());
}
#else
m_file = fopen(filename.c_str(), openmode);
#endif

View File

@@ -156,7 +156,10 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
class IOFile : public NonCopyable {
public:
IOFile();
IOFile(const std::string& filename, const char openmode[]);
// flags is used for windows specific file open mode flags, which
// allows yuzu to open the logs in shared write mode, so that the file
// isn't considered "locked" while yuzu is open and people can open the log file and view it
IOFile(const std::string& filename, const char openmode[], int flags = 0);
~IOFile();
@@ -165,7 +168,7 @@ public:
void Swap(IOFile& other) noexcept;
bool Open(const std::string& filename, const char openmode[]);
bool Open(const std::string& filename, const char openmode[], int flags = 0);
bool Close();
template <typename T>
@@ -220,6 +223,10 @@ public:
return WriteArray(&object, 1);
}
size_t WriteString(const std::string& str) {
return WriteArray(str.c_str(), str.length());
}
bool IsOpen() const {
return nullptr != m_file;
}

View File

@@ -2,16 +2,148 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <utility>
#include <algorithm>
#include <array>
#include <chrono>
#include <climits>
#include <condition_variable>
#include <memory>
#include <thread>
#ifdef _WIN32
#include <share.h> // For _SH_DENYWR
#else
#define _SH_DENYWR 0
#endif
#include "common/assert.h"
#include "common/common_funcs.h" // snprintf compatibility define
#include "common/logging/backend.h"
#include "common/logging/filter.h"
#include "common/logging/log.h"
#include "common/logging/text_formatter.h"
#include "common/string_util.h"
#include "common/threadsafe_queue.h"
namespace Log {
/**
* Static state as a singleton.
*/
class Impl {
public:
static Impl& Instance() {
static Impl backend;
return backend;
}
Impl(Impl const&) = delete;
const Impl& operator=(Impl const&) = delete;
void PushEntry(Entry e) {
std::lock_guard<std::mutex> lock(message_mutex);
message_queue.Push(std::move(e));
message_cv.notify_one();
}
void AddBackend(std::unique_ptr<Backend> backend) {
std::lock_guard<std::mutex> lock(writing_mutex);
backends.push_back(std::move(backend));
}
void RemoveBackend(const std::string& backend_name) {
std::lock_guard<std::mutex> lock(writing_mutex);
auto it = std::remove_if(backends.begin(), backends.end(), [&backend_name](const auto& i) {
return !strcmp(i->GetName(), backend_name.c_str());
});
backends.erase(it, backends.end());
}
const Filter& GetGlobalFilter() const {
return filter;
}
void SetGlobalFilter(const Filter& f) {
filter = f;
}
Backend* GetBackend(const std::string& backend_name) {
auto it = std::find_if(backends.begin(), backends.end(), [&backend_name](const auto& i) {
return !strcmp(i->GetName(), backend_name.c_str());
});
if (it == backends.end())
return nullptr;
return it->get();
}
private:
Impl() {
backend_thread = std::thread([&] {
Entry entry;
auto write_logs = [&](Entry& e) {
std::lock_guard<std::mutex> lock(writing_mutex);
for (const auto& backend : backends) {
backend->Write(e);
}
};
while (true) {
{
std::unique_lock<std::mutex> lock(message_mutex);
message_cv.wait(lock, [&] { return !running || message_queue.Pop(entry); });
}
if (!running) {
break;
}
write_logs(entry);
}
// Drain the logging queue. Only writes out up to MAX_LOGS_TO_WRITE to prevent a case
// where a system is repeatedly spamming logs even on close.
const int MAX_LOGS_TO_WRITE = filter.IsDebug() ? INT_MAX : 100;
int logs_written = 0;
while (logs_written++ < MAX_LOGS_TO_WRITE && message_queue.Pop(entry)) {
write_logs(entry);
}
});
}
~Impl() {
running = false;
message_cv.notify_one();
backend_thread.join();
}
std::atomic_bool running{true};
std::mutex message_mutex, writing_mutex;
std::condition_variable message_cv;
std::thread backend_thread;
std::vector<std::unique_ptr<Backend>> backends;
Common::MPSCQueue<Log::Entry> message_queue;
Filter filter;
};
void ConsoleBackend::Write(const Entry& entry) {
PrintMessage(entry);
}
void ColorConsoleBackend::Write(const Entry& entry) {
PrintColoredMessage(entry);
}
// _SH_DENYWR allows read only access to the file for other programs.
// It is #defined to 0 on other platforms
FileBackend::FileBackend(const std::string& filename)
: file(filename, "w", _SH_DENYWR), bytes_written(0) {}
void FileBackend::Write(const Entry& entry) {
// prevent logs from going over the maximum size (in case its spamming and the user doesn't
// know)
constexpr size_t MAX_BYTES_WRITTEN = 50 * 1024L * 1024L;
if (!file.IsOpen() || bytes_written > MAX_BYTES_WRITTEN) {
return;
}
bytes_written += file.WriteString(FormatLogMessage(entry) + '\n');
if (entry.log_level >= Level::Error) {
file.Flush();
}
}
/// Macro listing all log classes. Code should define CLS and SUB as desired before invoking this.
#define ALL_LOG_CLASSES() \
CLS(Log) \
@@ -41,6 +173,7 @@ namespace Log {
SUB(Service, FS) \
SUB(Service, HID) \
SUB(Service, LM) \
SUB(Service, MM) \
SUB(Service, NFP) \
SUB(Service, NIFM) \
SUB(Service, NS) \
@@ -124,20 +257,32 @@ Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsign
return entry;
}
static Filter* filter = nullptr;
void SetGlobalFilter(const Filter& filter) {
Impl::Instance().SetGlobalFilter(filter);
}
void SetFilter(Filter* new_filter) {
filter = new_filter;
void AddBackend(std::unique_ptr<Backend> backend) {
Impl::Instance().AddBackend(std::move(backend));
}
void RemoveBackend(const std::string& backend_name) {
Impl::Instance().RemoveBackend(backend_name);
}
Backend* GetBackend(const std::string& backend_name) {
return Impl::Instance().GetBackend(backend_name);
}
void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
unsigned int line_num, const char* function, const char* format,
const fmt::format_args& args) {
if (filter && !filter->CheckMessage(log_class, log_level))
auto filter = Impl::Instance().GetGlobalFilter();
if (!filter.CheckMessage(log_class, log_level))
return;
Entry entry =
CreateEntry(log_class, log_level, filename, line_num, function, fmt::vformat(format, args));
PrintColoredMessage(entry);
Impl::Instance().PushEntry(std::move(entry));
}
} // namespace Log

View File

@@ -1,13 +1,15 @@
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <chrono>
#include <cstdarg>
#include <memory>
#include <string>
#include <utility>
#include "common/file_util.h"
#include "common/logging/filter.h"
#include "common/logging/log.h"
namespace Log {
@@ -34,6 +36,80 @@ struct Entry {
Entry& operator=(const Entry& o) = default;
};
/**
* Interface for logging backends. As loggers can be created and removed at runtime, this can be
* used by a frontend for adding a custom logging backend as needed
*/
class Backend {
public:
virtual ~Backend() = default;
virtual void SetFilter(const Filter& new_filter) {
filter = new_filter;
}
virtual const char* GetName() const = 0;
virtual void Write(const Entry& entry) = 0;
private:
Filter filter;
};
/**
* Backend that writes to stderr without any color commands
*/
class ConsoleBackend : public Backend {
public:
static const char* Name() {
return "console";
}
const char* GetName() const override {
return Name();
}
void Write(const Entry& entry) override;
};
/**
* Backend that writes to stderr and with color
*/
class ColorConsoleBackend : public Backend {
public:
static const char* Name() {
return "color_console";
}
const char* GetName() const override {
return Name();
}
void Write(const Entry& entry) override;
};
/**
* Backend that writes to a file passed into the constructor
*/
class FileBackend : public Backend {
public:
explicit FileBackend(const std::string& filename);
static const char* Name() {
return "file";
}
const char* GetName() const override {
return Name();
}
void Write(const Entry& entry) override;
private:
FileUtil::IOFile file;
size_t bytes_written;
};
void AddBackend(std::unique_ptr<Backend> backend);
void RemoveBackend(const std::string& backend_name);
Backend* GetBackend(const std::string& backend_name);
/**
* Returns the name of the passed log class as a C-string. Subclasses are separated by periods
* instead of underscores as in the enumeration.
@@ -49,5 +125,10 @@ const char* GetLevelName(Level log_level);
Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
const char* function, std::string message);
void SetFilter(Filter* filter);
} // namespace Log
/**
* The global filter will prevent any messages from even being processed if they are filtered. Each
* backend can have a filter, but if the level is lower than the global filter, the backend will
* never get the message
*/
void SetGlobalFilter(const Filter& filter);
} // namespace Log

View File

@@ -65,14 +65,14 @@ bool Filter::ParseFilterRule(const std::string::const_iterator begin,
const std::string::const_iterator end) {
auto level_separator = std::find(begin, end, ':');
if (level_separator == end) {
NGLOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: %s",
std::string(begin, end).c_str());
LOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: {}",
std::string(begin, end));
return false;
}
const Level level = GetLevelByName(level_separator + 1, end);
if (level == Level::Count) {
NGLOG_ERROR(Log, "Unknown log level in filter: %s", std::string(begin, end).c_str());
LOG_ERROR(Log, "Unknown log level in filter: {}", std::string(begin, end));
return false;
}
@@ -83,7 +83,7 @@ bool Filter::ParseFilterRule(const std::string::const_iterator begin,
const Class log_class = GetClassByName(begin, level_separator);
if (log_class == Class::Count) {
NGLOG_ERROR(Log, "Unknown log class in filter: %s", std::string(begin, end).c_str());
LOG_ERROR(Log, "Unknown log class in filter: {}", std::string(begin, end));
return false;
}
@@ -94,4 +94,11 @@ bool Filter::ParseFilterRule(const std::string::const_iterator begin,
bool Filter::CheckMessage(Class log_class, Level level) const {
return static_cast<u8>(level) >= static_cast<u8>(class_levels[static_cast<size_t>(log_class)]);
}
bool Filter::IsDebug() const {
return std::any_of(class_levels.begin(), class_levels.end(), [](const Level& l) {
return static_cast<u8>(l) <= static_cast<u8>(Level::Debug);
});
}
} // namespace Log

View File

@@ -47,6 +47,9 @@ public:
/// Matches class/level combination against the filter, returning true if it passed.
bool CheckMessage(Class log_class, Level level) const;
/// Returns true if any logging classes are set to debug
bool IsDebug() const;
private:
std::array<Level, (size_t)Class::Count> class_levels;
};

View File

@@ -61,6 +61,7 @@ enum class Class : ClassType {
Service_FS, ///< The FS (Filesystem) service
Service_HID, ///< The HID (Human interface device) service
Service_LM, ///< The LM (Logger) service
Service_MM, ///< The MM (Multimedia) service
Service_NFP, ///< The NFP service
Service_NIFM, ///< The NIFM (Network interface) service
Service_NS, ///< The NS services
@@ -108,25 +109,25 @@ void FmtLogMessage(Class log_class, Level log_level, const char* filename, unsig
} // namespace Log
#ifdef _DEBUG
#define NGLOG_TRACE(log_class, ...) \
#define LOG_TRACE(log_class, ...) \
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Trace, __FILE__, __LINE__, \
__func__, __VA_ARGS__)
#else
#define NGLOG_TRACE(log_class, fmt, ...) (void(0))
#define LOG_TRACE(log_class, fmt, ...) (void(0))
#endif
#define NGLOG_DEBUG(log_class, ...) \
#define LOG_DEBUG(log_class, ...) \
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Debug, __FILE__, __LINE__, \
__func__, __VA_ARGS__)
#define NGLOG_INFO(log_class, ...) \
#define LOG_INFO(log_class, ...) \
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Info, __FILE__, __LINE__, \
__func__, __VA_ARGS__)
#define NGLOG_WARNING(log_class, ...) \
#define LOG_WARNING(log_class, ...) \
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Warning, __FILE__, __LINE__, \
__func__, __VA_ARGS__)
#define NGLOG_ERROR(log_class, ...) \
#define LOG_ERROR(log_class, ...) \
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Error, __FILE__, __LINE__, \
__func__, __VA_ARGS__)
#define NGLOG_CRITICAL(log_class, ...) \
#define LOG_CRITICAL(log_class, ...) \
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Critical, __FILE__, __LINE__, \
__func__, __VA_ARGS__)

View File

@@ -16,7 +16,7 @@
#include <sys/mman.h>
#endif
#if !defined(_WIN32) && defined(ARCHITECTURE_X64) && !defined(MAP_32BIT)
#if !defined(_WIN32) && defined(ARCHITECTURE_x86_64) && !defined(MAP_32BIT)
#include <unistd.h>
#define PAGE_MASK (getpagesize() - 1)
#define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK))
@@ -30,7 +30,7 @@ void* AllocateExecutableMemory(size_t size, bool low) {
void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
#else
static char* map_hint = nullptr;
#if defined(ARCHITECTURE_X64) && !defined(MAP_32BIT)
#if defined(ARCHITECTURE_x86_64) && !defined(MAP_32BIT)
// This OS has no flag to enforce allocation below the 4 GB boundary,
// but if we hint that we want a low address it is very likely we will
// get one.
@@ -42,7 +42,7 @@ void* AllocateExecutableMemory(size_t size, bool low) {
#endif
void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_ANON | MAP_PRIVATE
#if defined(ARCHITECTURE_X64) && defined(MAP_32BIT)
#if defined(ARCHITECTURE_x86_64) && defined(MAP_32BIT)
| (low ? MAP_32BIT : 0)
#endif
,
@@ -55,9 +55,9 @@ void* AllocateExecutableMemory(size_t size, bool low) {
if (ptr == MAP_FAILED) {
ptr = nullptr;
#endif
NGLOG_ERROR(Common_Memory, "Failed to allocate executable memory");
LOG_ERROR(Common_Memory, "Failed to allocate executable memory");
}
#if !defined(_WIN32) && defined(ARCHITECTURE_X64) && !defined(MAP_32BIT)
#if !defined(_WIN32) && defined(ARCHITECTURE_x86_64) && !defined(MAP_32BIT)
else {
if (low) {
map_hint += size;
@@ -68,7 +68,7 @@ void* AllocateExecutableMemory(size_t size, bool low) {
#if EMU_ARCH_BITS == 64
if ((u64)ptr >= 0x80000000 && low == true)
NGLOG_ERROR(Common_Memory, "Executable memory ended up above 2GB!");
LOG_ERROR(Common_Memory, "Executable memory ended up above 2GB!");
#endif
return ptr;
@@ -85,7 +85,7 @@ void* AllocateMemoryPages(size_t size) {
#endif
if (ptr == nullptr)
NGLOG_ERROR(Common_Memory, "Failed to allocate raw memory");
LOG_ERROR(Common_Memory, "Failed to allocate raw memory");
return ptr;
}
@@ -99,12 +99,12 @@ void* AllocateAlignedMemory(size_t size, size_t alignment) {
ptr = memalign(alignment, size);
#else
if (posix_memalign(&ptr, alignment, size) != 0)
NGLOG_ERROR(Common_Memory, "Failed to allocate aligned memory");
LOG_ERROR(Common_Memory, "Failed to allocate aligned memory");
#endif
#endif
if (ptr == nullptr)
NGLOG_ERROR(Common_Memory, "Failed to allocate aligned memory");
LOG_ERROR(Common_Memory, "Failed to allocate aligned memory");
return ptr;
}
@@ -113,7 +113,7 @@ void FreeMemoryPages(void* ptr, size_t size) {
if (ptr) {
#ifdef _WIN32
if (!VirtualFree(ptr, 0, MEM_RELEASE))
NGLOG_ERROR(Common_Memory, "FreeMemoryPages failed!\n{}", GetLastErrorMsg());
LOG_ERROR(Common_Memory, "FreeMemoryPages failed!\n{}", GetLastErrorMsg());
#else
munmap(ptr, size);
#endif
@@ -134,7 +134,7 @@ void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) {
#ifdef _WIN32
DWORD oldValue;
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue))
NGLOG_ERROR(Common_Memory, "WriteProtectMemory failed!\n{}", GetLastErrorMsg());
LOG_ERROR(Common_Memory, "WriteProtectMemory failed!\n{}", GetLastErrorMsg());
#else
mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ);
#endif
@@ -145,7 +145,7 @@ void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) {
DWORD oldValue;
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE,
&oldValue))
NGLOG_ERROR(Common_Memory, "UnWriteProtectMemory failed!\n{}", GetLastErrorMsg());
LOG_ERROR(Common_Memory, "UnWriteProtectMemory failed!\n{}", GetLastErrorMsg());
#else
mprotect(ptr, size,
allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ);

View File

@@ -25,7 +25,7 @@ ParamPackage::ParamPackage(const std::string& serialized) {
std::vector<std::string> key_value;
Common::SplitString(pair, KEY_VALUE_SEPARATOR, key_value);
if (key_value.size() != 2) {
NGLOG_ERROR(Common, "invalid key pair {}", pair);
LOG_ERROR(Common, "invalid key pair {}", pair);
continue;
}
@@ -64,7 +64,7 @@ std::string ParamPackage::Serialize() const {
std::string ParamPackage::Get(const std::string& key, const std::string& default_value) const {
auto pair = data.find(key);
if (pair == data.end()) {
NGLOG_DEBUG(Common, "key '{}' not found", key);
LOG_DEBUG(Common, "key '{}' not found", key);
return default_value;
}
@@ -74,14 +74,14 @@ std::string ParamPackage::Get(const std::string& key, const std::string& default
int ParamPackage::Get(const std::string& key, int default_value) const {
auto pair = data.find(key);
if (pair == data.end()) {
NGLOG_DEBUG(Common, "key '{}' not found", key);
LOG_DEBUG(Common, "key '{}' not found", key);
return default_value;
}
try {
return std::stoi(pair->second);
} catch (const std::logic_error&) {
NGLOG_ERROR(Common, "failed to convert {} to int", pair->second);
LOG_ERROR(Common, "failed to convert {} to int", pair->second);
return default_value;
}
}
@@ -89,14 +89,14 @@ int ParamPackage::Get(const std::string& key, int default_value) const {
float ParamPackage::Get(const std::string& key, float default_value) const {
auto pair = data.find(key);
if (pair == data.end()) {
NGLOG_DEBUG(Common, "key {} not found", key);
LOG_DEBUG(Common, "key {} not found", key);
return default_value;
}
try {
return std::stof(pair->second);
} catch (const std::logic_error&) {
NGLOG_ERROR(Common, "failed to convert {} to float", pair->second);
LOG_ERROR(Common, "failed to convert {} to float", pair->second);
return default_value;
}
}

View File

@@ -64,6 +64,10 @@ std::string ArrayToString(const u8* data, size_t size, int line_len, bool spaces
return oss.str();
}
std::string StringFromBuffer(const std::vector<u8>& data) {
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
}
// Turns " hej " into "hej". Also handles tabs.
std::string StripSpaces(const std::string& str) {
const size_t s = str.find_first_not_of(" \t\r\n");
@@ -130,7 +134,7 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
size_t dir_end = full_path.find_last_of("/"
// windows needs the : included for something like just "C:" to be considered a directory
#ifdef _WIN32
":"
"\\:"
#endif
);
if (std::string::npos == dir_end)
@@ -277,7 +281,7 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>&
iconv_t const conv_desc = iconv_open("UTF-8", fromcode);
if ((iconv_t)(-1) == conv_desc) {
NGLOG_ERROR(Common, "Iconv initialization failure [{}]: {}", fromcode, strerror(errno));
LOG_ERROR(Common, "Iconv initialization failure [{}]: {}", fromcode, strerror(errno));
iconv_close(conv_desc);
return {};
}
@@ -306,7 +310,7 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>&
++src_buffer;
}
} else {
NGLOG_ERROR(Common, "iconv failure [{}]: {}", fromcode, strerror(errno));
LOG_ERROR(Common, "iconv failure [{}]: {}", fromcode, strerror(errno));
break;
}
}
@@ -325,7 +329,7 @@ std::u16string UTF8ToUTF16(const std::string& input) {
iconv_t const conv_desc = iconv_open("UTF-16LE", "UTF-8");
if ((iconv_t)(-1) == conv_desc) {
NGLOG_ERROR(Common, "Iconv initialization failure [UTF-8]: {}", strerror(errno));
LOG_ERROR(Common, "Iconv initialization failure [UTF-8]: {}", strerror(errno));
iconv_close(conv_desc);
return {};
}
@@ -354,7 +358,7 @@ std::u16string UTF8ToUTF16(const std::string& input) {
++src_buffer;
}
} else {
NGLOG_ERROR(Common, "iconv failure [UTF-8]: {}", strerror(errno));
LOG_ERROR(Common, "iconv failure [UTF-8]: {}", strerror(errno));
break;
}
}

View File

@@ -21,6 +21,8 @@ std::string ToUpper(std::string str);
std::string ArrayToString(const u8* data, size_t size, int line_len = 20, bool spaces = true);
std::string StringFromBuffer(const std::vector<u8>& data);
std::string StripSpaces(const std::string& s);
std::string StripQuotes(const std::string& s);

View File

@@ -69,7 +69,7 @@ inline u32 swap32(u32 _data) {
inline u64 swap64(u64 _data) {
return _byteswap_uint64(_data);
}
#elif _M_ARM
#elif ARCHITECTURE_ARM
inline u16 swap16(u16 _data) {
u32 data = _data;
__asm__("rev16 %0, %1\n" : "=l"(data) : "l"(data));

View File

@@ -40,6 +40,8 @@ add_library(core STATIC
hle/config_mem.h
hle/ipc.h
hle/ipc_helpers.h
hle/kernel/address_arbiter.cpp
hle/kernel/address_arbiter.h
hle/kernel/client_port.cpp
hle/kernel/client_port.h
hle/kernel/client_session.cpp
@@ -124,6 +126,8 @@ add_library(core STATIC
hle/service/audio/audren_u.h
hle/service/audio/codecctl.cpp
hle/service/audio/codecctl.h
hle/service/audio/hwopus.cpp
hle/service/audio/hwopus.h
hle/service/bcat/module.cpp
hle/service/bcat/module.h
hle/service/bcat/bcat.cpp
@@ -148,6 +152,8 @@ add_library(core STATIC
hle/service/hid/hid.h
hle/service/lm/lm.cpp
hle/service/lm/lm.h
hle/service/mm/mm_u.cpp
hle/service/mm/mm_u.h
hle/service/nifm/nifm.cpp
hle/service/nifm/nifm.h
hle/service/nifm/nifm_a.cpp
@@ -255,6 +261,8 @@ add_library(core STATIC
loader/linker.h
loader/loader.cpp
loader/loader.h
loader/nca.cpp
loader/nca.h
loader/nro.cpp
loader/nro.h
loader/nso.cpp

View File

@@ -116,6 +116,8 @@ public:
*/
virtual void LoadContext(const ThreadContext& ctx) = 0;
virtual void ClearExclusiveState() = 0;
/// Prepare core for thread reschedule (if needed to correctly handle state)
virtual void PrepareReschedule() = 0;
};

View File

@@ -55,8 +55,8 @@ public:
}
void InterpreterFallback(u64 pc, size_t num_instructions) override {
NGLOG_INFO(Core_ARM, "Unicorn fallback @ 0x{:X} for {} instructions (instr = {:08X})", pc,
num_instructions, MemoryReadCode(pc));
LOG_INFO(Core_ARM, "Unicorn fallback @ 0x{:X} for {} instructions (instr = {:08X})", pc,
num_instructions, MemoryReadCode(pc));
ARM_Interface::ThreadContext ctx;
parent.SaveContext(ctx);
@@ -226,6 +226,10 @@ void ARM_Dynarmic::ClearInstructionCache() {
jit->ClearCache();
}
void ARM_Dynarmic::ClearExclusiveState() {
jit->ClearExclusiveState();
}
void ARM_Dynarmic::PageTableChanged() {
jit = MakeJit(cb);
current_page_table = Memory::GetCurrentPageTable();

View File

@@ -39,6 +39,7 @@ public:
void LoadContext(const ThreadContext& ctx) override;
void PrepareReschedule() override;
void ClearExclusiveState() override;
void ClearInstructionCache() override;
void PageTableChanged() override;

View File

@@ -35,6 +35,17 @@ LoadDll LoadDll::g_load_dll;
} \
} while (0)
static void CodeHook(uc_engine* uc, uint64_t address, uint32_t size, void* user_data) {
GDBStub::BreakpointAddress bkpt =
GDBStub::GetNextBreakpointFromAddress(address, GDBStub::BreakpointType::Execute);
if (GDBStub::IsMemoryBreak() ||
(bkpt.type != GDBStub::BreakpointType::None && address == bkpt.address)) {
auto core = static_cast<ARM_Unicorn*>(user_data);
core->RecordBreak(bkpt);
uc_emu_stop(uc);
}
}
static void InterruptHook(uc_engine* uc, u32 intNo, void* user_data) {
u32 esr{};
CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR, &esr));
@@ -67,6 +78,10 @@ ARM_Unicorn::ARM_Unicorn() {
uc_hook hook{};
CHECKED(uc_hook_add(uc, &hook, UC_HOOK_INTR, (void*)InterruptHook, this, 0, -1));
CHECKED(uc_hook_add(uc, &hook, UC_HOOK_MEM_INVALID, (void*)UnmappedMemoryHook, this, 0, -1));
if (GDBStub::IsServerEnabled()) {
CHECKED(uc_hook_add(uc, &hook, UC_HOOK_CODE, (void*)CodeHook, this, 0, -1));
last_bkpt_hit = false;
}
}
ARM_Unicorn::~ARM_Unicorn() {
@@ -155,7 +170,11 @@ void ARM_Unicorn::SetTlsAddress(VAddr base) {
}
void ARM_Unicorn::Run() {
ExecuteInstructions(std::max(CoreTiming::GetDowncount(), 0));
if (GDBStub::IsServerEnabled()) {
ExecuteInstructions(std::max(4000000, 0));
} else {
ExecuteInstructions(std::max(CoreTiming::GetDowncount(), 0));
}
}
void ARM_Unicorn::Step() {
@@ -168,6 +187,18 @@ void ARM_Unicorn::ExecuteInstructions(int num_instructions) {
MICROPROFILE_SCOPE(ARM_Jit);
CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions));
CoreTiming::AddTicks(num_instructions);
if (GDBStub::IsServerEnabled()) {
if (last_bkpt_hit) {
uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address);
}
Kernel::Thread* thread = Kernel::GetCurrentThread();
SaveContext(thread->context);
if (last_bkpt_hit || (num_instructions == 1)) {
last_bkpt_hit = false;
GDBStub::Break();
GDBStub::SendTrap(thread, 5);
}
}
}
void ARM_Unicorn::SaveContext(ARM_Interface::ThreadContext& ctx) {
@@ -232,4 +263,11 @@ void ARM_Unicorn::PrepareReschedule() {
CHECKED(uc_emu_stop(uc));
}
void ARM_Unicorn::ClearExclusiveState() {}
void ARM_Unicorn::ClearInstructionCache() {}
void ARM_Unicorn::RecordBreak(GDBStub::BreakpointAddress bkpt) {
last_bkpt = bkpt;
last_bkpt_hit = true;
}

View File

@@ -7,6 +7,7 @@
#include <unicorn/unicorn.h>
#include "common/common_types.h"
#include "core/arm/arm_interface.h"
#include "core/gdbstub/gdbstub.h"
class ARM_Unicorn final : public ARM_Interface {
public:
@@ -30,12 +31,16 @@ public:
void SaveContext(ThreadContext& ctx) override;
void LoadContext(const ThreadContext& ctx) override;
void PrepareReschedule() override;
void ClearExclusiveState() override;
void ExecuteInstructions(int num_instructions);
void Run() override;
void Step() override;
void ClearInstructionCache() override;
void PageTableChanged() override{};
void RecordBreak(GDBStub::BreakpointAddress bkpt);
private:
uc_engine* uc{};
GDBStub::BreakpointAddress last_bkpt{};
bool last_bkpt_hit;
};

View File

@@ -87,15 +87,15 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
app_loader = Loader::GetLoader(filepath);
if (!app_loader) {
NGLOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
return ResultStatus::ErrorGetLoader;
}
std::pair<boost::optional<u32>, Loader::ResultStatus> system_mode =
app_loader->LoadKernelSystemMode();
if (system_mode.second != Loader::ResultStatus::Success) {
NGLOG_CRITICAL(Core, "Failed to determine system mode (Error {})!",
static_cast<int>(system_mode.second));
LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!",
static_cast<int>(system_mode.second));
switch (system_mode.second) {
case Loader::ResultStatus::ErrorEncrypted:
@@ -111,15 +111,15 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
ResultStatus init_result{Init(emu_window, system_mode.first.get())};
if (init_result != ResultStatus::Success) {
NGLOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
static_cast<int>(init_result));
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
static_cast<int>(init_result));
System::Shutdown();
return init_result;
}
const Loader::ResultStatus load_result{app_loader->Load(current_process)};
if (Loader::ResultStatus::Success != load_result) {
NGLOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result));
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result));
System::Shutdown();
switch (load_result) {
@@ -161,7 +161,7 @@ Cpu& System::CpuCore(size_t core_index) {
}
System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
NGLOG_DEBUG(HW_Memory, "initialized OK");
LOG_DEBUG(HW_Memory, "initialized OK");
CoreTiming::Init();
@@ -196,7 +196,7 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
}
}
NGLOG_DEBUG(Core, "Initialized OK");
LOG_DEBUG(Core, "Initialized OK");
// Reset counters and set time origin to current frame
GetAndResetPerfStats();
@@ -245,7 +245,7 @@ void System::Shutdown() {
// Close app loader
app_loader.reset();
NGLOG_DEBUG(Core, "Shutdown OK");
LOG_DEBUG(Core, "Shutdown OK");
}
Service::SM::ServiceManager& System::ServiceManager() {

View File

@@ -56,7 +56,7 @@ Cpu::Cpu(std::shared_ptr<CpuBarrier> cpu_barrier, size_t core_index)
arm_interface = std::make_shared<ARM_Dynarmic>();
#else
cpu_core = std::make_shared<ARM_Unicorn>();
NGLOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
#endif
} else {
arm_interface = std::make_shared<ARM_Unicorn>();
@@ -75,7 +75,7 @@ void Cpu::RunLoop(bool tight_loop) {
// If we don't have a currently active thread then don't execute instructions,
// instead advance to the next event and try to yield to the next thread
if (Kernel::GetCurrentThread() == nullptr) {
NGLOG_TRACE(Core, "Core-{} idling", core_index);
LOG_TRACE(Core, "Core-{} idling", core_index);
if (IsMainCore()) {
CoreTiming::Idle();

View File

@@ -74,11 +74,11 @@ static void EmptyTimedCallback(u64 userdata, s64 cyclesLate) {}
s64 usToCycles(s64 us) {
if (us / 1000000 > MAX_VALUE_TO_MULTIPLY) {
NGLOG_ERROR(Core_Timing, "Integer overflow, use max value");
LOG_ERROR(Core_Timing, "Integer overflow, use max value");
return std::numeric_limits<s64>::max();
}
if (us > MAX_VALUE_TO_MULTIPLY) {
NGLOG_DEBUG(Core_Timing, "Time very big, do rounding");
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
return BASE_CLOCK_RATE * (us / 1000000);
}
return (BASE_CLOCK_RATE * us) / 1000000;
@@ -86,11 +86,11 @@ s64 usToCycles(s64 us) {
s64 usToCycles(u64 us) {
if (us / 1000000 > MAX_VALUE_TO_MULTIPLY) {
NGLOG_ERROR(Core_Timing, "Integer overflow, use max value");
LOG_ERROR(Core_Timing, "Integer overflow, use max value");
return std::numeric_limits<s64>::max();
}
if (us > MAX_VALUE_TO_MULTIPLY) {
NGLOG_DEBUG(Core_Timing, "Time very big, do rounding");
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
return BASE_CLOCK_RATE * static_cast<s64>(us / 1000000);
}
return (BASE_CLOCK_RATE * static_cast<s64>(us)) / 1000000;
@@ -98,11 +98,11 @@ s64 usToCycles(u64 us) {
s64 nsToCycles(s64 ns) {
if (ns / 1000000000 > MAX_VALUE_TO_MULTIPLY) {
NGLOG_ERROR(Core_Timing, "Integer overflow, use max value");
LOG_ERROR(Core_Timing, "Integer overflow, use max value");
return std::numeric_limits<s64>::max();
}
if (ns > MAX_VALUE_TO_MULTIPLY) {
NGLOG_DEBUG(Core_Timing, "Time very big, do rounding");
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
return BASE_CLOCK_RATE * (ns / 1000000000);
}
return (BASE_CLOCK_RATE * ns) / 1000000000;
@@ -110,11 +110,11 @@ s64 nsToCycles(s64 ns) {
s64 nsToCycles(u64 ns) {
if (ns / 1000000000 > MAX_VALUE_TO_MULTIPLY) {
NGLOG_ERROR(Core_Timing, "Integer overflow, use max value");
LOG_ERROR(Core_Timing, "Integer overflow, use max value");
return std::numeric_limits<s64>::max();
}
if (ns > MAX_VALUE_TO_MULTIPLY) {
NGLOG_DEBUG(Core_Timing, "Time very big, do rounding");
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
return BASE_CLOCK_RATE * (static_cast<s64>(ns) / 1000000000);
}
return (BASE_CLOCK_RATE * static_cast<s64>(ns)) / 1000000000;

View File

@@ -58,11 +58,13 @@ ResultVal<std::unique_ptr<StorageBackend>> Disk_FileSystem::OpenFile(const std::
}
ResultCode Disk_FileSystem::DeleteFile(const std::string& path) const {
if (!FileUtil::Exists(path)) {
std::string full_path = base_directory + path;
if (!FileUtil::Exists(full_path)) {
return ERROR_PATH_NOT_FOUND;
}
FileUtil::Delete(path);
FileUtil::Delete(full_path);
return RESULT_SUCCESS;
}
@@ -80,19 +82,19 @@ ResultCode Disk_FileSystem::RenameFile(const std::string& src_path,
}
ResultCode Disk_FileSystem::DeleteDirectory(const Path& path) const {
NGLOG_WARNING(Service_FS, "(STUBBED) called");
LOG_WARNING(Service_FS, "(STUBBED) called");
// TODO(wwylele): Use correct error code
return ResultCode(-1);
}
ResultCode Disk_FileSystem::DeleteDirectoryRecursively(const Path& path) const {
NGLOG_WARNING(Service_FS, "(STUBBED) called");
LOG_WARNING(Service_FS, "(STUBBED) called");
// TODO(wwylele): Use correct error code
return ResultCode(-1);
}
ResultCode Disk_FileSystem::CreateFile(const std::string& path, u64 size) const {
NGLOG_WARNING(Service_FS, "(STUBBED) called");
LOG_WARNING(Service_FS, "(STUBBED) called");
std::string full_path = base_directory + path;
if (size == 0) {
@@ -107,7 +109,7 @@ ResultCode Disk_FileSystem::CreateFile(const std::string& path, u64 size) const
return RESULT_SUCCESS;
}
NGLOG_ERROR(Service_FS, "Too large file");
LOG_ERROR(Service_FS, "Too large file");
// TODO(Subv): Find out the correct error code
return ResultCode(-1);
}
@@ -120,13 +122,13 @@ ResultCode Disk_FileSystem::CreateDirectory(const std::string& path) const {
return RESULT_SUCCESS;
}
NGLOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating {}", full_path);
LOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating {}", full_path);
// TODO(wwylele): Use correct error code
return ResultCode(-1);
}
ResultCode Disk_FileSystem::RenameDirectory(const Path& src_path, const Path& dest_path) const {
NGLOG_WARNING(Service_FS, "(STUBBED) called");
LOG_WARNING(Service_FS, "(STUBBED) called");
// TODO(wwylele): Use correct error code
return ResultCode(-1);
}
@@ -146,7 +148,7 @@ ResultVal<std::unique_ptr<DirectoryBackend>> Disk_FileSystem::OpenDirectory(
}
u64 Disk_FileSystem::GetFreeSpaceSize() const {
NGLOG_WARNING(Service_FS, "(STUBBED) called");
LOG_WARNING(Service_FS, "(STUBBED) called");
return 0;
}
@@ -163,14 +165,14 @@ ResultVal<FileSys::EntryType> Disk_FileSystem::GetEntryType(const std::string& p
}
ResultVal<size_t> Disk_Storage::Read(const u64 offset, const size_t length, u8* buffer) const {
NGLOG_TRACE(Service_FS, "called offset={}, length={}", offset, length);
LOG_TRACE(Service_FS, "called offset={}, length={}", offset, length);
file->Seek(offset, SEEK_SET);
return MakeResult<size_t>(file->ReadBytes(buffer, length));
}
ResultVal<size_t> Disk_Storage::Write(const u64 offset, const size_t length, const bool flush,
const u8* buffer) const {
NGLOG_WARNING(Service_FS, "(STUBBED) called");
LOG_WARNING(Service_FS, "(STUBBED) called");
file->Seek(offset, SEEK_SET);
size_t written = file->WriteBytes(buffer, length);
if (flush) {
@@ -204,7 +206,7 @@ u64 Disk_Directory::Read(const u64 count, Entry* entries) {
const std::string& filename = file.virtualName;
Entry& entry = entries[entries_read];
NGLOG_TRACE(Service_FS, "File {}: size={} dir={}", filename, file.size, file.isDirectory);
LOG_TRACE(Service_FS, "File {}: size={} dir={}", filename, file.size, file.isDirectory);
// TODO(Link Mauve): use a proper conversion to UTF-16.
for (size_t j = 0; j < FILENAME_LENGTH; ++j) {

View File

@@ -11,6 +11,9 @@ namespace FileSys {
namespace ErrCodes {
enum {
NotFound = 1,
SaveDataNotFound = 1002,
SdCardNotFound = 2001,
RomFSNotFound = 2520,
};
}

View File

@@ -71,7 +71,7 @@ std::string Path::AsString() const {
case Binary:
default:
// TODO(yuriks): Add assert
NGLOG_ERROR(Service_FS, "LowPathType cannot be converted to string!");
LOG_ERROR(Service_FS, "LowPathType cannot be converted to string!");
return {};
}
}
@@ -87,7 +87,7 @@ std::u16string Path::AsU16Str() const {
case Invalid:
case Binary:
// TODO(yuriks): Add assert
NGLOG_ERROR(Service_FS, "LowPathType cannot be converted to u16string!");
LOG_ERROR(Service_FS, "LowPathType cannot be converted to u16string!");
return {};
}
@@ -115,7 +115,7 @@ std::vector<u8> Path::AsBinary() const {
case Invalid:
default:
// TODO(yuriks): Add assert
NGLOG_ERROR(Service_FS, "LowPathType cannot be converted to binary!");
LOG_ERROR(Service_FS, "LowPathType cannot be converted to binary!");
return {};
}
}

View File

@@ -167,35 +167,4 @@ public:
virtual ResultVal<EntryType> GetEntryType(const std::string& path) const = 0;
};
class FileSystemFactory : NonCopyable {
public:
virtual ~FileSystemFactory() {}
/**
* Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.)
*/
virtual std::string GetName() const = 0;
/**
* Tries to open the archive of this type with the specified path
* @param path Path to the archive
* @return An ArchiveBackend corresponding operating specified archive path.
*/
virtual ResultVal<std::unique_ptr<FileSystemBackend>> Open(const Path& path) = 0;
/**
* Deletes the archive contents and then re-creates the base folder
* @param path Path to the archive
* @return ResultCode of the operation, 0 on success
*/
virtual ResultCode Format(const Path& path) = 0;
/**
* Retrieves the format info about the archive with the specified path
* @param path Path to the archive
* @return Format information about the archive or error code
*/
virtual ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const = 0;
};
} // namespace FileSys

View File

@@ -19,13 +19,20 @@ Loader::ResultStatus PartitionFilesystem::Load(const std::string& file_path, siz
if (file.GetSize() < sizeof(Header))
return Loader::ResultStatus::Error;
file.Seek(offset, SEEK_SET);
// For cartridges, HFSs can get very large, so we need to calculate the size up to
// the actual content itself instead of just blindly reading in the entire file.
Header pfs_header;
if (!file.ReadBytes(&pfs_header, sizeof(Header)))
return Loader::ResultStatus::Error;
bool is_hfs = (memcmp(pfs_header.magic.data(), "HFS", 3) == 0);
if (pfs_header.magic != Common::MakeMagic('H', 'F', 'S', '0') &&
pfs_header.magic != Common::MakeMagic('P', 'F', 'S', '0')) {
return Loader::ResultStatus::ErrorInvalidFormat;
}
bool is_hfs = pfs_header.magic == Common::MakeMagic('H', 'F', 'S', '0');
size_t entry_size = is_hfs ? sizeof(HFSEntry) : sizeof(PFSEntry);
size_t metadata_size =
sizeof(Header) + (pfs_header.num_entries * entry_size) + pfs_header.strtab_size;
@@ -39,7 +46,7 @@ Loader::ResultStatus PartitionFilesystem::Load(const std::string& file_path, siz
Loader::ResultStatus result = Load(file_data);
if (result != Loader::ResultStatus::Success)
NGLOG_ERROR(Service_FS, "Failed to load PFS from file {}!", file_path);
LOG_ERROR(Service_FS, "Failed to load PFS from file {}!", file_path);
return result;
}
@@ -50,7 +57,12 @@ Loader::ResultStatus PartitionFilesystem::Load(const std::vector<u8>& file_data,
return Loader::ResultStatus::Error;
memcpy(&pfs_header, &file_data[offset], sizeof(Header));
is_hfs = (memcmp(pfs_header.magic.data(), "HFS", 3) == 0);
if (pfs_header.magic != Common::MakeMagic('H', 'F', 'S', '0') &&
pfs_header.magic != Common::MakeMagic('P', 'F', 'S', '0')) {
return Loader::ResultStatus::ErrorInvalidFormat;
}
is_hfs = pfs_header.magic == Common::MakeMagic('H', 'F', 'S', '0');
size_t entries_offset = offset + sizeof(Header);
size_t entry_size = is_hfs ? sizeof(HFSEntry) : sizeof(PFSEntry);
@@ -73,21 +85,21 @@ u32 PartitionFilesystem::GetNumEntries() const {
return pfs_header.num_entries;
}
u64 PartitionFilesystem::GetEntryOffset(int index) const {
u64 PartitionFilesystem::GetEntryOffset(u32 index) const {
if (index > GetNumEntries())
return 0;
return content_offset + pfs_entries[index].fs_entry.offset;
}
u64 PartitionFilesystem::GetEntrySize(int index) const {
u64 PartitionFilesystem::GetEntrySize(u32 index) const {
if (index > GetNumEntries())
return 0;
return pfs_entries[index].fs_entry.size;
}
std::string PartitionFilesystem::GetEntryName(int index) const {
std::string PartitionFilesystem::GetEntryName(u32 index) const {
if (index > GetNumEntries())
return "";
@@ -113,12 +125,12 @@ u64 PartitionFilesystem::GetFileSize(const std::string& name) const {
}
void PartitionFilesystem::Print() const {
NGLOG_DEBUG(Service_FS, "Magic: {:.4}", pfs_header.magic.data());
NGLOG_DEBUG(Service_FS, "Files: {}", pfs_header.num_entries);
LOG_DEBUG(Service_FS, "Magic: {}", pfs_header.magic);
LOG_DEBUG(Service_FS, "Files: {}", pfs_header.num_entries);
for (u32 i = 0; i < pfs_header.num_entries; i++) {
NGLOG_DEBUG(Service_FS, " > File {}: {} (0x{:X} bytes, at 0x{:X})", i,
pfs_entries[i].name.c_str(), pfs_entries[i].fs_entry.size,
GetFileOffset(pfs_entries[i].name));
LOG_DEBUG(Service_FS, " > File {}: {} (0x{:X} bytes, at 0x{:X})", i,
pfs_entries[i].name.c_str(), pfs_entries[i].fs_entry.size,
GetFileOffset(pfs_entries[i].name));
}
}
} // namespace FileSys

View File

@@ -27,9 +27,9 @@ public:
Loader::ResultStatus Load(const std::vector<u8>& file_data, size_t offset = 0);
u32 GetNumEntries() const;
u64 GetEntryOffset(int index) const;
u64 GetEntrySize(int index) const;
std::string GetEntryName(int index) const;
u64 GetEntryOffset(u32 index) const;
u64 GetEntrySize(u32 index) const;
std::string GetEntryName(u32 index) const;
u64 GetFileOffset(const std::string& name) const;
u64 GetFileSize(const std::string& name) const;
@@ -37,7 +37,7 @@ public:
private:
struct Header {
std::array<char, 4> magic;
u32_le magic;
u32_le num_entries;
u32_le strtab_size;
INSERT_PADDING_BYTES(0x4);

View File

@@ -21,7 +21,7 @@ Loader::ResultStatus ProgramMetadata::Load(const std::string& file_path) {
Loader::ResultStatus result = Load(file_data);
if (result != Loader::ResultStatus::Success)
NGLOG_ERROR(Service_FS, "Failed to load NPDM from file {}!", file_path);
LOG_ERROR(Service_FS, "Failed to load NPDM from file {}!", file_path);
return result;
}
@@ -76,14 +76,14 @@ u64 ProgramMetadata::GetFilesystemPermissions() const {
}
void ProgramMetadata::Print() const {
NGLOG_DEBUG(Service_FS, "Magic: {:.4}", npdm_header.magic.data());
NGLOG_DEBUG(Service_FS, "Main thread priority: 0x{:02X}", npdm_header.main_thread_priority);
NGLOG_DEBUG(Service_FS, "Main thread core: {}", npdm_header.main_thread_cpu);
NGLOG_DEBUG(Service_FS, "Main thread stack size: 0x{:X} bytes", npdm_header.main_stack_size);
NGLOG_DEBUG(Service_FS, "Process category: {}", npdm_header.process_category);
NGLOG_DEBUG(Service_FS, "Flags: 0x{:02X}", npdm_header.flags);
NGLOG_DEBUG(Service_FS, " > 64-bit instructions: {}",
npdm_header.has_64_bit_instructions ? "YES" : "NO");
LOG_DEBUG(Service_FS, "Magic: {:.4}", npdm_header.magic.data());
LOG_DEBUG(Service_FS, "Main thread priority: 0x{:02X}", npdm_header.main_thread_priority);
LOG_DEBUG(Service_FS, "Main thread core: {}", npdm_header.main_thread_cpu);
LOG_DEBUG(Service_FS, "Main thread stack size: 0x{:X} bytes", npdm_header.main_stack_size);
LOG_DEBUG(Service_FS, "Process category: {}", npdm_header.process_category);
LOG_DEBUG(Service_FS, "Flags: 0x{:02X}", npdm_header.flags);
LOG_DEBUG(Service_FS, " > 64-bit instructions: {}",
npdm_header.has_64_bit_instructions ? "YES" : "NO");
auto address_space = "Unknown";
switch (npdm_header.address_space_type) {
@@ -95,19 +95,19 @@ void ProgramMetadata::Print() const {
break;
}
NGLOG_DEBUG(Service_FS, " > Address space: {}\n", address_space);
LOG_DEBUG(Service_FS, " > Address space: {}\n", address_space);
// Begin ACID printing (potential perms, signed)
NGLOG_DEBUG(Service_FS, "Magic: {:.4}", acid_header.magic.data());
NGLOG_DEBUG(Service_FS, "Flags: 0x{:02X}", acid_header.flags);
NGLOG_DEBUG(Service_FS, " > Is Retail: {}", acid_header.is_retail ? "YES" : "NO");
NGLOG_DEBUG(Service_FS, "Title ID Min: 0x{:016X}", acid_header.title_id_min);
NGLOG_DEBUG(Service_FS, "Title ID Max: 0x{:016X}", acid_header.title_id_max);
NGLOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", acid_file_access.permissions);
LOG_DEBUG(Service_FS, "Magic: {:.4}", acid_header.magic.data());
LOG_DEBUG(Service_FS, "Flags: 0x{:02X}", acid_header.flags);
LOG_DEBUG(Service_FS, " > Is Retail: {}", acid_header.is_retail ? "YES" : "NO");
LOG_DEBUG(Service_FS, "Title ID Min: 0x{:016X}", acid_header.title_id_min);
LOG_DEBUG(Service_FS, "Title ID Max: 0x{:016X}", acid_header.title_id_max);
LOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", acid_file_access.permissions);
// Begin ACI0 printing (actual perms, unsigned)
NGLOG_DEBUG(Service_FS, "Magic: {:.4}", aci_header.magic.data());
NGLOG_DEBUG(Service_FS, "Title ID: 0x{:016X}", aci_header.title_id);
NGLOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", aci_file_access.permissions);
LOG_DEBUG(Service_FS, "Magic: {:.4}", aci_header.magic.data());
LOG_DEBUG(Service_FS, "Title ID: 0x{:016X}", aci_header.title_id);
LOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", aci_file_access.permissions);
}
} // namespace FileSys

View File

@@ -11,28 +11,17 @@
namespace FileSys {
RomFS_Factory::RomFS_Factory(Loader::AppLoader& app_loader) {
RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader) {
// Load the RomFS from the app
if (Loader::ResultStatus::Success != app_loader.ReadRomFS(romfs_file, data_offset, data_size)) {
NGLOG_ERROR(Service_FS, "Unable to read RomFS!");
LOG_ERROR(Service_FS, "Unable to read RomFS!");
}
}
ResultVal<std::unique_ptr<FileSystemBackend>> RomFS_Factory::Open(const Path& path) {
ResultVal<std::unique_ptr<FileSystemBackend>> RomFSFactory::Open(u64 title_id) {
// TODO(DarkLordZach): Use title id.
auto archive = std::make_unique<RomFS_FileSystem>(romfs_file, data_offset, data_size);
return MakeResult<std::unique_ptr<FileSystemBackend>>(std::move(archive));
}
ResultCode RomFS_Factory::Format(const Path& path) {
NGLOG_ERROR(Service_FS, "Unimplemented Format archive {}", GetName());
// TODO(bunnei): Find the right error code for this
return ResultCode(-1);
}
ResultVal<ArchiveFormatInfo> RomFS_Factory::GetFormatInfo(const Path& path) const {
NGLOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName());
// TODO(bunnei): Find the right error code for this
return ResultCode(-1);
}
} // namespace FileSys

View File

@@ -15,16 +15,11 @@
namespace FileSys {
/// File system interface to the RomFS archive
class RomFS_Factory final : public FileSystemFactory {
class RomFSFactory {
public:
explicit RomFS_Factory(Loader::AppLoader& app_loader);
explicit RomFSFactory(Loader::AppLoader& app_loader);
std::string GetName() const override {
return "ArchiveFactory_RomFS";
}
ResultVal<std::unique_ptr<FileSystemBackend>> Open(const Path& path) override;
ResultCode Format(const Path& path) override;
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
ResultVal<std::unique_ptr<FileSystemBackend>> Open(u64 title_id);
private:
std::shared_ptr<FileUtil::IOFile> romfs_file;

View File

@@ -21,72 +21,70 @@ ResultVal<std::unique_ptr<StorageBackend>> RomFS_FileSystem::OpenFile(const std:
}
ResultCode RomFS_FileSystem::DeleteFile(const std::string& path) const {
NGLOG_CRITICAL(Service_FS, "Attempted to delete a file from an ROMFS archive ({}).", GetName());
LOG_CRITICAL(Service_FS, "Attempted to delete a file from an ROMFS archive ({}).", GetName());
// TODO(bunnei): Use correct error code
return ResultCode(-1);
}
ResultCode RomFS_FileSystem::RenameFile(const std::string& src_path,
const std::string& dest_path) const {
NGLOG_CRITICAL(Service_FS, "Attempted to rename a file within an ROMFS archive ({}).",
GetName());
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an ROMFS archive ({}).", GetName());
// TODO(wwylele): Use correct error code
return ResultCode(-1);
}
ResultCode RomFS_FileSystem::DeleteDirectory(const Path& path) const {
NGLOG_CRITICAL(Service_FS, "Attempted to delete a directory from an ROMFS archive ({}).",
GetName());
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an ROMFS archive ({}).",
GetName());
// TODO(wwylele): Use correct error code
return ResultCode(-1);
}
ResultCode RomFS_FileSystem::DeleteDirectoryRecursively(const Path& path) const {
NGLOG_CRITICAL(Service_FS, "Attempted to delete a directory from an ROMFS archive ({}).",
GetName());
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an ROMFS archive ({}).",
GetName());
// TODO(wwylele): Use correct error code
return ResultCode(-1);
}
ResultCode RomFS_FileSystem::CreateFile(const std::string& path, u64 size) const {
NGLOG_CRITICAL(Service_FS, "Attempted to create a file in an ROMFS archive ({}).", GetName());
LOG_CRITICAL(Service_FS, "Attempted to create a file in an ROMFS archive ({}).", GetName());
// TODO(bunnei): Use correct error code
return ResultCode(-1);
}
ResultCode RomFS_FileSystem::CreateDirectory(const std::string& path) const {
NGLOG_CRITICAL(Service_FS, "Attempted to create a directory in an ROMFS archive ({}).",
GetName());
LOG_CRITICAL(Service_FS, "Attempted to create a directory in an ROMFS archive ({}).",
GetName());
// TODO(wwylele): Use correct error code
return ResultCode(-1);
}
ResultCode RomFS_FileSystem::RenameDirectory(const Path& src_path, const Path& dest_path) const {
NGLOG_CRITICAL(Service_FS, "Attempted to rename a file within an ROMFS archive ({}).",
GetName());
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an ROMFS archive ({}).", GetName());
// TODO(wwylele): Use correct error code
return ResultCode(-1);
}
ResultVal<std::unique_ptr<DirectoryBackend>> RomFS_FileSystem::OpenDirectory(
const std::string& path) const {
NGLOG_WARNING(Service_FS, "Opening Directory in a ROMFS archive");
LOG_WARNING(Service_FS, "Opening Directory in a ROMFS archive");
return MakeResult<std::unique_ptr<DirectoryBackend>>(std::make_unique<ROMFSDirectory>());
}
u64 RomFS_FileSystem::GetFreeSpaceSize() const {
NGLOG_WARNING(Service_FS, "Attempted to get the free space in an ROMFS archive");
LOG_WARNING(Service_FS, "Attempted to get the free space in an ROMFS archive");
return 0;
}
ResultVal<FileSys::EntryType> RomFS_FileSystem::GetEntryType(const std::string& path) const {
NGLOG_CRITICAL(Service_FS, "Called within an ROMFS archive (path {}).", path);
LOG_CRITICAL(Service_FS, "Called within an ROMFS archive (path {}).", path);
// TODO(wwylele): Use correct error code
return ResultCode(-1);
}
ResultVal<size_t> RomFS_Storage::Read(const u64 offset, const size_t length, u8* buffer) const {
NGLOG_TRACE(Service_FS, "called offset={}, length={}", offset, length);
LOG_TRACE(Service_FS, "called offset={}, length={}", offset, length);
romfs_file->Seek(data_offset + offset, SEEK_SET);
size_t read_length = (size_t)std::min((u64)length, data_size - offset);
@@ -95,7 +93,7 @@ ResultVal<size_t> RomFS_Storage::Read(const u64 offset, const size_t length, u8*
ResultVal<size_t> RomFS_Storage::Write(const u64 offset, const size_t length, const bool flush,
const u8* buffer) const {
NGLOG_ERROR(Service_FS, "Attempted to write to ROMFS file");
LOG_ERROR(Service_FS, "Attempted to write to ROMFS file");
// TODO(Subv): Find error code
return MakeResult<size_t>(0);
}
@@ -105,7 +103,7 @@ u64 RomFS_Storage::GetSize() const {
}
bool RomFS_Storage::SetSize(const u64 size) const {
NGLOG_ERROR(Service_FS, "Attempted to set the size of an ROMFS file");
LOG_ERROR(Service_FS, "Attempted to set the size of an ROMFS file");
return false;
}

View File

@@ -12,11 +12,64 @@
namespace FileSys {
SaveData_Factory::SaveData_Factory(std::string nand_directory)
std::string SaveDataDescriptor::DebugInfo() {
return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}]",
static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id);
}
SaveDataFactory::SaveDataFactory(std::string nand_directory)
: nand_directory(std::move(nand_directory)) {}
ResultVal<std::unique_ptr<FileSystemBackend>> SaveData_Factory::Open(const Path& path) {
std::string save_directory = GetFullPath();
ResultVal<std::unique_ptr<FileSystemBackend>> SaveDataFactory::Open(SaveDataSpaceId space,
SaveDataDescriptor meta) {
if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) {
if (meta.zero_1 != 0) {
LOG_WARNING(Service_FS,
"Possibly incorrect SaveDataDescriptor, type is "
"SystemSaveData||SaveData but offset 0x28 is non-zero ({:016X}).",
meta.zero_1);
}
if (meta.zero_2 != 0) {
LOG_WARNING(Service_FS,
"Possibly incorrect SaveDataDescriptor, type is "
"SystemSaveData||SaveData but offset 0x30 is non-zero ({:016X}).",
meta.zero_2);
}
if (meta.zero_3 != 0) {
LOG_WARNING(Service_FS,
"Possibly incorrect SaveDataDescriptor, type is "
"SystemSaveData||SaveData but offset 0x38 is non-zero ({:016X}).",
meta.zero_3);
}
}
if (meta.type == SaveDataType::SystemSaveData && meta.title_id != 0) {
LOG_WARNING(Service_FS,
"Possibly incorrect SaveDataDescriptor, type is SystemSaveData but title_id is "
"non-zero ({:016X}).",
meta.title_id);
}
std::string 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.
if (!FileUtil::Exists(save_directory)) {
// 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.
FileUtil::CreateFullPath(save_directory);
}
// TODO(DarkLordZach): For some reason, CreateFullPath doesn't create the last bit. Should be
// fixed with VFS.
if (!FileUtil::IsDirectory(save_directory)) {
FileUtil::CreateDir(save_directory);
}
// Return an error if the save data doesn't actually exist.
if (!FileUtil::IsDirectory(save_directory)) {
// TODO(Subv): Find out correct error code.
@@ -27,28 +80,35 @@ ResultVal<std::unique_ptr<FileSystemBackend>> SaveData_Factory::Open(const Path&
return MakeResult<std::unique_ptr<FileSystemBackend>>(std::move(archive));
}
ResultCode SaveData_Factory::Format(const Path& path) {
NGLOG_WARNING(Service_FS, "Format archive {}", GetName());
// Create the save data directory.
if (!FileUtil::CreateFullPath(GetFullPath())) {
// TODO(Subv): Find the correct error code.
return ResultCode(-1);
std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id,
u128 user_id, u64 save_id) const {
// According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
// be interpreted as the title id of the current process.
if (type == SaveDataType::SaveData && title_id == 0)
title_id = Core::CurrentProcess()->program_id;
std::string prefix;
switch (space) {
case SaveDataSpaceId::NandSystem:
prefix = nand_directory + "system/save/";
break;
case SaveDataSpaceId::NandUser:
prefix = nand_directory + "user/save/";
break;
default:
ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space));
}
return RESULT_SUCCESS;
}
ResultVal<ArchiveFormatInfo> SaveData_Factory::GetFormatInfo(const Path& path) const {
NGLOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName());
// TODO(bunnei): Find the right error code for this
return ResultCode(-1);
}
std::string SaveData_Factory::GetFullPath() const {
u64 title_id = Core::CurrentProcess()->program_id;
// TODO(Subv): Somehow obtain this value.
u32 user = 0;
return fmt::format("{}save/{:016X}/{:08X}/", nand_directory, title_id, user);
switch (type) {
case SaveDataType::SystemSaveData:
return fmt::format("{}{:016X}/{:016X}{:016X}", prefix, save_id, user_id[1], user_id[0]);
case SaveDataType::SaveData:
return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", prefix, 0, user_id[1], user_id[0],
title_id);
default:
ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type));
}
}
} // namespace FileSys

View File

@@ -12,22 +12,50 @@
namespace FileSys {
/// File system interface to the SaveData archive
class SaveData_Factory final : public FileSystemFactory {
public:
explicit SaveData_Factory(std::string nand_directory);
enum class SaveDataSpaceId : u8 {
NandSystem = 0,
NandUser = 1,
SdCard = 2,
TemporaryStorage = 3,
};
std::string GetName() const override {
return "SaveData_Factory";
}
ResultVal<std::unique_ptr<FileSystemBackend>> Open(const Path& path) override;
ResultCode Format(const Path& path) override;
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
enum class SaveDataType : u8 {
SystemSaveData = 0,
SaveData = 1,
BcatDeliveryCacheStorage = 2,
DeviceSaveData = 3,
TemporaryStorage = 4,
CacheStorage = 5,
};
struct SaveDataDescriptor {
u64_le title_id;
u128 user_id;
u64_le save_id;
SaveDataType type;
INSERT_PADDING_BYTES(7);
u64_le zero_1;
u64_le zero_2;
u64_le zero_3;
std::string DebugInfo();
};
static_assert(sizeof(SaveDataDescriptor) == 0x40, "SaveDataDescriptor has incorrect size.");
/// File system interface to the SaveData archive
class SaveDataFactory {
public:
explicit SaveDataFactory(std::string nand_directory);
ResultVal<std::unique_ptr<FileSystemBackend>> Open(SaveDataSpaceId space,
SaveDataDescriptor meta);
private:
std::string nand_directory;
std::string sd_directory;
std::string GetFullPath() const;
std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, u128 user_id,
u64 save_id) const;
};
} // namespace FileSys

View File

@@ -12,9 +12,9 @@
namespace FileSys {
SDMC_Factory::SDMC_Factory(std::string sd_directory) : sd_directory(std::move(sd_directory)) {}
SDMCFactory::SDMCFactory(std::string sd_directory) : sd_directory(std::move(sd_directory)) {}
ResultVal<std::unique_ptr<FileSystemBackend>> SDMC_Factory::Open(const Path& path) {
ResultVal<std::unique_ptr<FileSystemBackend>> SDMCFactory::Open() {
// Create the SD Card directory if it doesn't already exist.
if (!FileUtil::IsDirectory(sd_directory)) {
FileUtil::CreateFullPath(sd_directory);
@@ -24,16 +24,4 @@ ResultVal<std::unique_ptr<FileSystemBackend>> SDMC_Factory::Open(const Path& pat
return MakeResult<std::unique_ptr<FileSystemBackend>>(std::move(archive));
}
ResultCode SDMC_Factory::Format(const Path& path) {
NGLOG_ERROR(Service_FS, "Unimplemented Format archive {}", GetName());
// TODO(Subv): Find the right error code for this
return ResultCode(-1);
}
ResultVal<ArchiveFormatInfo> SDMC_Factory::GetFormatInfo(const Path& path) const {
NGLOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName());
// TODO(bunnei): Find the right error code for this
return ResultCode(-1);
}
} // namespace FileSys

View File

@@ -13,16 +13,11 @@
namespace FileSys {
/// File system interface to the SDCard archive
class SDMC_Factory final : public FileSystemFactory {
class SDMCFactory {
public:
explicit SDMC_Factory(std::string sd_directory);
explicit SDMCFactory(std::string sd_directory);
std::string GetName() const override {
return "SDMC_Factory";
}
ResultVal<std::unique_ptr<FileSystemBackend>> Open(const Path& path) override;
ResultCode Format(const Path& path) override;
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
ResultVal<std::unique_ptr<FileSystemBackend>> Open();
private:
std::string sd_directory;

View File

@@ -59,7 +59,7 @@ template <typename InputDeviceType>
void RegisterFactory(const std::string& name, std::shared_ptr<Factory<InputDeviceType>> factory) {
auto pair = std::make_pair(name, std::move(factory));
if (!Impl::FactoryList<InputDeviceType>::list.insert(std::move(pair)).second) {
NGLOG_ERROR(Input, "Factory '{}' already registered", name);
LOG_ERROR(Input, "Factory '{}' already registered", name);
}
}
@@ -71,7 +71,7 @@ void RegisterFactory(const std::string& name, std::shared_ptr<Factory<InputDevic
template <typename InputDeviceType>
void UnregisterFactory(const std::string& name) {
if (Impl::FactoryList<InputDeviceType>::list.erase(name) == 0) {
NGLOG_ERROR(Input, "Factory '{}' not registered", name);
LOG_ERROR(Input, "Factory '{}' not registered", name);
}
}
@@ -88,7 +88,7 @@ std::unique_ptr<InputDeviceType> CreateDevice(const std::string& params) {
const auto pair = factory_list.find(engine);
if (pair == factory_list.end()) {
if (engine != "null") {
NGLOG_ERROR(Input, "Unknown engine name: {}", engine);
LOG_ERROR(Input, "Unknown engine name: {}", engine);
}
return std::make_unique<InputDeviceType>();
}

View File

@@ -32,9 +32,13 @@
#include "common/logging/log.h"
#include "common/string_util.h"
#include "common/swap.h"
#include "core/arm/arm_interface.h"
#include "core/core.h"
#include "core/core_cpu.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/scheduler.h"
#include "core/loader/loader.h"
#include "core/memory.h"
@@ -57,10 +61,16 @@ const u32 SIGTERM = 15;
const u32 MSG_WAITALL = 8;
#endif
const u32 X30_REGISTER = 30;
const u32 LR_REGISTER = 30;
const u32 SP_REGISTER = 31;
const u32 PC_REGISTER = 32;
const u32 CPSR_REGISTER = 33;
const u32 UC_ARM64_REG_Q0 = 34;
const u32 FPSCR_REGISTER = 66;
// TODO/WiP - Used while working on support for FPU
const u32 TODO_DUMMY_REG_997 = 997;
const u32 TODO_DUMMY_REG_998 = 998;
// For sample XML files see the GDB source /gdb/features
// GDB also wants the l character at the start
@@ -126,6 +136,8 @@ static const char* target_xml =
</flags>
<reg name="cpsr" bitsize="32" type="cpsr_flags"/>
</feature>
<feature name="org.gnu.gdb.aarch64.fpu">
</feature>
</target>
)";
@@ -137,15 +149,18 @@ static u8 command_buffer[GDB_BUFFER_SIZE];
static u32 command_length;
static u32 latest_signal = 0;
static bool step_break = false;
static bool memory_break = false;
static Kernel::Thread* current_thread = nullptr;
static u32 current_core = 0;
// Binding to a port within the reserved ports range (0-1023) requires root permissions,
// so default to a port outside of that range.
static u16 gdbstub_port = 24689;
static bool halt_loop = true;
static bool step_loop = false;
static bool send_trap = false;
// If set to false, the server will never be started and no
// gdbstub-related functions will be executed.
@@ -165,6 +180,78 @@ static std::map<u64, Breakpoint> breakpoints_execute;
static std::map<u64, Breakpoint> breakpoints_read;
static std::map<u64, Breakpoint> breakpoints_write;
struct Module {
std::string name;
PAddr beg;
PAddr end;
};
static std::vector<Module> modules;
void RegisterModule(std::string name, PAddr beg, PAddr end, bool add_elf_ext) {
Module module;
if (add_elf_ext) {
Common::SplitPath(name, nullptr, &module.name, nullptr);
module.name += ".elf";
} else {
module.name = std::move(name);
}
module.beg = beg;
module.end = end;
modules.push_back(std::move(module));
}
static Kernel::Thread* FindThreadById(int id) {
for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) {
const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList();
for (auto& thread : threads) {
if (thread->GetThreadId() == id) {
current_core = core;
return thread.get();
}
}
}
return nullptr;
}
static u64 RegRead(int id, Kernel::Thread* thread = nullptr) {
if (!thread) {
return 0;
}
if (id < SP_REGISTER) {
return thread->context.cpu_registers[id];
} else if (id == SP_REGISTER) {
return thread->context.sp;
} else if (id == PC_REGISTER) {
return thread->context.pc;
} else if (id == CPSR_REGISTER) {
return thread->context.cpsr;
} else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) {
return thread->context.fpu_registers[id - UC_ARM64_REG_Q0][0];
} else {
return 0;
}
}
static void RegWrite(int id, u64 val, Kernel::Thread* thread = nullptr) {
if (!thread) {
return;
}
if (id < SP_REGISTER) {
thread->context.cpu_registers[id] = val;
} else if (id == SP_REGISTER) {
thread->context.sp = val;
} else if (id == PC_REGISTER) {
thread->context.pc = val;
} else if (id == CPSR_REGISTER) {
thread->context.cpsr = val;
} else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) {
thread->context.fpu_registers[id - (CPSR_REGISTER + 1)][0] = val;
}
}
/**
* Turns hex string character into the equivalent byte.
*
@@ -179,7 +266,7 @@ static u8 HexCharToValue(u8 hex) {
return hex - 'A' + 0xA;
}
NGLOG_ERROR(Debug_GDBStub, "Invalid nibble: {} ({:02X})", hex, hex);
LOG_ERROR(Debug_GDBStub, "Invalid nibble: {} ({:02X})", hex, hex);
return 0;
}
@@ -193,7 +280,7 @@ static u8 NibbleToHex(u8 n) {
if (n < 0xA) {
return '0' + n;
} else {
return 'A' + n - 0xA;
return 'a' + n - 0xA;
}
}
@@ -319,7 +406,7 @@ static u8 ReadByte() {
u8 c;
size_t received_size = recv(gdbserver_socket, reinterpret_cast<char*>(&c), 1, MSG_WAITALL);
if (received_size != 1) {
NGLOG_ERROR(Debug_GDBStub, "recv failed: {}", received_size);
LOG_ERROR(Debug_GDBStub, "recv failed: {}", received_size);
Shutdown();
}
@@ -360,8 +447,8 @@ static void RemoveBreakpoint(BreakpointType type, PAddr addr) {
auto bp = p.find(static_cast<u64>(addr));
if (bp != p.end()) {
NGLOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:016X} bytes at {:016X} of type {}",
bp->second.len, bp->second.addr, static_cast<int>(type));
LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:016X} bytes at {:016X} of type {}",
bp->second.len, bp->second.addr, static_cast<int>(type));
p.erase(static_cast<u64>(addr));
}
}
@@ -406,10 +493,10 @@ bool CheckBreakpoint(PAddr addr, BreakpointType type) {
}
if (bp->second.active && (addr >= bp->second.addr && addr < bp->second.addr + len)) {
NGLOG_DEBUG(Debug_GDBStub,
"Found breakpoint type {} @ {:016X}, range: {:016X}"
" - {:016X} ({:X} bytes)",
static_cast<int>(type), addr, bp->second.addr, bp->second.addr + len, len);
LOG_DEBUG(Debug_GDBStub,
"Found breakpoint type {} @ {:016X}, range: {:016X}"
" - {:016X} ({:X} bytes)",
static_cast<int>(type), addr, bp->second.addr, bp->second.addr + len, len);
return true;
}
}
@@ -425,7 +512,7 @@ bool CheckBreakpoint(PAddr addr, BreakpointType type) {
static void SendPacket(const char packet) {
size_t sent_size = send(gdbserver_socket, &packet, 1, 0);
if (sent_size != 1) {
NGLOG_ERROR(Debug_GDBStub, "send failed");
LOG_ERROR(Debug_GDBStub, "send failed");
}
}
@@ -439,11 +526,13 @@ static void SendReply(const char* reply) {
return;
}
LOG_DEBUG(Debug_GDBStub, "Reply: {}", reply);
memset(command_buffer, 0, sizeof(command_buffer));
command_length = static_cast<u32>(strlen(reply));
if (command_length + 4 > sizeof(command_buffer)) {
NGLOG_ERROR(Debug_GDBStub, "command_buffer overflow in SendReply");
LOG_ERROR(Debug_GDBStub, "command_buffer overflow in SendReply");
return;
}
@@ -460,7 +549,7 @@ static void SendReply(const char* reply) {
while (left > 0) {
int sent_size = send(gdbserver_socket, reinterpret_cast<char*>(ptr), left, 0);
if (sent_size < 0) {
NGLOG_ERROR(Debug_GDBStub, "gdb: send failed");
LOG_ERROR(Debug_GDBStub, "gdb: send failed");
return Shutdown();
}
@@ -471,7 +560,7 @@ static void SendReply(const char* reply) {
/// Handle query command from gdb client.
static void HandleQuery() {
NGLOG_DEBUG(Debug_GDBStub, "gdb: query '{}'", command_buffer + 1);
LOG_DEBUG(Debug_GDBStub, "gdb: query '{}'", command_buffer + 1);
const char* query = reinterpret_cast<const char*>(command_buffer + 1);
@@ -479,10 +568,55 @@ static void HandleQuery() {
SendReply("T0");
} else if (strncmp(query, "Supported", strlen("Supported")) == 0) {
// PacketSize needs to be large enough for target xml
SendReply("PacketSize=2000;qXfer:features:read+");
std::string buffer = "PacketSize=2000;qXfer:features:read+;qXfer:threads:read+";
if (!modules.empty()) {
buffer += ";qXfer:libraries:read+";
}
SendReply(buffer.c_str());
} else if (strncmp(query, "Xfer:features:read:target.xml:",
strlen("Xfer:features:read:target.xml:")) == 0) {
SendReply(target_xml);
} else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) {
std::string buffer = fmt::format("TextSeg={:0x}", Memory::PROCESS_IMAGE_VADDR);
SendReply(buffer.c_str());
} else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) {
std::string val = "m";
for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) {
const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList();
for (const auto& thread : threads) {
val += fmt::format("{:x}", thread->GetThreadId());
val += ",";
}
}
val.pop_back();
SendReply(val.c_str());
} else if (strncmp(query, "sThreadInfo", strlen("sThreadInfo")) == 0) {
SendReply("l");
} else if (strncmp(query, "Xfer:threads:read", strlen("Xfer:threads:read")) == 0) {
std::string buffer;
buffer += "l<?xml version=\"1.0\"?>";
buffer += "<threads>";
for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) {
const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList();
for (const auto& thread : threads) {
buffer +=
fmt::format(R"*(<thread id="{:x}" core="{:d}" name="Thread {:x}"></thread>)*",
thread->GetThreadId(), core, thread->GetThreadId());
}
}
buffer += "</threads>";
SendReply(buffer.c_str());
} else if (strncmp(query, "Xfer:libraries:read", strlen("Xfer:libraries:read")) == 0) {
std::string buffer;
buffer += "l<?xml version=\"1.0\"?>";
buffer += "<library-list>";
for (const auto& module : modules) {
buffer +=
fmt::format(R"*("<library name = "{}"><segment address = "0x{:x}"/></library>)*",
module.name, module.beg);
}
buffer += "</library-list>";
SendReply(buffer.c_str());
} else {
SendReply("");
}
@@ -490,11 +624,34 @@ static void HandleQuery() {
/// Handle set thread command from gdb client.
static void HandleSetThread() {
if (memcmp(command_buffer, "Hg0", 3) == 0 || memcmp(command_buffer, "Hc-1", 4) == 0 ||
memcmp(command_buffer, "Hc0", 4) == 0 || memcmp(command_buffer, "Hc1", 4) == 0) {
return SendReply("OK");
int thread_id = -1;
if (command_buffer[2] != '-') {
thread_id = static_cast<int>(HexToInt(command_buffer + 2, command_length - 2));
}
if (thread_id >= 1) {
current_thread = FindThreadById(thread_id);
}
if (!current_thread) {
thread_id = 1;
current_thread = FindThreadById(thread_id);
}
if (current_thread) {
SendReply("OK");
return;
}
SendReply("E01");
}
/// Handle thread alive command from gdb client.
static void HandleThreadAlive() {
int thread_id = static_cast<int>(HexToInt(command_buffer + 1, command_length - 1));
if (thread_id == 0) {
thread_id = 1;
}
if (FindThreadById(thread_id)) {
SendReply("OK");
return;
}
SendReply("E01");
}
@@ -503,15 +660,31 @@ static void HandleSetThread() {
*
* @param signal Signal to be sent to client.
*/
static void SendSignal(u32 signal) {
static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) {
if (gdbserver_socket == -1) {
return;
}
latest_signal = signal;
std::string buffer = fmt::format("T{:02x}", latest_signal);
NGLOG_DEBUG(Debug_GDBStub, "Response: {}", buffer);
if (!thread) {
full = false;
}
std::string buffer;
if (full) {
buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};{:02x}:{:016x}", latest_signal,
PC_REGISTER, Common::swap64(RegRead(PC_REGISTER, thread)), SP_REGISTER,
Common::swap64(RegRead(SP_REGISTER, thread)), LR_REGISTER,
Common::swap64(RegRead(LR_REGISTER, thread)));
} else {
buffer = fmt::format("T{:02x}", latest_signal);
}
if (thread) {
buffer += fmt::format(";thread:{:x};", thread->GetThreadId());
}
SendReply(buffer.c_str());
}
@@ -525,18 +698,18 @@ static void ReadCommand() {
// ignore ack
return;
} else if (c == 0x03) {
NGLOG_INFO(Debug_GDBStub, "gdb: found break command");
LOG_INFO(Debug_GDBStub, "gdb: found break command");
halt_loop = true;
SendSignal(SIGTRAP);
SendSignal(current_thread, SIGTRAP);
return;
} else if (c != GDB_STUB_START) {
NGLOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte {:02X}", c);
LOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte {:02X}", c);
return;
}
while ((c = ReadByte()) != GDB_STUB_END) {
if (command_length >= sizeof(command_buffer)) {
NGLOG_ERROR(Debug_GDBStub, "gdb: command_buffer overflow");
LOG_ERROR(Debug_GDBStub, "gdb: command_buffer overflow");
SendPacket(GDB_STUB_NACK);
return;
}
@@ -549,10 +722,9 @@ static void ReadCommand() {
u8 checksum_calculated = CalculateChecksum(command_buffer, command_length);
if (checksum_received != checksum_calculated) {
NGLOG_ERROR(
Debug_GDBStub,
"gdb: invalid checksum: calculated {:02X} and read {:02X} for ${}# (length: {})",
checksum_calculated, checksum_received, command_buffer, command_length);
LOG_ERROR(Debug_GDBStub,
"gdb: invalid checksum: calculated {:02X} and read {:02X} for ${}# (length: {})",
checksum_calculated, checksum_received, command_buffer, command_length);
command_length = 0;
@@ -579,7 +751,7 @@ static bool IsDataAvailable() {
t.tv_usec = 0;
if (select(gdbserver_socket + 1, &fd_socket, nullptr, nullptr, &t) < 0) {
NGLOG_ERROR(Debug_GDBStub, "select failed");
LOG_ERROR(Debug_GDBStub, "select failed");
return false;
}
@@ -598,13 +770,17 @@ static void ReadRegister() {
}
if (id <= SP_REGISTER) {
LongToGdbHex(reply, Core::CurrentArmInterface().GetReg(static_cast<int>(id)));
LongToGdbHex(reply, RegRead(id, current_thread));
} else if (id == PC_REGISTER) {
LongToGdbHex(reply, Core::CurrentArmInterface().GetPC());
LongToGdbHex(reply, RegRead(id, current_thread));
} else if (id == CPSR_REGISTER) {
IntToGdbHex(reply, Core::CurrentArmInterface().GetCPSR());
IntToGdbHex(reply, (u32)RegRead(id, current_thread));
} else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) {
LongToGdbHex(reply, RegRead(id, current_thread));
} else if (id == FPSCR_REGISTER) {
LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_998, current_thread));
} else {
return SendReply("E01");
LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_997, current_thread));
}
SendReply(reinterpret_cast<char*>(reply));
@@ -618,16 +794,26 @@ static void ReadRegisters() {
u8* bufptr = buffer;
for (int reg = 0; reg <= SP_REGISTER; reg++) {
LongToGdbHex(bufptr + reg * 16, Core::CurrentArmInterface().GetReg(reg));
LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread));
}
bufptr += (32 * 16);
bufptr += 32 * 16;
LongToGdbHex(bufptr, Core::CurrentArmInterface().GetPC());
LongToGdbHex(bufptr, RegRead(PC_REGISTER, current_thread));
bufptr += 16;
IntToGdbHex(bufptr, Core::CurrentArmInterface().GetCPSR());
IntToGdbHex(bufptr, (u32)RegRead(CPSR_REGISTER, current_thread));
bufptr += 8;
for (int reg = UC_ARM64_REG_Q0; reg <= UC_ARM64_REG_Q0 + 31; reg++) {
LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread));
}
bufptr += 32 * 32;
LongToGdbHex(bufptr, RegRead(TODO_DUMMY_REG_998, current_thread));
bufptr += 8;
@@ -646,15 +832,22 @@ static void WriteRegister() {
}
if (id <= SP_REGISTER) {
Core::CurrentArmInterface().SetReg(id, GdbHexToLong(buffer_ptr));
RegWrite(id, GdbHexToLong(buffer_ptr), current_thread);
} else if (id == PC_REGISTER) {
Core::CurrentArmInterface().SetPC(GdbHexToLong(buffer_ptr));
RegWrite(id, GdbHexToLong(buffer_ptr), current_thread);
} else if (id == CPSR_REGISTER) {
Core::CurrentArmInterface().SetCPSR(GdbHexToInt(buffer_ptr));
RegWrite(id, GdbHexToInt(buffer_ptr), current_thread);
} else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) {
RegWrite(id, GdbHexToLong(buffer_ptr), current_thread);
} else if (id == FPSCR_REGISTER) {
RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr), current_thread);
} else {
return SendReply("E01");
RegWrite(TODO_DUMMY_REG_997, GdbHexToLong(buffer_ptr), current_thread);
}
// Update Unicorn context skipping scheduler, no running threads at this point
Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context);
SendReply("OK");
}
@@ -665,18 +858,25 @@ static void WriteRegisters() {
if (command_buffer[0] != 'G')
return SendReply("E01");
for (int i = 0, reg = 0; reg <= CPSR_REGISTER; i++, reg++) {
for (int i = 0, reg = 0; reg <= FPSCR_REGISTER; i++, reg++) {
if (reg <= SP_REGISTER) {
Core::CurrentArmInterface().SetReg(reg, GdbHexToLong(buffer_ptr + i * 16));
RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread);
} else if (reg == PC_REGISTER) {
Core::CurrentArmInterface().SetPC(GdbHexToLong(buffer_ptr + i * 16));
RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread);
} else if (reg == CPSR_REGISTER) {
Core::CurrentArmInterface().SetCPSR(GdbHexToInt(buffer_ptr + i * 16));
RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread);
} else if (reg >= UC_ARM64_REG_Q0 && reg < FPSCR_REGISTER) {
RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread);
} else if (reg == FPSCR_REGISTER) {
RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr + i * 16), current_thread);
} else {
UNIMPLEMENTED();
}
}
// Update Unicorn context skipping scheduler, no running threads at this point
Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context);
SendReply("OK");
}
@@ -692,12 +892,16 @@ static void ReadMemory() {
u64 len =
HexToLong(start_offset, static_cast<u64>((command_buffer + command_length) - start_offset));
NGLOG_DEBUG(Debug_GDBStub, "gdb: addr: {:016X} len: {:016X}", addr, len);
LOG_DEBUG(Debug_GDBStub, "gdb: addr: {:016X} len: {:016X}", addr, len);
if (len * 2 > sizeof(reply)) {
SendReply("E01");
}
if (addr < Memory::PROCESS_IMAGE_VADDR || addr >= Memory::MAP_REGION_VADDR_END) {
return SendReply("E00");
}
if (!Memory::IsValidVirtualAddress(addr)) {
return SendReply("E00");
}
@@ -732,22 +936,24 @@ static void WriteMemory() {
}
void Break(bool is_memory_break) {
if (!halt_loop) {
halt_loop = true;
SendSignal(SIGTRAP);
}
send_trap = true;
memory_break = is_memory_break;
}
/// Tell the CPU that it should perform a single step.
static void Step() {
if (command_length > 1) {
RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread);
// Update Unicorn context skipping scheduler, no running threads at this point
Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context);
}
step_loop = true;
halt_loop = true;
step_break = true;
SendSignal(SIGTRAP);
send_trap = true;
}
/// Tell the CPU if we hit a memory breakpoint.
bool IsMemoryBreak() {
if (IsConnected()) {
return false;
@@ -759,7 +965,6 @@ bool IsMemoryBreak() {
/// Tell the CPU to continue executing.
static void Continue() {
memory_break = false;
step_break = false;
step_loop = false;
halt_loop = false;
}
@@ -780,8 +985,8 @@ static bool CommitBreakpoint(BreakpointType type, PAddr addr, u64 len) {
breakpoint.len = len;
p.insert({addr, breakpoint});
NGLOG_DEBUG(Debug_GDBStub, "gdb: added {} breakpoint: {:016X} bytes at {:016X}",
static_cast<int>(type), breakpoint.len, breakpoint.addr);
LOG_DEBUG(Debug_GDBStub, "gdb: added {} breakpoint: {:016X} bytes at {:016X}",
static_cast<int>(type), breakpoint.len, breakpoint.addr);
return true;
}
@@ -888,7 +1093,7 @@ void HandlePacket() {
return;
}
NGLOG_DEBUG(Debug_GDBStub, "Packet: {}", command_buffer);
LOG_DEBUG(Debug_GDBStub, "Packet: {}", command_buffer);
switch (command_buffer[0]) {
case 'q':
@@ -898,11 +1103,11 @@ void HandlePacket() {
HandleSetThread();
break;
case '?':
SendSignal(latest_signal);
SendSignal(current_thread, latest_signal);
break;
case 'k':
Shutdown();
NGLOG_INFO(Debug_GDBStub, "killed by gdb");
LOG_INFO(Debug_GDBStub, "killed by gdb");
return;
case 'g':
ReadRegisters();
@@ -935,6 +1140,9 @@ void HandlePacket() {
case 'Z':
AddBreakpoint();
break;
case 'T':
HandleThreadAlive();
break;
default:
SendReply("");
break;
@@ -980,8 +1188,10 @@ static void Init(u16 port) {
breakpoints_read.clear();
breakpoints_write.clear();
modules.clear();
// Start gdb server
NGLOG_INFO(Debug_GDBStub, "Starting GDB server on port {}...", port);
LOG_INFO(Debug_GDBStub, "Starting GDB server on port {}...", port);
sockaddr_in saddr_server = {};
saddr_server.sin_family = AF_INET;
@@ -994,28 +1204,28 @@ static void Init(u16 port) {
int tmpsock = static_cast<int>(socket(PF_INET, SOCK_STREAM, 0));
if (tmpsock == -1) {
NGLOG_ERROR(Debug_GDBStub, "Failed to create gdb socket");
LOG_ERROR(Debug_GDBStub, "Failed to create gdb socket");
}
// Set socket to SO_REUSEADDR so it can always bind on the same port
int reuse_enabled = 1;
if (setsockopt(tmpsock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse_enabled,
sizeof(reuse_enabled)) < 0) {
NGLOG_ERROR(Debug_GDBStub, "Failed to set gdb socket option");
LOG_ERROR(Debug_GDBStub, "Failed to set gdb socket option");
}
const sockaddr* server_addr = reinterpret_cast<const sockaddr*>(&saddr_server);
socklen_t server_addrlen = sizeof(saddr_server);
if (bind(tmpsock, server_addr, server_addrlen) < 0) {
NGLOG_ERROR(Debug_GDBStub, "Failed to bind gdb socket");
LOG_ERROR(Debug_GDBStub, "Failed to bind gdb socket");
}
if (listen(tmpsock, 1) < 0) {
NGLOG_ERROR(Debug_GDBStub, "Failed to listen to gdb socket");
LOG_ERROR(Debug_GDBStub, "Failed to listen to gdb socket");
}
// Wait for gdb to connect
NGLOG_INFO(Debug_GDBStub, "Waiting for gdb to connect...");
LOG_INFO(Debug_GDBStub, "Waiting for gdb to connect...");
sockaddr_in saddr_client;
sockaddr* client_addr = reinterpret_cast<sockaddr*>(&saddr_client);
socklen_t client_addrlen = sizeof(saddr_client);
@@ -1026,9 +1236,9 @@ static void Init(u16 port) {
halt_loop = false;
step_loop = false;
NGLOG_ERROR(Debug_GDBStub, "Failed to accept gdb client");
LOG_ERROR(Debug_GDBStub, "Failed to accept gdb client");
} else {
NGLOG_INFO(Debug_GDBStub, "Client connected.");
LOG_INFO(Debug_GDBStub, "Client connected.");
saddr_client.sin_addr.s_addr = ntohl(saddr_client.sin_addr.s_addr);
}
@@ -1047,7 +1257,7 @@ void Shutdown() {
return;
}
NGLOG_INFO(Debug_GDBStub, "Stopping GDB ...");
LOG_INFO(Debug_GDBStub, "Stopping GDB ...");
if (gdbserver_socket != -1) {
shutdown(gdbserver_socket, SHUT_RDWR);
gdbserver_socket = -1;
@@ -1057,7 +1267,7 @@ void Shutdown() {
WSACleanup();
#endif
NGLOG_INFO(Debug_GDBStub, "GDB stopped.");
LOG_INFO(Debug_GDBStub, "GDB stopped.");
}
bool IsServerEnabled() {
@@ -1079,4 +1289,15 @@ bool GetCpuStepFlag() {
void SetCpuStepFlag(bool is_step) {
step_loop = is_step;
}
void SendTrap(Kernel::Thread* thread, int trap) {
if (send_trap) {
if (!halt_loop || current_thread == thread) {
current_thread = thread;
SendSignal(thread, trap);
}
halt_loop = true;
send_trap = false;
}
}
}; // namespace GDBStub

View File

@@ -6,7 +6,9 @@
#pragma once
#include <string>
#include "common/common_types.h"
#include "core/hle/kernel/thread.h"
namespace GDBStub {
@@ -50,6 +52,9 @@ bool IsServerEnabled();
/// Returns true if there is an active socket connection.
bool IsConnected();
/// Register module.
void RegisterModule(std::string name, PAddr beg, PAddr end, bool add_elf_ext = true);
/**
* Signal to the gdbstub server that it should halt CPU execution.
*
@@ -79,10 +84,10 @@ BreakpointAddress GetNextBreakpointFromAddress(PAddr addr, GDBStub::BreakpointTy
*/
bool CheckBreakpoint(PAddr addr, GDBStub::BreakpointType type);
// If set to true, the CPU will halt at the beginning of the next CPU loop.
/// If set to true, the CPU will halt at the beginning of the next CPU loop.
bool GetCpuHaltFlag();
// If set to true and the CPU is halted, the CPU will step one instruction.
/// If set to true and the CPU is halted, the CPU will step one instruction.
bool GetCpuStepFlag();
/**
@@ -91,4 +96,12 @@ bool GetCpuStepFlag();
* @param is_step
*/
void SetCpuStepFlag(bool is_step);
/**
* Send trap signal from thread back to the gdbstub server.
*
* @param thread Sending thread.
* @param trap Trap no.
*/
void SendTrap(Kernel::Thread* thread, int trap);
} // namespace GDBStub

View File

@@ -0,0 +1,175 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/assert.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/core.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/lock.h"
#include "core/memory.h"
namespace Kernel {
namespace AddressArbiter {
// Performs actual address waiting logic.
static ResultCode WaitForAddress(VAddr address, s64 timeout) {
SharedPtr<Thread> current_thread = GetCurrentThread();
current_thread->arb_wait_address = address;
current_thread->status = THREADSTATUS_WAIT_ARB;
current_thread->wakeup_callback = nullptr;
current_thread->WakeAfterDelay(timeout);
Core::System::GetInstance().CpuCore(current_thread->processor_id).PrepareReschedule();
return RESULT_TIMEOUT;
}
// Gets the threads waiting on an address.
static void GetThreadsWaitingOnAddress(std::vector<SharedPtr<Thread>>& waiting_threads,
VAddr address) {
auto RetrieveWaitingThreads =
[](size_t core_index, std::vector<SharedPtr<Thread>>& waiting_threads, VAddr arb_addr) {
const auto& scheduler = Core::System::GetInstance().Scheduler(core_index);
auto& thread_list = scheduler->GetThreadList();
for (auto& thread : thread_list) {
if (thread->arb_wait_address == arb_addr)
waiting_threads.push_back(thread);
}
};
// Retrieve a list of all threads that are waiting for this address.
RetrieveWaitingThreads(0, waiting_threads, address);
RetrieveWaitingThreads(1, waiting_threads, address);
RetrieveWaitingThreads(2, waiting_threads, address);
RetrieveWaitingThreads(3, waiting_threads, address);
// Sort them by priority, such that the highest priority ones come first.
std::sort(waiting_threads.begin(), waiting_threads.end(),
[](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) {
return lhs->current_priority < rhs->current_priority;
});
}
// Wake up num_to_wake (or all) threads in a vector.
static void WakeThreads(std::vector<SharedPtr<Thread>>& waiting_threads, s32 num_to_wake) {
// Only process up to 'target' threads, unless 'target' is <= 0, in which case process
// them all.
size_t last = waiting_threads.size();
if (num_to_wake > 0)
last = num_to_wake;
// Signal the waiting threads.
for (size_t i = 0; i < last; i++) {
ASSERT(waiting_threads[i]->status = THREADSTATUS_WAIT_ARB);
waiting_threads[i]->SetWaitSynchronizationResult(RESULT_SUCCESS);
waiting_threads[i]->arb_wait_address = 0;
waiting_threads[i]->ResumeFromWait();
}
}
// Signals an address being waited on.
ResultCode SignalToAddress(VAddr address, s32 num_to_wake) {
// Get threads waiting on the address.
std::vector<SharedPtr<Thread>> waiting_threads;
GetThreadsWaitingOnAddress(waiting_threads, address);
WakeThreads(waiting_threads, num_to_wake);
return RESULT_SUCCESS;
}
// Signals an address being waited on and increments its value if equal to the value argument.
ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) {
// Ensure that we can write to the address.
if (!Memory::IsValidVirtualAddress(address)) {
return ERR_INVALID_ADDRESS_STATE;
}
if (static_cast<s32>(Memory::Read32(address)) == value) {
Memory::Write32(address, static_cast<u32>(value + 1));
} else {
return ERR_INVALID_STATE;
}
return SignalToAddress(address, num_to_wake);
}
// Signals an address being waited on and modifies its value based on waiting thread count if equal
// to the value argument.
ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value,
s32 num_to_wake) {
// Ensure that we can write to the address.
if (!Memory::IsValidVirtualAddress(address)) {
return ERR_INVALID_ADDRESS_STATE;
}
// Get threads waiting on the address.
std::vector<SharedPtr<Thread>> waiting_threads;
GetThreadsWaitingOnAddress(waiting_threads, address);
// Determine the modified value depending on the waiting count.
s32 updated_value;
if (waiting_threads.size() == 0) {
updated_value = value - 1;
} else if (num_to_wake <= 0 || waiting_threads.size() <= static_cast<u32>(num_to_wake)) {
updated_value = value + 1;
} else {
updated_value = value;
}
if (static_cast<s32>(Memory::Read32(address)) == value) {
Memory::Write32(address, static_cast<u32>(updated_value));
} else {
return ERR_INVALID_STATE;
}
WakeThreads(waiting_threads, num_to_wake);
return RESULT_SUCCESS;
}
// Waits on an address if the value passed is less than the argument value, optionally decrementing.
ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement) {
// Ensure that we can read the address.
if (!Memory::IsValidVirtualAddress(address)) {
return ERR_INVALID_ADDRESS_STATE;
}
s32 cur_value = static_cast<s32>(Memory::Read32(address));
if (cur_value < value) {
if (should_decrement) {
Memory::Write32(address, static_cast<u32>(cur_value - 1));
}
} else {
return ERR_INVALID_STATE;
}
// Short-circuit without rescheduling, if timeout is zero.
if (timeout == 0) {
return RESULT_TIMEOUT;
}
return WaitForAddress(address, timeout);
}
// Waits on an address if the value passed is equal to the argument value.
ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) {
// Ensure that we can read the address.
if (!Memory::IsValidVirtualAddress(address)) {
return ERR_INVALID_ADDRESS_STATE;
}
// Only wait for the address if equal.
if (static_cast<s32>(Memory::Read32(address)) != value) {
return ERR_INVALID_STATE;
}
// Short-circuit without rescheduling, if timeout is zero.
if (timeout == 0) {
return RESULT_TIMEOUT;
}
return WaitForAddress(address, timeout);
}
} // namespace AddressArbiter
} // namespace Kernel

View File

@@ -0,0 +1,32 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/hle/result.h"
namespace Kernel {
namespace AddressArbiter {
enum class ArbitrationType {
WaitIfLessThan = 0,
DecrementAndWaitIfLessThan = 1,
WaitIfEqual = 2,
};
enum class SignalType {
Signal = 0,
IncrementAndSignalIfEqual = 1,
ModifyByWaitingCountAndSignalIfEqual = 2,
};
ResultCode SignalToAddress(VAddr address, s32 num_to_wake);
ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake);
ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake);
ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement);
ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout);
} // namespace AddressArbiter
} // namespace Kernel

View File

@@ -20,13 +20,16 @@ enum {
MaxConnectionsReached = 52,
// Confirmed Switch OS error codes
MisalignedAddress = 102,
InvalidAddress = 102,
InvalidMemoryState = 106,
InvalidProcessorId = 113,
InvalidHandle = 114,
InvalidCombination = 116,
Timeout = 117,
SynchronizationCanceled = 118,
TooLarge = 119,
InvalidEnumValue = 120,
InvalidState = 125,
};
}
@@ -39,14 +42,15 @@ constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE(-1);
constexpr ResultCode ERR_PORT_NAME_TOO_LONG(-1);
constexpr ResultCode ERR_WRONG_PERMISSION(-1);
constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(-1);
constexpr ResultCode ERR_INVALID_ENUM_VALUE(-1);
constexpr ResultCode ERR_INVALID_ENUM_VALUE(ErrorModule::Kernel, ErrCodes::InvalidEnumValue);
constexpr ResultCode ERR_INVALID_ENUM_VALUE_FND(-1);
constexpr ResultCode ERR_INVALID_COMBINATION(-1);
constexpr ResultCode ERR_INVALID_COMBINATION_KERNEL(-1);
constexpr ResultCode ERR_OUT_OF_MEMORY(-1);
constexpr ResultCode ERR_INVALID_ADDRESS(-1);
constexpr ResultCode ERR_INVALID_ADDRESS_STATE(-1);
constexpr ResultCode ERR_INVALID_ADDRESS(ErrorModule::Kernel, ErrCodes::InvalidAddress);
constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::InvalidMemoryState);
constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle);
constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState);
constexpr ResultCode ERR_INVALID_POINTER(-1);
constexpr ResultCode ERR_INVALID_OBJECT_ADDR(-1);
constexpr ResultCode ERR_NOT_AUTHORIZED(-1);

View File

@@ -26,7 +26,7 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
u16 slot = next_free_slot;
if (slot >= generations.size()) {
NGLOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use.");
LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use.");
return ERR_OUT_OF_HANDLES;
}
next_free_slot = generations[slot];
@@ -48,7 +48,7 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
SharedPtr<Object> object = GetGeneric(handle);
if (object == nullptr) {
NGLOG_ERROR(Kernel, "Tried to duplicate invalid handle: {:08X}", handle);
LOG_ERROR(Kernel, "Tried to duplicate invalid handle: {:08X}", handle);
return ERR_INVALID_HANDLE;
}
return Create(std::move(object));

View File

@@ -29,7 +29,8 @@ void SessionRequestHandler::ClientDisconnected(SharedPtr<ServerSession> server_s
SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
const std::string& reason, u64 timeout,
WakeupCallback&& callback) {
WakeupCallback&& callback,
Kernel::SharedPtr<Kernel::Event> event) {
// Put the client thread to sleep until the wait event is signaled or the timeout expires.
thread->wakeup_callback =
@@ -41,7 +42,12 @@ SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
return true;
};
auto event = Kernel::Event::Create(Kernel::ResetType::OneShot, "HLE Pause Event: " + reason);
if (!event) {
// Create event if not provided
event = Kernel::Event::Create(Kernel::ResetType::OneShot, "HLE Pause Event: " + reason);
}
event->Clear();
thread->status = THREADSTATUS_WAIT_HLE_EVENT;
thread->wait_objects = {event};
event->AddWaitingThread(thread);
@@ -120,7 +126,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
std::make_shared<IPC::DomainMessageHeader>(rp.PopRaw<IPC::DomainMessageHeader>());
} else {
if (Session()->IsDomain())
NGLOG_WARNING(IPC, "Domain request has no DomainMessageHeader!");
LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!");
}
}
@@ -214,8 +220,8 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) {
(sizeof(IPC::CommandHeader) + sizeof(IPC::HandleDescriptorHeader)) / sizeof(u32);
ASSERT_MSG(!handle_descriptor_header->send_current_pid, "Sending PID is not implemented");
ASSERT_MSG(copy_objects.size() == handle_descriptor_header->num_handles_to_copy);
ASSERT_MSG(move_objects.size() == handle_descriptor_header->num_handles_to_move);
ASSERT(copy_objects.size() == handle_descriptor_header->num_handles_to_copy);
ASSERT(move_objects.size() == handle_descriptor_header->num_handles_to_move);
// We don't make a distinction between copy and move handles when translating since HLE
// services don't deal with handles directly. However, the guest applications might check
@@ -271,11 +277,16 @@ std::vector<u8> HLERequestContext::ReadBuffer(int buffer_index) const {
}
size_t HLERequestContext::WriteBuffer(const void* buffer, size_t size, int buffer_index) const {
if (size == 0) {
LOG_WARNING(Core, "skip empty buffer write");
return 0;
}
const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[buffer_index].Size()};
const size_t buffer_size{GetWriteBufferSize(buffer_index)};
if (size > buffer_size) {
NGLOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size,
buffer_size);
LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size,
buffer_size);
size = buffer_size; // TODO(bunnei): This needs to be HW tested
}

View File

@@ -118,10 +118,12 @@ public:
* @param callback Callback to be invoked when the thread is resumed. This callback must write
* the entire command response once again, regardless of the state of it before this function
* was called.
* @param event Event to use to wake up the thread. If unspecified, an event will be created.
* @returns Event that when signaled will resume the thread and call the callback function.
*/
SharedPtr<Event> SleepClientThread(SharedPtr<Thread> thread, const std::string& reason,
u64 timeout, WakeupCallback&& callback);
u64 timeout, WakeupCallback&& callback,
Kernel::SharedPtr<Kernel::Event> event = nullptr);
void ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming);

View File

@@ -59,7 +59,7 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle,
Handle requesting_thread_handle) {
// The mutex address must be 4-byte aligned
if ((address % sizeof(u32)) != 0) {
return ResultCode(ErrorModule::Kernel, ErrCodes::MisalignedAddress);
return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress);
}
SharedPtr<Thread> holding_thread = g_handle_table.Get<Thread>(holding_thread_handle);
@@ -97,7 +97,7 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle,
ResultCode Mutex::Release(VAddr address) {
// The mutex address must be 4-byte aligned
if ((address % sizeof(u32)) != 0) {
return ResultCode(ErrorModule::Kernel, ErrCodes::MisalignedAddress);
return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress);
}
auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(GetCurrentThread(), address);

View File

@@ -54,7 +54,7 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
continue;
} else if ((type & 0xF00) == 0xE00) { // 0x0FFF
// Allowed interrupts list
NGLOG_WARNING(Loader, "ExHeader allowed interrupts list ignored");
LOG_WARNING(Loader, "ExHeader allowed interrupts list ignored");
} else if ((type & 0xF80) == 0xF00) { // 0x07FF
// Allowed syscalls mask
unsigned int index = ((descriptor >> 24) & 7) * 24;
@@ -74,7 +74,7 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
} else if ((type & 0xFFE) == 0xFF8) { // 0x001F
// Mapped memory range
if (i + 1 >= len || ((kernel_caps[i + 1] >> 20) & 0xFFE) != 0xFF8) {
NGLOG_WARNING(Loader, "Incomplete exheader memory range descriptor ignored.");
LOG_WARNING(Loader, "Incomplete exheader memory range descriptor ignored.");
continue;
}
u32 end_desc = kernel_caps[i + 1];
@@ -109,9 +109,9 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
int minor = kernel_version & 0xFF;
int major = (kernel_version >> 8) & 0xFF;
NGLOG_INFO(Loader, "ExHeader kernel version: {}.{}", major, minor);
LOG_INFO(Loader, "ExHeader kernel version: {}.{}", major, minor);
} else {
NGLOG_ERROR(Loader, "Unhandled kernel caps descriptor: 0x{:08X}", descriptor);
LOG_ERROR(Loader, "Unhandled kernel caps descriptor: 0x{:08X}", descriptor);
}
}
}

View File

@@ -29,7 +29,7 @@ SharedPtr<ResourceLimit> ResourceLimit::GetForCategory(ResourceLimitCategory cat
case ResourceLimitCategory::OTHER:
return resource_limits[static_cast<u8>(category)];
default:
NGLOG_CRITICAL(Kernel, "Unknown resource limit category");
LOG_CRITICAL(Kernel, "Unknown resource limit category");
UNREACHABLE();
}
}
@@ -55,7 +55,7 @@ s32 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const {
case ResourceType::CPUTime:
return current_cpu_time;
default:
NGLOG_ERROR(Kernel, "Unknown resource type={:08X}", static_cast<u32>(resource));
LOG_ERROR(Kernel, "Unknown resource type={:08X}", static_cast<u32>(resource));
UNIMPLEMENTED();
return 0;
}
@@ -84,7 +84,7 @@ u32 ResourceLimit::GetMaxResourceValue(ResourceType resource) const {
case ResourceType::CPUTime:
return max_cpu_time;
default:
NGLOG_ERROR(Kernel, "Unknown resource type={:08X}", static_cast<u32>(resource));
LOG_ERROR(Kernel, "Unknown resource type={:08X}", static_cast<u32>(resource));
UNIMPLEMENTED();
return 0;
}

View File

@@ -85,6 +85,7 @@ void Scheduler::SwitchContext(Thread* new_thread) {
cpu_core->LoadContext(new_thread->context);
cpu_core->SetTlsAddress(new_thread->GetTLSAddress());
cpu_core->ClearExclusiveState();
} else {
current_thread = nullptr;
// Note: We do not reset the current process and current page table when idling because
@@ -99,11 +100,11 @@ void Scheduler::Reschedule() {
Thread* next = PopNextReadyThread();
if (cur && next) {
NGLOG_TRACE(Kernel, "context switch {} -> {}", cur->GetObjectId(), next->GetObjectId());
LOG_TRACE(Kernel, "context switch {} -> {}", cur->GetObjectId(), next->GetObjectId());
} else if (cur) {
NGLOG_TRACE(Kernel, "context switch {} -> idle", cur->GetObjectId());
LOG_TRACE(Kernel, "context switch {} -> idle", cur->GetObjectId());
} else if (next) {
NGLOG_TRACE(Kernel, "context switch idle -> {}", next->GetObjectId());
LOG_TRACE(Kernel, "context switch idle -> {}", next->GetObjectId());
}
SwitchContext(next);

View File

@@ -71,7 +71,7 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con
return domain_request_handlers[object_id - 1]->HandleSyncRequest(context);
case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
NGLOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id);
LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id);
domain_request_handlers[object_id - 1] = nullptr;
@@ -81,8 +81,8 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con
}
}
NGLOG_CRITICAL(IPC, "Unknown domain command={}",
static_cast<int>(domain_message_header->command.Value()));
LOG_CRITICAL(IPC, "Unknown domain command={}",
static_cast<int>(domain_message_header->command.Value()));
ASSERT(false);
}

View File

@@ -107,16 +107,16 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
// Error out if the requested permissions don't match what the creator process allows.
if (static_cast<u32>(permissions) & ~static_cast<u32>(own_other_permissions)) {
NGLOG_ERROR(Kernel, "cannot map id={}, address=0x{:X} name={}, permissions don't match",
GetObjectId(), address, name);
LOG_ERROR(Kernel, "cannot map id={}, address=0x{:X} name={}, permissions don't match",
GetObjectId(), address, name);
return ERR_INVALID_COMBINATION;
}
// Error out if the provided permissions are not compatible with what the creator process needs.
if (other_permissions != MemoryPermission::DontCare &&
static_cast<u32>(this->permissions) & ~static_cast<u32>(other_permissions)) {
NGLOG_ERROR(Kernel, "cannot map id={}, address=0x{:X} name={}, permissions don't match",
GetObjectId(), address, name);
LOG_ERROR(Kernel, "cannot map id={}, address=0x{:X} name={}, permissions don't match",
GetObjectId(), address, name);
return ERR_WRONG_PERMISSION;
}
@@ -131,7 +131,7 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
auto result = target_process->vm_manager.MapMemoryBlock(
target_address, backing_block, backing_block_offset, size, MemoryState::Shared);
if (result.Failed()) {
NGLOG_ERROR(
LOG_ERROR(
Kernel,
"cannot map id={}, target_address=0x{:X} name={}, error mapping to virtual memory",
GetObjectId(), target_address, name);

View File

@@ -11,6 +11,7 @@
#include "common/string_util.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/kernel/address_arbiter.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/event.h"
@@ -31,7 +32,7 @@ namespace Kernel {
/// Set the process heap to a given Size. It can both extend and shrink the heap.
static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
NGLOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size);
LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size);
auto& process = *Core::CurrentProcess();
CASCADE_RESULT(*heap_addr,
process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite));
@@ -39,21 +40,21 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
}
static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state1) {
NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, addr=0x{:X}", addr);
LOG_WARNING(Kernel_SVC, "(STUBBED) called, addr=0x{:X}", addr);
return RESULT_SUCCESS;
}
/// Maps a memory range into a different range.
static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
NGLOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
src_addr, size);
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
src_addr, size);
return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size);
}
/// Unmaps a region that was previously mapped with svcMapMemory
static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
NGLOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
src_addr, size);
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
src_addr, size);
return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size);
}
@@ -68,11 +69,11 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address
if (port_name.size() > PortNameMaxLength)
return ERR_PORT_NAME_TOO_LONG;
NGLOG_TRACE(Kernel_SVC, "called port_name={}", port_name);
LOG_TRACE(Kernel_SVC, "called port_name={}", port_name);
auto it = Service::g_kernel_named_ports.find(port_name);
if (it == Service::g_kernel_named_ports.end()) {
NGLOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name);
LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name);
return ERR_NOT_FOUND;
}
@@ -90,11 +91,11 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address
static ResultCode SendSyncRequest(Handle handle) {
SharedPtr<ClientSession> session = g_handle_table.Get<ClientSession>(handle);
if (!session) {
NGLOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle);
LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle);
return ERR_INVALID_HANDLE;
}
NGLOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
Core::System::GetInstance().PrepareReschedule();
@@ -105,7 +106,7 @@ static ResultCode SendSyncRequest(Handle handle) {
/// Get the ID for the specified thread.
static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) {
NGLOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
if (!thread) {
@@ -118,7 +119,7 @@ static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) {
/// Get the ID of the specified process
static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
NGLOG_TRACE(Kernel_SVC, "called process=0x{:08X}", process_handle);
LOG_TRACE(Kernel_SVC, "called process=0x{:08X}", process_handle);
const SharedPtr<Process> process = g_handle_table.Get<Process>(process_handle);
if (!process) {
@@ -148,8 +149,8 @@ static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thr
/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 handle_count,
s64 nano_seconds) {
NGLOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}",
handles_address, handle_count, nano_seconds);
LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}",
handles_address, handle_count, nano_seconds);
if (!Memory::IsValidVirtualAddress(handles_address))
return ERR_INVALID_POINTER;
@@ -209,7 +210,7 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
/// Resumes a thread waiting on WaitSynchronization
static ResultCode CancelSynchronization(Handle thread_handle) {
NGLOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle);
LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle);
const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
if (!thread) {
@@ -226,24 +227,24 @@ static ResultCode CancelSynchronization(Handle thread_handle) {
/// Attempts to locks a mutex, creating it if it does not already exist
static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr,
Handle requesting_thread_handle) {
NGLOG_TRACE(Kernel_SVC,
"called holding_thread_handle=0x{:08X}, mutex_addr=0x{:X}, "
"requesting_current_thread_handle=0x{:08X}",
holding_thread_handle, mutex_addr, requesting_thread_handle);
LOG_TRACE(Kernel_SVC,
"called holding_thread_handle=0x{:08X}, mutex_addr=0x{:X}, "
"requesting_current_thread_handle=0x{:08X}",
holding_thread_handle, mutex_addr, requesting_thread_handle);
return Mutex::TryAcquire(mutex_addr, holding_thread_handle, requesting_thread_handle);
}
/// Unlock a mutex
static ResultCode ArbitrateUnlock(VAddr mutex_addr) {
NGLOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr);
LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr);
return Mutex::Release(mutex_addr);
}
/// Break program execution
static void Break(u64 unk_0, u64 unk_1, u64 unk_2) {
NGLOG_CRITICAL(Debug_Emulated, "Emulated program broke execution!");
LOG_CRITICAL(Debug_Emulated, "Emulated program broke execution!");
ASSERT(false);
}
@@ -251,13 +252,13 @@ static void Break(u64 unk_0, u64 unk_1, u64 unk_2) {
static void OutputDebugString(VAddr address, s32 len) {
std::string str(len, '\0');
Memory::ReadBlock(address, str.data(), str.size());
NGLOG_DEBUG(Debug_Emulated, "{}", str);
LOG_DEBUG(Debug_Emulated, "{}", str);
}
/// Gets system/memory information for the current process
static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) {
NGLOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id,
info_sub_id, handle);
LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id,
info_sub_id, handle);
auto& vm_manager = Core::CurrentProcess()->vm_manager;
@@ -308,12 +309,17 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
*result = Core::CurrentProcess()->is_virtual_address_memory_enabled;
break;
case GetInfoType::TitleId:
NGLOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query titleid, returned 0");
LOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query titleid, returned 0");
*result = 0;
break;
case GetInfoType::PrivilegedProcessId:
NGLOG_WARNING(Kernel_SVC,
"(STUBBED) Attempted to query privileged process id bounds, returned 0");
LOG_WARNING(Kernel_SVC,
"(STUBBED) Attempted to query privileged process id bounds, returned 0");
*result = 0;
break;
case GetInfoType::UserExceptionContextAddr:
LOG_WARNING(Kernel_SVC,
"(STUBBED) Attempted to query user exception context address, returned 0");
*result = 0;
break;
default:
@@ -325,14 +331,13 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
/// Sets the thread activity
static ResultCode SetThreadActivity(Handle handle, u32 unknown) {
NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, unknown=0x{:08X}", handle,
unknown);
LOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, unknown=0x{:08X}", handle, unknown);
return RESULT_SUCCESS;
}
/// Gets the thread context
static ResultCode GetThreadContext(Handle handle, VAddr addr) {
NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, addr=0x{:X}", handle, addr);
LOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, addr=0x{:X}", handle, addr);
return RESULT_SUCCESS;
}
@@ -371,16 +376,15 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) {
/// Get which CPU core is executing the current thread
static u32 GetCurrentProcessorNumber() {
NGLOG_TRACE(Kernel_SVC, "called");
LOG_TRACE(Kernel_SVC, "called");
return GetCurrentThread()->processor_id;
}
static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size,
u32 permissions) {
NGLOG_TRACE(
Kernel_SVC,
"called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
shared_memory_handle, addr, size, permissions);
LOG_TRACE(Kernel_SVC,
"called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
shared_memory_handle, addr, size, permissions);
SharedPtr<SharedMemory> shared_memory = g_handle_table.Get<SharedMemory>(shared_memory_handle);
if (!shared_memory) {
@@ -400,15 +404,15 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s
return shared_memory->Map(Core::CurrentProcess().get(), addr, permissions_type,
MemoryPermission::DontCare);
default:
NGLOG_ERROR(Kernel_SVC, "unknown permissions=0x{:08X}", permissions);
LOG_ERROR(Kernel_SVC, "unknown permissions=0x{:08X}", permissions);
}
return RESULT_SUCCESS;
}
static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) {
NGLOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}",
shared_memory_handle, addr, size);
LOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}",
shared_memory_handle, addr, size);
SharedPtr<SharedMemory> shared_memory = g_handle_table.Get<SharedMemory>(shared_memory_handle);
@@ -436,19 +440,19 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_i
memory_info->type = static_cast<u32>(vma->second.meminfo_state);
}
NGLOG_TRACE(Kernel_SVC, "called process=0x{:08X} addr={:X}", process_handle, addr);
LOG_TRACE(Kernel_SVC, "called process=0x{:08X} addr={:X}", process_handle, addr);
return RESULT_SUCCESS;
}
/// Query memory
static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, VAddr addr) {
NGLOG_TRACE(Kernel_SVC, "called, addr={:X}", addr);
LOG_TRACE(Kernel_SVC, "called, addr={:X}", addr);
return QueryProcessMemory(memory_info, page_info, CurrentProcess, addr);
}
/// Exits the current process
static void ExitProcess() {
NGLOG_INFO(Kernel_SVC, "Process {} exiting", Core::CurrentProcess()->process_id);
LOG_INFO(Kernel_SVC, "Process {} exiting", Core::CurrentProcess()->process_id);
ASSERT_MSG(Core::CurrentProcess()->status == ProcessStatus::Running,
"Process has already exited");
@@ -524,17 +528,17 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
Core::System::GetInstance().PrepareReschedule();
Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule();
NGLOG_TRACE(Kernel_SVC,
"called entrypoint=0x{:08X} ({}), arg=0x{:08X}, stacktop=0x{:08X}, "
"threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}",
entry_point, name, arg, stack_top, priority, processor_id, *out_handle);
LOG_TRACE(Kernel_SVC,
"called entrypoint=0x{:08X} ({}), arg=0x{:08X}, stacktop=0x{:08X}, "
"threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}",
entry_point, name, arg, stack_top, priority, processor_id, *out_handle);
return RESULT_SUCCESS;
}
/// Starts the thread for the provided handle
static ResultCode StartThread(Handle thread_handle) {
NGLOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
if (!thread) {
@@ -551,7 +555,7 @@ static ResultCode StartThread(Handle thread_handle) {
/// Called when a thread exits
static void ExitThread() {
NGLOG_TRACE(Kernel_SVC, "called, pc=0x{:08X}", Core::CurrentArmInterface().GetPC());
LOG_TRACE(Kernel_SVC, "called, pc=0x{:08X}", Core::CurrentArmInterface().GetPC());
ExitCurrentThread();
Core::System::GetInstance().PrepareReschedule();
@@ -559,7 +563,7 @@ static void ExitThread() {
/// Sleep the current thread
static void SleepThread(s64 nanoseconds) {
NGLOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds);
LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds);
// Don't attempt to yield execution if there are no available threads to run,
// this way we avoid a useless reschedule to the idle thread.
@@ -575,10 +579,10 @@ static void SleepThread(s64 nanoseconds) {
Core::System::GetInstance().PrepareReschedule();
}
/// Signal process wide key atomic
/// Wait process wide key atomic
static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_variable_addr,
Handle thread_handle, s64 nano_seconds) {
NGLOG_TRACE(
LOG_TRACE(
Kernel_SVC,
"called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle=0x{:08X}, timeout={}",
mutex_addr, condition_variable_addr, thread_handle, nano_seconds);
@@ -605,8 +609,8 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var
/// Signal process wide key
static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target) {
NGLOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x{:X}, target=0x{:08X}",
condition_variable_addr, target);
LOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x{:X}, target=0x{:08X}",
condition_variable_addr, target);
auto RetrieveWaitingThreads =
[](size_t core_index, std::vector<SharedPtr<Thread>>& waiting_threads, VAddr condvar_addr) {
@@ -684,6 +688,57 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
return RESULT_SUCCESS;
}
// Wait for an address (via Address Arbiter)
static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout) {
LOG_WARNING(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, timeout={}",
address, type, value, timeout);
// If the passed address is a kernel virtual address, return invalid memory state.
if (Memory::IsKernelVirtualAddress(address)) {
return ERR_INVALID_ADDRESS_STATE;
}
// If the address is not properly aligned to 4 bytes, return invalid address.
if (address % sizeof(u32) != 0) {
return ERR_INVALID_ADDRESS;
}
switch (static_cast<AddressArbiter::ArbitrationType>(type)) {
case AddressArbiter::ArbitrationType::WaitIfLessThan:
return AddressArbiter::WaitForAddressIfLessThan(address, value, timeout, false);
case AddressArbiter::ArbitrationType::DecrementAndWaitIfLessThan:
return AddressArbiter::WaitForAddressIfLessThan(address, value, timeout, true);
case AddressArbiter::ArbitrationType::WaitIfEqual:
return AddressArbiter::WaitForAddressIfEqual(address, value, timeout);
default:
return ERR_INVALID_ENUM_VALUE;
}
}
// Signals to an address (via Address Arbiter)
static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to_wake) {
LOG_WARNING(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, num_to_wake=0x{:X}",
address, type, value, num_to_wake);
// If the passed address is a kernel virtual address, return invalid memory state.
if (Memory::IsKernelVirtualAddress(address)) {
return ERR_INVALID_ADDRESS_STATE;
}
// If the address is not properly aligned to 4 bytes, return invalid address.
if (address % sizeof(u32) != 0) {
return ERR_INVALID_ADDRESS;
}
switch (static_cast<AddressArbiter::SignalType>(type)) {
case AddressArbiter::SignalType::Signal:
return AddressArbiter::SignalToAddress(address, num_to_wake);
case AddressArbiter::SignalType::IncrementAndSignalIfEqual:
return AddressArbiter::IncrementAndSignalToAddressIfEqual(address, value, num_to_wake);
case AddressArbiter::SignalType::ModifyByWaitingCountAndSignalIfEqual:
return AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(address, value,
num_to_wake);
default:
return ERR_INVALID_ENUM_VALUE;
}
}
/// This returns the total CPU ticks elapsed since the CPU was powered-on
static u64 GetSystemTick() {
const u64 result{CoreTiming::GetTicks()};
@@ -696,13 +751,13 @@ static u64 GetSystemTick() {
/// Close a handle
static ResultCode CloseHandle(Handle handle) {
NGLOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle);
LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle);
return g_handle_table.Close(handle);
}
/// Reset an event
static ResultCode ResetSignal(Handle handle) {
NGLOG_WARNING(Kernel_SVC, "(STUBBED) called handle 0x{:08X}", handle);
LOG_WARNING(Kernel_SVC, "(STUBBED) called handle 0x{:08X}", handle);
auto event = g_handle_table.Get<Event>(handle);
ASSERT(event != nullptr);
event->Clear();
@@ -711,14 +766,14 @@ static ResultCode ResetSignal(Handle handle) {
/// Creates a TransferMemory object
static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32 permissions) {
NGLOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr,
size, permissions);
LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, size,
permissions);
*handle = 0;
return RESULT_SUCCESS;
}
static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask) {
NGLOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
if (!thread) {
@@ -732,8 +787,8 @@ static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask)
}
static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
NGLOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:16X}, core=0x{:X}", thread_handle,
mask, core);
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:16X}, core=0x{:X}", thread_handle,
mask, core);
const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
if (!thread) {
@@ -744,7 +799,7 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
ASSERT(thread->owner_process->ideal_processor != THREADPROCESSORID_DEFAULT);
// Set the target CPU to the one specified in the process' exheader.
core = thread->owner_process->ideal_processor;
mask = 1 << core;
mask = 1ull << core;
}
if (mask == 0) {
@@ -761,7 +816,7 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
}
// Error out if the input core isn't enabled in the input mask.
if (core < Core::NUM_CPU_CORES && (mask & (1 << core)) == 0) {
if (core < Core::NUM_CPU_CORES && (mask & (1ull << core)) == 0) {
return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidCombination);
}
@@ -772,8 +827,8 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permissions,
u32 remote_permissions) {
NGLOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size,
local_permissions, remote_permissions);
LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size,
local_permissions, remote_permissions);
auto sharedMemHandle =
SharedMemory::Create(g_handle_table.Get<Process>(KernelHandle::CurrentProcess), size,
static_cast<MemoryPermission>(local_permissions),
@@ -784,7 +839,7 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss
}
static ResultCode ClearEvent(Handle handle) {
NGLOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle);
LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle);
SharedPtr<Event> evt = g_handle_table.Get<Event>(handle);
if (evt == nullptr)
@@ -856,8 +911,8 @@ static const FunctionDef SVC_Table[] = {
{0x31, nullptr, "GetResourceLimitCurrentValue"},
{0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"},
{0x33, SvcWrap<GetThreadContext>, "GetThreadContext"},
{0x34, nullptr, "WaitForAddress"},
{0x35, nullptr, "SignalToAddress"},
{0x34, SvcWrap<WaitForAddress>, "WaitForAddress"},
{0x35, SvcWrap<SignalToAddress>, "SignalToAddress"},
{0x36, nullptr, "Unknown"},
{0x37, nullptr, "Unknown"},
{0x38, nullptr, "Unknown"},
@@ -936,7 +991,7 @@ static const FunctionDef SVC_Table[] = {
static const FunctionDef* GetSVCInfo(u32 func_num) {
if (func_num >= std::size(SVC_Table)) {
NGLOG_ERROR(Kernel_SVC, "Unknown svc=0x{:02X}", func_num);
LOG_ERROR(Kernel_SVC, "Unknown svc=0x{:02X}", func_num);
return nullptr;
}
return &SVC_Table[func_num];
@@ -955,10 +1010,10 @@ void CallSVC(u32 immediate) {
if (info->func) {
info->func();
} else {
NGLOG_CRITICAL(Kernel_SVC, "Unimplemented SVC function {}(..)", info->name);
LOG_CRITICAL(Kernel_SVC, "Unimplemented SVC function {}(..)", info->name);
}
} else {
NGLOG_CRITICAL(Kernel_SVC, "Unknown SVC function 0x{:X}", immediate);
LOG_CRITICAL(Kernel_SVC, "Unknown SVC function 0x{:X}", immediate);
}
}

View File

@@ -179,6 +179,20 @@ void SvcWrap() {
FuncReturn(retval);
}
template <ResultCode func(u64, u32, s32, s64)>
void SvcWrap() {
FuncReturn(
func(PARAM(0), (u32)(PARAM(1) & 0xFFFFFFFF), (s32)(PARAM(2) & 0xFFFFFFFF), (s64)PARAM(3))
.raw);
}
template <ResultCode func(u64, u32, s32, s32)>
void SvcWrap() {
FuncReturn(func(PARAM(0), (u32)(PARAM(1) & 0xFFFFFFFF), (s32)(PARAM(2) & 0xFFFFFFFF),
(s32)(PARAM(3) & 0xFFFFFFFF))
.raw);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Function wrappers that return type u32

View File

@@ -104,7 +104,7 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
const auto proper_handle = static_cast<Handle>(thread_handle);
SharedPtr<Thread> thread = wakeup_callback_handle_table.Get<Thread>(proper_handle);
if (thread == nullptr) {
NGLOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle);
LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle);
return;
}
@@ -140,6 +140,11 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
}
}
if (thread->arb_wait_address != 0) {
ASSERT(thread->status == THREADSTATUS_WAIT_ARB);
thread->arb_wait_address = 0;
}
if (resume)
thread->ResumeFromWait();
}
@@ -179,6 +184,7 @@ void Thread::ResumeFromWait() {
case THREADSTATUS_WAIT_SLEEP:
case THREADSTATUS_WAIT_IPC:
case THREADSTATUS_WAIT_MUTEX:
case THREADSTATUS_WAIT_ARB:
break;
case THREADSTATUS_READY:
@@ -284,19 +290,19 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
SharedPtr<Process> owner_process) {
// Check if priority is in ranged. Lowest priority -> highest priority id.
if (priority > THREADPRIO_LOWEST) {
NGLOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority);
LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority);
return ERR_OUT_OF_RANGE;
}
if (processor_id > THREADPROCESSORID_MAX) {
NGLOG_ERROR(Kernel_SVC, "Invalid processor id: {}", processor_id);
LOG_ERROR(Kernel_SVC, "Invalid processor id: {}", processor_id);
return ERR_OUT_OF_RANGE_KERNEL;
}
// TODO(yuriks): Other checks, returning 0xD9001BEA
if (!Memory::IsValidVirtualAddress(*owner_process, entry_point)) {
NGLOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point);
LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point);
// TODO (bunnei): Find the correct error code to use here
return ResultCode(-1);
}
@@ -337,8 +343,8 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
auto& linheap_memory = memory_region->linear_heap_memory;
if (linheap_memory->size() + Memory::PAGE_SIZE > memory_region->size) {
NGLOG_ERROR(Kernel_SVC,
"Not enough space in region to allocate a new TLS page for thread");
LOG_ERROR(Kernel_SVC,
"Not enough space in region to allocate a new TLS page for thread");
return ERR_OUT_OF_MEMORY;
}

View File

@@ -45,6 +45,7 @@ enum ThreadStatus {
THREADSTATUS_WAIT_SYNCH_ANY, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false
THREADSTATUS_WAIT_SYNCH_ALL, ///< Waiting due to WaitSynchronizationN with wait_all = true
THREADSTATUS_WAIT_MUTEX, ///< Waiting due to an ArbitrateLock/WaitProcessWideKey svc
THREADSTATUS_WAIT_ARB, ///< Waiting due to a SignalToAddress/WaitForAddress svc
THREADSTATUS_DORMANT, ///< Created but not yet made ready
THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated
};
@@ -230,6 +231,9 @@ public:
VAddr mutex_wait_address; ///< If waiting on a Mutex, this is the mutex address
Handle wait_handle; ///< The handle used to wait for the mutex.
// If waiting for an AddressArbiter, this is the address being waited on.
VAddr arb_wait_address{0};
std::string name;
/// Handle used by guest emulated application to access this thread

View File

@@ -78,7 +78,7 @@ void Timer::WakeupAllWaitingThreads() {
}
void Timer::Signal(int cycles_late) {
NGLOG_TRACE(Kernel, "Timer {} fired", GetObjectId());
LOG_TRACE(Kernel, "Timer {} fired", GetObjectId());
signaled = true;
@@ -98,7 +98,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) {
timer_callback_handle_table.Get<Timer>(static_cast<Handle>(timer_handle));
if (timer == nullptr) {
NGLOG_CRITICAL(Kernel, "Callback fired for invalid timer {:016X}", timer_handle);
LOG_CRITICAL(Kernel, "Callback fired for invalid timer {:016X}", timer_handle);
return;
}

View File

@@ -242,12 +242,12 @@ void VMManager::RefreshMemoryBlockMappings(const std::vector<u8>* block) {
void VMManager::LogLayout() const {
for (const auto& p : vma_map) {
const VirtualMemoryArea& vma = p.second;
NGLOG_DEBUG(Kernel, "{:016X} - {:016X} size: {:016X} {}{}{} {}", vma.base,
vma.base + vma.size, vma.size,
(u8)vma.permissions & (u8)VMAPermission::Read ? 'R' : '-',
(u8)vma.permissions & (u8)VMAPermission::Write ? 'W' : '-',
(u8)vma.permissions & (u8)VMAPermission::Execute ? 'X' : '-',
GetMemoryStateName(vma.meminfo_state));
LOG_DEBUG(Kernel, "{:016X} - {:016X} size: {:016X} {}{}{} {}", vma.base,
vma.base + vma.size, vma.size,
(u8)vma.permissions & (u8)VMAPermission::Read ? 'R' : '-',
(u8)vma.permissions & (u8)VMAPermission::Write ? 'W' : '-',
(u8)vma.permissions & (u8)VMAPermission::Execute ? 'X' : '-',
GetMemoryStateName(vma.meminfo_state));
}
}
@@ -392,22 +392,22 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
}
u64 VMManager::GetTotalMemoryUsage() {
NGLOG_WARNING(Kernel, "(STUBBED) called");
LOG_WARNING(Kernel, "(STUBBED) called");
return 0xF8000000;
}
u64 VMManager::GetTotalHeapUsage() {
NGLOG_WARNING(Kernel, "(STUBBED) called");
LOG_WARNING(Kernel, "(STUBBED) called");
return 0x0;
}
VAddr VMManager::GetAddressSpaceBaseAddr() {
NGLOG_WARNING(Kernel, "(STUBBED) called");
LOG_WARNING(Kernel, "(STUBBED) called");
return 0x8000000;
}
u64 VMManager::GetAddressSpaceSize() {
NGLOG_WARNING(Kernel, "(STUBBED) called");
LOG_WARNING(Kernel, "(STUBBED) called");
return MAX_ADDRESS;
}

View File

@@ -47,7 +47,7 @@ public:
private:
void GetBase(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_ACC, "(STUBBED) called");
LOG_WARNING(Service_ACC, "(STUBBED) called");
ProfileBase profile_base{};
IPC::ResponseBuilder rb{ctx, 16};
rb.Push(RESULT_SUCCESS);
@@ -72,14 +72,14 @@ public:
private:
void CheckAvailability(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_ACC, "(STUBBED) called");
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(true); // TODO: Check when this is supposed to return true and when not
}
void GetAccountId(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_ACC, "(STUBBED) called");
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(0x12345678ABCDEF);
@@ -87,14 +87,14 @@ private:
};
void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_ACC, "(STUBBED) called");
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(true); // TODO: Check when this is supposed to return true and when not
}
void Module::Interface::ListAllUsers(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_ACC, "(STUBBED) called");
LOG_WARNING(Service_ACC, "(STUBBED) called");
constexpr std::array<u128, 10> user_ids{DEFAULT_USER_ID};
ctx.WriteBuffer(user_ids.data(), user_ids.size());
IPC::ResponseBuilder rb{ctx, 2};
@@ -102,7 +102,7 @@ void Module::Interface::ListAllUsers(Kernel::HLERequestContext& ctx) {
}
void Module::Interface::ListOpenUsers(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_ACC, "(STUBBED) called");
LOG_WARNING(Service_ACC, "(STUBBED) called");
constexpr std::array<u128, 10> user_ids{DEFAULT_USER_ID};
ctx.WriteBuffer(user_ids.data(), user_ids.size());
IPC::ResponseBuilder rb{ctx, 2};
@@ -113,11 +113,11 @@ void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IProfile>();
NGLOG_DEBUG(Service_ACC, "called");
LOG_DEBUG(Service_ACC, "called");
}
void Module::Interface::InitializeApplicationInfo(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_ACC, "(STUBBED) called");
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
@@ -126,11 +126,11 @@ void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestCo
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IManagerForApplication>();
NGLOG_DEBUG(Service_ACC, "called");
LOG_DEBUG(Service_ACC, "called");
}
void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_ACC, "(STUBBED) called");
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(RESULT_SUCCESS);
rb.PushRaw(DEFAULT_USER_ID);

View File

@@ -4,9 +4,11 @@
#include <cinttypes>
#include <stack>
#include "core/core.h"
#include "core/file_sys/filesystem.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/process.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h"
@@ -30,14 +32,14 @@ IWindowController::IWindowController() : ServiceFramework("IWindowController") {
}
void IWindowController::GetAppletResourceUserId(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(0);
}
void IWindowController::AcquireForegroundRights(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
@@ -56,20 +58,20 @@ IAudioController::IAudioController() : ServiceFramework("IAudioController") {
}
void IAudioController::SetExpectedMasterVolume(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void IAudioController::GetMainAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(volume);
}
void IAudioController::GetLibraryAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(volume);
@@ -155,7 +157,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
RegisterHandlers(functions);
launchable_event =
Kernel::Event::Create(Kernel::ResetType::OneShot, "ISelfController:LaunchableEvent");
Kernel::Event::Create(Kernel::ResetType::Sticky, "ISelfController:LaunchableEvent");
}
void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
@@ -174,14 +176,14 @@ void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ISelfController::SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx) {
@@ -192,14 +194,14 @@ void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestCo
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
}
void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx) {
@@ -210,7 +212,7 @@ void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestCont
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
}
void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx) {
@@ -223,21 +225,21 @@ void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext&
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled);
LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled);
}
void ISelfController::LockExit(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) {
@@ -247,7 +249,7 @@ void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext&
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(launchable_event);
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) {
@@ -260,14 +262,14 @@ void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx)
rb.Push(RESULT_SUCCESS);
rb.Push(layer_id);
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
}
ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter") {
@@ -311,7 +313,7 @@ void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(event);
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) {
@@ -319,7 +321,7 @@ void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(15);
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
@@ -327,7 +329,7 @@ void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u8>(FocusState::InFocus));
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
@@ -336,7 +338,7 @@ void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld));
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
@@ -346,7 +348,7 @@ void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked
: APM::PerformanceMode::Handheld));
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
}
class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
@@ -370,7 +372,7 @@ private:
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u64>(buffer.size()));
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void Write(Kernel::HLERequestContext& ctx) {
@@ -386,7 +388,7 @@ private:
IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)};
rb.Push(RESULT_SUCCESS);
NGLOG_DEBUG(Service_AM, "called, offset={}", offset);
LOG_DEBUG(Service_AM, "called, offset={}", offset);
}
void Read(Kernel::HLERequestContext& ctx) {
@@ -402,7 +404,7 @@ private:
IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)};
rb.Push(RESULT_SUCCESS);
NGLOG_DEBUG(Service_AM, "called, offset={}", offset);
LOG_DEBUG(Service_AM, "called, offset={}", offset);
}
};
@@ -426,7 +428,7 @@ private:
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<AM::IStorageAccessor>(buffer);
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
};
@@ -436,13 +438,13 @@ public:
static const FunctionInfo functions[] = {
{0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"},
{1, nullptr, "IsCompleted"},
{10, nullptr, "Start"},
{10, &ILibraryAppletAccessor::Start, "Start"},
{20, nullptr, "RequestExit"},
{25, nullptr, "Terminate"},
{30, nullptr, "GetResult"},
{30, &ILibraryAppletAccessor::GetResult, "GetResult"},
{50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"},
{100, &ILibraryAppletAccessor::PushInData, "PushInData"},
{101, nullptr, "PopOutData"},
{101, &ILibraryAppletAccessor::PopOutData, "PopOutData"},
{102, nullptr, "PushExtraStorage"},
{103, nullptr, "PushInteractiveInData"},
{104, nullptr, "PopInteractiveOutData"},
@@ -467,7 +469,21 @@ private:
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(state_changed_event);
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void GetResult(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void Start(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void PushInData(Kernel::HLERequestContext& ctx) {
@@ -477,7 +493,17 @@ private:
IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)};
rb.Push(RESULT_SUCCESS);
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void PopOutData(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<AM::IStorage>(std::move(storage_stack.top()));
storage_stack.pop();
LOG_DEBUG(Service_AM, "called");
}
std::stack<std::shared_ptr<AM::IStorage>> storage_stack;
@@ -502,7 +528,7 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx)
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<AM::ILibraryAppletAccessor>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
@@ -514,7 +540,7 @@ void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<AM::IStorage>(std::move(buffer));
NGLOG_DEBUG(Service_AM, "called, size={}", size);
LOG_DEBUG(Service_AM, "called, size={}", size);
}
IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationFunctions") {
@@ -537,7 +563,7 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF
{32, nullptr, "BeginBlockingHomeButton"},
{33, nullptr, "EndBlockingHomeButton"},
{40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"},
{50, nullptr, "GetPseudoDeviceId"},
{50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"},
{60, nullptr, "SetMediaPlaybackStateForApplication"},
{65, nullptr, "IsGamePlayRecordingSupported"},
{66, &IApplicationFunctions::InitializeGamePlayRecording, "InitializeGamePlayRecording"},
@@ -578,37 +604,26 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<AM::IStorage>(buffer);
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(
Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
u128 uid = rp.PopRaw<u128>();
u128 uid = rp.PopRaw<u128>(); // What does this do?
NGLOG_WARNING(Service, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]);
LOG_WARNING(Service, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]);
IPC::ResponseBuilder rb{ctx, 4};
FileSys::Path unused;
auto savedata = FileSystem::OpenFileSystem(FileSystem::Type::SaveData, unused);
if (savedata.Failed()) {
// Create the save data and return an error indicating that the operation was performed.
FileSystem::FormatFileSystem(FileSystem::Type::SaveData);
// TODO(Subv): Find out the correct error code for this.
rb.Push(ResultCode(ErrorModule::FS, 40));
} else {
rb.Push(RESULT_SUCCESS);
}
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(0);
}
} // namespace Service::AM
void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) {
// Takes an input u32 Result, no output.
@@ -620,7 +635,7 @@ void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result);
LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result);
}
void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) {
@@ -628,7 +643,7 @@ void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(1);
rb.Push<u64>(0);
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
@@ -636,20 +651,20 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u64>(Service::Set::LanguageCode::EN_US));
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void IApplicationFunctions::SetGamePlayRecordingState(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) {
@@ -657,7 +672,18 @@ void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
rb.Push<u8>(0); // Unknown, seems to be ignored by official processes
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(RESULT_SUCCESS);
// Returns a 128-bit UUID
rb.Push<u64>(0);
rb.Push<u64>(0);
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void InstallInterfaces(SM::ServiceManager& service_manager,
@@ -682,7 +708,7 @@ IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions"
void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_AM, "(STUBBED) called");
LOG_WARNING(Service_AM, "(STUBBED) called");
}
IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStateController") {

View File

@@ -138,6 +138,7 @@ private:
void InitializeGamePlayRecording(Kernel::HLERequestContext& ctx);
void SetGamePlayRecordingState(Kernel::HLERequestContext& ctx);
void NotifyRunning(Kernel::HLERequestContext& ctx);
void GetPseudoDeviceId(Kernel::HLERequestContext& ctx);
};
class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {

View File

@@ -33,63 +33,63 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ICommonStateGetter>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetSelfController(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISelfController>(nvflinger);
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetWindowController(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IWindowController>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetAudioController(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IAudioController>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetDisplayController(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IDisplayController>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetProcessWindingController(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IProcessWindingController>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IDebugFunctions>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILibraryAppletCreator>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IApplicationFunctions>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
@@ -120,70 +120,70 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ICommonStateGetter>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetSelfController(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISelfController>(nvflinger);
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetWindowController(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IWindowController>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetAudioController(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IAudioController>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetDisplayController(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IDisplayController>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IDebugFunctions>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILibraryAppletCreator>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IHomeMenuFunctions>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetGlobalStateController(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IGlobalStateController>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetApplicationCreator(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IApplicationCreator>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
};
@@ -192,21 +192,21 @@ void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystemAppletProxy>(nvflinger);
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger);
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger);
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)

View File

@@ -33,56 +33,56 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IAudioController>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetDisplayController(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IDisplayController>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IDebugFunctions>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetWindowController(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IWindowController>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetSelfController(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISelfController>(nvflinger);
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ICommonStateGetter>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILibraryAppletCreator>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IApplicationFunctions>();
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
@@ -92,7 +92,7 @@ void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IApplicationProxy>(nvflinger);
NGLOG_DEBUG(Service_AM, "called");
LOG_DEBUG(Service_AM, "called");
}
AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)

View File

@@ -27,14 +27,14 @@ void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(0);
NGLOG_WARNING(Service_AOC, "(STUBBED) called");
LOG_WARNING(Service_AOC, "(STUBBED) called");
}
void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(0);
NGLOG_WARNING(Service_AOC, "(STUBBED) called");
LOG_WARNING(Service_AOC, "(STUBBED) called");
}
void InstallInterfaces(SM::ServiceManager& service_manager) {

View File

@@ -29,8 +29,8 @@ private:
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_APM, "(STUBBED) called mode={} config={}", static_cast<u32>(mode),
config);
LOG_WARNING(Service_APM, "(STUBBED) called mode={} config={}", static_cast<u32>(mode),
config);
}
void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
@@ -42,7 +42,7 @@ private:
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0); // Performance configuration
NGLOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode));
LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode));
}
};

View File

@@ -8,6 +8,7 @@
#include "core/hle/service/audio/audrec_u.h"
#include "core/hle/service/audio/audren_u.h"
#include "core/hle/service/audio/codecctl.h"
#include "core/hle/service/audio/hwopus.h"
namespace Service::Audio {
@@ -17,6 +18,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<AudRecU>()->InstallAsService(service_manager);
std::make_shared<AudRenU>()->InstallAsService(service_manager);
std::make_shared<CodecCtl>()->InstallAsService(service_manager);
std::make_shared<HwOpus>()->InstallAsService(service_manager);
}
} // namespace Service::Audio

View File

@@ -27,12 +27,12 @@ public:
{0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
{1, &IAudioOut::StartAudioOut, "StartAudioOut"},
{2, &IAudioOut::StopAudioOut, "StopAudioOut"},
{3, &IAudioOut::AppendAudioOutBuffer, "AppendAudioOutBuffer"},
{3, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBuffer"},
{4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"},
{5, &IAudioOut::GetReleasedAudioOutBuffer, "GetReleasedAudioOutBuffer"},
{5, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBuffer"},
{6, nullptr, "ContainsAudioOutBuffer"},
{7, nullptr, "AppendAudioOutBufferAuto"},
{8, nullptr, "GetReleasedAudioOutBufferAuto"},
{7, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBufferAuto"},
{8, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBufferAuto"},
{9, nullptr, "GetAudioOutBufferCount"},
{10, nullptr, "GetAudioOutPlayedSampleCount"},
{11, nullptr, "FlushAudioOutBuffers"},
@@ -60,14 +60,14 @@ public:
private:
void GetAudioOutState(Kernel::HLERequestContext& ctx) {
NGLOG_DEBUG(Service_Audio, "called");
LOG_DEBUG(Service_Audio, "called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u32>(audio_out_state));
}
void StartAudioOut(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_Audio, "(STUBBED) called");
LOG_WARNING(Service_Audio, "(STUBBED) called");
// Start audio
audio_out_state = AudioState::Started;
@@ -77,7 +77,7 @@ private:
}
void StopAudioOut(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_Audio, "(STUBBED) called");
LOG_WARNING(Service_Audio, "(STUBBED) called");
// Stop audio
audio_out_state = AudioState::Stopped;
@@ -89,15 +89,15 @@ private:
}
void RegisterBufferEvent(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_Audio, "(STUBBED) called");
LOG_WARNING(Service_Audio, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(buffer_event);
}
void AppendAudioOutBuffer(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_Audio, "(STUBBED) called");
void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_Audio, "(STUBBED) called");
IPC::RequestParser rp{ctx};
const u64 key{rp.Pop<u64>()};
@@ -107,8 +107,8 @@ private:
rb.Push(RESULT_SUCCESS);
}
void GetReleasedAudioOutBuffer(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_Audio, "(STUBBED) called");
void GetReleasedAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_Audio, "(STUBBED) called");
// TODO(st4rk): This is how libtransistor currently implements the
// GetReleasedAudioOutBuffer, it should return the key (a VAddr) to the app and this address
@@ -163,8 +163,8 @@ private:
AudioState audio_out_state;
};
void AudOutU::ListAudioOuts(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_Audio, "(STUBBED) called");
void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_Audio, "(STUBBED) called");
IPC::RequestParser rp{ctx};
const std::string audio_interface = "AudioInterface";
@@ -179,8 +179,8 @@ void AudOutU::ListAudioOuts(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(1);
}
void AudOutU::OpenAudioOut(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_Audio, "(STUBBED) called");
void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_Audio, "(STUBBED) called");
if (!audio_out_interface) {
audio_out_interface = std::make_shared<IAudioOut>();
@@ -196,10 +196,10 @@ void AudOutU::OpenAudioOut(Kernel::HLERequestContext& ctx) {
}
AudOutU::AudOutU() : ServiceFramework("audout:u") {
static const FunctionInfo functions[] = {{0, &AudOutU::ListAudioOuts, "ListAudioOuts"},
{1, &AudOutU::OpenAudioOut, "OpenAudioOut"},
{2, nullptr, "ListAudioOutsAuto"},
{3, nullptr, "OpenAudioOutAuto"}};
static const FunctionInfo functions[] = {{0, &AudOutU::ListAudioOutsImpl, "ListAudioOuts"},
{1, &AudOutU::OpenAudioOutImpl, "OpenAudioOut"},
{2, &AudOutU::ListAudioOutsImpl, "ListAudioOutsAuto"},
{3, &AudOutU::OpenAudioOutImpl, "OpenAudioOutAuto"}};
RegisterHandlers(functions);
}

View File

@@ -22,8 +22,8 @@ public:
private:
std::shared_ptr<IAudioOut> audio_out_interface;
void ListAudioOuts(Kernel::HLERequestContext& ctx);
void OpenAudioOut(Kernel::HLERequestContext& ctx);
void ListAudioOutsImpl(Kernel::HLERequestContext& ctx);
void OpenAudioOutImpl(Kernel::HLERequestContext& ctx);
enum class PcmFormat : u32 {
Invalid = 0,

View File

@@ -17,7 +17,8 @@ constexpr u64 audio_ticks{static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / 200)};
class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
public:
IAudioRenderer() : ServiceFramework("IAudioRenderer") {
IAudioRenderer(AudioRendererParameter audren_params)
: ServiceFramework("IAudioRenderer"), worker_params(audren_params) {
static const FunctionInfo functions[] = {
{0, nullptr, "GetAudioRendererSampleRate"},
{1, nullptr, "GetAudioRendererSampleCount"},
@@ -46,6 +47,7 @@ public:
// Start the audio event
CoreTiming::ScheduleEvent(audio_ticks, audio_event);
voice_status_list.resize(worker_params.voice_count);
}
~IAudioRenderer() {
CoreTiming::UnscheduleEvent(audio_event, 0);
@@ -57,30 +59,61 @@ private:
}
void RequestUpdateAudioRenderer(Kernel::HLERequestContext& ctx) {
NGLOG_DEBUG(Service_Audio, "{}", ctx.Description());
AudioRendererResponseData response_data{};
UpdateDataHeader config{};
auto buf = ctx.ReadBuffer();
std::memcpy(&config, buf.data(), sizeof(UpdateDataHeader));
u32 memory_pool_count = worker_params.effect_count + (worker_params.voice_count * 4);
response_data.section_0_size =
static_cast<u32>(response_data.state_entries.size() * sizeof(AudioRendererStateEntry));
response_data.section_1_size = static_cast<u32>(response_data.section_1.size());
response_data.section_2_size = static_cast<u32>(response_data.section_2.size());
response_data.section_3_size = static_cast<u32>(response_data.section_3.size());
response_data.section_4_size = static_cast<u32>(response_data.section_4.size());
response_data.section_5_size = static_cast<u32>(response_data.section_5.size());
response_data.total_size = sizeof(AudioRendererResponseData);
std::vector<MemoryPoolInfo> mem_pool_info(memory_pool_count);
std::memcpy(mem_pool_info.data(),
buf.data() + sizeof(UpdateDataHeader) + config.behavior_size,
memory_pool_count * sizeof(MemoryPoolInfo));
for (unsigned i = 0; i < response_data.state_entries.size(); i++) {
// 4 = Busy and 5 = Ready?
response_data.state_entries[i].state = 5;
std::vector<VoiceInfo> voice_info(worker_params.voice_count);
std::memcpy(voice_info.data(),
buf.data() + sizeof(UpdateDataHeader) + config.behavior_size +
config.memory_pools_size + config.voice_resource_size,
worker_params.voice_count * sizeof(VoiceInfo));
UpdateDataHeader response_data{worker_params};
ASSERT(ctx.GetWriteBufferSize() == response_data.total_size);
std::vector<u8> output(response_data.total_size);
std::memcpy(output.data(), &response_data, sizeof(UpdateDataHeader));
std::vector<MemoryPoolEntry> memory_pool(memory_pool_count);
for (unsigned i = 0; i < memory_pool.size(); i++) {
if (mem_pool_info[i].pool_state == MemoryPoolStates::RequestAttach)
memory_pool[i].state = MemoryPoolStates::Attached;
else if (mem_pool_info[i].pool_state == MemoryPoolStates::RequestDetach)
memory_pool[i].state = MemoryPoolStates::Detached;
}
std::memcpy(output.data() + sizeof(UpdateDataHeader), memory_pool.data(),
response_data.memory_pools_size);
ctx.WriteBuffer(&response_data, response_data.total_size);
for (unsigned i = 0; i < voice_info.size(); i++) {
if (voice_info[i].is_new) {
voice_status_list[i].played_sample_count = 0;
voice_status_list[i].wave_buffer_consumed = 0;
} else if (voice_info[i].play_state == (u8)PlayStates::Started) {
for (u32 buff_idx = 0; buff_idx < voice_info[i].wave_buffer_count; buff_idx++) {
voice_status_list[i].played_sample_count +=
(voice_info[i].wave_buffer[buff_idx].end_sample_offset -
voice_info[i].wave_buffer[buff_idx].start_sample_offset) /
2;
voice_status_list[i].wave_buffer_consumed++;
}
}
}
std::memcpy(output.data() + sizeof(UpdateDataHeader) + response_data.memory_pools_size,
voice_status_list.data(), response_data.voices_size);
ctx.WriteBuffer(output);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_Audio, "(STUBBED) called");
LOG_WARNING(Service_Audio, "(STUBBED) called");
}
void StartAudioRenderer(Kernel::HLERequestContext& ctx) {
@@ -88,7 +121,7 @@ private:
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_Audio, "(STUBBED) called");
LOG_WARNING(Service_Audio, "(STUBBED) called");
}
void StopAudioRenderer(Kernel::HLERequestContext& ctx) {
@@ -96,7 +129,7 @@ private:
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_Audio, "(STUBBED) called");
LOG_WARNING(Service_Audio, "(STUBBED) called");
}
void QuerySystemEvent(Kernel::HLERequestContext& ctx) {
@@ -106,51 +139,134 @@ private:
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(system_event);
NGLOG_WARNING(Service_Audio, "(STUBBED) called");
LOG_WARNING(Service_Audio, "(STUBBED) called");
}
struct AudioRendererStateEntry {
u32_le state;
enum class MemoryPoolStates : u32 { // Should be LE
Invalid = 0x0,
Unknown = 0x1,
RequestDetach = 0x2,
Detached = 0x3,
RequestAttach = 0x4,
Attached = 0x5,
Released = 0x6,
};
enum class PlayStates : u8 {
Started = 0,
Stopped = 1,
};
struct MemoryPoolEntry {
MemoryPoolStates state;
u32_le unknown_4;
u32_le unknown_8;
u32_le unknown_c;
};
static_assert(sizeof(AudioRendererStateEntry) == 0x10,
"AudioRendererStateEntry has wrong size");
static_assert(sizeof(MemoryPoolEntry) == 0x10, "MemoryPoolEntry has wrong size");
struct AudioRendererResponseData {
u32_le unknown_0;
u32_le section_5_size;
u32_le section_0_size;
u32_le section_1_size;
u32_le unknown_10;
u32_le section_2_size;
u32_le unknown_18;
u32_le section_3_size;
u32_le section_4_size;
u32_le unknown_24;
u32_le unknown_28;
u32_le unknown_2c;
u32_le unknown_30;
u32_le unknown_34;
u32_le unknown_38;
u32_le total_size;
std::array<AudioRendererStateEntry, 0x18e> state_entries;
std::array<u8, 0x600> section_1;
std::array<u8, 0xe0> section_2;
std::array<u8, 0x20> section_3;
std::array<u8, 0x10> section_4;
std::array<u8, 0xb0> section_5;
struct MemoryPoolInfo {
u64_le pool_address;
u64_le pool_size;
MemoryPoolStates pool_state;
INSERT_PADDING_WORDS(3); // Unknown
};
static_assert(sizeof(AudioRendererResponseData) == 0x20e0,
"AudioRendererResponseData has wrong size");
static_assert(sizeof(MemoryPoolInfo) == 0x20, "MemoryPoolInfo has wrong size");
struct UpdateDataHeader {
UpdateDataHeader() {}
UpdateDataHeader(const AudioRendererParameter& config) {
revision = Common::MakeMagic('R', 'E', 'V', '4'); // 5.1.0 Revision
behavior_size = 0xb0;
memory_pools_size = (config.effect_count + (config.voice_count * 4)) * 0x10;
voices_size = config.voice_count * 0x10;
voice_resource_size = 0x0;
effects_size = config.effect_count * 0x10;
mixes_size = 0x0;
sinks_size = config.sink_count * 0x20;
performance_manager_size = 0x10;
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;
};
static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size");
struct BiquadFilter {
u8 enable;
INSERT_PADDING_BYTES(1);
s16_le numerator[3];
s16_le denominator[2];
};
static_assert(sizeof(BiquadFilter) == 0xc, "BiquadFilter has wrong size");
struct WaveBuffer {
u64_le buffer_addr;
u64_le buffer_sz;
s32_le start_sample_offset;
s32_le end_sample_offset;
u8 loop;
u8 end_of_stream;
u8 sent_to_server;
INSERT_PADDING_BYTES(5);
u64 context_addr;
u64 context_sz;
INSERT_PADDING_BYTES(8);
};
static_assert(sizeof(WaveBuffer) == 0x38, "WaveBuffer has wrong size");
struct VoiceInfo {
u32_le id;
u32_le node_id;
u8 is_new;
u8 is_in_use;
u8 play_state;
u8 sample_format;
u32_le sample_rate;
u32_le priority;
u32_le sorting_order;
u32_le channel_count;
float_le pitch;
float_le volume;
BiquadFilter biquad_filter[2];
u32_le wave_buffer_count;
u16_le wave_buffer_head;
INSERT_PADDING_BYTES(6);
u64_le additional_params_addr;
u64_le additional_params_sz;
u32_le mix_id;
u32_le splitter_info_id;
WaveBuffer wave_buffer[4];
u32_le voice_channel_resource_ids[6];
INSERT_PADDING_BYTES(24);
};
static_assert(sizeof(VoiceInfo) == 0x170, "VoiceInfo is wrong size");
struct VoiceOutStatus {
u64_le played_sample_count;
u32_le wave_buffer_consumed;
INSERT_PADDING_WORDS(1);
};
static_assert(sizeof(VoiceOutStatus) == 0x10, "VoiceOutStatus has wrong size");
/// This is used to trigger the audio event callback.
CoreTiming::EventType* audio_event;
Kernel::SharedPtr<Kernel::Event> system_event;
AudioRendererParameter worker_params;
std::vector<VoiceOutStatus> voice_status_list;
};
class IAudioDevice final : public ServiceFramework<IAudioDevice> {
@@ -179,7 +295,7 @@ public:
private:
void ListAudioDeviceName(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_Audio, "(STUBBED) called");
LOG_WARNING(Service_Audio, "(STUBBED) called");
IPC::RequestParser rp{ctx};
const std::string audio_interface = "AudioInterface";
@@ -191,7 +307,7 @@ private:
}
void SetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_Audio, "(STUBBED) called");
LOG_WARNING(Service_Audio, "(STUBBED) called");
IPC::RequestParser rp{ctx};
f32 volume = static_cast<f32>(rp.Pop<u32>());
@@ -204,7 +320,7 @@ private:
}
void GetActiveAudioDeviceName(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_Audio, "(STUBBED) called");
LOG_WARNING(Service_Audio, "(STUBBED) called");
IPC::RequestParser rp{ctx};
const std::string audio_interface = "AudioDevice";
@@ -216,7 +332,7 @@ private:
}
void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_Audio, "(STUBBED) called");
LOG_WARNING(Service_Audio, "(STUBBED) called");
buffer_event->Signal();
@@ -226,7 +342,7 @@ private:
}
void GetActiveChannelCount(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_Audio, "(STUBBED) called");
LOG_WARNING(Service_Audio, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(1);
@@ -248,31 +364,33 @@ AudRenU::AudRenU() : ServiceFramework("audren:u") {
}
void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto params = rp.PopRaw<AudioRendererParameter>();
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<Audio::IAudioRenderer>();
rb.PushIpcInterface<Audio::IAudioRenderer>(std::move(params));
NGLOG_DEBUG(Service_Audio, "called");
LOG_DEBUG(Service_Audio, "called");
}
void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto params = rp.PopRaw<WorkerBufferParameters>();
auto params = rp.PopRaw<AudioRendererParameter>();
u64 buffer_sz = Common::AlignUp(4 * params.unknown8, 0x40);
buffer_sz += params.unknownC * 1024;
buffer_sz += 0x940 * (params.unknownC + 1);
u64 buffer_sz = Common::AlignUp(4 * params.unknown_8, 0x40);
buffer_sz += params.unknown_c * 1024;
buffer_sz += 0x940 * (params.unknown_c + 1);
buffer_sz += 0x3F0 * params.voice_count;
buffer_sz += Common::AlignUp(8 * (params.unknownC + 1), 0x10);
buffer_sz += Common::AlignUp(8 * (params.unknown_c + 1), 0x10);
buffer_sz += Common::AlignUp(8 * params.voice_count, 0x10);
buffer_sz +=
Common::AlignUp((0x3C0 * (params.sink_count + params.unknownC) + 4 * params.sample_count) *
(params.unknown8 + 6),
Common::AlignUp((0x3C0 * (params.sink_count + params.unknown_c) + 4 * params.sample_count) *
(params.unknown_8 + 6),
0x40);
if (IsFeatureSupported(AudioFeatures::Splitter, params.magic)) {
u32 count = params.unknownC + 1;
if (IsFeatureSupported(AudioFeatures::Splitter, params.revision)) {
u32 count = params.unknown_c + 1;
u64 node_count = Common::AlignUp(count, 0x40);
u64 node_state_buffer_sz =
4 * (node_count * node_count) + 0xC * node_count + 2 * (node_count / 8);
@@ -287,20 +405,20 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
}
buffer_sz += 0x20 * (params.effect_count + 4 * params.voice_count) + 0x50;
if (IsFeatureSupported(AudioFeatures::Splitter, params.magic)) {
buffer_sz += 0xE0 * params.unknown2c;
if (IsFeatureSupported(AudioFeatures::Splitter, params.revision)) {
buffer_sz += 0xE0 * params.unknown_2c;
buffer_sz += 0x20 * params.splitter_count;
buffer_sz += Common::AlignUp(4 * params.unknown2c, 0x10);
buffer_sz += Common::AlignUp(4 * params.unknown_2c, 0x10);
}
buffer_sz = Common::AlignUp(buffer_sz, 0x40) + 0x170 * params.sink_count;
u64 output_sz = buffer_sz + 0x280 * params.sink_count + 0x4B0 * params.effect_count +
((params.voice_count * 256) | 0x40);
if (params.unknown1c >= 1) {
if (params.unknown_1c >= 1) {
output_sz = Common::AlignUp(((16 * params.sink_count + 16 * params.effect_count +
16 * params.voice_count + 16) +
0x658) *
(params.unknown1c + 1) +
(params.unknown_1c + 1) +
0xc0,
0x40) +
output_sz;
@@ -312,7 +430,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(output_sz);
NGLOG_DEBUG(Service_Audio, "called, buffer_size=0x{:X}", output_sz);
LOG_DEBUG(Service_Audio, "called, buffer_size=0x{:X}", output_sz);
}
void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) {
@@ -321,14 +439,14 @@ void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<Audio::IAudioDevice>();
NGLOG_DEBUG(Service_Audio, "called");
LOG_DEBUG(Service_Audio, "called");
}
bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const {
u32_be version_num = (revision - Common::MakeMagic('R', 'E', 'V', '0')); // Byte swap
switch (feature) {
case AudioFeatures::Splitter:
return version_num >= 2;
return version_num >= 2u;
default:
return false;
}

View File

@@ -12,6 +12,24 @@ class HLERequestContext;
namespace Service::Audio {
struct AudioRendererParameter {
u32_le sample_rate;
u32_le sample_count;
u32_le unknown_8;
u32_le unknown_c;
u32_le voice_count;
u32_le sink_count;
u32_le effect_count;
u32_le unknown_1c;
u8 unknown_20;
INSERT_PADDING_BYTES(3);
u32_le splitter_count;
u32_le unknown_2c;
INSERT_PADDING_WORDS(1);
u32_le revision;
};
static_assert(sizeof(AudioRendererParameter) == 52, "AudioRendererParameter is an invalid size");
class AudRenU final : public ServiceFramework<AudRenU> {
public:
explicit AudRenU();
@@ -22,25 +40,6 @@ private:
void GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx);
void GetAudioDevice(Kernel::HLERequestContext& ctx);
struct WorkerBufferParameters {
u32_le sample_rate;
u32_le sample_count;
u32_le unknown8;
u32_le unknownC;
u32_le voice_count;
u32_le sink_count;
u32_le effect_count;
u32_le unknown1c;
u8 unknown20;
u8 padding1[3];
u32_le splitter_count;
u32_le unknown2c;
u8 padding2[4];
u32_le magic;
};
static_assert(sizeof(WorkerBufferParameters) == 52,
"WorkerBufferParameters is an invalid size");
enum class AudioFeatures : u32 {
Splitter,
};

View File

@@ -0,0 +1,29 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/audio/hwopus.h"
namespace Service::Audio {
void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_Audio, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0x4000);
}
HwOpus::HwOpus() : ServiceFramework("hwopus") {
static const FunctionInfo functions[] = {
{0, nullptr, "Initialize"},
{1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"},
{2, nullptr, "InitializeMultiStream"},
{3, nullptr, "GetWorkBufferSizeMultiStream"},
};
RegisterHandlers(functions);
}
} // namespace Service::Audio

View File

@@ -0,0 +1,20 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/hle/service/service.h"
namespace Service::Audio {
class HwOpus final : public ServiceFramework<HwOpus> {
public:
explicit HwOpus();
~HwOpus() = default;
private:
void GetWorkBufferSize(Kernel::HLERequestContext& ctx);
};
} // namespace Service::Audio

View File

@@ -36,7 +36,7 @@ void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IBcatService>();
NGLOG_DEBUG(Service_BCAT, "called");
LOG_DEBUG(Service_BCAT, "called");
}
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)

View File

@@ -16,13 +16,13 @@ Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
void Module::Interface::ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
u32 error_code = rp.Pop<u32>();
NGLOG_WARNING(Service_Fatal, "(STUBBED) called, error_code=0x{:X}", error_code);
LOG_WARNING(Service_Fatal, "(STUBBED) called, error_code=0x{:X}", error_code);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void Module::Interface::ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_Fatal, "(STUBBED) called");
LOG_WARNING(Service_Fatal, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}

View File

@@ -4,6 +4,7 @@
#include <boost/container/flat_map.hpp>
#include "common/file_util.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/filesystem.h"
#include "core/file_sys/savedata_factory.h"
#include "core/file_sys/sdmc_factory.h"
@@ -16,57 +17,77 @@ namespace Service::FileSystem {
* Map of registered file systems, identified by type. Once an file system is registered here, it
* is never removed until UnregisterFileSystems is called.
*/
static boost::container::flat_map<Type, std::unique_ptr<FileSys::FileSystemFactory>> filesystem_map;
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;
ResultCode RegisterFileSystem(std::unique_ptr<FileSys::FileSystemFactory>&& factory, Type type) {
auto result = filesystem_map.emplace(type, std::move(factory));
bool inserted = result.second;
ASSERT_MSG(inserted, "Tried to register more than one system with same id code");
auto& filesystem = result.first->second;
NGLOG_DEBUG(Service_FS, "Registered file system {} with id code 0x{:08X}",
filesystem->GetName(), static_cast<u32>(type));
ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory) {
ASSERT_MSG(romfs_factory == nullptr, "Tried to register a second RomFS");
romfs_factory = std::move(factory);
LOG_DEBUG(Service_FS, "Registered RomFS");
return RESULT_SUCCESS;
}
ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type,
FileSys::Path& path) {
NGLOG_TRACE(Service_FS, "Opening FileSystem with type={}", static_cast<u32>(type));
auto itr = filesystem_map.find(type);
if (itr == filesystem_map.end()) {
// TODO(bunnei): Find a better error code for this
return ResultCode(-1);
}
return itr->second->Open(path);
ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory) {
ASSERT_MSG(romfs_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 FormatFileSystem(Type type) {
NGLOG_TRACE(Service_FS, "Formatting FileSystem with type={}", static_cast<u32>(type));
ResultCode 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;
}
auto itr = filesystem_map.find(type);
if (itr == filesystem_map.end()) {
ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenRomFS(u64 title_id) {
LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}", title_id);
if (romfs_factory == nullptr) {
// TODO(bunnei): Find a better error code for this
return ResultCode(-1);
}
FileSys::Path unused;
return itr->second->Format(unused);
return romfs_factory->Open(title_id);
}
ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenSaveData(
FileSys::SaveDataSpaceId space, FileSys::SaveDataDescriptor save_struct) {
LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}",
static_cast<u8>(space), SaveStructDebugInfo(save_struct));
if (save_data_factory == nullptr) {
return ResultCode(ErrorModule::FS, FileSys::ErrCodes::SaveDataNotFound);
}
return save_data_factory->Open(space, save_struct);
}
ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenSDMC() {
LOG_TRACE(Service_FS, "Opening SDMC");
if (sdmc_factory == nullptr) {
return ResultCode(ErrorModule::FS, FileSys::ErrCodes::SdCardNotFound);
}
return sdmc_factory->Open();
}
void RegisterFileSystems() {
filesystem_map.clear();
romfs_factory = nullptr;
save_data_factory = nullptr;
sdmc_factory = nullptr;
std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX);
std::string sd_directory = FileUtil::GetUserPath(D_SDMC_IDX);
auto savedata = std::make_unique<FileSys::SaveData_Factory>(std::move(nand_directory));
RegisterFileSystem(std::move(savedata), Type::SaveData);
auto savedata = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory));
save_data_factory = std::move(savedata);
auto sdcard = std::make_unique<FileSys::SDMC_Factory>(std::move(sd_directory));
RegisterFileSystem(std::move(sdcard), Type::SDMC);
auto sdcard = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory));
sdmc_factory = std::move(sdcard);
}
void InstallInterfaces(SM::ServiceManager& service_manager) {

View File

@@ -6,12 +6,13 @@
#include <memory>
#include "common/common_types.h"
#include "core/file_sys/romfs_factory.h"
#include "core/file_sys/savedata_factory.h"
#include "core/file_sys/sdmc_factory.h"
#include "core/hle/result.h"
namespace FileSys {
class FileSystemBackend;
class FileSystemFactory;
class Path;
} // namespace FileSys
namespace Service {
@@ -22,35 +23,20 @@ class ServiceManager;
namespace FileSystem {
/// Supported FileSystem types
enum class Type {
RomFS = 1,
SaveData = 2,
SDMC = 3,
};
ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory);
ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory);
ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory);
/**
* Registers a FileSystem, instances of which can later be opened using its IdCode.
* @param factory FileSystem backend interface to use
* @param type Type used to access this type of FileSystem
*/
ResultCode RegisterFileSystem(std::unique_ptr<FileSys::FileSystemFactory>&& factory, Type type);
// TODO(DarkLordZach): BIS Filesystem
// ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory);
/**
* Opens a file system
* @param type Type of the file system to open
* @param path Path to the file system, used with Binary paths
* @return FileSys::FileSystemBackend interface to the file system
*/
ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type,
FileSys::Path& path);
ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenRomFS(u64 title_id);
ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenSaveData(
FileSys::SaveDataSpaceId space, FileSys::SaveDataDescriptor save_struct);
ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenSDMC();
/**
* Formats a file system
* @param type Type of the file system to format
* @return ResultCode of the operation
*/
ResultCode FormatFileSystem(Type type);
// TODO(DarkLordZach): BIS Filesystem
// ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenBIS();
/// Registers all Filesystem services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);

View File

@@ -4,18 +4,30 @@
#include <cinttypes>
#include "common/logging/log.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/file_sys/directory.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/filesystem.h"
#include "core/file_sys/storage.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/process.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/filesystem/fsp_srv.h"
namespace Service::FileSystem {
enum class StorageId : u8 {
None = 0,
Host = 1,
GameCard = 2,
NandSystem = 3,
NandUser = 4,
SdCard = 5
};
class IStorage final : public ServiceFramework<IStorage> {
public:
IStorage(std::unique_ptr<FileSys::StorageBackend>&& backend)
@@ -35,7 +47,7 @@ private:
const s64 offset = rp.Pop<s64>();
const s64 length = rp.Pop<s64>();
NGLOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
// Error checking
if (length < 0) {
@@ -87,7 +99,7 @@ private:
const s64 offset = rp.Pop<s64>();
const s64 length = rp.Pop<s64>();
NGLOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
// Error checking
if (length < 0) {
@@ -124,7 +136,7 @@ private:
const s64 offset = rp.Pop<s64>();
const s64 length = rp.Pop<s64>();
NGLOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
// Error checking
if (length < 0) {
@@ -152,7 +164,7 @@ private:
}
void Flush(Kernel::HLERequestContext& ctx) {
NGLOG_DEBUG(Service_FS, "called");
LOG_DEBUG(Service_FS, "called");
backend->Flush();
IPC::ResponseBuilder rb{ctx, 2};
@@ -163,7 +175,7 @@ private:
IPC::RequestParser rp{ctx};
const u64 size = rp.Pop<u64>();
backend->SetSize(size);
NGLOG_DEBUG(Service_FS, "called, size={}", size);
LOG_DEBUG(Service_FS, "called, size={}", size);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -171,7 +183,7 @@ private:
void GetSize(Kernel::HLERequestContext& ctx) {
const u64 size = backend->GetSize();
NGLOG_DEBUG(Service_FS, "called, size={}", size);
LOG_DEBUG(Service_FS, "called, size={}", size);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
@@ -197,7 +209,7 @@ private:
IPC::RequestParser rp{ctx};
const u64 unk = rp.Pop<u64>();
NGLOG_DEBUG(Service_FS, "called, unk=0x{:X}", unk);
LOG_DEBUG(Service_FS, "called, unk=0x{:X}", unk);
// Calculate how many entries we can fit in the output buffer
u64 count_entries = ctx.GetWriteBufferSize() / sizeof(FileSys::Entry);
@@ -219,7 +231,7 @@ private:
}
void GetEntryCount(Kernel::HLERequestContext& ctx) {
NGLOG_DEBUG(Service_FS, "called");
LOG_DEBUG(Service_FS, "called");
u64 count = backend->GetEntryCount();
@@ -258,14 +270,12 @@ public:
IPC::RequestParser rp{ctx};
auto file_buffer = ctx.ReadBuffer();
auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0');
std::string name(file_buffer.begin(), end);
std::string name = Common::StringFromBuffer(file_buffer);
u64 mode = rp.Pop<u64>();
u32 size = rp.Pop<u32>();
NGLOG_DEBUG(Service_FS, "called file {} mode 0x{:X} size 0x{:08X}", name, mode, size);
LOG_DEBUG(Service_FS, "called file {} mode 0x{:X} size 0x{:08X}", name, mode, size);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(backend->CreateFile(name, size));
@@ -275,11 +285,9 @@ public:
IPC::RequestParser rp{ctx};
auto file_buffer = ctx.ReadBuffer();
auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0');
std::string name = Common::StringFromBuffer(file_buffer);
std::string name(file_buffer.begin(), end);
NGLOG_DEBUG(Service_FS, "called file {}", name);
LOG_DEBUG(Service_FS, "called file {}", name);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(backend->DeleteFile(name));
@@ -289,11 +297,9 @@ public:
IPC::RequestParser rp{ctx};
auto file_buffer = ctx.ReadBuffer();
auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0');
std::string name = Common::StringFromBuffer(file_buffer);
std::string name(file_buffer.begin(), end);
NGLOG_DEBUG(Service_FS, "called directory {}", name);
LOG_DEBUG(Service_FS, "called directory {}", name);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(backend->CreateDirectory(name));
@@ -305,15 +311,13 @@ public:
std::vector<u8> buffer;
buffer.resize(ctx.BufferDescriptorX()[0].Size());
Memory::ReadBlock(ctx.BufferDescriptorX()[0].Address(), buffer.data(), buffer.size());
auto end = std::find(buffer.begin(), buffer.end(), '\0');
std::string src_name(buffer.begin(), end);
std::string src_name = Common::StringFromBuffer(buffer);
buffer.resize(ctx.BufferDescriptorX()[1].Size());
Memory::ReadBlock(ctx.BufferDescriptorX()[1].Address(), buffer.data(), buffer.size());
end = std::find(buffer.begin(), buffer.end(), '\0');
std::string dst_name(buffer.begin(), end);
std::string dst_name = Common::StringFromBuffer(buffer);
NGLOG_DEBUG(Service_FS, "called file '{}' to file '{}'", src_name, dst_name);
LOG_DEBUG(Service_FS, "called file '{}' to file '{}'", src_name, dst_name);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(backend->RenameFile(src_name, dst_name));
@@ -323,13 +327,11 @@ public:
IPC::RequestParser rp{ctx};
auto file_buffer = ctx.ReadBuffer();
auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0');
std::string name(file_buffer.begin(), end);
std::string name = Common::StringFromBuffer(file_buffer);
auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>());
NGLOG_DEBUG(Service_FS, "called file {} mode {}", name, static_cast<u32>(mode));
LOG_DEBUG(Service_FS, "called file {} mode {}", name, static_cast<u32>(mode));
auto result = backend->OpenFile(name, mode);
if (result.Failed()) {
@@ -349,14 +351,12 @@ public:
IPC::RequestParser rp{ctx};
auto file_buffer = ctx.ReadBuffer();
auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0');
std::string name(file_buffer.begin(), end);
std::string name = Common::StringFromBuffer(file_buffer);
// TODO(Subv): Implement this filter.
u32 filter_flags = rp.Pop<u32>();
NGLOG_DEBUG(Service_FS, "called directory {} filter {}", name, filter_flags);
LOG_DEBUG(Service_FS, "called directory {} filter {}", name, filter_flags);
auto result = backend->OpenDirectory(name);
if (result.Failed()) {
@@ -376,11 +376,9 @@ public:
IPC::RequestParser rp{ctx};
auto file_buffer = ctx.ReadBuffer();
auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0');
std::string name = Common::StringFromBuffer(file_buffer);
std::string name(file_buffer.begin(), end);
NGLOG_DEBUG(Service_FS, "called file {}", name);
LOG_DEBUG(Service_FS, "called file {}", name);
auto result = backend->GetEntryType(name);
if (result.Failed()) {
@@ -395,7 +393,7 @@ public:
}
void Commit(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_FS, "(STUBBED) called");
LOG_WARNING(Service_FS, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -499,29 +497,17 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
RegisterHandlers(functions);
}
void FSP_SRV::TryLoadRomFS() {
if (romfs) {
return;
}
FileSys::Path unused;
auto res = OpenFileSystem(Type::RomFS, unused);
if (res.Succeeded()) {
romfs = std::move(res.Unwrap());
}
}
void FSP_SRV::Initialize(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_FS, "(STUBBED) called");
LOG_WARNING(Service_FS, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) {
NGLOG_DEBUG(Service_FS, "called");
LOG_DEBUG(Service_FS, "called");
FileSys::Path unused;
auto filesystem = OpenFileSystem(Type::SDMC, unused).Unwrap();
IFileSystem filesystem(OpenSDMC().Unwrap());
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -531,29 +517,40 @@ void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) {
void FSP_SRV::CreateSaveData(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto save_struct = rp.PopRaw<std::array<u8, 0x40>>();
auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>();
auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
u128 uid = rp.PopRaw<u128>();
NGLOG_WARNING(Service_FS, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]);
LOG_WARNING(Service_FS, "(STUBBED) called save_struct = {}, uid = {:016X}{:016X}",
save_struct.DebugInfo(), uid[1], uid[0]);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_FS, "(STUBBED) called");
IPC::RequestParser rp{ctx};
FileSys::Path unused;
auto filesystem = OpenFileSystem(Type::SaveData, unused).Unwrap();
auto space_id = rp.PopRaw<FileSys::SaveDataSpaceId>();
auto unk = rp.Pop<u32>();
LOG_INFO(Service_FS, "called with unknown={:08X}", unk);
auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>();
auto filesystem = OpenSaveData(space_id, save_struct);
if (filesystem.Failed()) {
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
rb.Push(ResultCode(ErrorModule::FS, FileSys::ErrCodes::SaveDataNotFound));
return;
}
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
rb.PushIpcInterface<IFileSystem>(std::move(filesystem.Unwrap()));
}
void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_FS, "(STUBBED) called");
LOG_WARNING(Service_FS, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
@@ -561,21 +558,21 @@ void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
}
void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
NGLOG_DEBUG(Service_FS, "called");
LOG_DEBUG(Service_FS, "called");
TryLoadRomFS();
if (!romfs) {
auto romfs = OpenRomFS(Core::System::GetInstance().CurrentProcess()->program_id);
if (romfs.Failed()) {
// TODO (bunnei): Find the right error code to use here
NGLOG_CRITICAL(Service_FS, "no file system interface available!");
LOG_CRITICAL(Service_FS, "no file system interface available!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultCode(-1));
return;
}
// Attempt to open a StorageBackend interface to the RomFS
auto storage = romfs->OpenFile({}, {});
auto storage = romfs.Unwrap()->OpenFile({}, {});
if (storage.Failed()) {
NGLOG_CRITICAL(Service_FS, "no storage interface available!");
LOG_CRITICAL(Service_FS, "no storage interface available!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(storage.Code());
return;
@@ -587,8 +584,40 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
}
void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_FS, "(STUBBED) called, using OpenDataStorageByCurrentProcess");
OpenDataStorageByCurrentProcess(ctx);
IPC::RequestParser rp{ctx};
auto storage_id = rp.PopRaw<StorageId>();
auto title_id = rp.PopRaw<u64>();
LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}",
static_cast<u8>(storage_id), title_id);
if (title_id != Core::System::GetInstance().CurrentProcess()->program_id) {
LOG_CRITICAL(
Service_FS,
"Attempting to access RomFS of another title id (current={:016X}, requested={:016X}).",
Core::System::GetInstance().CurrentProcess()->program_id, title_id);
}
auto romfs = OpenRomFS(title_id);
if (romfs.Failed()) {
LOG_CRITICAL(Service_FS, "no file system interface available!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultCode(ErrorModule::FS, FileSys::ErrCodes::RomFSNotFound));
return;
}
auto storage = romfs.Unwrap()->OpenFile({}, {});
if (storage.Failed()) {
LOG_CRITICAL(Service_FS, "no storage interface available!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(storage.Code());
return;
}
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IStorage>(std::move(storage.Unwrap()));
}
} // namespace Service::FileSystem

View File

@@ -19,8 +19,6 @@ public:
~FSP_SRV() = default;
private:
void TryLoadRomFS();
void Initialize(Kernel::HLERequestContext& ctx);
void MountSdCard(Kernel::HLERequestContext& ctx);
void CreateSaveData(Kernel::HLERequestContext& ctx);

View File

@@ -13,7 +13,7 @@ namespace Service::Friend {
void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_Friend, "(STUBBED) called");
LOG_WARNING(Service_Friend, "(STUBBED) called");
}
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)

View File

@@ -18,9 +18,9 @@ namespace Service::HID {
// Updating period for each HID device.
// TODO(shinyquagsire23): These need better values.
constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 10000;
constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 10000;
constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 10000;
constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
class IAppletResource final : public ServiceFramework<IAppletResource> {
public:
@@ -53,7 +53,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(shared_mem);
NGLOG_DEBUG(Service_HID, "called");
LOG_DEBUG(Service_HID, "called");
}
void LoadInputDevices() {
@@ -75,7 +75,7 @@ private:
// Set up controllers as neon red+blue Joy-Con attached to console
ControllerHeader& controller_header = mem.controllers[Controller_Handheld].header;
controller_header.type = ControllerType_Handheld | ControllerType_JoyconPair;
controller_header.type = ControllerType_Handheld;
controller_header.single_colors_descriptor = ColorDesc_ColorsNonexistent;
controller_header.right_color_body = JOYCON_BODY_NEON_RED;
controller_header.right_color_buttons = JOYCON_BUTTONS_NEON_RED;
@@ -90,19 +90,22 @@ private:
// HID shared memory stores the state of the past 17 samples in a circlular buffer,
// each with a timestamp in number of samples since boot.
const ControllerInputEntry& last_entry = layout.entries[layout.header.latest_entry];
layout.header.timestamp_ticks = CoreTiming::GetTicks();
layout.header.latest_entry = (layout.header.latest_entry + 1) % HID_NUM_ENTRIES;
ControllerInputEntry& entry = layout.entries[layout.header.latest_entry];
entry.connection_state = ConnectionState_Connected | ConnectionState_Wired;
entry.timestamp++;
entry.timestamp = last_entry.timestamp + 1;
// TODO(shinyquagsire23): Is this always identical to timestamp?
entry.timestamp_2++;
entry.timestamp_2 = entry.timestamp;
// TODO(shinyquagsire23): More than just handheld input
if (controller != Controller_Handheld)
continue;
entry.connection_state = ConnectionState_Connected | ConnectionState_Wired;
// TODO(shinyquagsire23): Set up some LUTs for each layout mapping in the future?
// For now everything is just the default handheld layout, but split Joy-Con will
// rotate the face buttons and directions for certain layouts.
@@ -262,7 +265,7 @@ private:
void ActivateVibrationDevice(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_HID, "(STUBBED) called");
LOG_WARNING(Service_HID, "(STUBBED) called");
}
};
@@ -394,144 +397,144 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IAppletResource>(applet_resource);
NGLOG_DEBUG(Service_HID, "called");
LOG_DEBUG(Service_HID, "called");
}
void ActivateDebugPad(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_HID, "(STUBBED) called");
LOG_WARNING(Service_HID, "(STUBBED) called");
}
void ActivateTouchScreen(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_HID, "(STUBBED) called");
LOG_WARNING(Service_HID, "(STUBBED) called");
}
void ActivateMouse(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_HID, "(STUBBED) called");
LOG_WARNING(Service_HID, "(STUBBED) called");
}
void ActivateKeyboard(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_HID, "(STUBBED) called");
LOG_WARNING(Service_HID, "(STUBBED) called");
}
void StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_HID, "(STUBBED) called");
LOG_WARNING(Service_HID, "(STUBBED) called");
}
void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_HID, "(STUBBED) called");
LOG_WARNING(Service_HID, "(STUBBED) called");
}
void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_HID, "(STUBBED) called");
LOG_WARNING(Service_HID, "(STUBBED) called");
}
void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0);
NGLOG_WARNING(Service_HID, "(STUBBED) called");
LOG_WARNING(Service_HID, "(STUBBED) called");
}
void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_HID, "(STUBBED) called");
LOG_WARNING(Service_HID, "(STUBBED) called");
}
void ActivateNpad(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_HID, "(STUBBED) called");
LOG_WARNING(Service_HID, "(STUBBED) called");
}
void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(event);
NGLOG_WARNING(Service_HID, "(STUBBED) called");
LOG_WARNING(Service_HID, "(STUBBED) called");
}
void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_HID, "(STUBBED) called");
LOG_WARNING(Service_HID, "(STUBBED) called");
}
void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_HID, "(STUBBED) called");
LOG_WARNING(Service_HID, "(STUBBED) called");
}
void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(joy_hold_type);
NGLOG_WARNING(Service_HID, "(STUBBED) called");
LOG_WARNING(Service_HID, "(STUBBED) called");
}
void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_HID, "(STUBBED) called");
LOG_WARNING(Service_HID, "(STUBBED) called");
}
void SendVibrationValue(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_HID, "(STUBBED) called");
LOG_WARNING(Service_HID, "(STUBBED) called");
}
void GetActualVibrationValue(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_HID, "(STUBBED) called");
LOG_WARNING(Service_HID, "(STUBBED) called");
}
void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_HID, "(STUBBED) called");
LOG_WARNING(Service_HID, "(STUBBED) called");
}
void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_HID, "(STUBBED) called");
LOG_WARNING(Service_HID, "(STUBBED) called");
}
void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(0);
NGLOG_WARNING(Service_HID, "(STUBBED) called");
LOG_WARNING(Service_HID, "(STUBBED) called");
}
void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IActiveVibrationDeviceList>();
NGLOG_DEBUG(Service_HID, "called");
LOG_DEBUG(Service_HID, "called");
}
void SendVibrationValues(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_HID, "(STUBBED) called");
LOG_WARNING(Service_HID, "(STUBBED) called");
}
};

View File

@@ -12,7 +12,7 @@ namespace Service::HID {
// Begin enums and output structs
constexpr u32 HID_NUM_ENTRIES = 17;
constexpr u32 HID_NUM_LAYOUTS = 2;
constexpr u32 HID_NUM_LAYOUTS = 7;
constexpr s32 HID_JOYSTICK_MAX = 0x8000;
constexpr s32 HID_JOYSTICK_MIN = -0x8000;

View File

@@ -141,19 +141,19 @@ private:
if (header.IsTailLog()) {
switch (header.severity) {
case MessageHeader::Severity::Trace:
NGLOG_TRACE(Debug_Emulated, "{}", log_stream.str());
LOG_TRACE(Debug_Emulated, "{}", log_stream.str());
break;
case MessageHeader::Severity::Info:
NGLOG_INFO(Debug_Emulated, "{}", log_stream.str());
LOG_INFO(Debug_Emulated, "{}", log_stream.str());
break;
case MessageHeader::Severity::Warning:
NGLOG_WARNING(Debug_Emulated, "{}", log_stream.str());
LOG_WARNING(Debug_Emulated, "{}", log_stream.str());
break;
case MessageHeader::Severity::Error:
NGLOG_ERROR(Debug_Emulated, "{}", log_stream.str());
LOG_ERROR(Debug_Emulated, "{}", log_stream.str());
break;
case MessageHeader::Severity::Critical:
NGLOG_CRITICAL(Debug_Emulated, "{}", log_stream.str());
LOG_CRITICAL(Debug_Emulated, "{}", log_stream.str());
break;
}
}
@@ -178,7 +178,7 @@ void LM::Initialize(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<Logger>();
NGLOG_DEBUG(Service_LM, "called");
LOG_DEBUG(Service_LM, "called");
}
LM::LM() : ServiceFramework("lm") {

View File

@@ -0,0 +1,50 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/service/mm/mm_u.h"
namespace Service::MM {
void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<MM_U>()->InstallAsService(service_manager);
}
void MM_U::Initialize(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_MM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void MM_U::SetAndWait(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
min = rp.Pop<u32>();
max = rp.Pop<u32>();
current = min;
LOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void MM_U::Get(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_MM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(current);
}
MM_U::MM_U() : ServiceFramework("mm:u") {
static const FunctionInfo functions[] = {
{0, nullptr, "InitializeOld"}, {1, nullptr, "FinalizeOld"},
{2, nullptr, "SetAndWaitOld"}, {3, nullptr, "GetOld"},
{4, &MM_U::Initialize, "Initialize"}, {5, nullptr, "Finalize"},
{6, &MM_U::SetAndWait, "SetAndWait"}, {7, &MM_U::Get, "Get"},
};
RegisterHandlers(functions);
}
} // namespace Service::MM

View File

@@ -0,0 +1,29 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/hle/service/service.h"
namespace Service::MM {
class MM_U final : public ServiceFramework<MM_U> {
public:
MM_U();
~MM_U() = default;
private:
void Initialize(Kernel::HLERequestContext& ctx);
void SetAndWait(Kernel::HLERequestContext& ctx);
void Get(Kernel::HLERequestContext& ctx);
u32 min{0};
u32 max{0};
u32 current{0};
};
/// Registers all MM services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
} // namespace Service::MM

View File

@@ -4,6 +4,8 @@
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/event.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/nfp/nfp.h"
#include "core/hle/service/nfp/nfp_user.h"
@@ -18,7 +20,7 @@ public:
static const FunctionInfo functions[] = {
{0, &IUser::Initialize, "Initialize"},
{1, nullptr, "Finalize"},
{2, nullptr, "ListDevices"},
{2, &IUser::ListDevices, "ListDevices"},
{3, nullptr, "StartDetection"},
{4, nullptr, "StopDetection"},
{5, nullptr, "Mount"},
@@ -33,28 +35,120 @@ public:
{14, nullptr, "GetRegisterInfo"},
{15, nullptr, "GetCommonInfo"},
{16, nullptr, "GetModelInfo"},
{17, nullptr, "AttachActivateEvent"},
{18, nullptr, "AttachDeactivateEvent"},
{19, nullptr, "GetState"},
{20, nullptr, "GetDeviceState"},
{21, nullptr, "GetNpadId"},
{17, &IUser::AttachActivateEvent, "AttachActivateEvent"},
{18, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"},
{19, &IUser::GetState, "GetState"},
{20, &IUser::GetDeviceState, "GetDeviceState"},
{21, &IUser::GetNpadId, "GetNpadId"},
{22, nullptr, "GetApplicationArea2"},
{23, nullptr, "AttachAvailabilityChangeEvent"},
{23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
{24, nullptr, "RecreateApplicationArea"},
};
RegisterHandlers(functions);
activate_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "IUser:ActivateEvent");
deactivate_event =
Kernel::Event::Create(Kernel::ResetType::OneShot, "IUser:DeactivateEvent");
availability_change_event =
Kernel::Event::Create(Kernel::ResetType::OneShot, "IUser:AvailabilityChangeEvent");
}
private:
enum class State : u32 {
NonInitialized = 0,
Initialized = 1,
};
enum class DeviceState : u32 {
Initialized = 0,
};
void Initialize(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_NFP, "(STUBBED) called");
LOG_WARNING(Service_NFP, "(STUBBED) called");
state = State::Initialized;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void ListDevices(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 array_size = rp.Pop<u32>();
ctx.WriteBuffer(&device_handle, sizeof(device_handle));
LOG_WARNING(Service_NFP, "(STUBBED) called, array_size={}", array_size);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0);
}
void AttachActivateEvent(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 dev_handle = rp.Pop<u64>();
LOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle);
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(activate_event);
}
void AttachDeactivateEvent(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 dev_handle = rp.Pop<u64>();
LOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle);
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(deactivate_event);
}
void GetState(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NFP, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(static_cast<u32>(state));
}
void GetDeviceState(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NFP, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(static_cast<u32>(device_state));
}
void GetNpadId(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 dev_handle = rp.Pop<u64>();
LOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(npad_id);
}
void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 dev_handle = rp.Pop<u64>();
LOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle);
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(availability_change_event);
}
const u64 device_handle{0xDEAD};
const HID::ControllerID npad_id{HID::Controller_Player1};
State state{State::NonInitialized};
DeviceState device_state{DeviceState::Initialized};
Kernel::SharedPtr<Kernel::Event> activate_event;
Kernel::SharedPtr<Kernel::Event> deactivate_event;
Kernel::SharedPtr<Kernel::Event> availability_change_event;
};
void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
NGLOG_DEBUG(Service_NFP, "called");
LOG_DEBUG(Service_NFP, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IUser>();

View File

@@ -38,7 +38,7 @@ public:
{8, nullptr, "SetPriority"},
{9, nullptr, "SetNetworkProfileId"},
{10, nullptr, "SetRejectable"},
{11, nullptr, "SetConnectionConfirmationOption"},
{11, &IRequest::SetConnectionConfirmationOption, "SetConnectionConfirmationOption"},
{12, nullptr, "SetPersistent"},
{13, nullptr, "SetInstant"},
{14, nullptr, "SetSustainable"},
@@ -62,24 +62,33 @@ public:
private:
void GetRequestState(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_NIFM, "(STUBBED) called");
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0);
}
void GetResult(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_NIFM, "(STUBBED) called");
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_NIFM, "(STUBBED) called");
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 2};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(event1, event2);
}
void Cancel(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_NIFM, "(STUBBED) called");
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void SetConnectionConfirmationOption(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
@@ -105,7 +114,7 @@ public:
private:
void GetClientId(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_NIFM, "(STUBBED) called");
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(0);
@@ -116,7 +125,7 @@ private:
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IScanRequest>();
NGLOG_DEBUG(Service_NIFM, "called");
LOG_DEBUG(Service_NIFM, "called");
}
void CreateRequest(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -124,10 +133,10 @@ private:
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IRequest>();
NGLOG_DEBUG(Service_NIFM, "called");
LOG_DEBUG(Service_NIFM, "called");
}
void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_NIFM, "(STUBBED) called");
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
@@ -137,7 +146,25 @@ private:
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<INetworkProfile>();
NGLOG_DEBUG(Service_NIFM, "called");
LOG_DEBUG(Service_NIFM, "called");
}
void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u8>(0);
}
void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u8>(0);
}
void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u8>(0);
}
};
@@ -158,11 +185,11 @@ IGeneralService::IGeneralService() : ServiceFramework("IGeneralService") {
{14, &IGeneralService::CreateTemporaryNetworkProfile, "CreateTemporaryNetworkProfile"},
{15, nullptr, "GetCurrentIpConfigInfo"},
{16, nullptr, "SetWirelessCommunicationEnabled"},
{17, nullptr, "IsWirelessCommunicationEnabled"},
{17, &IGeneralService::IsWirelessCommunicationEnabled, "IsWirelessCommunicationEnabled"},
{18, nullptr, "GetInternetConnectionStatus"},
{19, nullptr, "SetEthernetCommunicationEnabled"},
{20, nullptr, "IsEthernetCommunicationEnabled"},
{21, nullptr, "IsAnyInternetRequestAccepted"},
{20, &IGeneralService::IsEthernetCommunicationEnabled, "IsEthernetCommunicationEnabled"},
{21, &IGeneralService::IsAnyInternetRequestAccepted, "IsAnyInternetRequestAccepted"},
{22, nullptr, "IsAnyForegroundRequestAccepted"},
{23, nullptr, "PutToSleep"},
{24, nullptr, "WakeUp"},
@@ -187,14 +214,14 @@ void Module::Interface::CreateGeneralServiceOld(Kernel::HLERequestContext& ctx)
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IGeneralService>();
NGLOG_DEBUG(Service_NIFM, "called");
LOG_DEBUG(Service_NIFM, "called");
}
void Module::Interface::CreateGeneralService(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IGeneralService>();
NGLOG_DEBUG(Service_NIFM, "called");
LOG_DEBUG(Service_NIFM, "called");
}
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)

View File

@@ -52,7 +52,7 @@ PL_U::PL_U() : ServiceFramework("pl:u") {
ASSERT(file.GetSize() == SHARED_FONT_MEM_SIZE);
file.ReadBytes(shared_font->data(), shared_font->size());
} else {
NGLOG_WARNING(Service_NS, "Unable to load shared font: {}", filepath);
LOG_WARNING(Service_NS, "Unable to load shared font: {}", filepath);
}
}
@@ -60,7 +60,7 @@ void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 shared_font_type{rp.Pop<u32>()};
NGLOG_DEBUG(Service_NS, "called, shared_font_type={}", shared_font_type);
LOG_DEBUG(Service_NS, "called, shared_font_type={}", shared_font_type);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
@@ -69,7 +69,7 @@ void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 font_id{rp.Pop<u32>()};
NGLOG_DEBUG(Service_NS, "called, font_id={}", font_id);
LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(static_cast<u32>(LoadState::Done));
@@ -79,7 +79,7 @@ void PL_U::GetSize(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 font_id{rp.Pop<u32>()};
NGLOG_DEBUG(Service_NS, "called, font_id={}", font_id);
LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(SHARED_FONT_REGIONS[font_id].size);
@@ -89,7 +89,7 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 font_id{rp.Pop<u32>()};
NGLOG_DEBUG(Service_NS, "called, font_id={}", font_id);
LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(SHARED_FONT_REGIONS[font_id].offset);
@@ -110,7 +110,7 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE,
"PL_U:shared_font_mem");
NGLOG_DEBUG(Service_NS, "called");
LOG_DEBUG(Service_NS, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(shared_font_mem);
@@ -119,7 +119,7 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 language_code{rp.Pop<u64>()}; // TODO(ogniK): Find out what this is used for
NGLOG_DEBUG(Service_NS, "called, language_code=%lx", language_code);
LOG_DEBUG(Service_NS, "called, language_code=%lx", language_code);
IPC::ResponseBuilder rb{ctx, 4};
std::vector<u32> font_codes;
std::vector<u32> font_offsets;

View File

@@ -18,15 +18,17 @@ u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, std::vector
}
void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height,
u32 stride, NVFlinger::BufferQueue::BufferTransformFlags transform) {
u32 stride, NVFlinger::BufferQueue::BufferTransformFlags transform,
const MathUtil::Rectangle<int>& crop_rect) {
VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle);
NGLOG_WARNING(Service,
"Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}",
addr, offset, width, height, stride, format);
LOG_WARNING(Service,
"Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}",
addr, offset, width, height, stride, format);
using PixelFormat = Tegra::FramebufferConfig::PixelFormat;
const Tegra::FramebufferConfig framebuffer{
addr, offset, width, height, stride, static_cast<PixelFormat>(format), transform};
addr, offset, width, height, stride, static_cast<PixelFormat>(format),
transform, crop_rect};
Core::System::GetInstance().perf_stats.EndGameFrame();

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