Compare commits

...

753 Commits

Author SHA1 Message Date
kmather73
b56dcacf2d Merge branch 'master' of https://github.com/yuzu-emu/yuzu into u/kemathe/GPU-puller 2018-12-28 18:04:21 -08:00
bunnei
8495f1df2a Merge pull request #1955 from bunnei/g8r8-fix
gpu: Remove PixelFormat G8R8U and G8R8S, as they do not seem to exist.
2018-12-28 20:23:57 -05:00
kmather73
d0600bc029 Fix clang error 2018-12-28 15:45:51 -08:00
kmather73
574ce43406 Set up the regs and regs_assert_positions up properly 2018-12-28 15:41:31 -08:00
bunnei
2020ba06e1 gpu: Remove PixelFormat G8R8U and G8R8S, as they do not seem to exist.
- Fixes UI rendering issues in The Legend of Zelda: Breath of the Wild.
2018-12-28 15:36:45 -05:00
bunnei
af9336df57 Merge pull request #1958 from lioncash/audio
audio_core: Convert LOG_CRITICAL + UNREACHABLE over to UNIMPLEMENTED/UNIMPLEMENTED_MSG
2018-12-28 15:32:41 -05:00
Lioncash
a73c7c73eb audio_core: Convert LOG_CRITICAL + UNREACHABLE over to UNIMPLEMENTED/UNIMPLEMENTED_MSG
These two macros being used in tandem were used prior to the
introduction of UNIMPLEMENTED and UNIMPLEMENTED_MSG. This provides
equivalent behavior, just with less typing/reading involved.
2018-12-28 14:13:58 -05:00
kmather73
624f21f859 Remove local var 2018-12-28 00:41:42 -08:00
kmather73
08b484b11e union magic refcnt as well 2018-12-28 00:23:19 -08:00
kmather73
6574bbbbda More union magic for setting regs value. 2018-12-28 00:13:49 -08:00
kmather73
b1339327a9 Removing unused funcitons and other pr comment 2018-12-27 23:13:24 -08:00
kmather73
459dcffee7 Removing unused funcitons and other pr comment 2018-12-27 21:01:29 -08:00
bunnei
19bfbb28ce Merge pull request #1954 from lioncash/npdm
file_sys/program_metadata: Print out more descriptive address space descriptions
2018-12-27 19:58:36 -05:00
bunnei
357bc956ae Merge pull request #1953 from lioncash/mem
kernel/process: Remove most allocation functions from Process' interface
2018-12-27 19:57:51 -05:00
Lioncash
9aa68212d9 file_sys/program_metadata: Print out more descriptive address space descriptions
Provides extra information that makes it easier to tell if an executable
being run is using a 36-bit address space or a 39-bit address space.
While we don't support AArch32 executables yet, this also puts in
distinguishing information for the 32-bit address space types as well.
2018-12-27 19:16:45 -05:00
Lioncash
fbeaa330a3 kernel/process: Remove most allocation functions from Process' interface
In all cases that these functions are needed, the VMManager can just be
retrieved and used instead of providing the same functions in Process'
interface.

This also makes it a little nicer dependency-wise, since it gets rid of
cases where the VMManager interface was being used, and then switched
over to using the interface for a Process instance. Instead, it makes
all accesses uniform and uses the VMManager instance for all necessary
tasks.

All the basic memory mapping functions did was forward to the Process'
VMManager instance anyways.
2018-12-27 19:08:47 -05:00
bunnei
e84e4fd3f8 Merge pull request #1951 from Tinob/master
Add missing uintBitsToFloat to SetRegisterToHalfFloat
2018-12-27 13:55:21 -05:00
Rodolfo Bogado
fbe900ba6d Add missing uintBitsToFloat to SetRegisterToHalfFloat 2018-12-27 14:39:10 -03:00
bunnei
795335af0f Merge pull request #1928 from lioncash/caps
kernel: Handle kernel capability descriptors
2018-12-27 11:15:34 -05:00
bunnei
fa9acc26d9 Merge pull request #1892 from Tinob/master
Improve Zero flag implementation
2018-12-27 11:06:59 -05:00
bunnei
8e23e40a72 Merge pull request #1929 from bunnei/fix-hid
hid: Fix SetNpadJoyHoldType and improve logging.
2018-12-27 11:04:56 -05:00
bunnei
2991c747c9 Merge pull request #1945 from bunnei/fix-hid-horiz
npad: Remove code to invert input in horizontal mode.
2018-12-27 11:04:40 -05:00
bunnei
7477c12fe2 Merge pull request #1949 from lioncash/unmap
kernel/vm_manager: Reset region attributes when unmapping a VMA
2018-12-27 11:04:26 -05:00
bunnei
c4515d305b Merge pull request #1879 from DarkLordZach/am-save-data-size
am: Implement GetSaveDataSize and ExtendSaveData using files
2018-12-27 11:04:05 -05:00
Zach Hilman
c643f364b4 am: Implement GetSaveDataSize and ExtendSaveData
These functions come in a pair and are needed by Smash Ultimate, Minecraft, and Skyrim, amongst others.
2018-12-27 00:18:00 -05:00
Zach Hilman
2e6b67a079 filesystem: Populate save data sizes from control data 2018-12-27 00:18:00 -05:00
Zach Hilman
4082c4eda6 savedata_factory: Partially implement IVFC save sizes using files
This stores a file in the save directory called '.yuzu_save_size' which stores the two save sizes (normal area and journaled area) sequentially as u64s.
2018-12-27 00:18:00 -05:00
Zach Hilman
0756f29a2c loader: Add accessor for game control data 2018-12-27 00:16:55 -05:00
Zach Hilman
417e1ef09c control_metadata: Update NACP fields with latest Switchbrew data 2018-12-27 00:16:55 -05:00
Zach Hilman
5c4259ec1a control_metadata: Use value member instead of unique_ptr to store struct
Serves no actual purpose in this instance besides making NACP's copy assignment deleted, which is not intended behavior.
2018-12-27 00:16:55 -05:00
Zach Hilman
4a6ba58073 vfs: Add reinterpret_casts to WriteArray and Object
Allows these functions to compile when T is not u8.
2018-12-27 00:16:55 -05:00
bunnei
73c9ffc422 Merge pull request #1946 from lioncash/decl
renderer_opengl: Correct forward declaration of FramebufferLayout
2018-12-26 20:39:54 -05:00
bunnei
17fa0ffff9 Merge pull request #1948 from lioncash/translatable
configure_per_general: Mark UI strings as translatable in the constructor
2018-12-26 20:39:30 -05:00
Lioncash
1392597ede kernel/vm_manager: Reset region attributes when unmapping a VMA
Like the other members related to memory regions, the attributes need to
be reset back to their defaults as well.
2018-12-26 20:15:29 -05:00
kmather73
1ddb570250 White space clang error 2018-12-26 17:06:46 -08:00
kmather73
9cb18798be Fix clang style issues 2018-12-26 15:14:24 -08:00
bunnei
c9269a4a4b Merge pull request #1947 from lioncash/init
configure_input_simple: Make input profile array constexpr
2018-12-26 18:10:56 -05:00
kmather73
ca9203b847 Updated to use Memory::WriteBlock instead of Memory::Write* 2018-12-26 15:10:37 -08:00
Lioncash
0c18d47348 configure_per_general: Mark UI strings as translatable in the constructor
These are user-facing strings, so they should be translatable.
2018-12-26 17:45:15 -05:00
Lioncash
faa9110541 configure_input_simple: Make input profile array constexpr
Calling tr() from a file-scope array isn't advisable, since it can be
executed before the Qt libraries are even fully initialized, which can
lead to crashes.

Instead, the translatable strings should be annotated, and the tr()
function should be called at the string's usage site.
2018-12-26 17:36:36 -05:00
Lioncash
67fa21e143 renderer_opengl: Correct forward declaration of FramebufferLayout
This is actually a struct, not a class, which can lead to compilation
warnings.
2018-12-26 17:32:32 -05:00
kmather73
a6b8baaff3 Move puller members into the regs union 2018-12-26 14:26:50 -08:00
Rodolfo Bogado
33056dd833 Apply CC test to the final value to be stored in the register 2018-12-26 18:16:31 -03:00
David
8047873a66 Fixed shader linking error due to TLDS (#1934)
* Fixed shader linking error due to TLDS

coord should be coords

* Fix remaining coords
2018-12-26 15:55:39 -05:00
bunnei
ae582b6669 Merge pull request #1849 from encounter/svcSetThreadActivity
svc: Implement SetThreadActivity (thread suspension)
2018-12-26 15:54:14 -05:00
bunnei
46b8b03015 Merge pull request #1943 from ReinUsesLisp/fixup-texs
shader_bytecode: Fixup TEXS.F16 encoding
2018-12-26 15:49:41 -05:00
bunnei
7e622c5575 npad: Remove code to invert input in horizontal mode.
- This was incorrect, the game appears to handle this for us.
- Fixes horizontal mode with Puyo Puyo Tetris and Super Mario Odyssey.
2018-12-26 15:47:11 -05:00
ReinUsesLisp
aaa0e6c346 shader_bytecode: Fixup TEXS.F16 encoding 2018-12-26 01:35:44 -03:00
bunnei
9a22a94a51 Merge pull request #1886 from FearlessTobi/port-4164
Port citra-emu/citra#4164: "citra_qt, video_core: Screenshot functionality"
2018-12-23 14:36:51 -05:00
bunnei
52726342bd Merge pull request #1930 from lioncash/common
common/quaternion: Ensure that w is always initialized
2018-12-23 14:35:29 -05:00
bunnei
f95f6c7d86 Merge pull request #1781 from DarkLordZach/applet-profile-select
am: Implement HLE profile selector applet
2018-12-23 14:35:13 -05:00
bunnei
d08bdc861f Merge pull request #1780 from DarkLordZach/controller-profiles
configure_input: Add Controller Setup Profiles and simplify input UI
2018-12-23 14:34:29 -05:00
Rodolfo Bogado
bbf8d6bf01 Includde saturation in the evaluation of the control code 2018-12-22 19:19:18 -03:00
Rodolfo Bogado
946777601b Handle RZ cases evaluating the expression instead of the register value. 2018-12-22 19:19:18 -03:00
Rodolfo Bogado
7e72b5e453 complete emulation of ZeroFlag 2018-12-22 19:19:18 -03:00
Lioncash
acddf16e57 common/quaternion: Ensure that w is always initialized
Previously xyz was always being zero initialized due to its constructor,
but w wasn't. Ensures that we always have a deterministic initial state.
2018-12-21 15:25:31 -05:00
bunnei
e75e8b9580 Merge pull request #1921 from ogniK5377/no-unit
Fixed uninitialized memory due to missing returns in canary
2018-12-21 14:12:54 -05:00
bunnei
42427b9c7a Merge pull request #1920 from heapo/texture_format_selection
Texture format fixes for RGBA16UI for copies and R16U when used as depth
2018-12-21 13:46:17 -05:00
bunnei
59ac3346eb Merge pull request #1925 from lioncash/pid
kernel/{process, thread}: Amend behavior related to IDs
2018-12-21 13:45:27 -05:00
bunnei
41cbd088c2 Merge pull request #1914 from lioncash/id
service/am: Unstub GetAppletResourceUserId
2018-12-21 13:43:51 -05:00
bunnei
1120e0b4d2 hid: Fix SetNpadJoyHoldType and improve logging. 2018-12-21 13:37:39 -05:00
Lioncash
002ae08bbd kernel/process: Hook up the process capability parser to the process itself
While we're at it, we can also toss out the leftover capability parsing
from Citra.
2018-12-21 07:05:34 -05:00
Lioncash
d09fb82113 kernel/process_capability: Handle debug capability flags 2018-12-21 07:05:34 -05:00
Lioncash
10824c5d63 kernel/process_capability: Handle handle table capability flags
This just specifies the handle table size. There's also a section of
reserved bits that are checked against.
2018-12-21 07:05:34 -05:00
Lioncash
e0e84aede0 kernel/process_capability: Handle kernel version capability flags 2018-12-21 07:05:34 -05:00
Lioncash
010bc677f3 kernel/process_capability: Handle program capability flags 2018-12-21 07:05:34 -05:00
Lioncash
0f216d20e3 kernel/process_capability: Handle interrupt capability flags
Similar to the service capability flags, however, we currently don't
emulate the GIC, so this currently handles all interrupts as being valid
for the time being.
2018-12-21 07:05:34 -05:00
Lioncash
3dc59b74ec kernel/process_capability: Handle syscall capability flags 2018-12-21 07:05:34 -05:00
Lioncash
27caf71204 kernel/process_capability: Handle the priority mask and core mask flags
Handles the priority mask and core mask flags to allow building up the
masks to determine the usable thread priorities and cores for a kernel
process instance.
2018-12-21 07:05:34 -05:00
Lioncash
6ff5135521 kernel/process: Introduce process capability parsing skeleton
We've had the old kernel capability parser from Citra, however, this is
unused code and doesn't actually map to how the kernel on the Switch
does it. This introduces the basic functional skeleton for parsing
process capabilities.
2018-12-21 07:05:31 -05:00
Lioncash
fc8da2d5e3 common: Add basic bit manipulation utility function to Common 2018-12-21 07:04:18 -05:00
bunnei
4923df10cc Merge pull request #1923 from ogniK5377/nfp-device-list
Device handle should not be a random id, instead it's the current npad id
2018-12-19 13:14:43 -05:00
bunnei
3050f3a7ba Merge pull request #1909 from heapo/shadow_sampling_fixes
Fix arrayed texture LOD selection and depth comparison ordering
2018-12-19 13:10:37 -05:00
bunnei
80d36634e1 Merge pull request #1915 from lioncash/sm
service/sm: Improve debug log for RegisterService
2018-12-19 13:10:11 -05:00
Lioncash
b74eb88c68 kernel/svc: Handle thread handles within GetProcessId
If a thread handle is passed to svcGetProcessId, the kernel attempts to
access the process ID via the thread's instance's owning process.

Technically, this function should also be handling the kernel debug
objects as well, however we currently don't handle those kernel objects
yet, so I've left a note via a comment about it to remind myself when
implementing it in the future.
2018-12-19 12:16:15 -05:00
bunnei
e73dd39413 Merge pull request #1907 from lioncash/attribute
kernel/svc: Implement svcSetMemoryAttribute
2018-12-19 11:50:50 -05:00
Lioncash
caab838bdb svc: Implement svcSetMemoryAttribute
With all the basic backing functionality implemented, we can now unstub
svcSetMemoryAttribute.
2018-12-19 10:59:40 -05:00
Lioncash
622242e345 vm_manager: Add member function for setting memory attributes across an address range
This puts the backing functionality for svcSetMemoryAttribute in place,
which will be utilized in a following change.
2018-12-19 10:59:40 -05:00
Lioncash
603cc72168 vm_manager: Add member function for checking a memory range adheres to certain attributes, permissions and states 2018-12-19 10:59:36 -05:00
Lioncash
62d4377053 kernel/kernel: Use correct initial PID for userland Process instances
Starts the process ID counter off at 81, which is what the kernel itself
checks against internally when creating processes. It's actually
supposed to panic if the PID is less than 81 for a userland process.
2018-12-18 22:54:01 -05:00
Lioncash
0906302ca9 kernel/svc: Correct output parameter for svcGetThreadId
The service call uses a 64-bit value, just like svcGetProcessId. This
amends the function signature accordingly.
2018-12-18 22:38:26 -05:00
Lioncash
8435451093 kernel/thread: Make thread_id a 64-bit value
The kernel uses a 64-bit value for the thread ID, so we shouldn't be
using a 32-bit value.
2018-12-18 22:37:03 -05:00
Lioncash
43e1189688 kernel/svc: Correct output parameter for svcGetProcessId
svcGetProcessId's out parameter is a pointer to a 64-bit value, not a
32-bit one.
2018-12-18 22:30:56 -05:00
Lioncash
9b3a38e3d3 kernel/process: Make process_id a 64-bit value
In the actual kernel, this is a 64-bit value, so we shouldn't be using a
32-bit type to handle it.
2018-12-18 22:28:55 -05:00
David Marcec
807e7640aa Device handle should not be a random id, instead it's the current npad id
Found during hardware testing
2018-12-19 14:16:30 +11:00
David Marcec
20859802f0 hopefully fix clang format issue 2018-12-19 13:22:09 +11:00
David Marcec
fdd649e2ef Fixed uninitialized memory due to missing returns in canary
Functions which are suppose to crash on non canary builds usually don't return anything which lead to uninitialized memory being used.
2018-12-19 12:52:32 +11:00
Lioncash
2a533f0067 service/sm: Improve debug log for RegisterService
Now it also indicates the name and max session count. This also gives a
name to the unknown bool. This indicates if the created port is supposed
to be using light handles or regular handles internally. This is passed
to the respective svcCreatePort parameter internally.
2018-12-18 18:22:22 -05:00
zhupengfei
a2be49305d yuzu, video_core: Screenshot functionality
Allows capturing screenshot at the current internal resolution (native for software renderer), but a setting is available to capture it in other resolutions. The screenshot is saved to a single PNG in the current layout.
2018-12-18 22:54:41 +01:00
heapo
37280cf555 Texture format fixes: Flag RGBA16UI as GL_RGBA_INTEGER format, and interpret R16U as Z16 when depth_compare is enabled. 2018-12-18 11:34:51 -08:00
bunnei
39262921f2 Merge pull request #1913 from MerryMage/default-fpcr
kernel/thread: Set default fpcr
2018-12-18 14:13:57 -05:00
bunnei
5bae002aaa Merge pull request #1918 from MerryMage/cntfrq
arm_dynarmic: Set CNTFRQ value
2018-12-18 14:13:35 -05:00
MerryMage
eef6ce79a9 kernel/thread: Set default fpcr 2018-12-18 17:37:03 +00:00
MerryMage
fd2c42bfcd arm_dynarmic: Set CNTFRQ value 2018-12-18 17:28:12 +00:00
bunnei
325dcf2881 Merge pull request #1917 from ReinUsesLisp/fixup-half
shader_bytecode: Fixup half float's operator B encoding
2018-12-18 10:45:58 -05:00
bunnei
116e6247ce Merge pull request #1889 from DarkLordZach/swkbd-state-changed
applets: Correct usage of SignalStateChanged event
2018-12-18 09:59:27 -05:00
ReinUsesLisp
ef061481c5 shader_bytecode: Fixup half float's operator B encoding 2018-12-18 04:28:50 -03:00
bunnei
95255899e7 Merge pull request #1903 from heapo/fmul_postfactor
Implement postfactor multiplication/division for fmul instructions
2018-12-17 22:00:43 -05:00
Lioncash
dd272298aa service/am: Unstub GetAppletResourceUserId
This is supposed to return the current process' ID. (0 indicates an
invalid ID for both process IDs and ARU IDs).
2018-12-17 21:01:14 -05:00
heapo
72599cc667 Implement postfactor multiplication/division for fmul instructions 2018-12-17 07:56:25 -08:00
heapo
a6daed74f5 Fix arrayed shadow sampler array slice/depth comparison ordering, as well as invalid GLSL LOD selection. 2018-12-17 07:53:48 -08:00
kmather73
3e84c12de4 two more white spaces for the Clang formatting. 2018-12-16 23:37:55 -08:00
kmather73
f13c6a480a More clang formatting. 2018-12-16 23:32:17 -08:00
kmather73
e90c0a41a6 Fix the clang-format issues. 2018-12-16 23:21:50 -08:00
kmather73
3446f72f08 Forgot to remove GpuSmaphoreAddress union. 2018-12-16 18:57:08 -08:00
kmather73
2f7712ebc2 Update for comments. Added ReferenceCount method 2018-12-16 18:45:07 -08:00
kmather73
43a8354eaa Fix style. 2018-12-16 01:48:18 -08:00
kmather73
5ce2f715ce Nit: Add Break to default case. 2018-12-16 01:15:20 -08:00
kmather73
73708f4582 Nit: Fix 2 style issues 2018-12-16 01:08:49 -08:00
kmather73
7ff68f6588 Implemented the puller semaphore operations. 2018-12-16 00:59:57 -08:00
Lioncash
4dc8a7da3f vm_manager: Rename meminfo_state to state
This is shorter and more concise. This also removes the now-innaccurate
comment, as it's not returned wholesale to svcQueryMemory anymore.
2018-12-15 19:43:36 -05:00
Lioncash
34b24a47e9 vm_manager: Add backing functionality for memory attributes
Adds the barebones enumeration constants and functions in place to
handle memory attributes, while also essentially leaving the attribute
itself non-functional.
2018-12-15 19:43:32 -05:00
bunnei
84823a3036 Merge pull request #1905 from bunnei/ignore-empty-gpu-lists
nvhost_gpu: Skip empty GPU command lists.
2018-12-15 00:35:33 -05:00
bunnei
040d84d816 nvhost_gpu: Skip empty GPU command lists. 2018-12-15 00:33:22 -05:00
bunnei
d1603a0abb Merge pull request #1901 from jschmer/ServiceLeak
Fix Service object leak on emulation stop
2018-12-15 00:30:10 -05:00
bunnei
2f2fc47af2 Merge pull request #1732 from DarkLordZach/yield-types
svc: Implement yield types 0 and -1
2018-12-15 00:28:12 -05:00
bunnei
b88430c299 Merge pull request #1902 from lioncash/audio
audio_core: Make g_sink_details internally linked
2018-12-14 21:48:17 -05:00
bunnei
1a23970d17 Merge pull request #1899 from lioncash/state
vm_manager/svc: Modify MemoryState enum, and correct error handling for svcQueryMemory
2018-12-14 15:30:02 -05:00
bunnei
7d39b19edc Merge pull request #1871 from lioncash/move
yuzu/wait_tree: Pass QString by value and std::move in the initializer list for WaitTreeText
2018-12-14 13:13:32 -05:00
bunnei
1006df7fc1 Merge pull request #1900 from lioncash/wrapper
svc_wrap: Correct register index for a wrapper specialization
2018-12-14 13:12:55 -05:00
Lioncash
6beb823f15 audio_core: Make g_sink_details internally linked
We can hide the direct array from external view and instead provide
functions to retrieve the necessary info. This has the benefit of
completely hiding the makeup of the SinkDetails structure from the rest
of the code.

Given that this makes the array hidden, we can also make the array
constexpr by altering the members slightly. This gets rid of several
static constructor calls related to std::vector and std::function.

Now we don't have heap allocations here that need to occur before the
program can even enter main(). It also has the benefit of saving a
little bit of heap space, but this doesn't matter too much, since the
savings in that regard are pretty tiny.
2018-12-13 16:44:32 -05:00
Jens Schmer
27a9cc2e63 Fix Service object leak on emulation stop
Services created with the ServiceFramework base class install themselves as HleHandlers with an owning shared_ptr in the ServerPort ServiceFrameworkBase::port member variable, creating a cyclic ownership between ServiceFrameworkBase and the ServerPort, preventing deletion of the service objects.

Fix that by removing the ServiceFrameworkBase::port member because that was only used to detect multiple attempts at installing a port. Instead store a flag if the port was already installed to achieve the same functionality.
2018-12-13 20:08:23 +01:00
Mat M
700075beb6 Merge pull request #1890 from jschmer/master
Fix Process object leak on emulation stop
2018-12-12 16:24:23 -05:00
Lioncash
b79f086613 svc: Enable svcQueryProcessMemory
svcQueryProcessMemory is trivial to implement, given all the behavior
necessary for it is present, it just needs a handler for it.
2018-12-12 15:45:05 -05:00
Lioncash
09a219d5b4 svc: Write out the complete MemoryInfo structure in QueryProcessMemory
In the previous change, the memory writing was moved into the service
function itself, however it still had a problem, in that the entire
MemoryInfo structure wasn't being written out, only the first 32 bytes
of it were being written out. We still need to write out the trailing
two reference count members and zero out the padding bits.

Not doing this can result in wrong behavior in userland code in the following
scenario:

MemoryInfo info;                 // Put on the stack, not quaranteed to be zeroed out.
svcQueryMemory(&info, ...);

if (info.device_refcount == ...) // Whoops, uninitialized read.

This can also cause the wrong thing to happen if the user code uses
std::memcmp to compare the struct, with another one (questionable, but
allowed), as the padding bits are not guaranteed to be a deterministic
value. Note that the kernel itself also fully zeroes out the structure
before writing it out including the padding bits.
2018-12-12 15:44:58 -05:00
Lioncash
d8deb39b83 svc: Handle memory writing explicitly within QueryProcessMemory
Moves the memory writes directly into QueryProcessMemory instead of
letting the wrapper function do it. It would be inaccurate to allow the
handler to do it because there's cases where memory shouldn't even be
written to. For example, if the given process handle is invalid.

HOWEVER, if the memory writing is within the wrapper, then we have no
control over if these memory writes occur, meaning in an error case, 68
bytes of memory randomly get trashed with zeroes, 64 of those being
written to wherever the memory info address points to, and the remaining
4 being written wherever the page info address points to.

One solution in this case would be to just conditionally check within
the handler itself, but this is kind of smelly, given the handler
shouldn't be performing conditional behavior itself, it's a behavior of
the managed function. In other words, if you remove the handler from the
equation entirely, does the function still retain its proper behavior?
In this case, no.

Now, we don't potentially trash memory from this function if an invalid
query is performed.
2018-12-12 15:43:31 -05:00
Lioncash
b1b855c5d9 vm_manager: Correct ordering of last two struct members of MemoryInfo
These should be swapped.
2018-12-12 15:43:31 -05:00
Lioncash
22230a2eca svc_wrap: Correct register index for a wrapper specialization
This would result in svcSetMemoryAttribute getting the wrong value for
its third parameter. This is currently fine, given the service function
is stubbed, however this will be unstubbed in a future change, so this
needs to change.
2018-12-12 15:14:28 -05:00
Lioncash
eb5f3f67f6 vm_manager: Amend the returned values for invalid memory queries in QueryMemory()
The kernel returns a memory info instance with the base address set to
the end of the address space, and the size of said block as
0 - address_space_end, it doesn't set both of said members to zero.
2018-12-12 15:08:06 -05:00
Lioncash
a8cc03502b vm_manager: Migrate memory querying to the VMManager interface
Gets rid of the need to directly access the managed VMAs outside of the
memory manager itself just for querying memory.
2018-12-12 15:07:30 -05:00
Lioncash
c02b8c895b vm_manager: Migrate MemoryInfo and PageInfo to vm_manager.h
Gets the two structures out of an unrelated header and places them with
the rest of the memory management code.

This also corrects the structures. PageInfo appears to only contain a
32-bit flags member, and the extra padding word in MemoryInfo isn't
necessary.
2018-12-12 14:03:53 -05:00
Lioncash
366985ca92 vm_manager: Amend MemoryState enum members
Amends the MemoryState enum to use the same values like the actual
kernel does. Also provides the necessary operators to operate on them.
This will be necessary in the future for implementing
svcSetMemoryAttribute, as memory block state is checked before applying
the attribute.
2018-12-12 14:03:50 -05:00
Jens Schmer
ae390ad5a2 Fix Process object leak on emulation stop
The Process object kept itself alive indefinitely because its handle_table
contains a SharedMemory object which owns a reference to the same Process object,
creating a circular ownership scenario.

Break that up by storing only a non-owning pointer in the SharedMemory object.
2018-12-12 17:25:56 +01:00
Mat M
9bae3ac33a Merge pull request #1891 from DarkLordZach/istorage-getsize
fsp_srv: Implement IStorage::GetSize
2018-12-12 07:31:33 -05:00
bunnei
e1f28afb98 Merge pull request #1893 from lioncash/warn
gl_shader_cache: Resolve truncation compiler warning
2018-12-11 20:47:10 -05:00
bunnei
785d6f9ce0 Merge pull request #1895 from lioncash/uninit
patch_manager: Prevent use of a dangling pointer within PatchRomFS
2018-12-11 20:27:37 -05:00
bunnei
2c6679bb01 Merge pull request #1877 from heapo/audio_interp
Perf: Avoid (expensive) audio interpolation when sample rates already match
2018-12-11 11:45:53 -05:00
bunnei
d63c883e66 Merge pull request #1888 from marcosvitali/glFrontFacing
gl_shader_decompiler: IPA fix FrontFacing.
2018-12-11 11:43:38 -05:00
Lioncash
5c72aa7c4c patch_manager: Prevent use of a dangling pointer within PatchRomFS
fmt::format() returns a std::string instance by value, so calling
.c_str() on it here is equivalent to doing:

auto* ptr = std::string{}.c_str();

The data being pointed to isn't guaranteed to actually be valid anymore
after that expression ends. Instead, we can just take the string as is,
and provide the necessary formatting parameters.
2018-12-11 10:08:13 -05:00
Lioncash
4c2b94559b gl_shader_cache: Dehardcode constant in CalculateProgramSize()
This constant is related to the size of the instruction.
2018-12-10 23:47:20 -05:00
Lioncash
861bfdbf5d gl_shader_cache: Resolve truncation compiler warning
The previous code would cause a warning, as it was truncating size_t
(64-bit) to a u32 (32-bit) implicitly.
2018-12-10 23:44:18 -05:00
bunnei
3b1043c58a Merge pull request #1846 from lioncash/dir
file_sys/directory: Amend path buffer size for directory entries
2018-12-10 21:54:03 -05:00
bunnei
2c45c6d234 Merge pull request #1819 from DarkLordZach/disable-addons
patch_manager: Add support for disabling patches
2018-12-10 21:52:19 -05:00
bunnei
9eb9b344c7 Merge pull request #1887 from FearlessTobi/port-4476
Port citra-emu/citra#4476: "web_service: move telemetry condition from TelemetrySession constructor to destructor"
2018-12-10 21:47:22 -05:00
bunnei
1aa9106244 Merge pull request #1883 from lioncash/log-fsp
service/fsp_srv: Correct returned value in GetGlobalAccessLogMode()
2018-12-10 21:45:29 -05:00
bunnei
01ab4aab91 Merge pull request #1885 from lioncash/data_id
file_sys/save_data_factory: Update SaveDataSpaceId enum
2018-12-10 21:44:50 -05:00
Zach Hilman
5e632caca5 fsp_srv: Implement IStorage::GetSize
Takes no input and returns the size as a u64. Needed by Katamari Damacy Reroll to boot.
2018-12-10 14:14:36 -05:00
bunnei
5b5d0199fe Merge pull request #1740 from FernandoS27/shader_props
Implemented Shader Unique Identifiers
2018-12-10 12:43:43 -05:00
Hexagon12
315f3342f7 Merge pull request #1872 from lioncash/proc-info
kernel/process: Set ideal core from metadata
2018-12-10 18:44:14 +02:00
Hexagon12
ee9e433517 Merge pull request #1880 from DarkLordZach/cache-storage
savedata_factory: Add CacheStorage and delete TemporaryStorage on boot
2018-12-10 18:41:46 +02:00
bunnei
74242a8fb4 Merge pull request #1876 from lioncash/vma
vm_manager: Make vma_map private
2018-12-10 10:09:50 -05:00
bunnei
be657036be Merge pull request #1862 from marcosvitali/tlds
gl_shader_decompiler: TLDS/TLD4/TLD4S Reworked reflecting the source registers, bugs fixed and modularize.
2018-12-10 10:08:20 -05:00
Marcos Vitali
430e1f864b gl_shader_decompiler: IPA FrontFacing: the right value when is the front face is 0xFFFFFFFF. 2018-12-09 23:36:21 -03:00
Lioncash
f3a555a484 service/fsp_srv: Correct returned value in GetGlobalAccessLogMode()
Based off RE, the backing code only ever seems to use 0-2 as the range
of values 1 being a generic log enable, with 2 indicating logging should
go to the SD card. These are used as a set of flags internally.

Given we only care about receiving the log in general, we can just
always signify that we want logging in general.
2018-12-09 20:42:35 -05:00
Zach Hilman
0d2ba2ca4c applets: Correct usage of SignalStateChanged event
This was causing some games (most notably Pokemon Quest) to softlock due to an event being fired when not supposed to. This also removes a hack wherein we were firing the state changed event when the game retrieves it, which is incorrect.
2018-12-09 19:46:15 -05:00
Fernando Sahmkow
d5d77848e6 Implemented a shader unique identifier. 2018-12-09 17:33:33 -04:00
fearlessTobi
ca4e20b4e0 web_service: move telemetry condition from TelemetrySession constructor to destructor
Fixes an issue where Testcases couldn't be sent when Telemetry was disabled, because both things are tied closely together in the backend.
2018-12-08 14:34:37 +01:00
bunnei
3bddd5351e Merge pull request #1864 from lioncash/nrr
service/ldr: Amend layouts of NRO and NRR headers
2018-12-07 22:26:31 -05:00
Lioncash
a4eaa6782f file_sys/save_data_factory: Update SaveDataSpaceId enum
Amends it with missing values deduced from RE (ProperSystem being from
SwitchBrew for naming)

(SdCardUser wasn't that difficult to discern given it's used alongside
SdCardSystem when creating the save data indexer, based off the usage of
the string "saveDataIxrDbSd" nearby).
2018-12-07 18:52:18 -05:00
bunnei
b9e80e97b7 Merge pull request #1874 from lioncash/bindings
hle/service, hle/sm: Minor cleanup
2018-12-07 18:31:04 -05:00
bunnei
713fc67b51 Merge pull request #1882 from FearlessTobi/backport-4418-fix
Backport review comment from citra-emu/citra#4418
2018-12-07 18:16:10 -05:00
bunnei
f85134021f Merge pull request #1873 from lioncash/const
loaders: Make GetFileType() a const qualified member function
2018-12-07 18:15:30 -05:00
Marcos Vitali
f4fa7ecb0e gl_shader_decompiler: TLDS/TLD4/TLD4S Reworked reflecting the source registers, bugs fixed and modularize. 2018-12-07 19:09:36 -03:00
Tobias
eb15711ee6 Backport review comment from citra-emu/citra#4418
Original reason:
As Windows multi-byte character codec is unspecified while we always assume std::string uses UTF-8 in our code base, this can output gibberish when the string contains non-ASCII characters. ::OutputDebugStringW combined with Common::UTF8ToUTF16W is preferred here.
2018-12-07 16:21:18 +01:00
Zach Hilman
fcfbae88e9 savedata_factory: Add support for CacheStorage 2018-12-07 08:47:32 -05:00
Zach Hilman
5721b8b5ad savedata_factory: Delete TemporaryStorage on startup
Mimics hardware behavior.
2018-12-06 22:07:34 -05:00
bunnei
f761e3ef86 Merge pull request #1868 from lioncash/config
configuration/config: Use an intermediary variable for accessing players
2018-12-06 15:24:28 -05:00
bunnei
30b5d8b0ae Merge pull request #1875 from DarkLordZach/oss-ngword2
system_archive: Implement open source NgWord2
2018-12-06 15:23:58 -05:00
Lioncash
15e3d4f357 memory: Convert ASSERT into a DEBUG_ASSERT within GetPointerFromVMA()
Given memory should always be expected to be valid during normal
execution, this should be a debug assertion, rather than a check in
regular builds.
2018-12-06 15:02:34 -05:00
Lioncash
d4c1b9d311 vm_manager: Make vma_map private
This was only ever public so that code could check whether or not a
handle was valid or not. Instead of exposing the object directly and
allowing external code to potentially mess with the map contents, we
just provide a member function that allows checking whether or not a
handle is valid.

This makes all member variables of the VMManager class private except
for the page table.
2018-12-06 15:02:17 -05:00
bunnei
8de6403a08 Merge pull request #1861 from lioncash/reset
kernel/svc: Correct behavior of svcResetSignal()
2018-12-06 13:42:46 -05:00
heapo
117b1f3ec1 Avoid (expensive) audio interpolation when sample rates already match 2018-12-06 09:46:08 -08:00
bunnei
9390452195 Merge pull request #1824 from ReinUsesLisp/fbcache
gl_rasterizer: Implement a framebuffer cache
2018-12-06 11:56:59 -05:00
bunnei
7fbd484f0e Merge pull request #1863 from ReinUsesLisp/texs-f16
gl_shader_decompiler: Implement TEXS.F16
2018-12-06 11:56:05 -05:00
Zach Hilman
8be475d4dc system_archive: Implement open source NgWord2 2018-12-06 10:17:50 -05:00
Lioncash
24f051d723 hle/service: Replace log + UNIMPLEMENTED with UNIMPLEMENTED_MSG
Combines the two into one, shortening the amount of code here.
2018-12-06 01:40:23 -05:00
Lioncash
9f56477539 hle/service: Remove unnecessary using declarations
Only one usage of the specified objects made use of the lack of
namespacing. Given the low usage, we can just remove these.
2018-12-06 01:37:41 -05:00
Lioncash
d8625f5544 hle/service, hle/sm: Compress usages of MakeResult()
These auto-deduce the result based off its arguments, so there's no need
to do that work for the compiler, plus, the function return value itself
already indicates what we're returning.
2018-12-06 01:33:22 -05:00
Lioncash
a8269fdae3 hle/service, hle/sm: Use structured bindings where applicable
Gets rid of the need to keep the variables separate from their actual
initialization spots.
2018-12-06 01:31:26 -05:00
bunnei
4c106b43a9 Merge pull request #1867 from lioncash/alloc
system_archive: Use a regular function pointer instead of std::function for the file-scope system archive array
2018-12-05 22:37:14 -05:00
bunnei
cca4665a69 Merge pull request #1866 from lioncash/cache
service/ldr: Deduplicate instruction cache clearing code in LoadNro()
2018-12-05 22:36:44 -05:00
Mat M
4d3d2fcebd Merge pull request #1870 from heapo/pagetable_shrink_to_fit
Perf: Call shrink_to_fit after page-table vector resizing to actually reduce vector capacity
2018-12-05 18:36:47 -05:00
Lioncash
17b4355391 yuzu/wait_tree: Pass QString by value and std::move in the initializer list for WaitTreeText
Just a trivial modernization that potentially avoids copying strings in certain scenarios.
2018-12-05 18:34:03 -05:00
Lioncash
01bf329f63 yuzu/game_list_worker: Don't retrieve the file type twice in AddFstEntriesToGameList()
Similarly, here we can avoid doing unnecessary work twice by retrieving
the file type only once and comparing it against relevant operands,
avoiding potential unnecessary object construction/destruction.
2018-12-05 17:58:15 -05:00
Lioncash
de095ded5c yuzu/game_list_worker: Don't retrieve file type and file type strings twice in MakeGameListEntry()
While GetFileType() is indeed a getter function, that doesn't mean it's
a trivial function, given some case require reading from the data or
constructing other objects in the background. Instead, only do necessary
work once.
2018-12-05 17:49:37 -05:00
Lioncash
de323851b4 loaders: Make GetFileType() a const qualified member function
No implementations actually modify instance state (and it would be
questionable to do that in the first place given the name), so we can
make this a const member function.
2018-12-05 17:49:34 -05:00
heapo
ca8ab1bc3b Call shrink_to_fit after page-table vector resizing to cause crt to actually lower vector capacity. For 36-bit titles saves 800MB of commit. 2018-12-05 14:40:56 -08:00
Lioncash
547eecf119 kernel/process: Set ideal core from metadata
A very trivial change. If metadata is available, the process should use
it to retrieve the desired core for the process to run on.
2018-12-05 16:59:37 -05:00
Zach Hilman
c07059e7fd configure_input_simple: Properly signal docked mode change 2018-12-05 14:05:57 -05:00
Zach Hilman
233a804196 configure_input: Add ConfigureInputSimple as default input UI config
Greatly simplifies the current input UI, while still allowing power users to tweak advanced settings. Adds 'input profiles', which are easy autoconfigurations to make getting started easy and fast. Also has a custom option which brings up the current, full UI.
2018-12-05 14:02:02 -05:00
Zach Hilman
59ca8d458d configure_input: Convert into QDialog 2018-12-05 14:02:02 -05:00
Zach Hilman
20dffc22a2 configure: Use ConfigureInputSimple for Input tab 2018-12-05 14:02:02 -05:00
Zach Hilman
281b64daf4 ui_settings: Add UI setting for input profile index 2018-12-05 14:02:02 -05:00
Lioncash
e90fa1ac54 configuration/config: Use an intermediary variable for accessing players
Avoids typing the same long accessor just to retrieve player attributes.
2018-12-05 03:41:33 -05:00
Lioncash
2207baaa04 ng_word: Deduplicate use of a constant value
We've already given the constant to the vector itself, so we don't need
to re-hardcode it in the array.
2018-12-05 02:36:45 -05:00
Lioncash
edd9bfd54a system_archive: Use a regular function pointer instead of std::function for file-scope system archive array
This allows the array to be constexpr. std::function is also allowed to
allocate memory, which makes its constructor non-trivial, we definitely
don't want to have all of these execute at runtime, taking up time
before the application can actually load.
2018-12-05 02:33:17 -05:00
Lioncash
7c9b194d63 service/ldr: Deduplicate instruction cache clearing code in LoadNro()
We don't need to specify all of the ARM interfaces explicitly.
2018-12-05 00:33:47 -05:00
Lioncash
05a6f1f676 service/ldr: Amend layout of the NRO header
The first word is just a padding byte, it's not an actual entry
instruction. Also renames the rest of the entries according to
SwitchBrew.
2018-12-05 00:16:49 -05:00
ReinUsesLisp
59a8df1b14 gl_shader_decompiler: Implement TEXS.F16 2018-12-05 02:06:34 -03:00
Lioncash
817fb18e30 service/ldr: Corrent padding within the NRR header layout
The padding after the magic signature value should be 12 bytes rather
than 28 bytes. The other 16 should be placed after the title ID pattern.
2018-12-05 00:05:04 -05:00
ReinUsesLisp
370980fdc3 gl_shader_decompiler: Fixup inverted if 2018-12-05 01:23:04 -03:00
Zach Hilman
e6f7825a24 svc: Avoid incorrect fast yield condition 2018-12-04 22:11:32 -05:00
bunnei
db3200b515 Merge pull request #1859 from heapo/lut_array_codegen
Convert high-frequency LUT arrays from constexpr to static constexpr
2018-12-04 22:07:12 -05:00
Lioncash
2f253986df kernel/svc: Correct behavior of svcResetSignal()
While partially correct, this service call allows the retrieved event to
be null, as it also uses the same handle to check if it was referring to
a Process instance. The previous two changes put the necessary machinery
in place to allow for this, so we can simply call those member functions
here and be done with it.
2018-12-04 20:14:59 -05:00
Lioncash
c7462ce712 kernel/process: Make Process a WaitObject
Process instances can be waited upon for state changes. This is also
utilized by svcResetSignal, which will be modified in an upcoming
change. This simply puts all of the WaitObject related machinery in
place.
2018-12-04 20:14:59 -05:00
Lioncash
a3aa7aaf0b kernel/readable_event: Add member function for enforcing a strict reset contract
svcResetSignal relies on the event instance to have already been
signaled before attempting to reset it. If this isn't the case, then an
error code has to be returned.
2018-12-04 20:14:55 -05:00
heapo
7853e6b5d4 Improve msvc codegen for hot-path array LUTs
In some constexpr functions, msvc is building the LUT at runtime
(pushing each element onto the stack) out of an abundance of caution. Moving the
arrays into be file-scoped constexpr's avoids this and turns the functions into
simple look-ups as intended.
2018-12-04 17:13:07 -08:00
bunnei
d08d4a366b Merge pull request #1704 from DarkLordZach/oss-sysarchive
file_sys: Implement open source system archives
2018-12-04 19:59:52 -05:00
bunnei
af286294f9 Merge pull request #1837 from lioncash/map
yuzu/game_list_worker: Minor cleanup and code deduplication
2018-12-04 19:57:41 -05:00
Lioncash
a49fd7fd57 yuzu/game_list_worker: Move std::string construction after the termination check in callbacks
Avoids potentially allocating a std::string instance when it isn't
needed.
2018-12-04 18:39:35 -05:00
bunnei
e5dd4cb392 Merge pull request #1838 from lioncash/dedup
file_sys/registered_cache: Eliminate variable shadowing
2018-12-04 18:34:49 -05:00
bunnei
173073c722 Merge pull request #1836 from lioncash/unused
crypto/key_manager: Remove unused variable in GetTicketblob()
2018-12-04 18:28:15 -05:00
bunnei
5ca586596d Merge pull request #1860 from lioncash/event
kernel/svc: Implement svcCreateEvent and svcSignalEvent
2018-12-04 18:27:54 -05:00
Lioncash
8ea1f28614 kernel/svc: Remove unused header inclusion 2018-12-04 15:48:20 -05:00
Lioncash
a543c35962 kernel/svc: Implement svcSignalEvent()
This function simply does a handle table lookup for a writable event
instance identified by the given handle value. If a writable event
cannot be found for the given handle, then an invalid handle error is
returned. If a writable event is found, then it simply signals the
event, as one would expect.
2018-12-04 15:47:59 -05:00
Lioncash
2a1f59b301 kernel/svc: Implement svcCreateEvent()
svcCreateEvent operates by creating both a readable and writable event
and then attempts to add both to the current process' handle table.

If adding either of the events to the handle table fails, then the
relevant error from the handle table is returned.

If adding the readable event after the writable event to the table
fails, then the writable event is removed from the handle table and the
relevant error from the handle table is returned.

Note that since we do not currently test resource limits, we don't check
the resource limit table yet.
2018-12-04 15:47:55 -05:00
Zach Hilman
f6f6503578 qt: Add Properties menu to game list right-click 2018-12-04 13:34:50 -05:00
bunnei
465f486160 Merge pull request #1845 from lioncash/nro
loader/{nro, nso}: Remove dependency on the System class
2018-12-04 12:26:12 -05:00
bunnei
d533767623 Merge pull request #1853 from lioncash/event
kernel/object: Amend handle types to distinguish between readable and writable events
2018-12-04 12:25:40 -05:00
Marcos
ab2108fb2a Rewrited TEX/TEXS (TEX Scalar). (#1826)
* Rewrited TEX/TEXS (TEX Scalar).

* Style fixes.

* Styles issues.
2018-12-04 12:24:35 -05:00
bunnei
da5659fb87 Merge pull request #1857 from lioncash/res-info
kernel/svc: Implement the resource limit svcGetInfo option
2018-12-04 12:23:19 -05:00
bunnei
7f6bc284e9 Merge pull request #1854 from Subv/old_command_processor
Don't try to route PFIFO methods (0-0x40) to the other engines.
2018-12-04 08:49:22 -05:00
Luke Street
a3d78b77f8 debugger: Set paused thread color 2018-12-04 02:25:34 -05:00
Lioncash
5eb057f422 kernel/object: Amend handle types to distinguish between readable and writable events
Two kernel object should absolutely never have the same handle ID type.
This can cause incorrect behavior when it comes to retrieving object
types from the handle table. In this case it allows converting a
WritableEvent into a ReadableEvent and vice-versa, which is undefined
behavior, since the object types are not the same.

This also corrects ClearEvent() to check both kernel types like the
kernel itself does.
2018-12-04 02:20:47 -05:00
Lioncash
ac966e4213 kernel/handle_table: Amend reference to CTR-OS in Create()
Another hold-over from Citra.
2018-12-04 01:50:44 -05:00
Lioncash
312690b450 kernel/svc: Implement the resource limit svcGetInfo option
Allows a process to register the resource limit as part of its handle
table.
2018-12-04 01:50:30 -05:00
Luke Street
3e75175d02 svc: Implement SetThreadActivity (thread suspension) 2018-12-04 01:23:50 -05:00
Subv
c4c19fa6c1 Removed unused file.
This is a leftover from #1792
2018-12-03 23:52:38 -05:00
Subv
b873253da1 GPU: Don't try to route PFIFO methods (0-0x40) to the other engines. 2018-12-03 23:52:18 -05:00
Mat M
adc4d332fc Merge pull request #1852 from VPeruS/fix-format-string
[Kernel::CreateThread] Match format specifiers to LOG_TRACE's arguments
2018-12-03 22:25:29 -05:00
V.Kalyuzhny
b330b495dc [Kernel::CreateThread] Match format specifiers to LOG_TRACE's arguments 2018-12-04 05:13:50 +02:00
Zach Hilman
ddf5903cd9 scheduler: Avoid manual Reschedule call
This will automatically occur anyway when PrepareReschedule is called
2018-12-03 21:22:09 -05:00
bunnei
9f1ac96afa Merge pull request #1840 from lioncash/info
svc: Reorganize svcGetInfo, handle more error cases for existing implemented info categories
2018-12-03 18:46:22 -05:00
Zach Hilman
b5af41a07b scheduler: Only work steal higher priority threads from other cores 2018-12-03 17:29:30 -05:00
Zach Hilman
e11e65b3d6 applets: Correct event ResetTypes from OneShot to Sticky
Fixes bugs relating to signalling in software keyboard.
2018-12-03 17:27:40 -05:00
Zach Hilman
bf90f2402d qt: Implement GUI dialog frontend for ProfileSelector
Presents profiles in a list, similar to switch.
2018-12-03 17:26:27 -05:00
Zach Hilman
60b59d554d am: Use ProfileSelect applet 2018-12-03 17:26:27 -05:00
Zach Hilman
4fb59fdfe1 applets: Implement ProfileSelect applet
Allows the player to select an emulated profile.
2018-12-03 17:26:27 -05:00
Zach Hilman
6deccc7e6b qt: Register to use Qt ProfileSelector instead of default 2018-12-03 17:26:27 -05:00
Zach Hilman
58fd0a1c50 core: Add getter/setter for ProfileSelector in System 2018-12-03 17:26:26 -05:00
Zach Hilman
d17f38494b frontend: Add frontend applet for ProfileSelect
Responsible for selecting a profile and firing callback upon completion.
2018-12-03 17:26:26 -05:00
Zach Hilman
877b31b33e software_keyboard: Signal state changed event upon construction
Previously, ILibraryAppletAccessor would signal upon creation of any applet, but this is incorrect. A flag inside of the applet code determines whether or not creation should signal state change and swkbd happens to be one of these applets.
2018-12-03 17:26:26 -05:00
Zach Hilman
60e27252a5 qt: Add UI to display game properties and disable add-ons 2018-12-03 17:21:25 -05:00
Zach Hilman
5f0217592b loader: Add support for reading the name of game's developer 2018-12-03 17:21:25 -05:00
Zach Hilman
51483d83bb aoc_u: Obey disabled add-ons list when listing DLC 2018-12-03 17:21:25 -05:00
Zach Hilman
0cea05cdf7 patch_manager: Obey disabled add-ons list when patching game 2018-12-03 17:21:25 -05:00
Zach Hilman
c7b41ade74 core: Make GetGameFileFromPath function externally accessible 2018-12-03 17:20:34 -05:00
Zach Hilman
c381f46428 config: Store and load disabled add-ons list 2018-12-03 17:20:34 -05:00
Zach Hilman
282b7e902c settings: Store list of disabled add-ons per title ID 2018-12-03 17:20:34 -05:00
bunnei
76525013c0 Merge pull request #1842 from lioncash/slot
yuzu/configuration: Minor clean-up related changes
2018-12-03 17:12:01 -05:00
bunnei
f6b22d9251 Merge pull request #1835 from lioncash/cache-global
filesystem: De-globalize registered_cache_union
2018-12-03 17:11:26 -05:00
bunnei
8a12daac8c Merge pull request #1822 from ReinUsesLisp/glsl-scope
gl_shader_decompiler: Introduce a scoped object and style changes
2018-12-03 17:10:02 -05:00
bunnei
ef69b4b830 Merge pull request #1803 from DarkLordZach/k-able-event
kernel: Divide Event into ReadableEvent and WritableEvent
2018-12-03 17:05:57 -05:00
bunnei
f7d5f72944 Merge pull request #1833 from lioncash/clean
service/fsp_srv: Implement CleanDirectoryRecursively
2018-12-03 17:04:05 -05:00
bunnei
118f402382 Merge pull request #1839 from lioncash/init
service/audio/audout_u: Amend constructor initialization list order
2018-12-03 17:03:00 -05:00
bunnei
a238cdb5ca Merge pull request #1841 from ogniK5377/npad-mode-fix
Fixed crash with SetNpadMode
2018-12-03 17:02:40 -05:00
Sebastian Valle
1ad158b2bb Merge pull request #1843 from lioncash/table
hle/service: Update function tables for erpt:c and usb's IClientEpSession
2018-12-03 12:21:28 -05:00
Lioncash
7695febfa1 loader/nso: Remove dependency on the System class
Similar to the NRO changes, we can also pass the process explicitly as a
parameter from Load instead of indirecting through the System class.
2018-12-02 23:39:03 -05:00
Lioncash
fc32d6256a loader/nro: Make the static LoadNro function internally linked
This simply acts as a forwarding function for the Load() function, so
this doesn't need to be directly exposed.
2018-12-02 23:38:58 -05:00
Lioncash
7e2467e695 file_sys/directory: Amend path buffer size for directory entries
The path buffer is actually 0x301 (769) characters in length, with the
extra character being intended for the null-terminator.
2018-12-02 23:15:58 -05:00
Lioncash
b110d2176c loader/nro: Remove dependency on the System class
Load() is already given the process instance as a parameter, so instead
of coupling the class to the System class, we can just forward that
parameter to LoadNro()
2018-12-02 22:18:52 -05:00
Lioncash
6306e54f45 service/usb: Update function table
Updates the function table for IClientEpSession based off information
provided by SwitchBrew.
2018-12-02 15:49:40 -05:00
Lioncash
f933b3370e service/erpt: Update function table
Updates the function table according to information provided by
SwitchBrew.
2018-12-02 15:46:44 -05:00
Lioncash
195cad9635 yuzu/configuration: Make slots private where applicable
These slots are only ever attached to event handling mechanisms within
the class itself, they're never used externally. Because of this, we can
make the functions private.

This also removes redundant usages of the private access specifier.
2018-12-02 14:18:36 -05:00
Lioncash
eabfb7730d yuzu/configuration: Add missing override specifiers to configuration-related classes
Resolves trivial compiler warnings.
2018-12-02 14:18:36 -05:00
Lioncash
f3253d0f14 yuzu/configuration/configure_input: Default destructor in the cpp file
The previous code could potentially be a compilation issue waiting to
occur, given we forward declare the type for a std::unique_ptr. If the
complete definition of the forward declared type isn't visible in a
translation unit that the class is used in, then it would fail to
compile.

Defaulting the destructor in a cpp file ensures the std::unique_ptr's
destructor is only invoked where its complete type is known.
2018-12-02 14:18:26 -05:00
David Marcec
a9223c8182 Fixed crash with SetNpadMode
fixed crash due to handheld
2018-12-03 02:45:08 +11:00
Lioncash
7fe27de26e svc: Use the current process' handle table for retrieving the process instance to act upon
The kernel uses the handle table of the current process to retrieve the
process that should be used to retrieve certain information. To someone
not familiar with the kernel, this might raise the question of "Ok,
sounds nice, but doesn't this make it impossible to retrieve information
about the current process?".

No, it doesn't, because HandleTable instances in the kernel have the
notion of a "pseudo-handle", where certain values allow the kernel to
lookup objects outside of a given handle table. Currently, there's only
a pseudo-handle for the current process (0xFFFF8001) and a pseudo-handle
for the current thread (0xFFFF8000), so to retrieve the current process,
one would just pass 0xFFFF8001 into svcGetInfo.

The lookup itself in the handle table would be something like:

template <typename T>
T* Lookup(Handle handle) {
    if (handle == PSEUDO_HANDLE_CURRENT_PROCESS) {
        return CurrentProcess();
    }

    if (handle == PSUEDO_HANDLE_CURRENT_THREAD) {
        return CurrentThread();
    }

    return static_cast<T*>(&objects[handle]);
}

which, as is shown, allows accessing the current process or current
thread, even if those two objects aren't actually within the HandleTable
instance.
2018-12-02 03:41:49 -05:00
Lioncash
6712e7402c svc: Reorganize svcGetInfo, handle more error cases for existing implemented info categories
Our implementation of svcGetInfo was slightly incorrect in that we
weren't doing proper error checking everywhere. Instead, reorganize it
to be similar to how the kernel seems to do it.
2018-12-02 03:40:10 -05:00
Zach Hilman
3476830b26 svc: Avoid performance-degrading unnecessary reschedule 2018-12-02 00:44:40 -05:00
Lioncash
57ac068a23 service/audio/audout_u: Amend constructor initialization list order
Orders the constructor initializer list the same way the members of the
class are declared. Prevents -Wreorder warnings
2018-12-01 23:56:20 -05:00
bunnei
7ce17b2cf6 Merge pull request #1827 from ReinUsesLisp/clip-and-shader
gl_rasterizer: Enable clip distances when set in register and in shader
2018-12-01 23:51:47 -05:00
Lioncash
efbcff0af0 file_sys/registered_cache: Eliminate variable shadowing
Also inverts if statements where applicable to allow unindenting code a
little bit.
2018-12-01 23:50:13 -05:00
bunnei
80aa124b1d Merge pull request #1825 from ReinUsesLisp/shader-pipeline-cache
gl_shader_manager: Update pipeline when programs have changed
2018-12-01 23:48:55 -05:00
bunnei
a6805e58ce Merge pull request #1795 from ReinUsesLisp/vc-cleanup
video_core: Minor style changes
2018-12-01 23:46:18 -05:00
bunnei
0e9be7be37 Merge pull request #1823 from bunnei/fix-surface-copy
gl_rasterizer_cache: Fix several surface copy issues.
2018-12-01 23:44:32 -05:00
Lioncash
db4523f1ec filesystem: De-globalize registered_cache_union
We can just return a new instance of this when it's requested. This only
ever holds pointers to the existing registed caches, so it's not a large
object. Plus, this also gets rid of the need to keep around a separate
member function just to properly clear out the union.

Gets rid of one of five globals in the filesystem code.
2018-12-01 23:43:23 -05:00
Lioncash
8c108eaca7 yuzu/game_list_worker: Deduplicate game list entry creation
Avoids duplicating the same code twice verbatim.
2018-12-01 23:23:39 -05:00
Lioncash
f1ecfcb8bc yuzu/game_list_worker: Tidy up string handling in FillControlMap()
We don't need to call out to our own file handling functions when we're
going to construct a QFileInfo instance right after it. We also don't
need to convert to a std::string again just to compare the file
extension.
2018-12-01 22:49:00 -05:00
Lioncash
a8aca4306d crypto/key_manager: Remove unused variable in GetTicketblob() 2018-12-01 22:37:51 -05:00
bunnei
c5e781e72a Merge pull request #1832 from Simek/remove-game-list-border
UI: Remove border from Game List
2018-12-01 22:26:34 -05:00
bunnei
97e73591e3 Merge pull request #1830 from Subv/vi_ub
Services/VI: Dereferencing an uninitialized std::optional is undefined behavior.
2018-12-01 22:25:10 -05:00
Lioncash
e88cdcc912 Fix debug build
A non-existent parameter was left in some formatting calls (the logging
macro for which only does anything meaningful on debug builds)
2018-12-01 02:11:42 -05:00
Lioncash
0ccaaafca3 file_sys: Override missing mutating functions to be stubbed out for ReadOnlyVfsDirectory by default
Ensures that read only indeed means read only.
2018-11-30 23:52:56 -05:00
Lioncash
a7d9fe993a service/fsp_srv: Implement CleanDirectoryRecursively
This is the same behavior-wise as DeleteDirectoryRecursively, with the
only difference being that it doesn't delete the top level directory in
the hierarchy, so given:

root_dir/
  - some_dir/
    - File.txt
  - OtherFile.txt

The end result is just:

root_dir/
2018-11-30 20:17:28 -05:00
Bartosz Kaszubowski
5f07ca3dce remove border from GameList 2018-11-30 23:35:08 +01:00
Subv
583bd20f02 Services/VI: Dereferencing an uninitialized std::optional is undefined behavior.
Assert that it is not empty before using it in the DequeueBuffer wait callback.
2018-11-30 16:06:49 -05:00
bunnei
b7104263ba Merge pull request #1829 from lioncash/lang
service/set: Implement MakeLanguageCode
2018-11-30 10:53:13 -05:00
Lioncash
308bbba8b9 service/set: Convert GetLanguageCode over to using PushEnum()
This code was around prior to the introduction of PushEnum, so convert
it over so we don't need to cast here.
2018-11-30 09:08:07 -05:00
Lioncash
7c04fe22b4 service/set: Implement MakeLanguageCode
This function simply converts a given index into a language code.
2018-11-30 09:08:03 -05:00
Lioncash
4b950728fd configure_input: Amend clang-format discrepancies 2018-11-30 03:31:56 -05:00
bunnei
0f43564d09 gl_rasterizer_cache: Update AccurateCopySurface to flush complete source surface.
- Fixes issues with Breath of the Wild with use_accurate_gpu_emulation setting.
2018-11-29 20:10:11 -05:00
ReinUsesLisp
2908d30274 gl_rasterizer: Enable clip distances when set in register and in shader 2018-11-29 16:58:20 -03:00
ReinUsesLisp
1a2bb596db gl_rasterizer: Implement a framebuffer cache 2018-11-29 16:34:46 -03:00
ReinUsesLisp
e8620eaa9a gl_shader_manager: Update pipeline when programs have changed 2018-11-29 16:26:42 -03:00
Zach Hilman
170d707850 hle_ipc: Refactor SleepClientThread to avoid ReadableEvent 2018-11-29 09:14:20 -05:00
Zach Hilman
a342bcc9b1 kernel/event: Reference ReadableEvent from WritableEvent 2018-11-29 08:48:40 -05:00
Zach Hilman
ff610103b5 core: Port all current usages of Event to Readable/WritableEvent 2018-11-29 08:45:41 -05:00
Zach Hilman
a56fc84e7a hle_ipc: Use event pair for SleepClientThread 2018-11-29 08:42:26 -05:00
Zach Hilman
c61d2a2841 kernel: Add named event table
Used to store ReadableEvents of all events on the system.
2018-11-29 08:42:26 -05:00
Zach Hilman
c713383816 kernel: Divide Event into ReadableEvent and WritableEvent
More hardware accurate. On the actual system, there is a differentiation between the signaler and signalee, they form a client/server relationship much like ServerPort and ClientPort.
2018-11-29 08:42:26 -05:00
Zach Hilman
d92989e787 kernel/object: Add descriptions to ResetTypes 2018-11-29 08:42:26 -05:00
bunnei
7befe0134d Merge pull request #1768 from greggameplayer/patch-2
Uncheck automatically joycons docked when docked mode is enable
2018-11-29 01:00:09 -05:00
bunnei
1e49a85106 Merge pull request #1801 from ogniK5377/log-before-execute
Changed logging to be "Log before execution", Added more error logging, all services/svc should now log on some level
2018-11-29 00:58:46 -05:00
bunnei
3d3cc35ee7 gl_rasterizer_cache: Remove BlitSurface and replace with more accurate copy.
- BlitSurface with different texture targets is inherently broken.
- When target is the same, we can just use FastCopySurface.
- Fixes rendering issues with Breath of the Wild.
2018-11-28 21:56:21 -05:00
ReinUsesLisp
eb700afcf0 gl_shader_decompiler: Remove texture temporal in TLD4 2018-11-28 23:46:16 -03:00
ReinUsesLisp
8d58e5da71 gl_shader_decompiler: Flip negated if else statement 2018-11-28 23:46:16 -03:00
ReinUsesLisp
f4abebd731 gl_shader_decompiler: Use GLSL scope on instructions unrelated to textures 2018-11-28 23:46:14 -03:00
ReinUsesLisp
78fc8f6b66 gl_shader_decompiler: Move texture code generation into lambdas 2018-11-28 23:45:53 -03:00
ReinUsesLisp
ab13b628d0 gl_shader_decompiler: Clean up texture instructions 2018-11-28 23:45:53 -03:00
ReinUsesLisp
6a642022dd gl_shader_decompiler: Scope GLSL variables with a scoped object 2018-11-28 23:45:51 -03:00
ReinUsesLisp
037449668e gl_rasterizer: Signal UNIMPLEMENTED when rt_separate_frag_data is not zero 2018-11-28 21:26:22 -03:00
ReinUsesLisp
653d7a3f0d gl_rasterizer_cache: Use brackets for two-line single-expresion blocks 2018-11-28 21:18:14 -03:00
ReinUsesLisp
432a9872ed gl_rasterizer: Remove unused struct declarations 2018-11-28 21:18:13 -03:00
ReinUsesLisp
22c7c710b4 gl_rasterizer: Remove extension booleans 2018-11-28 21:18:13 -03:00
bunnei
5a9a84994a Merge pull request #1808 from Tinob/master
Fix clip distance and viewport
2018-11-28 17:47:28 -05:00
bunnei
3fe8ab0d99 Merge pull request #1786 from Tinob/DepthClamp
Add Depth Clamp Support
2018-11-28 17:46:55 -05:00
bunnei
c5ab648554 Merge pull request #1817 from DarkLordZach/npad-idx-fix
npad: Use NPadIdToIndex to prevent invalid array access
2018-11-28 17:46:17 -05:00
bunnei
6f849887c9 Merge pull request #1792 from bunnei/dma-pusher
gpu: Rewrite GPU command list processing with DmaPusher class.
2018-11-28 10:12:37 -05:00
Zach Hilman
299224790c npad: Use NPadIdToIndex to prevent invalid array access 2018-11-28 09:01:58 -05:00
bunnei
881f5ad70f Merge pull request #1735 from FernandoS27/tex-spacing
Texture decoder: Implemented Tile Width Spacing
2018-11-27 19:21:17 -05:00
bunnei
adb882bf90 Merge pull request #1814 from lioncash/ptr
file_sys/registered_cache: Use regular const references instead of std::shared_ptr for InstallEntry()
2018-11-27 19:20:12 -05:00
bunnei
ac74b71d75 dma_pushbuffer: Optimize to avoid loop and copy on Push. 2018-11-27 19:17:33 -05:00
bunnei
c568f5cea7 gpu: Move command list profiling to DmaPusher::DispatchCalls. 2018-11-27 18:42:21 -05:00
bunnei
e89a3b9e59 Merge pull request #1811 from lioncash/input
yuzu/input: Minor changes
2018-11-27 18:38:12 -05:00
bunnei
71dfe4a7ae Merge pull request #1815 from DarkLordZach/npad-pos-fix
npad: Fix copy/paste error with LED position assignments
2018-11-27 17:26:58 -05:00
Zach Hilman
6df74ff579 npad: Fix copy/paste error with LED position assignments 2018-11-27 17:23:44 -05:00
Lioncash
2a22c1b27e yuzu/configure_input_player: Use std::size_t to represent the player index instead of u8
Prevents compiler warnings related to truncation when invoking the
dialog. It's also extremely suspect to use a u8 value here instead of a
more general type to begin with.
2018-11-27 16:37:21 -05:00
Lioncash
0782d3971b yuzu/configure_input: Make CallConfigureDialog a non-member template function
This doesn't depend on any part of the private interface, so it can be
made a non-member internal function.
2018-11-27 16:37:18 -05:00
bunnei
3cc204aff8 Merge pull request #1802 from DarkLordZach/user-data-storage
profile_manager: Save and load ProfileData from disk
2018-11-27 16:36:23 -05:00
Lioncash
7b1aaaa069 file_sys/registered_cache: Remove unused <map> include 2018-11-27 16:33:18 -05:00
Lioncash
d72c809030 file_sys/registered_cache: Use regular const references instead of std::shared_ptr for InstallEntry()
These parameters don't need to utilize a shared lifecycle directly in
the interface. Instead, the caller should provide a regular reference
for the function to use. This also allows the type system to flag
attempts to pass nullptr and makes it more generic, since it can now be
used in contexts where a shared_ptr isn't being used (in other words, we
don't constrain the usage of the interface to a particular mode of
memory management).
2018-11-27 16:33:14 -05:00
bunnei
bf055e14ab Merge pull request #1812 from lioncash/nacp
control_metadata: Correct typo in language name (Portugese -> Portuguese)
2018-11-27 16:29:53 -05:00
bunnei
066140854a Merge pull request #1813 from ReinUsesLisp/fixup-clip
gl_shader_decompiler: Fixup clip distance index
2018-11-27 16:28:55 -05:00
ReinUsesLisp
2e9b90abad gl_shader_decompiler: Fixup clip distance index 2018-11-27 15:35:26 -03:00
Lioncash
d4e3d567ce control_metadata: Correct typo in language name (Portugese -> Portuguese)
While we're at it, organize the array linearly, since clang formats the
array elements quite wide length-wise with the addition of the missing
'u'.

Technically also fixes patch lookup and icon lookup with Portuguese,
though I doubt anyone has actually run into this issue.
2018-11-27 13:21:46 -05:00
bunnei
5bea164a77 Merge pull request #1810 from degasus/dirty_flags
gl_rasterizer: Fixup for #1723.
2018-11-27 10:46:49 -05:00
Lioncash
11cf13a6e1 yuzu/configure_input_player: Use a lambda expression instead of std::bind
std::bind is the pre-C++11 way of doing this.
2018-11-27 05:08:13 -05:00
Lioncash
73a48d6523 yuzu/configure_input_player: Amend constructor initializer list order
Orders the elements the way they would actually be initialized in.
Resolves compiler warnings with gcc and clang
2018-11-27 05:04:51 -05:00
Lioncash
53bff53791 yuzu/configure_input: Remove unused function MoveGridElement 2018-11-27 05:03:26 -05:00
Lioncash
d67e88e59c yuzu/configure_input*: Move data members after function declarations
The common pattern is to put the data members after the function
interface where applicable.
2018-11-27 05:02:15 -05:00
Lioncash
ec7ea4ae96 yuzu/configure_input: Remove unnecessary includes 2018-11-27 05:00:56 -05:00
Markus Wick
8747f5fc0d gl_rasterizer: Fixup for #1723.
On invalidating the streaming buffer, we need to reupload all vertex buffers.
But we don't need to reconfigure the vertex format.
This was a (silly) misstake in #1723.

Thanks at Rodrigo for discovering the issue.

Fun fact, as configuring the vertex format also invalidate the vertex buffer,
this misstake had no affect on the behavior.
2018-11-27 10:32:41 +01:00
bunnei
1cd40f107f Merge pull request #1806 from ReinUsesLisp/morton-fixup
morton: Fixup compiler warning
2018-11-26 23:22:59 -05:00
bunnei
11c17465d8 Merge pull request #1804 from lioncash/cast
gdbstub: Silence value truncation warning within FpuWrite()
2018-11-26 23:19:40 -05:00
bunnei
abea6fa90c gpu: Rewrite GPU command list processing with DmaPusher class.
- More accurate impl., fixes Undertale (among other games).
2018-11-26 23:14:01 -05:00
bunnei
852a462df3 Merge pull request #1805 from lioncash/resource
svc: Implement svcCreateResourceLimit, svcGetResourceLimitCurrentValue(), svcGetResourceLimitLimitValue(), and svcSetResourceLimitLimitValue()
2018-11-26 22:59:51 -05:00
Rodolfo Bogado
6710eb4892 remove viewport_transform_enabled as it seems to be inactive when valid transforms are used. 2018-11-27 00:04:33 -03:00
Lioncash
5905162e36 svc: Implement svcSetResourceLimitLimitValue()
The opposite of the getter functions, this function sets the limit value
for a particular ResourceLimit resource category, with the restriction
that the  new limit value must be equal to or greater than the current
resource value. If this is violated, then ERR_INVALID_STATE is returned.

e.g.

Assume:

current[Events] = 10;
limit[Events] = 20;

a call to this service function lowering the limit value to 10 would be
fine, however, attempting to lower it to 9 in this case would cause an
invalid state error.
2018-11-26 21:23:15 -05:00
Lioncash
eb5596044d svc: Implement svcGetResourceLimitCurrentValue()
This kernel service function is essentially the exact same as
svcGetResourceLimitLimitValue(), with the only difference being that it
retrieves the current value for a given resource category using the
provided resource limit handle, rather than retrieving the limiting
value of that resource limit instance.

Given these are exactly the same and only differ on returned values, we
can extract the existing code for svcGetResourceLimitLimitValue() to
handle both values.
2018-11-26 21:23:11 -05:00
ReinUsesLisp
237c2026e9 morton: Fixup compiler warning 2018-11-26 23:22:57 -03:00
Lioncash
1d6399c222 svc: Implement svcGetResourceLimitLimitValue()
This kernel service function retrieves the maximum allowable value for
a provided resource category for a given resource limit instance. Given
we already have the functionality added to the resource limit instance
itself, it's sufficient to just hook it up.

The error scenarios for this are:

1. If an invalid resource category type is provided, then ERR_INVALID_ENUM is returned.

2. If an invalid handle is provided, then ERR_INVALID_HANDLE is returned (bad thing goes in, bad thing goes out, as one would expect).

If neither of the above error cases occur, then the out parameter is
provided with the maximum limit value for the given category and success
is returned.
2018-11-26 21:12:13 -05:00
Lioncash
4ef2af8c98 svc: Implement svcCreateResourceLimit()
This function simply creates a ResourceLimit instance and attempts to
create a handle for it within the current process' handle table. If the
kernal fails to either create the ResourceLimit instance or create a
handle for the ResourceLimit instance, it returns a failure code
(OUT_OF_RESOURCE, and HANDLE_TABLE_FULL respectively). Finally, it exits
by providing the output parameter with the handle value for the
ResourceLimit instance and returning that it was successful.

Note: We do not return OUT_OF_RESOURCE because, if yuzu runs out of
available memory, then new will currently throw. We *could* allocate the
kernel instance with std::nothrow, however this would be inconsistent
with how all other kernel objects are currently allocated.
2018-11-26 21:10:31 -05:00
David Marcec
cc4521fc70 Added comment on Main memory size for more clarity 2018-11-27 12:56:50 +11:00
David Marcec
f058de337e Made svcSetHeapSize and svcCreateSharedMemory more readable 2018-11-27 12:53:18 +11:00
David Marcec
f271316822 Reworked svcs slightly, improved error messages in AM and fsp_srv 2018-11-27 12:29:06 +11:00
Lioncash
474c745502 gdbstub: Silence value truncation warning within FpuWrite()
Previously this would cause an implicit truncation warning about
assigning a u64 value to a u32 value without an explicit cast.
2018-11-26 19:58:23 -05:00
Rodolfo Bogado
dfdbfa69e5 Implement depth clamp 2018-11-26 20:56:32 -03:00
Rodolfo Bogado
8e971f5062 Add support for Clip Distance enabled register 2018-11-26 20:45:21 -03:00
bunnei
1856d0ee8a Merge pull request #1794 from Tinob/master
Add support for viewport_transfom_enable register
2018-11-26 18:34:09 -05:00
bunnei
67a154e23d Merge pull request #1723 from degasus/dirty_flags
gl_rasterizer: Skip VB upload if the state is clean.
2018-11-26 18:33:22 -05:00
Marcos
cb8d51e37e GPU States: Implement Polygon Offset. This is used in SMO all the time. (#1784)
* GPU States: Implement Polygon Offset. This is used in SMO all the time.

* Clang Format fixes.

* Initialize polygon_offset in the constructor.
2018-11-26 18:31:44 -05:00
bunnei
7684f4d0cf Merge pull request #1713 from FernandoS27/bra-cc
Implemented BRA CC conditional and FSET CC Setting
2018-11-26 18:28:03 -05:00
bunnei
a41943dc55 Merge pull request #1798 from ReinUsesLisp/y-direction
gl_shader_decompiler: Implement S2R's Y_DIRECTION
2018-11-26 18:25:42 -05:00
Zach Hilman
dac0c33fd2 profile_manager: Save and load ProfileData from disk
The ProfileData is a 0x80-sized structure that stores various pieces of miscellaneous data for the account.
2018-11-26 17:11:12 -05:00
FernandoS27
ddfbe0b58d Implemented Tile Width Spacing 2018-11-26 09:05:12 -04:00
David Marcec
dace6087d6 Fixed hwopus compile error 2018-11-26 21:52:10 +11:00
David Marcec
3d627df4d8 Improved error messages in AM, HwOpus and NvMap 2018-11-26 20:05:09 +11:00
David Marcec
9662ca918d Improved error messages for SVCs 2018-11-26 19:47:39 +11:00
David Marcec
a2cc3b10bb Changed logging to be "Log before execution", Added more error logging, all services should now log on some level 2018-11-26 17:06:13 +11:00
bunnei
f9a211220c Merge pull request #1763 from ReinUsesLisp/bfi
gl_shader_decompiler: Implement BFI_IMM_R
2018-11-25 23:04:57 -05:00
bunnei
ee764c3b4b Merge pull request #1793 from lioncash/ref
service/sm: Take std::string by const reference in UnregisterService
2018-11-25 23:04:21 -05:00
bunnei
d7d1ab15b6 Merge pull request #1760 from ReinUsesLisp/r2p
gl_shader_decompiler: Implement R2P_IMM
2018-11-25 22:38:42 -05:00
bunnei
0394813401 Merge pull request #1782 from FernandoS27/dc
Fixed Coordinate Encodings in TEX and TEXS instructions
2018-11-25 22:36:25 -05:00
bunnei
8ce90a4f0b Merge pull request #1783 from ReinUsesLisp/clip-distances
gl_shader_decompiler: Implement clip distances
2018-11-25 22:35:30 -05:00
bunnei
ceb4bc22a4 Merge pull request #1796 from ReinUsesLisp/morton-move
video_core: Move morton functions out of gl_rasterizer_cache
2018-11-25 22:35:12 -05:00
Mat M
94fce28010 Merge pull request #1800 from encounter/svcgetinfo
svc: Return ERR_INVALID_ENUM_VALUE from svcGetInfo
2018-11-25 16:52:56 -05:00
Luke Street
94e8dfc0c7 svc: Return ERR_INVALID_ENUM_VALUE from svcGetInfo 2018-11-25 16:48:44 -05:00
Rodolfo Bogado
415e8383ba Limit the amount of viewports tested for state changes only to the usable ones 2018-11-25 12:18:29 -03:00
ReinUsesLisp
924e834b8f gl_shader_decompiler: Implement S2R's Y_DIRECTION 2018-11-25 04:37:29 -03:00
bunnei
932fbd5a25 Merge pull request #1791 from bunnei/nvdrv-stub
nvdrv: Implement/stub DumpGraphicsMemoryInfo and GetStatus.
2018-11-24 23:45:24 -05:00
bunnei
7d544c1b9d Merge pull request #1787 from bunnei/fix-gpu-mm
memory_manager: Do not allow 0 to be a valid GPUVAddr.
2018-11-24 23:45:00 -05:00
ReinUsesLisp
7ff2131cf9 morton: Style changes 2018-11-25 00:38:53 -03:00
ReinUsesLisp
dad3a6718e video_core: Move morton functions to their own file 2018-11-25 00:37:18 -03:00
FernandoS27
8c797464a2 Fix Texture Overlapping 2018-11-24 17:26:42 -04:00
FernandoS27
33afff1870 Implemented BRA CC conditional and FSET CC Setting 2018-11-24 13:25:54 -04:00
Rodolfo Bogado
13f6a603c2 Add support for viewport_transfom_enable register 2018-11-24 13:17:48 -03:00
Lioncash
b0df09335c service/sm: Take std::string by const reference in UnregisterService
Avoids the need to create a copy of the std::string instance
(potentially allocating).

The only reason RegisterService takes its argument by value is because
it's std::moved internally.
2018-11-24 00:08:13 -05:00
bunnei
f7a1827aaa Merge pull request #1641 from DarkLordZach/sm-register-unregister
sm: Implement RegisterService and UnregisterService
2018-11-23 23:59:01 -05:00
bunnei
7c4fb09a7c Merge pull request #1731 from DarkLordZach/change-dir-crash
filesystem: Clear registered union paths on factory creation
2018-11-23 23:58:31 -05:00
bunnei
d01bf170c4 Merge pull request #1725 from FernandoS27/gl43
Update OpenGL's backend version from 3.3 to 4.3
2018-11-23 23:56:57 -05:00
bunnei
e23543918b Merge pull request #1785 from Tinob/master
Add support for clear_flags register
2018-11-23 23:55:56 -05:00
bunnei
69a9bd8187 Merge pull request #1692 from Hedges/GDBClean
GDBStub Improvements
2018-11-23 23:36:36 -05:00
bunnei
e65966bcfc Merge pull request #1708 from ogniK5377/res-scale
Report resolution scaling support for vi and am
2018-11-23 23:32:19 -05:00
bunnei
67ff974387 Merge pull request #1747 from DarkLordZach/exefs-lfs
patch_manager: Add support for applying LayeredFS patches to ExeFS
2018-11-23 23:31:48 -05:00
bunnei
b6b78203cc Merge pull request #1769 from ReinUsesLisp/cc
gl_shader_decompiler: Rename cc to condition code and name internal flags
2018-11-23 23:31:04 -05:00
bunnei
0d673a84b6 nvdrv: Implement/stub DumpGraphicsMemoryInfo and GetStatus.
- Used by Undertale.
2018-11-23 23:22:04 -05:00
Rodolfo Bogado
54c2a4cafc Add support for clear_flags register 2018-11-24 00:16:33 -03:00
FernandoS27
7668ef51d6 Fix TEXS Instruction encodings 2018-11-23 22:46:50 -04:00
FernandoS27
9c2127d5eb Fix one encoding in TEX Instruction 2018-11-23 22:46:49 -04:00
FernandoS27
487d805899 Corrected inputs indexing in TEX instruction 2018-11-23 22:46:48 -04:00
bunnei
69b3f98d3a Merge pull request #1744 from degasus/shader_cache
shader_cache: Only lock covered instructions.
2018-11-23 21:09:36 -05:00
bunnei
d57e00801d Merge pull request #1741 from lioncash/kbd
software_keyboard: Minor changes
2018-11-23 21:09:18 -05:00
bunnei
0b1842294f memory_manager: Do not allow 0 to be a valid GPUVAddr.
- Fixes a bug with Undertale using 0 for a render target.
2018-11-23 12:58:55 -05:00
bunnei
c267aea29b Merge pull request #1770 from DarkLordZach/applet-stub
applets: Add StubApplet and use it as fallback when AppletId is not implemented
2018-11-23 09:02:25 -08:00
bunnei
f1969ee1f3 Merge pull request #1777 from lioncash/core-mgr
core: Relocate CPU core management to its own class
2018-11-23 09:00:41 -08:00
bunnei
24dfb43ac6 Merge pull request #1773 from lioncash/thread
common/thread: Minor cleanup
2018-11-23 08:52:05 -08:00
Hexagon12
3135dbc29c Added predicate comparison LessEqualWithNan (#1736)
* Added predicate comparison LessEqualWithNan

* oops

* Clang fix
2018-11-23 08:51:32 -08:00
bunnei
c4b5319446 Merge pull request #1756 from ReinUsesLisp/fix-textures
gl_shader_decompiler: Fix register overwriting on texture calls
2018-11-23 08:49:37 -08:00
bunnei
d77af9f8fd Merge pull request #1766 from FernandoS27/fix-txq
Properly Implemented TXQ Instruction
2018-11-23 08:48:57 -08:00
bunnei
cb5b68cb0a Merge pull request #1762 from bunnei/getgputime
nvhost_ctrl_gpu: Implement IoctlGetGpuTime.
2018-11-23 08:35:26 -08:00
ReinUsesLisp
b3853403b7 gl_shader_decompiler: Implement clip distances 2018-11-23 02:14:43 -03:00
Zach Hilman
86ad1f8db6 file_sys: Implement system archive synthesizer for NgWord (806) 2018-11-22 21:39:10 -05:00
Zach Hilman
f820e58be4 am: Return StubApplet instead of nullptr when AppletId not found 2018-11-22 15:58:11 -05:00
ReinUsesLisp
c9ac23683b gl_shader_decompiler: Add a message for unimplemented cc generation 2018-11-22 16:12:27 -03:00
Mat M
bee5a7acb1 Merge pull request #1779 from DarkLordZach/debug-pad-unmapped
debug_pad: Avoid loading input for nonexistent buttons (Home and Screenshot)
2018-11-22 13:41:32 -05:00
greggameplayer
c14af2f71d correct clang-format 2018-11-22 18:26:43 +01:00
Zach Hilman
b358e88512 debug_pad: Avoid loading input for nonexistent buttons (Home and Screenshot)
Prevents memory exceptions when the debug pad is enabled.
2018-11-22 12:23:43 -05:00
bunnei
50d2abaaa9 Merge pull request #1775 from bunnei/blend-eq
maxwell_3d: Implement alternate blend equations.
2018-11-22 08:44:05 -08:00
bunnei
af159a4d08 Merge pull request #1765 from bunnei/multi-audout
audout_u: Add support for multiple IAudioOut streams.
2018-11-22 08:43:53 -08:00
bunnei
e633021532 Merge pull request #1764 from bunnei/macrointerpreter
macro_interpreter: Implement AddWithCarry and SubtractWithBorrow.
2018-11-22 08:43:29 -08:00
Lioncash
232d95b56e core: Relocate CPU core management to its own class
Keeps the CPU-specific behavior from being spread throughout the main
System class. This will also act as the home to contain member functions
that perform operations on all cores. The reason for this being that the
following pattern is sort of prevalent throughout sections of the
codebase:

If clearing the instruction cache for all 4 cores is necessary:

Core::System::GetInstance().ArmInterface(0).ClearInstructionCache();
Core::System::GetInstance().ArmInterface(1).ClearInstructionCache();
Core::System::GetInstance().ArmInterface(2).ClearInstructionCache();
Core::System::GetInstance().ArmInterface(3).ClearInstructionCache();

This is kind of... well, silly to copy around whenever it's needed.
especially when it can be reduced down to a single line.

This change also puts the basics in place to begin "ungrafting" all of the
forwarding member functions from the System class that are used to
access CPU state or invoke CPU-specific behavior. As such, this change
itself makes no changes to the direct external interface of System. This
will be covered by another changeset.
2018-11-22 04:28:19 -05:00
bunnei
033b46253e macro_interpreter: Implement AddWithCarry and SubtractWithBorrow.
- Used by Undertale.
2018-11-22 00:58:00 -05:00
bunnei
5a6dc4d041 audout_u: Add support for multiple IAudioOut streams.
- Used by Undertale.
2018-11-22 00:53:39 -05:00
bunnei
0e6a608245 maxwell_3d: Implement alternate blend equations.
- Used by Undertale.
2018-11-22 00:51:01 -05:00
Lioncash
1bf5a337a5 common/thread: Drop Hungarian notation on SetCurrentThreadName's parameter
This is inconsistent with our coding style.
2018-11-22 00:40:26 -05:00
bunnei
b84f4cfb62 Merge pull request #1737 from FernandoS27/layer-copy
Implemented Fast Layered Copy
2018-11-21 21:39:16 -08:00
bunnei
f0d3f1b376 Merge pull request #1771 from lioncash/bit-set
common: Remove bit_set.h
2018-11-21 21:36:15 -08:00
Zach Hilman
820d81b9a5 scheduler: Add explanations for YieldWith and WithoutLoadBalancing 2018-11-22 00:33:53 -05:00
bunnei
f926559ef4 Merge pull request #1767 from lioncash/handle
kernel/handle_table: Minor changes
2018-11-21 21:26:48 -08:00
Lioncash
93f7677402 common/thread: Make Barrier's 'count' member non-const
While admirable as a means to ensure immutability, this has the
unfortunate downside of making the class non-movable. std::move cannot
actually perform a move operation if the provided operand has const data
members (std::move acts as an operation to "slide" resources out of an
object instance). Given Barrier contains move-only types such as
std::mutex, this can lead to confusing error messages if an object ever
contained a Barrier instance and said object was attempted to be moved.
2018-11-21 21:47:08 -05:00
Lioncash
756e773096 common/thread: Initialize class member variables where applicable
Simplifies the constructor interfaces for Barrier and Event classes.
2018-11-21 21:45:01 -05:00
Lioncash
02602afd10 common/thread: Group non-member functions together
Keeps the non-member interface in one spot instead of split into two
places, making it nicer to locate functions.
2018-11-21 21:42:33 -05:00
Lioncash
d6583d68f6 common/thread: Remove SleepCurrentThread()
This is also unused and superceded by standard functionality. The
standard library provides std::this_thread::sleep_for(), which provides
a much more flexible interface, as different time units can be used with
it.
2018-11-21 21:40:11 -05:00
Lioncash
1d555fdd25 common/thread: Remove unused CurrentThreadId()
This is an old function that's no longer necessary. C++11 introduced
proper threading support to the language and a thread ID can be
retrieved via std::this_thread::get_id() if it's ever needed.
2018-11-21 21:37:11 -05:00
Lioncash
8b27e73bd7 common: Remove bit_set.h
This is an analog of BitSet from Dolphin that was introduced to allow
iterating over a set of bits. Given it's currently unused, and given
that std::bitset exists, we can remove this. If it's ever needed in the
future it can be brought back.
2018-11-21 21:30:10 -05:00
Zach Hilman
699900eed0 applets: Add StubApplet
This will log all data it receives, log all calls to its methods and push dummy data into both channels on execution.
2018-11-21 21:20:02 -05:00
ReinUsesLisp
74eb16521f gl_shader_decompiler: Rename internal flag strings 2018-11-21 22:31:42 -03:00
ReinUsesLisp
8a5e6fce07 gl_shader_decompiler: Rename control codes to condition codes 2018-11-21 22:31:16 -03:00
greggameplayer
6d2adb0bc0 Automatically disable joycons docked
when docked mode is enable
2018-11-22 01:24:39 +01:00
ReinUsesLisp
864cbbaf4c gl_shader_decompiler: Fix register overwriting on texture calls 2018-11-21 21:21:19 -03:00
Lioncash
0e35f1bb18 kernel/handle_table: Move private static functions into the cpp file
These don't depend on class state, and are effectively implementation
details, so they can go into the cpp file .
2018-11-21 18:31:01 -05:00
Lioncash
568bcbc29d kernel/handle_table: Restrict handle table size to 1024 entries
The previous handle table size is a holdover from Citra. The actual
handle table construct on Horizon only allows for a maximum of 1024
entries.
2018-11-21 18:28:03 -05:00
Lioncash
f5ce71793e kernel/handle_table: Default destructor in the cpp file
We don't need to potentially inline the teardown logic of all of the
handle instances.
2018-11-21 18:23:09 -05:00
bunnei
ec38b4e883 Merge pull request #1753 from FernandoS27/ufbtype
Use default values for unknown framebuffer pixel format
2018-11-21 14:15:27 -08:00
bunnei
61586e8794 Merge pull request #1752 from ReinUsesLisp/unimpl-decompiler
gl_shader_decompiler: Use UNIMPLEMENTED when applicable
2018-11-21 14:13:28 -08:00
FernandoS27
4a6a9b6622 Properly Implemented TXQ Instruction 2018-11-21 18:12:36 -04:00
bunnei
d4012a4540 Merge pull request #1742 from lioncash/hle-swkbd
am/applets: Minor cleanup
2018-11-21 11:43:43 -08:00
ReinUsesLisp
642dfeda2a gl_shader_decompiler: Implement BFI_IMM_R 2018-11-21 16:12:30 -03:00
bunnei
7f10db1c20 nvhost_ctrl_gpu: Implement IoctlGetGpuTime.
- Used by Undertale.
2018-11-21 11:43:25 -05:00
bunnei
bb175ab430 Merge pull request #1754 from ReinUsesLisp/zero-register
gl_shader_decompiler: Remove UNREACHABLE when setting RZ
2018-11-21 08:06:29 -08:00
bunnei
8cdb48224d Merge pull request #1758 from lioncash/rect
common/math_util: Minor cleanup
2018-11-21 08:05:39 -08:00
bunnei
81e14c072a Merge pull request #1759 from lioncash/unused
common: Remove depencency on xbyak
2018-11-21 08:05:14 -08:00
FernandoS27
0368260c99 Removed pre 4.3 ARB extensions 2018-11-21 11:43:17 -04:00
FernandoS27
377c60645c Update OpenGL's backend version from 3.3 to 4.3 2018-11-21 11:43:17 -04:00
FernandoS27
0a9fedfac9 Use default values for unknown framebuffer pixel format 2018-11-21 07:33:34 -04:00
Lioncash
3533d33ff5 common: Remove dependency on xbyak
Xbyak is currently entirely unused. Rather than carting it along, remove
it and get rid of a dependency. If it's ever needed in the future, then
it can be re-added (and likely be more up to date at that point in
time).
2018-11-21 03:43:41 -05:00
ReinUsesLisp
d92afc7493 gl_shader_decompiler: Implement R2P_IMM 2018-11-21 04:56:00 -03:00
Lioncash
45211a7a91 common/math_util: Simplify std::make_signed usages to std::make_signed_t
Gets rid of the need to use typename to access the ::type alias.
2018-11-21 02:08:18 -05:00
Lioncash
f11173f88c common/math_util: Make Rectangle's constructors constexpr
Allows objects that contain rectangle instances to be constexpr
constructible as well.
2018-11-21 02:08:18 -05:00
Lioncash
cc0801745a common/math_util: Remove unnecessary static from PI
const/constexpr variables have internal linkage by default.
2018-11-21 02:08:18 -05:00
Lioncash
74fd0aa2e8 common/math_util: Remove unused IntervalsIntersect() function
This hasn't been used since the project started, so we may as well get
rid of it to keep it from bit rotting.
2018-11-21 02:08:15 -05:00
bunnei
5af4160bf2 Merge pull request #1751 from bunnei/color-mask-fix
maxwell_3d: Initialize rasterizer color mask registers as enabled.
2018-11-20 19:20:13 -08:00
ReinUsesLisp
423a3ed2c8 gl_shader_decompiler: Remove UNREACHABLE when setting RZ 2018-11-20 22:23:10 -03:00
bunnei
b55c7bbcf7 Merge pull request #1750 from lioncash/amend
am: Correct build failure
2018-11-20 17:00:29 -08:00
ReinUsesLisp
bb893188eb gl_shader_decompiler: Use UNIMPLEMENTED instead of LOG+UNREACHABLE when applicable 2018-11-20 22:00:13 -03:00
bunnei
1a543723ab maxwell_3d: Initialize rasterizer color mask registers as enabled.
- Fixes rendering regression with Sonic Mania.
2018-11-20 19:58:06 -05:00
Lioncash
f17e122025 am: Correct build failure
The interface for shared memory was changed, but another commit was
merged that relied on the (previously public) internals of SharedMemory.

This amends that discrepancy.
2018-11-20 19:49:07 -05:00
Zach Hilman
54e74b3572 patch_manager: Show LayeredExeFS patch in add-ons column
The decision was made to name them LayeredExeFS instead of just LayeredFS to differentiate from normal RomFS-based mods. The name may be long/unweildy, but conveys the meaning well.
2018-11-20 19:22:34 -05:00
bunnei
aa7e53ab5c Merge pull request #1734 from lioncash/shared
kernel/shared_memory: Make data members private, plus minor interface changes
2018-11-20 16:13:30 -08:00
bunnei
ab292c501c Merge pull request #1733 from lioncash/ldr
ldr: Clean up error codes
2018-11-20 16:13:09 -08:00
bunnei
67486c0568 Merge pull request #1746 from lioncash/random
kernel/process: Move <random> include to the cpp file
2018-11-20 16:12:29 -08:00
bunnei
1d0604e33c Merge pull request #1748 from lioncash/assert
common/assert: Make the UNIMPLEMENTED macro properly assert
2018-11-20 16:11:30 -08:00
bunnei
58d82243f7 Merge pull request #1749 from lioncash/gc-info
file_sys/card_image: Provide named members for the GamecardInfo struct
2018-11-20 16:10:55 -08:00
Lioncash
820bcee6a4 file_sys/card_image: Provide named members for the GamecardInfo struct
Fills out the struct according to information provided by SwitchBrew
2018-11-20 18:40:53 -05:00
Lioncash
9dcc229dfe common/assert: Add UNIMPLEMENTED_IF and UNIMPLEMENTED_IF_MSG for conditional assertions
Currently, there's no way to specify if an assertion should
conditionally occur due to unimplemented behavior. This is useful when
something is only partially implemented (e.g. due to ongoing RE work).
In particular, this would be useful within the graphics code.

The rationale behind this is it allows a dev to disable unimplemented
feature assertions (which can occur in an unrelated work area), while
still enabling regular assertions, which act as behavior guards for
conditions or states which must not occur. Previously, the only way a
dev could temporarily disable asserts, was to disable the regular
assertion macros, which has the downside of also disabling, well, the
regular assertions which hold more sanitizing value, as opposed to
unimplemented feature assertions.
2018-11-20 18:15:37 -05:00
Lioncash
aaec85df9e common/assert: Make the UNIMPLEMENTED macro properly assert
Currently, this was only performing a logging call, which doesn't
actually invoke any assertion behavior. This is unlike
UNIMPLEMENTED_MSG, which *does* assert.

This makes the expected behavior uniform across both macros.
2018-11-20 17:59:00 -05:00
Zach Hilman
da6d4cde56 patch_manager: Apply LayeredExeFS patches
This will scan the <mod>/exefs dir for all files and then layer those on top of the game's exefs and use this as the new exefs. This allows for overriding of the compressed NSOs or adding new files. This does use the same dir as IPS/IPSwitch patch, but since the loader will not look for those they are ignored.
2018-11-20 17:51:00 -05:00
Zach Hilman
17d8e25cbf settings: Add option to dump ExeFS of games upon launch
When enabled, all exefs(es) will be copied to yuzu/dump/<title_id>/exefs.
2018-11-20 17:49:09 -05:00
Lioncash
31d1e06eb1 kernel/process: Move <random> include to the cpp file
<random> isn't necesary directly within the header and can be placed in
the cpp file where its needed. Avoids propagating random generation
utilities via a header file.
2018-11-20 17:46:20 -05:00
Markus Wick
cfbae58b2b shader_cache: Only lock covered instructions. 2018-11-20 21:58:31 +01:00
Lioncash
73b7748984 am/applets: Make the applet data broker part of the applet itself.
The accessor should be doing just that, accessing, rather than retaining
the lifetime of the data broker as well.
2018-11-20 12:36:33 -05:00
Lioncash
8b4b560df5 am/applets: Replace includes with forward declarations where applicable
Also resolve places where includes should have been provided, but
weren't.
2018-11-20 11:53:55 -05:00
Lioncash
dd254c603d am/applets: Relocate comments above the relevant data member in AppletDataBroker
Avoids wonky wrapping and makes it nicer to read.
2018-11-20 11:49:49 -05:00
Lioncash
4dcdd3a837 yuzu/applets/software_keyboard: Override accept() and reject() instead of providing own differently named member functions
Uses Qt's built-in interface instead of rolling our own separate one on
top of it. This also fixes a bug in reject() where we were calling
accept() instead of reject().
2018-11-20 11:36:50 -05:00
Lioncash
3fa2b218ac yuzu/applets/software_keyboard: std::move std::function instances where applicable
std::function instances can potentially allocate. std::moveing them
prevents an avoidable allocation in that case.
2018-11-20 11:34:19 -05:00
Lioncash
fe2609cb77 yuzu/applets/software_keyboard: Make slots private functions
These aren't required to be public.
2018-11-20 11:29:22 -05:00
bunnei
b6d2c64f4d Merge pull request #1667 from DarkLordZach/swkbd
am: Implement HLE software keyboard applet
2018-11-20 08:24:11 -08:00
bunnei
e9265ac598 Merge pull request #1739 from lioncash/lm
lm: Implement SetDestination by doing nothing
2018-11-19 18:40:17 -08:00
bunnei
2caac4a395 Merge pull request #1738 from lioncash/res-limit
kernel/resource_limit: Clean up interface
2018-11-19 18:40:02 -08:00
FernandoS27
eb36463e03 Implemented Fast Layered Copy 2018-11-19 19:51:13 -04:00
Lioncash
5d46038c5c kernel/resource_limit: Clean up interface
Cleans out the citra/3DS-specific implementation details that don't
apply to the Switch. Sets the stage for implementing ResourceLimit
instances properly.

While we're at it, remove the erroneous checks within CreateThread() and
SetThreadPriority(). While these are indeed checked in some capacity,
they are not checked via a ResourceLimit instance.

In the process of moving out Citra-specifics, this also replaces the
system ResourceLimit instance's values with ones from the Switch.
2018-11-19 18:16:39 -05:00
Lioncash
34e4aaddd9 lm: Implement SetDestination by doing nothing
This service function was likely intended to be a way to redirect where
the output of a log went. e.g. Firing a log over a network, dumping over
a tunneling session, etc.

Given we always want to see the log and not change its output. It's one
of the lucky service functions where the easiest implementation is to
just do nothing at all and return success.
2018-11-19 18:09:40 -05:00
Zach Hilman
a9fa890f14 software_keyboard: Fix erroneous extra PushNormalData 2018-11-19 16:30:17 -05:00
Zach Hilman
d68795c665 software_keyboard: Return correct result code on user cancel operation 2018-11-19 15:10:01 -05:00
Zach Hilman
32775125b7 applet: Add AppletDataBroker to manage HLE to AM service interaction
This cleans up most of the callbacks and such in the Applets::Applet interface, while also properly implementing all four data channels.
2018-11-19 14:24:36 -05:00
bunnei
048da7240d Merge pull request #1634 from DarkLordZach/better-hid-2
hid: Add support for multiplayer and multilayout controllers
2018-11-19 08:30:10 -08:00
Zach Hilman
96535c13a5 software_keyboard: Use correct offset for inital text string 2018-11-19 11:22:04 -05:00
Lioncash
233e495c14 kernel/shared_memory: Make Map() and Unmap() take the target process by reference rather than as a pointer
Both member functions assume the passed in target process will not be
null. Instead of making this assumption implicit, we can change the
functions to be references and enforce this at the type-system level.
2018-11-19 09:20:29 -05:00
Lioncash
fb5d4b17de kernel/shared_memory: Add a const qualified member function overload for GetPointer()
Given this doesn't mutate instance state, we can provide a
const-qualified variant as well.
2018-11-19 09:20:29 -05:00
Lioncash
2d37ca3726 kernel/shared_memory: Use 64-bit types for offset and size in CreateForApplet
Keeps the interface consistent with the regular Create() function.
2018-11-19 09:20:29 -05:00
Lioncash
76ac234bf6 kernel/shared_memory: Make GetPointer() take a std::size_t instead of a u32
Makes the interface nicer to use in terms of 64-bit code, as it makes it
less likely for one to get truncation warnings (and also makes sense in
the context of the rest of the interface where 64-bit types are used for
sizes and offsets
2018-11-19 09:20:29 -05:00
Lioncash
f472232705 kernel/shared_memory: Make data members private
Rather than allow unfettered access to the class internals, we hide all
members by default and create and API that other code can operate
against.
2018-11-19 09:20:25 -05:00
Lioncash
43e7c6cf49 ldr: Clean up error codes
The separate enum isn't particularly necessary here, and the values can
just be directly put into the ResultCode instances, given the names are
also self-documenting here.
2018-11-19 08:12:25 -05:00
Zach Hilman
409dcf0e0a svc: Implement yield types 0 and -1 2018-11-18 23:44:19 -05:00
Zach Hilman
c3becdbca7 filesystem: Clear registered union paths on factory creation 2018-11-18 23:31:30 -05:00
Zach Hilman
aef0d88165 configure_input: Use Joycons Docked instead of Connected as label 2018-11-18 23:22:36 -05:00
Zach Hilman
312ef596a5 configure_input_player: Set minimum width on controls 2018-11-18 23:22:36 -05:00
Zach Hilman
dd92db3fb0 configure_input: Properly update UI components on removal of player 2018-11-18 23:22:36 -05:00
Zach Hilman
e58c951a59 configure_input: Make None a controller option instead of checkbox 2018-11-18 23:22:36 -05:00
Zach Hilman
3a6cd5b3c8 hid: Use player-defined controller type as PREFERRED_CONTROLLER 2018-11-18 23:22:36 -05:00
Zach Hilman
3d1a221893 qt: Move controller button config to separate dialog
Handles button configuration for all controller layouts and debug pads. Configurable at construction.
2018-11-18 23:22:36 -05:00
Zach Hilman
afe8df5020 qt: Add UI to configure touchscreen parameters
This allows adjusting the finger, diameter, and angle of the emulated touchscreen. It also provides a warning to the user about what changing these parameters can do.
2018-11-18 23:22:36 -05:00
Zach Hilman
2e1dd9c649 qt: Add UI to configure mouse buttons
Supports setting the five mouse buttons to any valid controller button/keyboard key (Left, Right, Middle, Foward, Back)
2018-11-18 23:22:36 -05:00
Zach Hilman
f1aec256d7 configure_input: Add support for multiplayer and controller types
This moves the actual button configuration to a separate dialog and only has the enabled and type controls in the tab.
2018-11-18 23:22:36 -05:00
Zach Hilman
55ded706d6 hid/npad: Update NPad to use player controller bindings and type 2018-11-18 23:22:36 -05:00
Zach Hilman
e9145c3e16 hid/touchscreen: Update Touchscreen to use advanced parameters
Including finger ID, diamater x/y, and angle. Additionally, checks if the touchscreen is enabled.
2018-11-18 23:22:36 -05:00
Zach Hilman
3b25426bd9 hid: Add controller bindings for Mouse controller 2018-11-18 23:22:36 -05:00
Zach Hilman
0fd45e78f4 hid: Add keyboard bindings for Keyboard controller 2018-11-18 23:22:36 -05:00
Zach Hilman
06cf050c0a hid: Add controller bindings for DebugPad controller
Used by developers to test games, not present on retail systems. Some games are known to respond to DebugPad input though, for example Kirby Star Allies.
2018-11-18 23:22:36 -05:00
Zach Hilman
d1b7c65b9e yuzu/config: Add (de-)serialization for multiplayer
Defaults to full keyboard for keyboard -- It did not seem to be necessary to make the keyboard configurable (besides enabled/disabled).
2018-11-18 23:22:36 -05:00
Zach Hilman
b8f7f9651e yuzu_cmd/config: Add config deserialization for multiplayer 2018-11-18 23:22:36 -05:00
Zach Hilman
c77454b9d0 settings: Add settings for multiple players and controllers
Uses the PlayerInput struct to represent all of the data that constitutes a player.
2018-11-18 23:21:33 -05:00
Zach Hilman
fd5fa48674 settings: Add Native type for keyboard 2018-11-18 23:21:33 -05:00
Zach Hilman
152422bab1 settings: Add Native type for mouse buttons 2018-11-18 23:21:33 -05:00
David Marcec
0c3e7b7086 Added missing start/end touch attributes to touchscreen 2018-11-18 23:21:33 -05:00
David Marcec
f66c6fe554 Added debugpad skeleton 2018-11-18 23:21:33 -05:00
David Marcec
362b28d052 Added controller helper funcs 2018-11-18 23:21:33 -05:00
David Marcec
a69b9d73f5 Changed polling rate of hid and Right joycon rotation 2018-11-18 23:21:33 -05:00
David Marcec
7fbe2c83a7 Left joycon rotation button remapping 2018-11-18 23:21:33 -05:00
David Marcec
b9c1e4b0e7 Added automatic npad switch based on supported stylesets 2018-11-18 23:21:33 -05:00
David Marcec
beab38601b Added multi-input support and controller assignment at any port 2018-11-18 23:21:33 -05:00
David Marcec
60fecee1ec Removed hard coded values for width and height 2018-11-19 15:20:47 +11:00
Zach Hilman
ea680bea60 software_keyboard: Check for UTF-8 config flag 2018-11-18 23:14:48 -05:00
bunnei
f02b125ac8 Merge pull request #1717 from FreddyFunk/swizzle-gob
textures/decoders: Replace magic numbers
2018-11-18 20:13:00 -08:00
bunnei
6dc33fb812 Merge pull request #1693 from Tinob/master
Missing ogl states
2018-11-18 19:59:10 -08:00
bunnei
5e6ad795cc Merge pull request #1555 from ccawley2011/clang-format-docker
travis: Use pre-built image for clang-format target
2018-11-18 19:54:38 -08:00
bunnei
997c3dc6ff Merge pull request #1619 from janisozaur/patch-12
Handle missing git info when building
2018-11-18 19:53:34 -08:00
Frederic L
11a1442229 Eliminated unnessessary memory allocation and copy (#1702) 2018-11-18 19:53:03 -08:00
bunnei
3e93c30630 Merge pull request #1640 from DarkLordZach/game-list-reload
game_list: Only reload game list after relevant settings changed
2018-11-18 19:24:53 -08:00
bunnei
e34d47e6e3 Merge pull request #1620 from DarkLordZach/ldr-ro
ldr_ro: Complete LDR:RO implementation
2018-11-18 19:23:38 -08:00
bunnei
f08b4cbbc8 Merge pull request #1718 from ogniK5377/lets-go-softlock
Implemented CalculateStandardUserSystemClockDifferenceByUser
2018-11-18 19:22:47 -08:00
Schplee
9a47e40dd6 Correctly sets default system language for yuzu-CLI (#1727)
* Correctly sets default system language for yuzu-CLI

A user reported that yuzu_cmd runs games in Japanese rather than the correct default of English (like yuzu-qt does correctly), this change fixes that.

* fix clang issue

deleted whitespace
2018-11-18 19:21:17 -08:00
bunnei
da238db6df Merge pull request #1730 from ReinUsesLisp/fix-intel
gl_rasterizer: Remove default clip distance
2018-11-18 19:19:43 -08:00
bunnei
611141e09f Merge pull request #1671 from DarkLordZach/vi-disconnect
vi: Implement TransactParcel for Disconnect and DetachBuffer
2018-11-18 19:18:46 -08:00
ReinUsesLisp
29e7c76d66 gl_rasterizer: Remove default clip distance 2018-11-18 23:57:52 -03:00
Mat M
9a1bac840e Merge pull request #1728 from FearlessTobi/reset-signal
svc: ResetSignal is not stubbed
2018-11-18 15:51:32 -05:00
Tobias
13f79cc5bd svc: ResetSignal is not stubbed
https://user-images.githubusercontent.com/20753089/48677874-b8e01c80-eb7b-11e8-8043-b99faa29022c.PNG
2018-11-18 21:49:17 +01:00
Zach Hilman
56cf5b7b17 software_keyboard: Add max and current length display to dialog 2018-11-18 10:53:47 -05:00
Zach Hilman
02e6602baa software_keyboard: Push all data over all channels on dialog completion 2018-11-18 10:53:47 -05:00
Zach Hilman
4ee087fb3c applet: Use std::queue instead of std::vector for storage stack 2018-11-18 10:53:47 -05:00
Zach Hilman
19b2571aec applet: Add operation completed callback 2018-11-18 10:53:47 -05:00
Zach Hilman
6209fe0c27 software_keyboard: Push buffer size to offset 0x4 in output data 2018-11-18 10:53:47 -05:00
Zach Hilman
8b433beff3 software_keyboard: Make GetText asynchronous
a
2018-11-18 10:53:47 -05:00
Zach Hilman
7cfb29de23 am: Allow applets to push multiple and different channels of data 2018-11-18 10:53:47 -05:00
Zach Hilman
3cf7246e37 am: Implement ILibraryAppletAccessor IsCompleted and GetResult 2018-11-18 10:53:47 -05:00
Zach Hilman
fed6ab14c3 am: Implement text check software keyboard mode
Allows the game to verify and send a message to the frontend.
2018-11-18 10:53:47 -05:00
Zach Hilman
e696ed1f4d am: Deglobalize software keyboard applet 2018-11-18 10:53:47 -05:00
Zach Hilman
a81645400f qt/main: Register Qt Software Keyboard frontend with AM
Allows using Qt provider over default.
2018-11-18 10:53:47 -05:00
Zach Hilman
48fcb43585 am: Construct and use proper applets with ILibraryAppletAccessor
Allows use of software keyboard applet and future applets to be easily added by adding enum ID and a switch case.
2018-11-18 10:53:47 -05:00
Zach Hilman
5454494adb qt/applets: Provide Qt frontend implementation of software keyboard
Implements all of the features of the keyboard, including length, default text, character validation, and UTF-16 character support.
2018-11-18 10:53:47 -05:00
Zach Hilman
de16c1e453 am/applets: Add connector between frontend and AM applet classes
Provides a middleman between the Frontend provider class and the expected AM::Applets::Applet class needed by ILibraryAppletAccessor
2018-11-18 10:53:47 -05:00
Zach Hilman
ae53b84efd frontend/applets: Add frontend software keyboard provider and default
Default implementation will return "yuzu" for any string. GUI clients (or CLI) can implement the Frontend::SoftwareKeyboardApplet class and register an instance to provide functionality.
2018-11-18 10:53:47 -05:00
Zach Hilman
5b95de0c9c am/applets: Add Applet superclass to describe a generic applet
Adds an Initialize and Execute methods which are used by the ILibraryAppletAccessor to start and control the applet.
2018-11-18 10:53:47 -05:00
Zach Hilman
731b4bd691 am: Unstub ILibraryAppletAccessor::Start
Now starts the applet provided in constructor.
2018-11-18 10:53:47 -05:00
Zach Hilman
ba03bfa430 am: Implement PopInteractiveOutData and PushInteractiveInData
Used by software keyboard applet for data transfer.
2018-11-18 10:53:47 -05:00
Zach Hilman
5ce6b8fea7 am: Convert storage stack to vector
std::stack was no longer suitable for non-trivial operations
2018-11-18 10:53:47 -05:00
Zach Hilman
0682a908c0 am: Move AM::IStorage to header
Needs to be accessible by applet files.
2018-11-18 10:53:47 -05:00
Zach Hilman
c7b6c9de9c am: Move IStorageAccessor to header and update backing buffer
Writes to an AM::IStorage object through an IStorageAccessor will now be preserved once the accessor is destroyed.
2018-11-18 10:53:47 -05:00
Zach Hilman
76d515327b am: Implement CreateTransferMemoryStorage
Creates an AM::IStorage object with the contents of the transfer memory located at the handle provided.
2018-11-18 10:53:47 -05:00
Zach Hilman
c70529c1ec string_util: Implement buffer to UTF-16 string helper function
Needed as most all software keyboard functions use fixed-length UTF16 string buffers.
2018-11-18 10:53:47 -05:00
Zach Hilman
7901de2b75 svc: Implement svcCreateTransferMemory
Seems to be used and created identically to SharedMemory, so just reuse that.
2018-11-18 10:53:47 -05:00
Rodolfo Bogado
4d1a0a24cc drop support for non separate alpha as it seems to cause issues in some games 2018-11-18 03:44:48 -03:00
Zach Hilman
51af996854 ldr_ro: Add error check for memory allocation failure 2018-11-17 21:40:26 -05:00
Rodolfo Bogado
81a9c5fe6f fix sampler configuration, thanks to Marcos for his investigation 2018-11-17 19:59:34 -03:00
Rodolfo Bogado
b312cca756 small type fix 2018-11-17 19:59:34 -03:00
Rodolfo Bogado
5297495c87 small fix for alphaToOne bit location 2018-11-17 19:59:34 -03:00
Rodolfo Bogado
e69eb3c760 fix for gcc compilation 2018-11-17 19:59:34 -03:00
Rodolfo Bogado
53b4a1af0f add AlphaToCoverage and AlphaToOne 2018-11-17 19:59:34 -03:00
Rodolfo Bogado
8ed7e1af2c add support for fragment_color_clamp 2018-11-17 19:59:33 -03:00
Rodolfo Bogado
02c22a3440 add missing MirrorOnceBorder support where supported 2018-11-17 19:59:33 -03:00
Rodolfo Bogado
1d60bb6544 set border color not depending on the wrap mode
only enable color mask for the first framebuffer id independent blending is disabled
2018-11-17 19:59:33 -03:00
Rodolfo Bogado
6a2aa6dbdb set default value for point size register 2018-11-17 19:59:33 -03:00
Rodolfo Bogado
1881e86c43 fix viewport and scissor behavior 2018-11-17 19:59:32 -03:00
Zach Hilman
c91dc417d5 vi: Implement TransactParcel for Disconnect and DetachBuffer
Used by homebrew on exit. According to switchbrew, returns an empty response parcel with one zero in it.
2018-11-17 17:10:19 -05:00
Hexagon12
a819116154 Merge pull request #1722 from MysticExile/enable-applictation-crash-report
am: Stub EnableApplicationCrashReport
2018-11-17 19:42:07 +02:00
MysticExile
03f274d8c1 Stubbed am:EnableApplicationCrashReport 2018-11-17 15:05:55 +01:00
Markus Wick
97f5c4ffd3 gl_rasterizer: Skip VB upload if the state is clean. 2018-11-17 14:28:54 +01:00
bunnei
0072275d25 Merge pull request #1678 from FearlessTobi/amiibo-hotkeys
Port citra-emu/citra#4387: "yuzu: Add hotkey for Amiibo loading"
2018-11-16 20:20:41 -08:00
bunnei
6273a7aeee Merge pull request #1705 from Jcw87/mingw-jpeg
Include QT imageformat dependencies with releases
2018-11-16 20:20:03 -08:00
bunnei
0149b4245c Merge pull request #1711 from ogniK5377/bluetooth-lets-go
Added various bluetooth based cmds for palma
2018-11-16 20:08:36 -08:00
bunnei
6552d75be1 Merge pull request #1719 from bunnei/hwopus-fix
hwopus: DecodeInterleavedWithPerformance: Fix ordering of output parameters.
2018-11-16 20:08:17 -08:00
bunnei
224fcabe46 Merge pull request #1714 from lioncash/kern-err
kernel/errors: Clean up error codes
2018-11-16 20:07:55 -08:00
bunnei
585e6fd426 hwopus: DecodeInterleavedWithPerformance: Fix ordering of output parameters.
- Fixes audio issues with Pokemon: Let's Go Pikachu & Eevee.
2018-11-16 22:54:38 -05:00
David Marcec
c440e8b8e1 Implemented CalculateStandardUserSystemClockDifferenceByUser
Seems pokemon calls this sometimes and it caused "random crashes"
2018-11-17 14:01:16 +11:00
Frederic Laing
7a400e2191 textures/decoders: Replace magic numbers 2018-11-17 01:55:28 +01:00
bunnei
3c7ba00d73 Merge pull request #1712 from FearlessTobi/port-4426
Port citra-emu/citra#4426: "Common/Bitfield: store value as unsigned type"
2018-11-16 14:42:59 -08:00
Lioncash
d21b2164e9 kernel/errors: Clean up error codes
Similar to PR 1706, which cleans up the error codes for the filesystem
code, but done for the kernel error codes. This removes the ErrCodes
namespace and specifies the errors directly. This also fixes up any
straggling lines of code that weren't using the named error codes where
applicable.
2018-11-16 14:32:30 -05:00
Mat M
14cede1a0c Merge pull request #1638 from FreddyFunk/SetMemoryPermission-Stubbed
Implement SetMemoryPermission
2018-11-16 10:35:56 -05:00
bunnei
405dd03dae Merge pull request #1700 from FreddyFunk/cleanup
gl_rasterizer_chache: Minor cleanup
2018-11-16 07:07:30 -08:00
bunnei
241646f423 Merge pull request #1701 from FreddyFunk/decoders
textures/decoders: Minor cleanup
2018-11-16 07:07:11 -08:00
bunnei
5b8f70ea2e Merge pull request #1632 from DarkLordZach/keys-manager-optimizations
game_list: Optimize game list refresh
2018-11-16 07:02:37 -08:00
bunnei
0b701751da Merge pull request #1676 from lioncash/warn
gl_state: Amend compilation warnings
2018-11-16 07:00:03 -08:00
bunnei
238bc4a077 Merge pull request #1706 from lioncash/file-err
file_sys/errors: Clean up error code values
2018-11-16 06:59:07 -08:00
bunnei
e156834297 Merge pull request #1710 from ogniK5377/palma-lets-go
Added SetIsPalmaAllConnectable, SetPalmaBoostMode
2018-11-16 06:58:05 -08:00
Weiyi Wang
786995a81e Common/Bitfield: store value as unsigned type
Storing signed type causes the following behaviour: extractValue can do overflow/negative left shift. Now it only relies on two implementation-defined behaviours (which are almost always defined as we want): unsigned->signed conversion and signed right shift
2018-11-16 15:49:57 +01:00
David Marcec
e8899e7027 Added various bluetooth based cmds for palma
It seems palma is done through bluetooth, we need this for pokemon go however more research needs to be done when we actually get palma working. This is presumably used for transfering data between the controller and the console, it does not seem for actual input as far as I know.
2018-11-17 01:42:17 +11:00
David Marcec
e658118aa9 Added SetIsPalmaAllConnectable, SetPalmaBoostMode
Currently unclear what these do yet, will be researched at a later time when we want to implement palma.
2018-11-17 01:40:18 +11:00
Hexagon12
d104478f1b Merge pull request #1709 from ogniK5377/docked-mode-crash
Fixed switching operation modes when not running a game
2018-11-16 16:25:40 +02:00
David Marcec
4476fd29d6 Fixed switching operation modes when not running a game
The service manager seems to be a nullptr before a game boots
2018-11-16 20:08:02 +11:00
David Marcec
9359655712 Report resolution scaling support for vi and am
Specifying an internal resolution in yuzu now will report the scaled changes to vi and am.
2018-11-16 18:07:42 +11:00
Jcw87
e634ce847f Remove whitespace 2018-11-15 22:44:18 -08:00
Jcw87
84364c9d4f Include imageformat dependencies with releases (appveyor) 2018-11-15 21:53:40 -08:00
Lioncash
5c9c33e8ad file_sys/errors: Remove currently unused filesystem error codes
Rather than keeping around unused values, we can just introduce them as
needed.
2018-11-16 00:18:22 -05:00
Lioncash
edd5b6f12f file_sys/errors: Get rid of the ErrCodes namespace
There's no real point to keeping the separate enum around, especially
given the name of the error code itself is supposed to document what the
value actually represents.
2018-11-16 00:13:50 -05:00
Lioncash
b725d1fdf7 file_sys/errors: Extract FS-related error codes to file_sys/errors.h
Keeps filesystem-related error codes in one spot.
2018-11-16 00:13:50 -05:00
Jcw87
287ee1cd63 Include imageformat dependencies with releases 2018-11-15 20:55:37 -08:00
David
87eca5b209 Fixed priority switching edge case for handheld (#1675)
* Fixed priority switching edge case for handheld

We accidently used controller index instead of npad id

* Moved NPadIdToIndex
2018-11-15 20:31:27 -08:00
bunnei
75640c9c71 Merge pull request #1699 from DarkLordZach/deterministic-rng-3
csrng: Use random integer distribution instead of raw engine
2018-11-15 20:18:47 -08:00
Zach Hilman
4838bc8ddc fsp_srv: Add support for using open source archive if not found in NAND 2018-11-15 22:35:16 -05:00
Zach Hilman
6aa69880ea file_sys: Add framework for synthesizing open source archives 2018-11-15 22:34:35 -05:00
Zach Hilman
34cd56980f vfs_vector: Add VFS backend for std::array
Allows using constexpr/static const data with VFS.
2018-11-15 22:33:52 -05:00
Zach Hilman
8cb2e7d881 csrng: Use random integer distribution instead of raw engine
Prevents returning the same value every single call.
2018-11-15 18:44:26 -05:00
bunnei
f7319b0d3c Merge pull request #1687 from lioncash/deduplication
kernel/thread: Deduplicate scheduler switching code
2018-11-15 14:47:42 -08:00
bunnei
97605e36f7 Merge pull request #1618 from DarkLordZach/dump-nso
patch_manager: Add support for dumping uncompressed NSOs
2018-11-15 14:46:10 -08:00
bunnei
98060c6f7b Merge pull request #1691 from lioncash/audren
service/audren_u: Forward RequestUpdateAuto through the same function as RequestUpdate
2018-11-15 14:44:36 -08:00
Frederic Laing
95d3965f31 textures/decoders: Minor cleanup 2018-11-15 21:04:17 +01:00
Frederic Laing
3844b5c0c5 gl_rasterizer_chache: Minor cleanup 2018-11-15 20:10:05 +01:00
Zach Hilman
c0a9abc3e1 ldr_ro: Implement UnloadNro (command 1)
Includes actual unmapping and address error checking.
2018-11-15 12:48:09 -05:00
Zach Hilman
056fa43dcd ldr_ro: Fully Implement LoadNro (command 0)
Includes NRO and BSS error checking, maximum loaded NRO check, NRR hash check, and proper remapping of BSS data.
2018-11-15 12:48:09 -05:00
Zach Hilman
5e8e7b6019 ldr_ro: Implement UnloadNrr (command 3)
Includes initialization check, proper address check, alignment check, and actual unloading of a loaded NRR.
2018-11-15 12:48:09 -05:00
Zach Hilman
6cd504feb9 ldr_ro: Fully implement LoadNrr (command 2)
Includes parameter error checking, hash enforcement, initialization check, and max NRR load check.
2018-11-15 12:48:09 -05:00
Zach Hilman
0276761a1e process: Make MirrorMemory take state to map new memory as
Credits to Subv
2018-11-15 12:48:09 -05:00
Zach Hilman
8aa17f0480 pl_u: Resize buffers in shared font data getter to what game requests
Fixes unmapped spam in SMP and buffer size errors in some other games
2018-11-15 12:47:36 -05:00
bunnei
8a537a2021 Merge pull request #1637 from FernandoS27/cache
Improved GPU Caches lookup Speed
2018-11-14 19:07:52 -08:00
bunnei
c6c74248fe Merge pull request #1697 from lioncash/acc
acc/profile_manager: Minor cleanup-related changes
2018-11-14 19:02:25 -08:00
bunnei
0478308094 Merge pull request #1696 from lioncash/acc-cond
service/acc: Correct error case within TrySelectUserWithoutInteraction()
2018-11-14 19:02:16 -08:00
bunnei
53b3c3ab7f Merge pull request #1695 from lioncash/tr
yuzu/configure_system: Mark the entropy mask string as nontranslatable
2018-11-14 15:32:04 -08:00
Lioncash
cd47af8af0 service/acc: Correct error case within TrySelectUserWithoutInteraction()
empty() in this case will always return false, since the returned
container is a std::array. Instead, check if all given users are invalid
before returning the error code.
2018-11-14 17:43:23 -05:00
Lioncash
9761936e02 profile_manager: Replace iterative loop with a ranged-for loop in ParseUserSaveFile() 2018-11-14 17:13:17 -05:00
Lioncash
1af13e0802 profile_manager: Move UUID Format function definitions into the cpp file
Avoids relying on fmt always being indirectly included.
2018-11-14 17:08:59 -05:00
bunnei
c681690358 Merge pull request #1690 from lioncash/nfp
nfp: Correct erroneous sizeof expression within GetTagInfo()
2018-11-14 11:55:09 -08:00
bunnei
7384b33c4f Merge pull request #1689 from lioncash/break
hid/npad: Add missing break in switch statement within Controller_NPad::OnUpdate
2018-11-14 11:54:45 -08:00
bunnei
c95ded3a4a Merge pull request #1688 from lioncash/unused
service: Mark MakeFunctionString with the [[maybe_unused]] attribute.
2018-11-14 11:54:29 -08:00
Lioncash
e6676afa18 yuzu/configure_system: Mark the entropy mask string as nontranslatable
There's no need for translators to concern themselves with the
validation mask used by the entry field.
2018-11-14 14:53:43 -05:00
bunnei
ebf1b58a22 Merge pull request #1684 from lioncash/common
common/string_util: Minor cleanup
2018-11-14 11:53:10 -08:00
bunnei
e1ea8cc721 Merge pull request #1679 from DarkLordZach/deterministic-rng-2
svc: Use proper random entropy generation algorithm
2018-11-14 11:52:27 -08:00
Lioncash
b4f63db04e nfp: Correct erroneous sizeof expression within GetTagInfo()
The previous expression would copy sizeof(size_t) amount of bytes (8 on
a 64-bit platform) rather than the full 10 bytes comprising the uuid
member.

Given the source and destination types are the same, we can just use an
assignment here instead.
2018-11-14 12:53:39 -05:00
Lioncash
3619b31fc0 service/audren_u: Forward RequestUpdateAuto through the same function as RequestUpdate
Based off RE, they both currently go through the same codepath with no
difference in behavior.
2018-11-14 02:36:21 -05:00
Lioncash
fcde356f15 hid/npad: Add missing break in switch statement within Controller_NPad::OnUpdate() 2018-11-14 00:59:17 -05:00
Lioncash
958fa15a4c service: Mark MakeFunctionString with the [[maybe_unused]] attribute.
When yuzu is compiled in release mode this function is unused, however,
when compiled in debug mode, it's used within a LOG_TRACE statement.
This prevents erroneous compilation warnings about an unused function
(that isn't actually totally unused).
2018-11-14 00:49:04 -05:00
Lioncash
f9db75fe40 kernel/thread: Deduplicate scheduler switching code
The code in both places was the same verbatim, so we can extract it to a
function to deduplicate the logic.
2018-11-14 00:02:42 -05:00
bunnei
3bd503d59c Merge pull request #1662 from FreddyFunk/CopySurface-Optimization
gl_rasterizer_cache: CopySurface optimization
2018-11-13 18:58:12 -08:00
bunnei
09f4150241 Merge pull request #1686 from DarkLordZach/move-open-yuzu-folder
qt: Move Open yuzu Folder action from Help to File
2018-11-13 18:56:44 -08:00
bunnei
d2b2b05b6a Merge pull request #1685 from lioncash/base
video_core/renderer_base: Remove GL include from the renderer base class files
2018-11-13 18:53:59 -08:00
bunnei
723bd89883 Merge pull request #1677 from FreddyFunk/skip-vao-binding-cleanup
engines/maxwell_3d: Minor cleanup
2018-11-13 18:53:38 -08:00
bunnei
70f189d7af Merge pull request #1680 from lioncash/mem
kernel/process: Migrate heap-related memory management out of the process class and into the vm manager
2018-11-13 18:52:18 -08:00
bunnei
a80467db57 Merge pull request #1682 from lioncash/audio
hle/audren_u: Implement Get/SetRenderingTimeLimit
2018-11-13 18:51:44 -08:00
bunnei
d2a630c41f Merge pull request #1683 from lioncash/typo
audio_core/audio_renderer: Fix typo in AuxInfo member name
2018-11-13 18:51:35 -08:00
bunnei
9b12623743 Merge pull request #1608 from DarkLordZach/save-data-reader
[ns|fsp_srv]: Implement various functions to boot Checkpoint
2018-11-13 18:51:08 -08:00
Lioncash
c7387e6504 string_util: Remove ArrayToString()
An old function from Dolphin. This is also unused, and pretty inflexible
when it comes to printing out different data types (for example, one
might not want to print out an array of u8s but a different type
instead. Given we use fmt, there's no need to keep this implementation
of the function around.
2018-11-13 18:14:11 -05:00
Lioncash
f1219e3a87 string_util: Remove TryParse()
This is an unused hold-over from Dolphin that was primarily used to
parse values out of the .ini files. Given we already have libraries that
do this for us, we don't need to keep this around.
2018-11-13 18:13:45 -05:00
Zach Hilman
6001af2b89 qt: Move Open yuzu Folder action from Help to File 2018-11-13 17:17:47 -05:00
Lioncash
4ed9ef15c4 video_core/renderer_base: Remove GL include from the renderer base class files
Keeps the base class source files implementation-agnostic.
2018-11-13 14:38:13 -05:00
Lioncash
9bc18eada8 string_util: Remove ThousandSeparate()
This is currently unused and doesn't really provide much value to keep
around either.
2018-11-13 14:04:26 -05:00
Lioncash
454cf1dc09 hle/audren_u: Implement Get/SetRenderingTimeLimit
These appear to be a basic getter and setter pair, so these are fairly
trivial to implement and get out of the way.
2018-11-13 13:49:09 -05:00
Lioncash
81a39181b0 audio_core/audio_renderer: Fix typo in AuxInfo member name 2018-11-13 13:32:13 -05:00
Lioncash
004277477a vm_manager: Unstub GetTotalHeapUsage()
Now that we've moved all of the heap-related stuff to the VMManager
class, we can unstub this function, as the necessary members are visible
now.
2018-11-13 13:08:26 -05:00
Lioncash
b8e885c6e5 kernel/process: Migrate heap-related memory management out of the process class and into the vm manager
Avoids a breach of responsibilities in the interface and keeps the
direct code for memory management within the VMManager class.
2018-11-13 13:08:19 -05:00
Zach Hilman
ab552e4a25 svc: Use proper random entropy generation algorithm 2018-11-13 12:26:03 -05:00
Hedges
af42320021 GDBStub improvements:
- Add FPU support
- Fix access to TLS
Fix clang-format.
2018-11-13 15:44:20 +00:00
fearlessTobi
9ea8eb6b2e yuzu: Add hotkey for Amiibo loading 2018-11-13 15:10:39 +01:00
Frederic L
ab362aa7e5 gl_rasterizer: Minor cleanup
Minor code cleanup from unaddressed feedback in #1654
2018-11-13 14:07:23 +01:00
Lioncash
9a0fb7d9fb gl_state: Amend compilation warnings
Makes float -> integral conversions explicit via casts and also silences
a sign conversion warning.
2018-11-13 07:10:40 -05:00
bunnei
65bd03d74c Merge pull request #1628 from greggameplayer/Texture2DArray
Implement SurfaceTarget Texture2DArray
2018-11-12 21:13:47 -08:00
bunnei
7f3c2525e6 Merge pull request #1670 from DarkLordZach/deterministic-rng
csrng: Add config option to set RNG seed
2018-11-12 21:10:08 -08:00
bunnei
fd72d889bf Merge pull request #1665 from ogniK5377/GetClockSnapshot
Implement GetClockSnapshot, ToPosixTime & ToPosixTimeWithMyRule
2018-11-12 20:13:47 -08:00
Zach Hilman
cb1e63ef09 svc: Return random seed for svcGetInfo RandomEntropy 2018-11-12 21:46:21 -05:00
greggameplayer
c8b3f09876 Implement ASTC_2D_10X8 & ASTC_2D_10X8_SRGB (#1666)
* Implement ASTC_2D_10X8 & ASTC_2D_10X8_SRGB
( needed by Mario+Rabbids Kingdom Battle )

* Small placement correction
2018-11-12 18:34:54 -08:00
bunnei
d08b876c9d Merge pull request #1650 from FreddyFunk/cast
yuzu/main: Fix compiler warning
2018-11-12 18:32:54 -08:00
James Rowe
b4a6ce02ce Merge pull request #1674 from FearlessTobi/fullscreen-fix
yuzu: Add a missing "!" to fix the stuck-in-fullscreen bug
2018-11-12 13:00:25 -07:00
Tobias
9333ee29ca yuzu: Add a missing "!" to fix the stuck-in-fullscreen bug 2018-11-12 20:57:15 +01:00
Zach Hilman
2a16fd7ffc settings: Add config option to set RNG seed 2018-11-11 23:09:46 -05:00
Zach Hilman
4b4f883aef csrng: Use std::mt19937 engine for random number generation 2018-11-11 23:08:39 -05:00
bunnei
2c6efda235 Merge pull request #1660 from Tinob/master
Map more missing opengl states
2018-11-11 19:58:16 -08:00
bunnei
7474382266 Merge pull request #1652 from FreddyFunk/static-cast
configure_system: Fix compiler warning
2018-11-11 12:19:03 -08:00
bunnei
a264fac943 Merge pull request #1664 from FreddyFunk/cast2
gl_rasterizer: Fix compiler warnings
2018-11-11 12:18:29 -08:00
Rodolfo Bogado
72b1fae984 Use core extensions when available to set max anisotropic filtering level 2018-11-11 16:36:53 -03:00
Rodolfo Bogado
4e6c64bf8d Improve state management by splitting some of the states id separated function to avoid a full apply overhead 2018-11-11 16:36:53 -03:00
Rodolfo Bogado
4a6eff3b7b Try to fix problems with stencil test in some games, relax translation to opengl enums to avoid crashing and only generate logs of the errors. 2018-11-11 16:31:00 -03:00
Rodolfo Bogado
e9610ec0dd set sampler max lod, min lod, lod bias and max anisotropy 2018-11-11 16:31:00 -03:00
FernandoS27
3088e36237 Improved GPU Caches lookup Speed 2018-11-11 12:53:25 -04:00
bunnei
eaee73f95d Merge pull request #1669 from ReinUsesLisp/fixup-gs
gl_shader_decompiler: Guard out of bound geometry shader input reads
2018-11-11 08:28:20 -08:00
bunnei
c82bccab56 Merge pull request #1663 from lioncash/raster
rasterizer_cache: Remove reliance on the System singleton
2018-11-11 08:20:27 -08:00
bunnei
1916213311 Merge pull request #1648 from FernandoS27/texs-3-array
Implement 3 coordinate array in TEXS instruction
2018-11-11 08:18:27 -08:00
bunnei
8ea6261547 Merge pull request #1654 from degasus/dirty_flags
gl_rasterizer: Skip VAO binding if the state is clean.
2018-11-11 08:17:57 -08:00
James Rowe
93fca5d9cf Merge pull request #1656 from ogniK5377/message-queue
Ability to switch between docked and undocked mode in-game
2018-11-10 11:27:17 -07:00
James Rowe
c21a6c6b37 Merge pull request #1661 from lioncash/dtor
rasterizer_cache: Add missing virtual destructor to RasterizerCacheObject
2018-11-10 11:08:55 -07:00
David Marcec
48cd61d9c8 Added maybe_unused 2018-11-10 18:07:34 +11:00
David Marcec
ddc242dd51 Added ToPosixTime & ToPosixTimeWithMyRule
Added instead of using a seperate PR to prevent conflicts
2018-11-10 17:41:57 +11:00
ReinUsesLisp
8d4bb10d44 gl_shader_decompiler: Guard out of bound geometry shader input reads
Geometry shaders follow a pattern that results in out of bound reads.
This pattern is:
- VSETP to predicate
- Use that predicate to conditionally set a register a big number
- Use the register to access geometry shaders
At the time of writing this commit I don't know what's the intent of
this number. Some drivers argue about these out of bound reads. To avoid
this issue, input reads are guarded limiting reads to the highest
posible vertex input of the current topology (e.g. points to 1 and
triangles to 3).
2018-11-10 03:10:50 -03:00
David Marcec
84c6134264 Added consts and static 2018-11-10 12:31:48 +11:00
David Marcec
4f78f5c0df Implement GetClockSnapshot
Needed by megaman 11
2018-11-10 01:25:56 +11:00
Frederic Laing
e2bf581e3a gl_rasterizer_cache: Remove unnecessary memory allocation and copy in CopySurface 2018-11-08 16:50:09 +01:00
Frederic Laing
1d36aec267 gl_rasterizer: Fix compiler warnings 2018-11-08 13:33:30 +01:00
Lioncash
9046f764bf rasterizer_cache: Remove reliance on the System singleton
Rather than have a transparent dependency, we can make it explicit in
the interface. This also gets rid of the need to put the core include in
a header.
2018-11-08 06:16:38 -05:00
Lioncash
9de523fd90 rasterizer_cache: Add missing virtual destructor to RasterizerCacheObject
Ensures that destruction will always do the right thing in any context.
2018-11-08 00:31:39 -05:00
Lioncash
29f082775b gl_resource_manager: Amend clang-format discrepancies
Fixes the buildbot.
2018-11-08 00:23:45 -05:00
bunnei
0e05a9d58f Merge pull request #1658 from ogniK5377/holdtype-style
Updated npad styles on holdtype switches
2018-11-07 20:59:01 -08:00
David
581406af18 svcBreak now dumps information from the debug buffer passed (#1646)
* svcBreak now dumps information from the debug buffer passed

info1 and info2 seem to somtimes hold an address to a buffer, this is usually 4 bytes or the size of the int and contains an error code. There's other circumstances where it can be something different so we hexdump these to examine them at a later date.

* Addressed comments
2018-11-07 20:43:54 -08:00
bunnei
481d8716e0 Merge pull request #1655 from ogniK5377/shantae
Implement acc:TrySelectUserWithoutInteraction
2018-11-07 20:41:06 -08:00
FernandoS27
d347623d6f Correct issue where texturelod could not be applied to 2darrayshadow 2018-11-07 21:48:45 -04:00
David Marcec
40db288a2a Renamed CheckIfOperationChanged to OnDockedModeChanged 2018-11-08 12:12:00 +11:00
FernandoS27
ad2f47b579 Implement 3 coordinate array in TEXS instruction 2018-11-07 17:04:30 -04:00
David Marcec
a9c25ab9e4 Updated npad styles on holdtype switches
Fixes input for megaman
2018-11-08 01:07:14 +11:00
David Marcec
fd1ef25257 Fixups 2018-11-07 20:12:27 +11:00
bunnei
81ff9e2473 Merge pull request #1630 from bunnei/fix-mapbufferex
memory_manager: Do not MapBufferEx over already in use memory.
2018-11-07 00:14:36 -08:00
bunnei
74bce4d68f Merge pull request #1635 from Tinob/master
Implement multi-target viewports and blending
2018-11-07 00:11:49 -08:00
bunnei
e5a0a23553 Merge pull request #1653 from degasus/profiler
gl_rasterizer: Update microprofile scopes.
2018-11-07 00:10:13 -08:00
David Marcec
41e99d8880 Ability to switch between docked and undocked mode in-game
Started implementation of the AM message queue mainly used in state getters. Added the ability to switch docked mode whilst in game without stopping emulation. Also removed some things which shouldn't be labelled as stubs as they're implemented correctly
2018-11-07 18:01:33 +11:00
David Marcec
ad45d68871 fixed spelling error 2018-11-07 12:04:43 +11:00
David Marcec
49cb4fa37b Added missing log 2018-11-07 11:46:04 +11:00
David Marcec
92fcc6d15a Implement acc:TrySelectUserWithoutInteraction
Needed for Shantae - Half-Genie Hero - Ultimate Edition!
2018-11-07 11:45:01 +11:00
Markus Wick
359db6a673 gl_rasterizer: Skip VAO binding if the state is clean. 2018-11-06 22:31:33 +01:00
Markus Wick
0590dd2971 gl_rasterizer: Split VAO and VB setup functions. 2018-11-06 22:31:33 +01:00
greggameplayer
d3b9599b2d Merge branch 'master' into Texture2DArray 2018-11-06 19:05:57 +01:00
Frederic Laing
d34d0bfc87 configure_system: Fix compiler warning 2018-11-06 16:38:10 +01:00
Frederic Laing
6c8b788d32 yuzu/main: Fix compiler warning 2018-11-06 15:22:24 +01:00
Frederic Laing
ba2cdcdc5a Implement SetMemoryPermission 2018-11-06 10:21:01 +01:00
Rodolfo Bogado
19038db489 Add support to color mask to avoid issues in blending caused by wrong values in the alpha channel in some render targets. 2018-11-05 00:24:19 -03:00
Rodolfo Bogado
145ae36963 Implement multi-target viewports and blending 2018-11-04 20:49:48 -03:00
Zach Hilman
52e7e8eed3 game_list: Only reload game list after relevant settings changed
Prevents unnecessary reloads on every configuration operation.
2018-11-03 20:38:39 -04:00
Zach Hilman
0080a8da58 sm: Implement RegisterService and UnregisterService
These are needed by Edizon to boot. They are used to see if a user is using SX OS, as SX OS registers a custom service called 'tx' and attempting to register a service of the same name lets the application know if it is present.
2018-11-03 20:02:18 -04:00
Frederic Laing
ab7472345b Stubbed SetMemoryPermission 2018-11-03 16:01:34 +01:00
greggameplayer
9249fadb9e correct syntax 2018-11-02 14:28:28 +01:00
greggameplayer
cb8e4a4633 Merge branch 'master' into Texture2DArray 2018-11-02 14:26:32 +01:00
Zach Hilman
2d2ef05d8c game_list: Make add-ons column optional
As the add-ons column takes the most processing time out of any (as it needs to search registration for updates/dlc, patch control NCAs, search for mods, etc.), an option was added to disable it. This does not affect the application of add-ons. In large game collections, this decreases game list refresh time by as much as 70%.
2018-11-01 20:27:12 -04:00
Zach Hilman
8f183a47dd filesystem: Cache RegisteredCacheUnion instead of constructing on demand
Prevents unnecessary re-reads of the metadata and unnecessary temporary objects.
2018-11-01 20:24:32 -04:00
Zach Hilman
97d425c304 file_sys: Use common KeyManager in NCA container types
Creates a single KeyManager for the entire container and then passes it into the NCA constructor, eliminating several unnecessary KeyManager reads.
2018-11-01 20:23:38 -04:00
Zach Hilman
e20db909ee content_archive: Add optional KeyManager parameter to constructor
Allows resuing a common KeyManager when a large amount of NCAs are handled by the same class. Should the parameter not be provided, a new KeyManager will be constructed, as was the default behavior prior to this.
2018-11-01 20:22:29 -04:00
bunnei
4aa9779ae1 memory_manager: Do not MapBufferEx over already in use memory.
- This fixes rendering when changing areas in Super Mario Odyssey.
2018-11-01 18:57:59 -04:00
greggameplayer
9ae972ab4e Implement SurfaceTarget Texture2DArray
( needed by Mario+Rabbids Kingdom Battle )
2018-10-31 04:29:15 +01:00
Michał Janiszewski
44c80e5d8b Handle missing git info when building 2018-10-29 23:39:33 +01:00
Zach Hilman
bdaa76c0db ns: Implement command 400: GetApplicationControlData
Returns the raw NACP bytes and the raw icon bytes into a title-provided buffer. Pulls from Registration Cache for control data, returning all zeros should it not exist.
2018-10-29 16:20:16 -04:00
Zach Hilman
1c0226815d patch_manager: Add support for dumping decompressed NSOs
When enabled in settings, PatchNSO will dump the unmodified NSO that it was passed to a file named <build id>.nso in the dump root for the current title ID.
2018-10-29 16:10:16 -04:00
Zach Hilman
48eb3742b9 settings: Add setting to control NSO dumping
Also adds UI option in Debug > Dump section, with the idea later things to be dumped (i.e. other game data or textures, etc) will use the same group box.
2018-10-29 16:09:08 -04:00
Zach Hilman
9078bb9854 bis_factory: Add getter for mod dump root for a title ID
Equates to yuzu_dir/dump/<title id>/
2018-10-29 16:08:03 -04:00
Zach Hilman
5ee19add1b fsp_srv: Implement ISaveDataInfoReader
An object to read SaveDataInfo objects, which describe a unique save on the system. This implementation iterates through all the directories in the save data space and uses the paths to reconstruct the metadata.
2018-10-29 13:54:39 -04:00
Zach Hilman
2e8177f0c9 fsp_srv: Implement command 61: OpenSaveDataInfoReaderBySaveDataSpaceId
Needed by Checkpoint. Returns an object that can iterate through all savedata on the system.
2018-10-29 13:54:39 -04:00
Zach Hilman
df264d2ccb savedata_factory: Expose accessors for SaveDataSpace 2018-10-29 13:54:38 -04:00
Zach Hilman
f2f679bf3f loader/nro: Call RegisterRomFS from Load
Allows NRO homebrew to use the RomFS in the ASET section.
2018-10-29 13:54:38 -04:00
Zach Hilman
b04e39107f control_metadata: Add GetRawBytes function to NACP
Returns the raw bytes of the NACP file. Needed for GetApplicationControlData which returns the raw, unprocessed NACP to the game.
2018-10-29 13:54:38 -04:00
Cameron Cawley
34eaf3a366 travis: Use pre-built image for clang-format target 2018-10-24 00:08:38 +01:00
342 changed files with 21300 additions and 9370 deletions

3
.gitmodules vendored
View File

@@ -13,9 +13,6 @@
[submodule "dynarmic"]
path = externals/dynarmic
url = https://github.com/MerryMage/dynarmic.git
[submodule "xbyak"]
path = externals/xbyak
url = https://github.com/herumi/xbyak.git
[submodule "fmt"]
path = externals/fmt
url = https://github.com/fmtlib/fmt.git

View File

@@ -1,3 +1,3 @@
#!/bin/bash -ex
docker run -v $(pwd):/yuzu ubuntu:18.04 /bin/bash -ex /yuzu/.travis/clang-format/docker.sh
docker run --env-file .travis/common/travis-ci.env -v $(pwd):/yuzu -v "$HOME/.ccache":/root/.ccache citraemu/build-environments:linux-clang-format /bin/bash -ex /yuzu/.travis/clang-format/docker.sh

View File

@@ -1,3 +1,3 @@
#!/bin/sh -ex
docker pull ubuntu:18.04
docker pull citraemu/build-environments:linux-clang-format

View File

@@ -1,8 +1,5 @@
#!/bin/bash -ex
apt-get update
apt-get install -y clang-format-6.0
# Run clang-format
cd /yuzu
./.travis/clang-format/script.sh

View File

@@ -57,3 +57,4 @@ done
pip3 install pefile
python3 .travis/linux-mingw/scan_dll.py package/*.exe "package/"
python3 .travis/linux-mingw/scan_dll.py package/imageformats/*.dll "package/"

View File

@@ -377,7 +377,7 @@ if (CLANG_FORMAT)
set(CCOMMENT "Running clang format against all the .h and .cpp files in src/")
if (WIN32)
add_custom_target(clang-format
COMMAND powershell.exe -Command "${CLANG_FORMAT} -i @(Get-ChildItem -Recurse ${SRCS}/* -Include \'*.h\', \'*.cpp\')"
COMMAND powershell.exe -Command "Get-ChildItem ${SRCS}/* -Include *.cpp,*.h -Recurse | Foreach {${CLANG_FORMAT} -i $_.fullname}"
COMMENT ${CCOMMENT})
elseif(MINGW)
add_custom_target(clang-format

View File

@@ -125,17 +125,6 @@ after_build:
Copy-Item -path "$CMAKE_SOURCE_DIR/license.txt" -destination $RELEASE_DIST
Copy-Item -path "$CMAKE_SOURCE_DIR/README.md" -destination $RELEASE_DIST
# copy all the dll dependencies to the release folder
. "./.appveyor/UtilityFunctions.ps1"
$DLLSearchPath = "C:\msys64\mingw64\bin;$env:PATH"
$MingwDLLs = RecursivelyGetDeps $DLLSearchPath "$RELEASE_DIST\yuzu.exe"
$MingwDLLs += RecursivelyGetDeps $DLLSearchPath "$RELEASE_DIST\yuzu_cmd.exe"
Write-Host "Detected the following dependencies:"
Write-Host $MingwDLLs
foreach ($file in $MingwDLLs) {
Copy-Item -path "$file" -force -destination "$RELEASE_DIST"
}
# 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"
@@ -145,6 +134,18 @@ after_build:
# copy the qt jpeg imageformat dll to platforms
Copy-Item -path "C:/msys64/mingw64/share/qt5/plugins/imageformats/qjpeg.dll" -force -destination "$RELEASE_DIST/imageformats"
# copy all the dll dependencies to the release folder
. "./.appveyor/UtilityFunctions.ps1"
$DLLSearchPath = "C:\msys64\mingw64\bin;$env:PATH"
$MingwDLLs = RecursivelyGetDeps $DLLSearchPath "$RELEASE_DIST\yuzu.exe"
$MingwDLLs += RecursivelyGetDeps $DLLSearchPath "$RELEASE_DIST\yuzu_cmd.exe"
$MingwDLLs += RecursivelyGetDeps $DLLSearchPath "$RELEASE_DIST\imageformats\qjpeg.dll"
Write-Host "Detected the following dependencies:"
Write-Host $MingwDLLs
foreach ($file in $MingwDLLs) {
Copy-Item -path "$file" -force -destination "$RELEASE_DIST"
}
7z a -tzip $MINGW_BUILD_ZIP $RELEASE_DIST\*
7z a $MINGW_SEVENZIP $RELEASE_DIST
}

View File

@@ -9,7 +9,6 @@ target_include_directories(catch-single-include INTERFACE catch/single_include)
# Dynarmic
if (ARCHITECTURE_x86_64)
add_library(xbyak INTERFACE)
set(DYNARMIC_TESTS OFF)
set(DYNARMIC_NO_BUNDLED_FMT ON)
add_subdirectory(dynarmic)
@@ -53,14 +52,6 @@ target_include_directories(unicorn-headers INTERFACE ./unicorn/include)
# SoundTouch
add_subdirectory(soundtouch)
# Xbyak
if (ARCHITECTURE_x86_64)
# Defined before "dynarmic" above
# add_library(xbyak INTERFACE)
target_include_directories(xbyak INTERFACE ./xbyak/xbyak)
target_compile_definitions(xbyak INTERFACE XBYAK_NO_OP_NAMES)
endif()
# Opus
add_subdirectory(opus)
target_include_directories(opus INTERFACE ./opus/include)

View File

@@ -33,6 +33,10 @@ else()
endif()
if(NOT HEAD_HASH)
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
string(STRIP "${HEAD_HASH}" HEAD_HASH)
if(EXISTS "@GIT_DATA@/head-ref")
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
string(STRIP "${HEAD_HASH}" HEAD_HASH)
else()
set(HEAD_HASH "Unknown")
endif()
endif()

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
externals/xbyak vendored

Submodule externals/xbyak deleted from 1de435ed04

View File

@@ -54,8 +54,9 @@ std::vector<s16> Interpolate(InterpolationState& state, std::vector<s16> input,
double l = 0.0;
double r = 0.0;
for (std::size_t j = 0; j < h.size(); j++) {
l += Lanczos(taps, pos + j - taps + 1) * h[j][0];
r += Lanczos(taps, pos + j - taps + 1) * h[j][1];
const double lanczos_calc = Lanczos(taps, pos + j - taps + 1);
l += lanczos_calc * h[j][0];
r += lanczos_calc * h[j][1];
}
output.emplace_back(static_cast<s16>(std::clamp(l, -32768.0, 32767.0)));
output.emplace_back(static_cast<s16>(std::clamp(r, -32768.0, 32767.0)));

View File

@@ -22,16 +22,14 @@ static Stream::Format ChannelsToStreamFormat(u32 num_channels) {
return Stream::Format::Multi51Channel16;
}
LOG_CRITICAL(Audio, "Unimplemented num_channels={}", num_channels);
UNREACHABLE();
UNIMPLEMENTED_MSG("Unimplemented num_channels={}", num_channels);
return {};
}
StreamPtr AudioOut::OpenStream(u32 sample_rate, u32 num_channels, std::string&& name,
Stream::ReleaseCallback&& release_callback) {
if (!sink) {
const SinkDetails& sink_details = GetSinkDetails(Settings::values.sink_id);
sink = sink_details.factory(Settings::values.audio_device_id);
sink = CreateSinkFromID(Settings::values.sink_id, Settings::values.audio_device_id);
}
return std::make_shared<Stream>(

View File

@@ -8,7 +8,7 @@
#include "audio_core/codec.h"
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/writable_event.h"
#include "core/memory.h"
namespace AudioCore {
@@ -72,7 +72,7 @@ private:
EffectInStatus info{};
};
AudioRenderer::AudioRenderer(AudioRendererParameter params,
Kernel::SharedPtr<Kernel::Event> buffer_event)
Kernel::SharedPtr<Kernel::WritableEvent> buffer_event)
: worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count),
effects(params.effect_count) {
@@ -260,8 +260,7 @@ void AudioRenderer::VoiceState::RefreshBuffer() {
break;
}
default:
LOG_CRITICAL(Audio, "Unimplemented sample_format={}", info.sample_format);
UNREACHABLE();
UNIMPLEMENTED_MSG("Unimplemented sample_format={}", info.sample_format);
break;
}
@@ -280,13 +279,15 @@ void AudioRenderer::VoiceState::RefreshBuffer() {
break;
}
default:
LOG_CRITICAL(Audio, "Unimplemented channel_count={}", info.channel_count);
UNREACHABLE();
UNIMPLEMENTED_MSG("Unimplemented channel_count={}", info.channel_count);
break;
}
samples =
Interpolate(interp_state, std::move(samples), GetInfo().sample_rate, STREAM_SAMPLE_RATE);
// Only interpolate when necessary, expensive.
if (GetInfo().sample_rate != STREAM_SAMPLE_RATE) {
samples = Interpolate(interp_state, std::move(samples), GetInfo().sample_rate,
STREAM_SAMPLE_RATE);
}
is_refresh_pending = false;
}

View File

@@ -15,7 +15,7 @@
#include "core/hle/kernel/object.h"
namespace Kernel {
class Event;
class WritableEvent;
}
namespace AudioCore {
@@ -143,7 +143,7 @@ struct AuxInfo {
std::array<u8, 24> output_mix_buffers;
u32_le mix_buffer_count;
u32_le sample_rate; // Stored in the aux buffer currently
u32_le sampe_count;
u32_le sample_count;
u64_le send_buffer_info;
u64_le send_buffer_base;
@@ -208,7 +208,8 @@ static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size
class AudioRenderer {
public:
AudioRenderer(AudioRendererParameter params, Kernel::SharedPtr<Kernel::Event> buffer_event);
AudioRenderer(AudioRendererParameter params,
Kernel::SharedPtr<Kernel::WritableEvent> buffer_event);
~AudioRenderer();
std::vector<u8> UpdateAudioRenderer(const std::vector<u8>& input_params);
@@ -224,7 +225,7 @@ private:
class VoiceState;
AudioRendererParameter worker_params;
Kernel::SharedPtr<Kernel::Event> buffer_event;
Kernel::SharedPtr<Kernel::WritableEvent> buffer_event;
std::vector<VoiceState> voices;
std::vector<EffectState> effects;
std::unique_ptr<AudioOut> audio_out;

View File

@@ -107,7 +107,7 @@ private:
static void StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state);
};
CubebSink::CubebSink(std::string target_device_name) {
CubebSink::CubebSink(std::string_view target_device_name) {
if (cubeb_init(&ctx, "yuzu", nullptr) != CUBEB_OK) {
LOG_CRITICAL(Audio_Sink, "cubeb_init failed");
return;

View File

@@ -15,7 +15,7 @@ namespace AudioCore {
class CubebSink final : public Sink {
public:
explicit CubebSink(std::string device_id);
explicit CubebSink(std::string_view device_id);
~CubebSink() override;
SinkStream& AcquireSinkStream(u32 sample_rate, u32 num_channels,

View File

@@ -10,7 +10,7 @@ namespace AudioCore {
class NullSink final : public Sink {
public:
explicit NullSink(std::string){};
explicit NullSink(std::string_view) {}
~NullSink() override = default;
SinkStream& AcquireSinkStream(u32 /*sample_rate*/, u32 /*num_channels*/,

View File

@@ -14,31 +14,68 @@
#include "common/logging/log.h"
namespace AudioCore {
namespace {
struct SinkDetails {
using FactoryFn = std::unique_ptr<Sink> (*)(std::string_view);
using ListDevicesFn = std::vector<std::string> (*)();
// g_sink_details is ordered in terms of desirability, with the best choice at the top.
const std::vector<SinkDetails> g_sink_details = {
/// Name for this sink.
const char* id;
/// A method to call to construct an instance of this type of sink.
FactoryFn factory;
/// A method to call to list available devices.
ListDevicesFn list_devices;
};
// sink_details is ordered in terms of desirability, with the best choice at the top.
constexpr SinkDetails sink_details[] = {
#ifdef HAVE_CUBEB
SinkDetails{"cubeb", &std::make_unique<CubebSink, std::string>, &ListCubebSinkDevices},
SinkDetails{"cubeb",
[](std::string_view device_id) -> std::unique_ptr<Sink> {
return std::make_unique<CubebSink>(device_id);
},
&ListCubebSinkDevices},
#endif
SinkDetails{"null", &std::make_unique<NullSink, std::string>,
SinkDetails{"null",
[](std::string_view device_id) -> std::unique_ptr<Sink> {
return std::make_unique<NullSink>(device_id);
},
[] { return std::vector<std::string>{"null"}; }},
};
const SinkDetails& GetSinkDetails(std::string_view sink_id) {
auto iter =
std::find_if(g_sink_details.begin(), g_sink_details.end(),
std::find_if(std::begin(sink_details), std::end(sink_details),
[sink_id](const auto& sink_detail) { return sink_detail.id == sink_id; });
if (sink_id == "auto" || iter == g_sink_details.end()) {
if (sink_id == "auto" || iter == std::end(sink_details)) {
if (sink_id != "auto") {
LOG_ERROR(Audio, "AudioCore::SelectSink given invalid sink_id {}", sink_id);
}
// Auto-select.
// g_sink_details is ordered in terms of desirability, with the best choice at the front.
iter = g_sink_details.begin();
// sink_details is ordered in terms of desirability, with the best choice at the front.
iter = std::begin(sink_details);
}
return *iter;
}
} // Anonymous namespace
std::vector<const char*> GetSinkIDs() {
std::vector<const char*> sink_ids(std::size(sink_details));
std::transform(std::begin(sink_details), std::end(sink_details), std::begin(sink_ids),
[](const auto& sink) { return sink.id; });
return sink_ids;
}
std::vector<std::string> GetDeviceListForSink(std::string_view sink_id) {
return GetSinkDetails(sink_id).list_devices();
}
std::unique_ptr<Sink> CreateSinkFromID(std::string_view sink_id, std::string_view device_id) {
return GetSinkDetails(sink_id).factory(device_id);
}
} // namespace AudioCore

View File

@@ -4,34 +4,21 @@
#pragma once
#include <functional>
#include <memory>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
namespace AudioCore {
class Sink;
struct SinkDetails {
using FactoryFn = std::function<std::unique_ptr<Sink>(std::string)>;
using ListDevicesFn = std::function<std::vector<std::string>()>;
/// Retrieves the IDs for all available audio sinks.
std::vector<const char*> GetSinkIDs();
SinkDetails(const char* id_, FactoryFn factory_, ListDevicesFn list_devices_)
: id(id_), factory(std::move(factory_)), list_devices(std::move(list_devices_)) {}
/// Gets the list of devices for a particular sink identified by the given ID.
std::vector<std::string> GetDeviceListForSink(std::string_view sink_id);
/// Name for this sink.
const char* id;
/// A method to call to construct an instance of this type of sink.
FactoryFn factory;
/// A method to call to list available devices.
ListDevicesFn list_devices;
};
extern const std::vector<SinkDetails> g_sink_details;
const SinkDetails& GetSinkDetails(std::string_view sink_id);
/// Creates an audio sink identified by the given device ID.
std::unique_ptr<Sink> CreateSinkFromID(std::string_view sink_id, std::string_view device_id);
} // namespace AudioCore

View File

@@ -28,8 +28,7 @@ u32 Stream::GetNumChannels() const {
case Format::Multi51Channel16:
return 6;
}
LOG_CRITICAL(Audio, "Unimplemented format={}", static_cast<u32>(format));
UNREACHABLE();
UNIMPLEMENTED_MSG("Unimplemented format={}", static_cast<u32>(format));
return {};
}
@@ -49,7 +48,7 @@ void Stream::Play() {
void Stream::Stop() {
state = State::Stopped;
ASSERT_MSG(false, "Unimplemented");
UNIMPLEMENTED();
}
Stream::State Stream::GetState() const {
@@ -120,7 +119,7 @@ bool Stream::QueueBuffer(BufferPtr&& buffer) {
}
bool Stream::ContainsBuffer(Buffer::Tag tag) const {
ASSERT_MSG(false, "Unimplemented");
UNIMPLEMENTED();
return {};
}

View File

@@ -44,7 +44,7 @@ add_library(common STATIC
detached_tasks.cpp
detached_tasks.h
bit_field.h
bit_set.h
bit_util.h
cityhash.cpp
cityhash.h
color.h
@@ -95,14 +95,9 @@ if(ARCHITECTURE_x86_64)
PRIVATE
x64/cpu_detect.cpp
x64/cpu_detect.h
x64/xbyak_abi.h
x64/xbyak_util.h
)
endif()
create_target_directory_groups(common)
target_link_libraries(common PUBLIC Boost::boost fmt microprofile)
if (ARCHITECTURE_x86_64)
target_link_libraries(common PRIVATE xbyak)
endif()

View File

@@ -52,5 +52,8 @@ __declspec(noinline, noreturn)
#define DEBUG_ASSERT_MSG(_a_, _desc_, ...)
#endif
#define UNIMPLEMENTED() LOG_CRITICAL(Debug, "Unimplemented code!")
#define UNIMPLEMENTED() ASSERT_MSG(false, "Unimplemented code!")
#define UNIMPLEMENTED_MSG(...) ASSERT_MSG(false, __VA_ARGS__)
#define UNIMPLEMENTED_IF(cond) ASSERT_MSG(!(cond), "Unimplemented code!")
#define UNIMPLEMENTED_IF_MSG(cond, ...) ASSERT_MSG(!(cond), __VA_ARGS__)

View File

@@ -117,21 +117,21 @@ private:
// We don't delete it because we want BitField to be trivially copyable.
constexpr BitField& operator=(const BitField&) = default;
// StorageType is T for non-enum types and the underlying type of T if
// UnderlyingType is T for non-enum types and the underlying type of T if
// T is an enumeration. Note that T is wrapped within an enable_if in the
// former case to workaround compile errors which arise when using
// std::underlying_type<T>::type directly.
using StorageType = typename std::conditional_t<std::is_enum<T>::value, std::underlying_type<T>,
std::enable_if<true, T>>::type;
using UnderlyingType = typename std::conditional_t<std::is_enum_v<T>, std::underlying_type<T>,
std::enable_if<true, T>>::type;
// Unsigned version of StorageType
using StorageTypeU = std::make_unsigned_t<StorageType>;
// We store the value as the unsigned type to avoid undefined behaviour on value shifting
using StorageType = std::make_unsigned_t<UnderlyingType>;
public:
/// Constants to allow limited introspection of fields if needed
static constexpr std::size_t position = Position;
static constexpr std::size_t bits = Bits;
static constexpr StorageType mask = (((StorageTypeU)~0) >> (8 * sizeof(T) - bits)) << position;
static constexpr StorageType mask = (((StorageType)~0) >> (8 * sizeof(T) - bits)) << position;
/**
* Formats a value by masking and shifting it according to the field parameters. A value
@@ -148,11 +148,12 @@ public:
* union in a constexpr context.
*/
static constexpr FORCE_INLINE T ExtractValue(const StorageType& storage) {
if (std::numeric_limits<T>::is_signed) {
if constexpr (std::numeric_limits<UnderlyingType>::is_signed) {
std::size_t shift = 8 * sizeof(T) - bits;
return (T)((storage << (shift - position)) >> shift);
return static_cast<T>(static_cast<UnderlyingType>(storage << (shift - position)) >>
shift);
} else {
return (T)((storage & mask) >> position);
return static_cast<T>((storage & mask) >> position);
}
}

View File

@@ -1,244 +0,0 @@
// This file is under the public domain.
#pragma once
#include <cstddef>
#ifdef _WIN32
#include <intrin.h>
#endif
#include <initializer_list>
#include <new>
#include <type_traits>
#include "common/common_types.h"
// namespace avoids conflict with OS X Carbon; don't use BitSet<T> directly
namespace Common {
// Helper functions:
#ifdef _MSC_VER
template <typename T>
static inline int CountSetBits(T v) {
// from https://graphics.stanford.edu/~seander/bithacks.html
// GCC has this built in, but MSVC's intrinsic will only emit the actual
// POPCNT instruction, which we're not depending on
v = v - ((v >> 1) & (T) ~(T)0 / 3);
v = (v & (T) ~(T)0 / 15 * 3) + ((v >> 2) & (T) ~(T)0 / 15 * 3);
v = (v + (v >> 4)) & (T) ~(T)0 / 255 * 15;
return (T)(v * ((T) ~(T)0 / 255)) >> (sizeof(T) - 1) * 8;
}
static inline int LeastSignificantSetBit(u8 val) {
unsigned long index;
_BitScanForward(&index, val);
return (int)index;
}
static inline int LeastSignificantSetBit(u16 val) {
unsigned long index;
_BitScanForward(&index, val);
return (int)index;
}
static inline int LeastSignificantSetBit(u32 val) {
unsigned long index;
_BitScanForward(&index, val);
return (int)index;
}
static inline int LeastSignificantSetBit(u64 val) {
unsigned long index;
_BitScanForward64(&index, val);
return (int)index;
}
#else
static inline int CountSetBits(u8 val) {
return __builtin_popcount(val);
}
static inline int CountSetBits(u16 val) {
return __builtin_popcount(val);
}
static inline int CountSetBits(u32 val) {
return __builtin_popcount(val);
}
static inline int CountSetBits(u64 val) {
return __builtin_popcountll(val);
}
static inline int LeastSignificantSetBit(u8 val) {
return __builtin_ctz(val);
}
static inline int LeastSignificantSetBit(u16 val) {
return __builtin_ctz(val);
}
static inline int LeastSignificantSetBit(u32 val) {
return __builtin_ctz(val);
}
static inline int LeastSignificantSetBit(u64 val) {
return __builtin_ctzll(val);
}
#endif
// Similar to std::bitset, this is a class which encapsulates a bitset, i.e.
// using the set bits of an integer to represent a set of integers. Like that
// class, it acts like an array of bools:
// BitSet32 bs;
// bs[1] = true;
// but also like the underlying integer ([0] = least significant bit):
// BitSet32 bs2 = ...;
// bs = (bs ^ bs2) & BitSet32(0xffff);
// The following additional functionality is provided:
// - Construction using an initializer list.
// BitSet bs { 1, 2, 4, 8 };
// - Efficiently iterating through the set bits:
// for (int i : bs)
// [i is the *index* of a set bit]
// (This uses the appropriate CPU instruction to find the next set bit in one
// operation.)
// - Counting set bits using .Count() - see comment on that method.
// TODO: use constexpr when MSVC gets out of the Dark Ages
template <typename IntTy>
class BitSet {
static_assert(!std::is_signed_v<IntTy>, "BitSet should not be used with signed types");
public:
// A reference to a particular bit, returned from operator[].
class Ref {
public:
Ref(Ref&& other) : m_bs(other.m_bs), m_mask(other.m_mask) {}
Ref(BitSet* bs, IntTy mask) : m_bs(bs), m_mask(mask) {}
operator bool() const {
return (m_bs->m_val & m_mask) != 0;
}
bool operator=(bool set) {
m_bs->m_val = (m_bs->m_val & ~m_mask) | (set ? m_mask : 0);
return set;
}
private:
BitSet* m_bs;
IntTy m_mask;
};
// A STL-like iterator is required to be able to use range-based for loops.
class Iterator {
public:
Iterator(const Iterator& other) : m_val(other.m_val), m_bit(other.m_bit) {}
Iterator(IntTy val) : m_val(val), m_bit(0) {}
Iterator& operator=(Iterator other) {
new (this) Iterator(other);
return *this;
}
int operator*() {
return m_bit + ComputeLsb();
}
Iterator& operator++() {
int lsb = ComputeLsb();
m_val >>= lsb + 1;
m_bit += lsb + 1;
m_has_lsb = false;
return *this;
}
Iterator operator++(int _) {
Iterator other(*this);
++*this;
return other;
}
bool operator==(Iterator other) const {
return m_val == other.m_val;
}
bool operator!=(Iterator other) const {
return m_val != other.m_val;
}
private:
int ComputeLsb() {
if (!m_has_lsb) {
m_lsb = LeastSignificantSetBit(m_val);
m_has_lsb = true;
}
return m_lsb;
}
IntTy m_val;
int m_bit;
int m_lsb = -1;
bool m_has_lsb = false;
};
BitSet() : m_val(0) {}
explicit BitSet(IntTy val) : m_val(val) {}
BitSet(std::initializer_list<int> init) {
m_val = 0;
for (int bit : init)
m_val |= (IntTy)1 << bit;
}
static BitSet AllTrue(std::size_t count) {
return BitSet(count == sizeof(IntTy) * 8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1));
}
Ref operator[](std::size_t bit) {
return Ref(this, (IntTy)1 << bit);
}
const Ref operator[](std::size_t bit) const {
return (*const_cast<BitSet*>(this))[bit];
}
bool operator==(BitSet other) const {
return m_val == other.m_val;
}
bool operator!=(BitSet other) const {
return m_val != other.m_val;
}
bool operator<(BitSet other) const {
return m_val < other.m_val;
}
bool operator>(BitSet other) const {
return m_val > other.m_val;
}
BitSet operator|(BitSet other) const {
return BitSet(m_val | other.m_val);
}
BitSet operator&(BitSet other) const {
return BitSet(m_val & other.m_val);
}
BitSet operator^(BitSet other) const {
return BitSet(m_val ^ other.m_val);
}
BitSet operator~() const {
return BitSet(~m_val);
}
BitSet& operator|=(BitSet other) {
return *this = *this | other;
}
BitSet& operator&=(BitSet other) {
return *this = *this & other;
}
BitSet& operator^=(BitSet other) {
return *this = *this ^ other;
}
operator u32() = delete;
operator bool() {
return m_val != 0;
}
// Warning: Even though on modern CPUs this is a single fast instruction,
// Dolphin's official builds do not currently assume POPCNT support on x86,
// so slower explicit bit twiddling is generated. Still should generally
// be faster than a loop.
unsigned int Count() const {
return CountSetBits(m_val);
}
Iterator begin() const {
return Iterator(m_val);
}
Iterator end() const {
return Iterator(0);
}
IntTy m_val;
};
} // namespace Common
typedef Common::BitSet<u8> BitSet8;
typedef Common::BitSet<u16> BitSet16;
typedef Common::BitSet<u32> BitSet32;
typedef Common::BitSet<u64> BitSet64;

61
src/common/bit_util.h Normal file
View File

@@ -0,0 +1,61 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <climits>
#include <cstddef>
#ifdef _MSC_VER
#include <intrin.h>
#endif
#include "common/common_types.h"
namespace Common {
/// Gets the size of a specified type T in bits.
template <typename T>
constexpr std::size_t BitSize() {
return sizeof(T) * CHAR_BIT;
}
#ifdef _MSC_VER
inline u32 CountLeadingZeroes32(u32 value) {
unsigned long leading_zero = 0;
if (_BitScanReverse(&leading_zero, value) != 0) {
return 31 - leading_zero;
}
return 32;
}
inline u64 CountLeadingZeroes64(u64 value) {
unsigned long leading_zero = 0;
if (_BitScanReverse64(&leading_zero, value) != 0) {
return 63 - leading_zero;
}
return 64;
}
#else
inline u32 CountLeadingZeroes32(u32 value) {
if (value == 0) {
return 32;
}
return __builtin_clz(value);
}
inline u64 CountLeadingZeroes64(u64 value) {
if (value == 0) {
return 64;
}
return __builtin_clzll(value);
}
#endif
} // namespace Common

View File

@@ -13,7 +13,7 @@
#include <vector>
#ifdef _WIN32
#include <share.h> // For _SH_DENYWR
#include <windows.h> // For OutputDebugStringA
#include <windows.h> // For OutputDebugStringW
#else
#define _SH_DENYWR 0
#endif
@@ -148,7 +148,7 @@ void FileBackend::Write(const Entry& entry) {
void DebuggerBackend::Write(const Entry& entry) {
#ifdef _WIN32
::OutputDebugStringA(FormatLogMessage(entry).append(1, '\n').c_str());
::OutputDebugStringW(Common::UTF8ToUTF16W(FormatLogMessage(entry).append(1, '\n')).c_str());
#endif
}

View File

@@ -4,18 +4,12 @@
#pragma once
#include <algorithm>
#include <cstdlib>
#include <type_traits>
namespace MathUtil {
static constexpr float PI = 3.14159265f;
inline bool IntervalsIntersect(unsigned start0, unsigned length0, unsigned start1,
unsigned length1) {
return (std::max(start0, start1) < std::min(start0 + length0, start1 + length1));
}
constexpr float PI = 3.14159265f;
template <class T>
struct Rectangle {
@@ -24,16 +18,16 @@ struct Rectangle {
T right{};
T bottom{};
Rectangle() = default;
constexpr Rectangle() = default;
Rectangle(T left, T top, T right, T bottom)
constexpr Rectangle(T left, T top, T right, T bottom)
: left(left), top(top), right(right), bottom(bottom) {}
T GetWidth() const {
return std::abs(static_cast<typename std::make_signed<T>::type>(right - left));
return std::abs(static_cast<std::make_signed_t<T>>(right - left));
}
T GetHeight() const {
return std::abs(static_cast<typename std::make_signed<T>::type>(bottom - top));
return std::abs(static_cast<std::make_signed_t<T>>(bottom - top));
}
Rectangle<T> TranslateX(const T x) const {
return Rectangle{left + x, top, right + x, bottom};

View File

@@ -12,7 +12,7 @@ template <typename T>
class Quaternion {
public:
Math::Vec3<T> xyz;
T w;
T w{};
Quaternion<decltype(-T{})> Inverse() const {
return {-xyz, w};

View File

@@ -4,11 +4,10 @@
#include <algorithm>
#include <cctype>
#include <cerrno>
#include <codecvt>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <locale>
#include <sstream>
#include "common/common_paths.h"
#include "common/logging/log.h"
#include "common/string_util.h"
@@ -33,24 +32,6 @@ std::string ToUpper(std::string str) {
return str;
}
// For Debugging. Read out an u8 array.
std::string ArrayToString(const u8* data, std::size_t size, int line_len, bool spaces) {
std::ostringstream oss;
oss << std::setfill('0') << std::hex;
for (int line = 0; size; ++data, --size) {
oss << std::setw(2) << (int)*data;
if (line_len == ++line) {
oss << '\n';
line = 0;
} else if (spaces)
oss << ' ';
}
return oss.str();
}
std::string StringFromBuffer(const std::vector<u8>& data) {
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
}
@@ -75,40 +56,6 @@ std::string StripQuotes(const std::string& s) {
return s;
}
bool TryParse(const std::string& str, u32* const output) {
char* endptr = nullptr;
// Reset errno to a value other than ERANGE
errno = 0;
unsigned long value = strtoul(str.c_str(), &endptr, 0);
if (!endptr || *endptr)
return false;
if (errno == ERANGE)
return false;
#if ULONG_MAX > UINT_MAX
if (value >= 0x100000000ull && value <= 0xFFFFFFFF00000000ull)
return false;
#endif
*output = static_cast<u32>(value);
return true;
}
bool TryParse(const std::string& str, bool* const output) {
if ("1" == str || "true" == ToLower(str))
*output = true;
else if ("0" == str || "false" == ToLower(str))
*output = false;
else
return false;
return true;
}
std::string StringFromBool(bool value) {
return value ? "True" : "False";
}
@@ -267,6 +214,15 @@ std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, std::size_t
return std::string(buffer, len);
}
std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer,
std::size_t max_len) {
std::size_t len = 0;
while (len < max_len && buffer[len] != '\0')
++len;
return std::u16string(buffer.begin(), buffer.begin() + len);
}
const char* TrimSourcePath(const char* path, const char* root) {
const char* p = path;

View File

@@ -5,8 +5,6 @@
#pragma once
#include <cstddef>
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>
#include "common/common_types.h"
@@ -19,44 +17,13 @@ std::string ToLower(std::string str);
/// Make a string uppercase
std::string ToUpper(std::string str);
std::string ArrayToString(const u8* data, std::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);
// Thousand separator. Turns 12345678 into 12,345,678
template <typename I>
std::string ThousandSeparate(I value, int spaces = 0) {
std::ostringstream oss;
// std::locale("") seems to be broken on many platforms
#if defined _WIN32 || (defined __linux__ && !defined __clang__)
oss.imbue(std::locale(""));
#endif
oss << std::setw(spaces) << value;
return oss.str();
}
std::string StringFromBool(bool value);
bool TryParse(const std::string& str, bool* output);
bool TryParse(const std::string& str, u32* output);
template <typename N>
static bool TryParse(const std::string& str, N* const output) {
std::istringstream iss(str);
N tmp = 0;
if (iss >> tmp) {
*output = tmp;
return true;
} else
return false;
}
std::string TabsToSpaces(int tab_size, std::string in);
void SplitString(const std::string& str, char delim, std::vector<std::string>& output);
@@ -99,6 +66,14 @@ bool ComparePartialString(InIt begin, InIt end, const char* other) {
*/
std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, std::size_t max_len);
/**
* Creates a UTF-16 std::u16string from a fixed-size NUL-terminated char buffer. If the buffer isn't
* null-terminated, then the string ends at the greatest multiple of two less then or equal to
* max_len_bytes.
*/
std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer,
std::size_t max_len);
/**
* Attempts to trim an arbitrary prefix from `path`, leaving only the part starting at `root`. It's
* intended to be used to strip a system-specific build directory from the `__FILE__` macro,

View File

@@ -25,23 +25,6 @@
namespace Common {
int CurrentThreadId() {
#ifdef _MSC_VER
return GetCurrentThreadId();
#elif defined __APPLE__
return mach_thread_self();
#else
return 0;
#endif
}
#ifdef _WIN32
// Supporting functions
void SleepCurrentThread(int ms) {
Sleep(ms);
}
#endif
#ifdef _MSC_VER
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) {
@@ -62,7 +45,7 @@ void SwitchCurrentThread() {
// This is implemented much nicer in upcoming msvc++, see:
// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx
void SetCurrentThreadName(const char* szThreadName) {
void SetCurrentThreadName(const char* name) {
static const DWORD MS_VC_EXCEPTION = 0x406D1388;
#pragma pack(push, 8)
@@ -75,7 +58,7 @@ void SetCurrentThreadName(const char* szThreadName) {
#pragma pack(pop)
info.dwType = 0x1000;
info.szName = szThreadName;
info.szName = name;
info.dwThreadID = -1; // dwThreadID;
info.dwFlags = 0;
@@ -107,10 +90,6 @@ void SetCurrentThreadAffinity(u32 mask) {
}
#ifndef _WIN32
void SleepCurrentThread(int ms) {
usleep(1000 * ms);
}
void SwitchCurrentThread() {
usleep(1000 * 1);
}
@@ -118,15 +97,15 @@ void SwitchCurrentThread() {
// MinGW with the POSIX threading model does not support pthread_setname_np
#if !defined(_WIN32) || defined(_MSC_VER)
void SetCurrentThreadName(const char* szThreadName) {
void SetCurrentThreadName(const char* name) {
#ifdef __APPLE__
pthread_setname_np(szThreadName);
pthread_setname_np(name);
#elif defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
pthread_set_name_np(pthread_self(), szThreadName);
pthread_set_name_np(pthread_self(), name);
#elif defined(__NetBSD__)
pthread_setname_np(pthread_self(), "%s", (void*)szThreadName);
pthread_setname_np(pthread_self(), "%s", (void*)name);
#else
pthread_setname_np(pthread_self(), szThreadName);
pthread_setname_np(pthread_self(), name);
#endif
}
#endif

View File

@@ -13,15 +13,8 @@
namespace Common {
int CurrentThreadId();
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask);
void SetCurrentThreadAffinity(u32 mask);
class Event {
public:
Event() : is_set(false) {}
void Set() {
std::lock_guard<std::mutex> lk(mutex);
if (!is_set) {
@@ -53,14 +46,14 @@ public:
}
private:
bool is_set;
bool is_set = false;
std::condition_variable condvar;
std::mutex mutex;
};
class Barrier {
public:
explicit Barrier(std::size_t count_) : count(count_), waiting(0), generation(0) {}
explicit Barrier(std::size_t count_) : count(count_) {}
/// Blocks until all "count" threads have called Sync()
void Sync() {
@@ -80,12 +73,13 @@ public:
private:
std::condition_variable condvar;
std::mutex mutex;
const std::size_t count;
std::size_t waiting;
std::size_t generation; // Incremented once each time the barrier is used
std::size_t count;
std::size_t waiting = 0;
std::size_t generation = 0; // Incremented once each time the barrier is used
};
void SleepCurrentThread(int ms);
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask);
void SetCurrentThreadAffinity(u32 mask);
void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms
void SetCurrentThreadName(const char* name);

View File

@@ -49,6 +49,22 @@ struct ThreadQueueList {
return T();
}
template <typename UnaryPredicate>
T get_first_filter(UnaryPredicate filter) const {
const Queue* cur = first;
while (cur != nullptr) {
if (!cur->data.empty()) {
for (const auto& item : cur->data) {
if (filter(item))
return item;
}
}
cur = cur->next_nonempty;
}
return T();
}
T pop_first() {
Queue* cur = first;
while (cur != nullptr) {

View File

@@ -1,222 +0,0 @@
// Copyright 2016 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <initializer_list>
#include <xbyak.h>
#include "common/assert.h"
#include "common/bit_set.h"
namespace Common::X64 {
inline int RegToIndex(const Xbyak::Reg& reg) {
using Kind = Xbyak::Reg::Kind;
ASSERT_MSG((reg.getKind() & (Kind::REG | Kind::XMM)) != 0,
"RegSet only support GPRs and XMM registers.");
ASSERT_MSG(reg.getIdx() < 16, "RegSet only supports XXM0-15.");
return reg.getIdx() + (reg.getKind() == Kind::REG ? 0 : 16);
}
inline Xbyak::Reg64 IndexToReg64(int reg_index) {
ASSERT(reg_index < 16);
return Xbyak::Reg64(reg_index);
}
inline Xbyak::Xmm IndexToXmm(int reg_index) {
ASSERT(reg_index >= 16 && reg_index < 32);
return Xbyak::Xmm(reg_index - 16);
}
inline Xbyak::Reg IndexToReg(int reg_index) {
if (reg_index < 16) {
return IndexToReg64(reg_index);
} else {
return IndexToXmm(reg_index);
}
}
inline BitSet32 BuildRegSet(std::initializer_list<Xbyak::Reg> regs) {
BitSet32 bits;
for (const Xbyak::Reg& reg : regs) {
bits[RegToIndex(reg)] = true;
}
return bits;
}
const BitSet32 ABI_ALL_GPRS(0x0000FFFF);
const BitSet32 ABI_ALL_XMMS(0xFFFF0000);
#ifdef _WIN32
// Microsoft x64 ABI
const Xbyak::Reg ABI_RETURN = Xbyak::util::rax;
const Xbyak::Reg ABI_PARAM1 = Xbyak::util::rcx;
const Xbyak::Reg ABI_PARAM2 = Xbyak::util::rdx;
const Xbyak::Reg ABI_PARAM3 = Xbyak::util::r8;
const Xbyak::Reg ABI_PARAM4 = Xbyak::util::r9;
const BitSet32 ABI_ALL_CALLER_SAVED = BuildRegSet({
// GPRs
Xbyak::util::rcx,
Xbyak::util::rdx,
Xbyak::util::r8,
Xbyak::util::r9,
Xbyak::util::r10,
Xbyak::util::r11,
// XMMs
Xbyak::util::xmm0,
Xbyak::util::xmm1,
Xbyak::util::xmm2,
Xbyak::util::xmm3,
Xbyak::util::xmm4,
Xbyak::util::xmm5,
});
const BitSet32 ABI_ALL_CALLEE_SAVED = BuildRegSet({
// GPRs
Xbyak::util::rbx,
Xbyak::util::rsi,
Xbyak::util::rdi,
Xbyak::util::rbp,
Xbyak::util::r12,
Xbyak::util::r13,
Xbyak::util::r14,
Xbyak::util::r15,
// XMMs
Xbyak::util::xmm6,
Xbyak::util::xmm7,
Xbyak::util::xmm8,
Xbyak::util::xmm9,
Xbyak::util::xmm10,
Xbyak::util::xmm11,
Xbyak::util::xmm12,
Xbyak::util::xmm13,
Xbyak::util::xmm14,
Xbyak::util::xmm15,
});
constexpr std::size_t ABI_SHADOW_SPACE = 0x20;
#else
// System V x86-64 ABI
const Xbyak::Reg ABI_RETURN = Xbyak::util::rax;
const Xbyak::Reg ABI_PARAM1 = Xbyak::util::rdi;
const Xbyak::Reg ABI_PARAM2 = Xbyak::util::rsi;
const Xbyak::Reg ABI_PARAM3 = Xbyak::util::rdx;
const Xbyak::Reg ABI_PARAM4 = Xbyak::util::rcx;
const BitSet32 ABI_ALL_CALLER_SAVED = BuildRegSet({
// GPRs
Xbyak::util::rcx,
Xbyak::util::rdx,
Xbyak::util::rdi,
Xbyak::util::rsi,
Xbyak::util::r8,
Xbyak::util::r9,
Xbyak::util::r10,
Xbyak::util::r11,
// XMMs
Xbyak::util::xmm0,
Xbyak::util::xmm1,
Xbyak::util::xmm2,
Xbyak::util::xmm3,
Xbyak::util::xmm4,
Xbyak::util::xmm5,
Xbyak::util::xmm6,
Xbyak::util::xmm7,
Xbyak::util::xmm8,
Xbyak::util::xmm9,
Xbyak::util::xmm10,
Xbyak::util::xmm11,
Xbyak::util::xmm12,
Xbyak::util::xmm13,
Xbyak::util::xmm14,
Xbyak::util::xmm15,
});
const BitSet32 ABI_ALL_CALLEE_SAVED = BuildRegSet({
// GPRs
Xbyak::util::rbx,
Xbyak::util::rbp,
Xbyak::util::r12,
Xbyak::util::r13,
Xbyak::util::r14,
Xbyak::util::r15,
});
constexpr std::size_t ABI_SHADOW_SPACE = 0;
#endif
inline void ABI_CalculateFrameSize(BitSet32 regs, std::size_t rsp_alignment,
std::size_t needed_frame_size, s32* out_subtraction,
s32* out_xmm_offset) {
int count = (regs & ABI_ALL_GPRS).Count();
rsp_alignment -= count * 8;
std::size_t subtraction = 0;
int xmm_count = (regs & ABI_ALL_XMMS).Count();
if (xmm_count) {
// If we have any XMMs to save, we must align the stack here.
subtraction = rsp_alignment & 0xF;
}
subtraction += 0x10 * xmm_count;
std::size_t xmm_base_subtraction = subtraction;
subtraction += needed_frame_size;
subtraction += ABI_SHADOW_SPACE;
// Final alignment.
rsp_alignment -= subtraction;
subtraction += rsp_alignment & 0xF;
*out_subtraction = (s32)subtraction;
*out_xmm_offset = (s32)(subtraction - xmm_base_subtraction);
}
inline std::size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs,
std::size_t rsp_alignment,
std::size_t needed_frame_size = 0) {
s32 subtraction, xmm_offset;
ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset);
for (int reg_index : (regs & ABI_ALL_GPRS)) {
code.push(IndexToReg64(reg_index));
}
if (subtraction != 0) {
code.sub(code.rsp, subtraction);
}
for (int reg_index : (regs & ABI_ALL_XMMS)) {
code.movaps(code.xword[code.rsp + xmm_offset], IndexToXmm(reg_index));
xmm_offset += 0x10;
}
return ABI_SHADOW_SPACE;
}
inline void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs,
std::size_t rsp_alignment,
std::size_t needed_frame_size = 0) {
s32 subtraction, xmm_offset;
ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset);
for (int reg_index : (regs & ABI_ALL_XMMS)) {
code.movaps(IndexToXmm(reg_index), code.xword[code.rsp + xmm_offset]);
xmm_offset += 0x10;
}
if (subtraction != 0) {
code.add(code.rsp, subtraction);
}
// GPRs need to be popped in reverse order
for (int reg_index = 15; reg_index >= 0; reg_index--) {
if (regs[reg_index]) {
code.pop(IndexToReg64(reg_index));
}
}
}
} // namespace Common::X64

View File

@@ -1,47 +0,0 @@
// Copyright 2016 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <type_traits>
#include <xbyak.h>
#include "common/x64/xbyak_abi.h"
namespace Common::X64 {
// Constants for use with cmpps/cmpss
enum {
CMP_EQ = 0,
CMP_LT = 1,
CMP_LE = 2,
CMP_UNORD = 3,
CMP_NEQ = 4,
CMP_NLT = 5,
CMP_NLE = 6,
CMP_ORD = 7,
};
inline bool IsWithin2G(uintptr_t ref, uintptr_t target) {
u64 distance = target - (ref + 5);
return !(distance >= 0x8000'0000ULL && distance <= ~0x8000'0000ULL);
}
inline bool IsWithin2G(const Xbyak::CodeGenerator& code, uintptr_t target) {
return IsWithin2G(reinterpret_cast<uintptr_t>(code.getCurr()), target);
}
template <typename T>
inline void CallFarFunction(Xbyak::CodeGenerator& code, const T f) {
static_assert(std::is_pointer_v<T>, "Argument must be a (function) pointer.");
std::size_t addr = reinterpret_cast<std::size_t>(f);
if (IsWithin2G(code, addr)) {
code.call(f);
} else {
// ABI_RETURN is a safe temp register to use before a call
code.mov(ABI_RETURN, addr);
code.call(ABI_RETURN);
}
}
} // namespace Common::X64

View File

@@ -12,6 +12,8 @@ add_library(core STATIC
core_timing.h
core_timing_util.cpp
core_timing_util.h
cpu_core_manager.cpp
cpu_core_manager.h
crypto/aes_util.cpp
crypto/aes_util.h
crypto/encryption_layer.cpp
@@ -61,6 +63,10 @@ add_library(core STATIC
file_sys/sdmc_factory.h
file_sys/submission_package.cpp
file_sys/submission_package.h
file_sys/system_archive/ng_word.cpp
file_sys/system_archive/ng_word.h
file_sys/system_archive/system_archive.cpp
file_sys/system_archive/system_archive.h
file_sys/vfs.cpp
file_sys/vfs.h
file_sys/vfs_concat.cpp
@@ -77,6 +83,10 @@ add_library(core STATIC
file_sys/vfs_vector.h
file_sys/xts_archive.cpp
file_sys/xts_archive.h
frontend/applets/profile_select.cpp
frontend/applets/profile_select.h
frontend/applets/software_keyboard.cpp
frontend/applets/software_keyboard.h
frontend/emu_window.cpp
frontend/emu_window.h
frontend/framebuffer_layout.cpp
@@ -93,8 +103,6 @@ add_library(core STATIC
hle/kernel/client_session.cpp
hle/kernel/client_session.h
hle/kernel/errors.h
hle/kernel/event.cpp
hle/kernel/event.h
hle/kernel/handle_table.cpp
hle/kernel/handle_table.h
hle/kernel/hle_ipc.cpp
@@ -107,6 +115,10 @@ add_library(core STATIC
hle/kernel/object.h
hle/kernel/process.cpp
hle/kernel/process.h
hle/kernel/process_capability.cpp
hle/kernel/process_capability.h
hle/kernel/readable_event.cpp
hle/kernel/readable_event.h
hle/kernel/resource_limit.cpp
hle/kernel/resource_limit.h
hle/kernel/scheduler.cpp
@@ -129,6 +141,8 @@ add_library(core STATIC
hle/kernel/vm_manager.h
hle/kernel/wait_object.cpp
hle/kernel/wait_object.h
hle/kernel/writable_event.cpp
hle/kernel/writable_event.h
hle/lock.cpp
hle/lock.h
hle/result.h
@@ -150,6 +164,14 @@ add_library(core STATIC
hle/service/am/applet_ae.h
hle/service/am/applet_oe.cpp
hle/service/am/applet_oe.h
hle/service/am/applets/applets.cpp
hle/service/am/applets/applets.h
hle/service/am/applets/profile_select.cpp
hle/service/am/applets/profile_select.h
hle/service/am/applets/software_keyboard.cpp
hle/service/am/applets/software_keyboard.h
hle/service/am/applets/stub_applet.cpp
hle/service/am/applets/stub_applet.h
hle/service/am/idle.cpp
hle/service/am/idle.h
hle/service/am/omm.cpp

View File

@@ -151,6 +151,7 @@ std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const {
config.tpidr_el0 = &cb->tpidr_el0;
config.dczid_el0 = 4;
config.ctr_el0 = 0x8444c004;
config.cntfrq_el0 = 19200000; // Value from fusee.
// Unpredictable instructions
config.define_unpredictable_behaviour = true;

View File

@@ -8,12 +8,14 @@
#include <thread>
#include <utility>
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/string_util.h"
#include "core/arm/exclusive_monitor.h"
#include "core/core.h"
#include "core/core_cpu.h"
#include "core/core_timing.h"
#include "core/cpu_core_manager.h"
#include "core/file_sys/mode.h"
#include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_real.h"
@@ -23,12 +25,13 @@
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/service/am/applets/software_keyboard.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
#include "core/loader/loader.h"
#include "core/perf_stats.h"
#include "core/settings.h"
#include "core/telemetry_session.h"
#include "frontend/applets/software_keyboard.h"
#include "video_core/debug_utils/debug_utils.h"
#include "video_core/gpu.h"
#include "video_core/renderer_base.h"
@@ -38,7 +41,6 @@ namespace Core {
/*static*/ System System::s_instance;
namespace {
FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
const std::string& path) {
// To account for split 00+01+etc files.
@@ -67,66 +69,26 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(concat, dir->GetName());
}
if (FileUtil::IsDirectory(path))
return vfs->OpenFile(path + "/" + "main", FileSys::Mode::Read);
return vfs->OpenFile(path, FileSys::Mode::Read);
}
/// Runs a CPU core while the system is powered on
void RunCpuCore(Cpu& cpu_state) {
while (Core::System::GetInstance().IsPoweredOn()) {
cpu_state.RunLoop(true);
}
}
} // Anonymous namespace
struct System::Impl {
Cpu& CurrentCpuCore() {
if (Settings::values.use_multi_core) {
const auto& search = thread_to_cpu.find(std::this_thread::get_id());
ASSERT(search != thread_to_cpu.end());
ASSERT(search->second);
return *search->second;
}
// Otherwise, use single-threaded mode active_core variable
return *cpu_cores[active_core];
Cpu& CurrentCpuCore() {
return cpu_core_manager.GetCurrentCore();
}
ResultStatus RunLoop(bool tight_loop) {
status = ResultStatus::Success;
// Update thread_to_cpu in case Core 0 is run from a different host thread
thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0].get();
if (GDBStub::IsServerEnabled()) {
GDBStub::HandlePacket();
// If the loop is halted and we want to step, use a tiny (1) number of instructions to
// execute. Otherwise, get out of the loop function.
if (GDBStub::GetCpuHaltFlag()) {
if (GDBStub::GetCpuStepFlag()) {
tight_loop = false;
} else {
return ResultStatus::Success;
}
}
}
for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) {
cpu_cores[active_core]->RunLoop(tight_loop);
if (Settings::values.use_multi_core) {
// Cores 1-3 are run on other threads in this mode
break;
}
}
if (GDBStub::IsServerEnabled()) {
GDBStub::SetCpuStepFlag(false);
}
cpu_core_manager.RunLoop(tight_loop);
return status;
}
ResultStatus Init(Frontend::EmuWindow& emu_window) {
ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) {
LOG_DEBUG(HW_Memory, "initialized OK");
CoreTiming::Init();
@@ -136,15 +98,15 @@ struct System::Impl {
if (virtual_filesystem == nullptr)
virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
/// Create default implementations of applets if one is not provided.
if (profile_selector == nullptr)
profile_selector = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>();
if (software_keyboard == nullptr)
software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
auto main_process = Kernel::Process::Create(kernel, "main");
kernel.MakeCurrentProcess(main_process.get());
cpu_barrier = std::make_unique<CpuBarrier>();
cpu_exclusive_monitor = Cpu::MakeExclusiveMonitor(cpu_cores.size());
for (std::size_t index = 0; index < cpu_cores.size(); ++index) {
cpu_cores[index] = std::make_unique<Cpu>(*cpu_exclusive_monitor, *cpu_barrier, index);
}
telemetry_session = std::make_unique<Core::TelemetrySession>();
service_manager = std::make_shared<Service::SM::ServiceManager>();
@@ -158,17 +120,8 @@ struct System::Impl {
gpu_core = std::make_unique<Tegra::GPU>(renderer->Rasterizer());
// Create threads for CPU cores 1-3, and build thread_to_cpu map
// CPU core 0 is run on the main thread
thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0].get();
if (Settings::values.use_multi_core) {
for (std::size_t index = 0; index < cpu_core_threads.size(); ++index) {
cpu_core_threads[index] =
std::make_unique<std::thread>(RunCpuCore, std::ref(*cpu_cores[index + 1]));
thread_to_cpu[cpu_core_threads[index]->get_id()] = cpu_cores[index + 1].get();
}
}
cpu_core_manager.Initialize(system);
is_powered_on = true;
LOG_DEBUG(Core, "Initialized OK");
// Reset counters and set time origin to current frame
@@ -178,7 +131,8 @@ struct System::Impl {
return ResultStatus::Success;
}
ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
ResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
const std::string& filepath) {
app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath));
if (!app_loader) {
@@ -195,7 +149,7 @@ struct System::Impl {
return ResultStatus::ErrorSystemMode;
}
ResultStatus init_result{Init(emu_window)};
ResultStatus init_result{Init(system, emu_window)};
if (init_result != ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
static_cast<int>(init_result));
@@ -225,6 +179,8 @@ struct System::Impl {
Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime",
perf_results.frametime * 1000.0);
is_powered_on = false;
// Shutdown emulation session
renderer.reset();
GDBStub::Shutdown();
@@ -234,19 +190,7 @@ struct System::Impl {
gpu_core.reset();
// Close all CPU/threading state
cpu_barrier->NotifyEnd();
if (Settings::values.use_multi_core) {
for (auto& thread : cpu_core_threads) {
thread->join();
thread.reset();
}
}
thread_to_cpu.clear();
for (auto& cpu_core : cpu_cores) {
cpu_core.reset();
}
cpu_exclusive_monitor.reset();
cpu_barrier.reset();
cpu_core_manager.Shutdown();
// Shutdown kernel and core timing
kernel.Shutdown();
@@ -283,11 +227,12 @@ struct System::Impl {
std::unique_ptr<VideoCore::RendererBase> renderer;
std::unique_ptr<Tegra::GPU> gpu_core;
std::shared_ptr<Tegra::DebugContext> debug_context;
std::unique_ptr<ExclusiveMonitor> cpu_exclusive_monitor;
std::unique_ptr<CpuBarrier> cpu_barrier;
std::array<std::unique_ptr<Cpu>, NUM_CPU_CORES> cpu_cores;
std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> cpu_core_threads;
std::size_t active_core{}; ///< Active core, only used in single thread mode
CpuCoreManager cpu_core_manager;
bool is_powered_on = false;
/// Frontend applets
std::unique_ptr<Core::Frontend::ProfileSelectApplet> profile_selector;
std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard;
/// Service manager
std::shared_ptr<Service::SM::ServiceManager> service_manager;
@@ -298,9 +243,6 @@ struct System::Impl {
ResultStatus status = ResultStatus::Success;
std::string status_details = "";
/// Map of guest threads to CPU cores
std::map<std::thread::id, Cpu*> thread_to_cpu;
Core::PerfStats perf_stats;
Core::FrameLimiter frame_limiter;
};
@@ -325,17 +267,15 @@ System::ResultStatus System::SingleStep() {
}
void System::InvalidateCpuInstructionCaches() {
for (auto& cpu : impl->cpu_cores) {
cpu->ArmInterface().ClearInstructionCache();
}
impl->cpu_core_manager.InvalidateAllInstructionCaches();
}
System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
return impl->Load(emu_window, filepath);
return impl->Load(*this, emu_window, filepath);
}
bool System::IsPoweredOn() const {
return impl->cpu_barrier && impl->cpu_barrier->IsAlive();
return impl->is_powered_on;
}
void System::PrepareReschedule() {
@@ -399,21 +339,20 @@ const ARM_Interface& System::ArmInterface(std::size_t core_index) const {
}
Cpu& System::CpuCore(std::size_t core_index) {
ASSERT(core_index < NUM_CPU_CORES);
return *impl->cpu_cores[core_index];
return impl->cpu_core_manager.GetCore(core_index);
}
const Cpu& System::CpuCore(std::size_t core_index) const {
ASSERT(core_index < NUM_CPU_CORES);
return *impl->cpu_cores[core_index];
return impl->cpu_core_manager.GetCore(core_index);
}
ExclusiveMonitor& System::Monitor() {
return *impl->cpu_exclusive_monitor;
return impl->cpu_core_manager.GetExclusiveMonitor();
}
const ExclusiveMonitor& System::Monitor() const {
return *impl->cpu_exclusive_monitor;
return impl->cpu_core_manager.GetExclusiveMonitor();
}
Tegra::GPU& System::GPU() {
@@ -488,8 +427,24 @@ std::shared_ptr<FileSys::VfsFilesystem> System::GetFilesystem() const {
return impl->virtual_filesystem;
}
void System::SetProfileSelector(std::unique_ptr<Core::Frontend::ProfileSelectApplet> applet) {
impl->profile_selector = std::move(applet);
}
const Core::Frontend::ProfileSelectApplet& System::GetProfileSelector() const {
return *impl->profile_selector;
}
void System::SetSoftwareKeyboard(std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> applet) {
impl->software_keyboard = std::move(applet);
}
const Core::Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() const {
return *impl->software_keyboard;
}
System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
return impl->Init(emu_window);
return impl->Init(*this, emu_window);
}
void System::Shutdown() {

View File

@@ -9,10 +9,13 @@
#include <string>
#include "common/common_types.h"
#include "core/file_sys/vfs_types.h"
#include "core/hle/kernel/object.h"
#include "frontend/applets/profile_select.h"
namespace Core::Frontend {
class EmuWindow;
class SoftwareKeyboardApplet;
} // namespace Core::Frontend
namespace FileSys {
@@ -54,6 +57,9 @@ class TelemetrySession;
struct PerfStatsResults;
FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
const std::string& path);
class System {
public:
System(const System&) = delete;
@@ -236,6 +242,14 @@ public:
std::shared_ptr<FileSys::VfsFilesystem> GetFilesystem() const;
void SetProfileSelector(std::unique_ptr<Core::Frontend::ProfileSelectApplet> applet);
const Core::Frontend::ProfileSelectApplet& GetProfileSelector() const;
void SetSoftwareKeyboard(std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> applet);
const Core::Frontend::SoftwareKeyboardApplet& GetSoftwareKeyboard() const;
private:
System();

View File

@@ -0,0 +1,142 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/assert.h"
#include "core/arm/exclusive_monitor.h"
#include "core/core.h"
#include "core/core_cpu.h"
#include "core/cpu_core_manager.h"
#include "core/gdbstub/gdbstub.h"
#include "core/settings.h"
namespace Core {
namespace {
void RunCpuCore(const System& system, Cpu& cpu_state) {
while (system.IsPoweredOn()) {
cpu_state.RunLoop(true);
}
}
} // Anonymous namespace
CpuCoreManager::CpuCoreManager() = default;
CpuCoreManager::~CpuCoreManager() = default;
void CpuCoreManager::Initialize(System& system) {
barrier = std::make_unique<CpuBarrier>();
exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size());
for (std::size_t index = 0; index < cores.size(); ++index) {
cores[index] = std::make_unique<Cpu>(*exclusive_monitor, *barrier, index);
}
// Create threads for CPU cores 1-3, and build thread_to_cpu map
// CPU core 0 is run on the main thread
thread_to_cpu[std::this_thread::get_id()] = cores[0].get();
if (!Settings::values.use_multi_core) {
return;
}
for (std::size_t index = 0; index < core_threads.size(); ++index) {
core_threads[index] = std::make_unique<std::thread>(RunCpuCore, std::cref(system),
std::ref(*cores[index + 1]));
thread_to_cpu[core_threads[index]->get_id()] = cores[index + 1].get();
}
}
void CpuCoreManager::Shutdown() {
barrier->NotifyEnd();
if (Settings::values.use_multi_core) {
for (auto& thread : core_threads) {
thread->join();
thread.reset();
}
}
thread_to_cpu.clear();
for (auto& cpu_core : cores) {
cpu_core.reset();
}
exclusive_monitor.reset();
barrier.reset();
}
Cpu& CpuCoreManager::GetCore(std::size_t index) {
return *cores.at(index);
}
const Cpu& CpuCoreManager::GetCore(std::size_t index) const {
return *cores.at(index);
}
ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() {
return *exclusive_monitor;
}
const ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() const {
return *exclusive_monitor;
}
Cpu& CpuCoreManager::GetCurrentCore() {
if (Settings::values.use_multi_core) {
const auto& search = thread_to_cpu.find(std::this_thread::get_id());
ASSERT(search != thread_to_cpu.end());
ASSERT(search->second);
return *search->second;
}
// Otherwise, use single-threaded mode active_core variable
return *cores[active_core];
}
const Cpu& CpuCoreManager::GetCurrentCore() const {
if (Settings::values.use_multi_core) {
const auto& search = thread_to_cpu.find(std::this_thread::get_id());
ASSERT(search != thread_to_cpu.end());
ASSERT(search->second);
return *search->second;
}
// Otherwise, use single-threaded mode active_core variable
return *cores[active_core];
}
void CpuCoreManager::RunLoop(bool tight_loop) {
// Update thread_to_cpu in case Core 0 is run from a different host thread
thread_to_cpu[std::this_thread::get_id()] = cores[0].get();
if (GDBStub::IsServerEnabled()) {
GDBStub::HandlePacket();
// If the loop is halted and we want to step, use a tiny (1) number of instructions to
// execute. Otherwise, get out of the loop function.
if (GDBStub::GetCpuHaltFlag()) {
if (GDBStub::GetCpuStepFlag()) {
tight_loop = false;
} else {
return;
}
}
}
for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) {
cores[active_core]->RunLoop(tight_loop);
if (Settings::values.use_multi_core) {
// Cores 1-3 are run on other threads in this mode
break;
}
}
if (GDBStub::IsServerEnabled()) {
GDBStub::SetCpuStepFlag(false);
}
}
void CpuCoreManager::InvalidateAllInstructionCaches() {
for (auto& cpu : cores) {
cpu->ArmInterface().ClearInstructionCache();
}
}
} // namespace Core

View File

@@ -0,0 +1,59 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <map>
#include <memory>
#include <thread>
namespace Core {
class Cpu;
class CpuBarrier;
class ExclusiveMonitor;
class System;
class CpuCoreManager {
public:
CpuCoreManager();
CpuCoreManager(const CpuCoreManager&) = delete;
CpuCoreManager(CpuCoreManager&&) = delete;
~CpuCoreManager();
CpuCoreManager& operator=(const CpuCoreManager&) = delete;
CpuCoreManager& operator=(CpuCoreManager&&) = delete;
void Initialize(System& system);
void Shutdown();
Cpu& GetCore(std::size_t index);
const Cpu& GetCore(std::size_t index) const;
Cpu& GetCurrentCore();
const Cpu& GetCurrentCore() const;
ExclusiveMonitor& GetExclusiveMonitor();
const ExclusiveMonitor& GetExclusiveMonitor() const;
void RunLoop(bool tight_loop);
void InvalidateAllInstructionCaches();
private:
static constexpr std::size_t NUM_CPU_CORES = 4;
std::unique_ptr<ExclusiveMonitor> exclusive_monitor;
std::unique_ptr<CpuBarrier> barrier;
std::array<std::unique_ptr<Cpu>, NUM_CPU_CORES> cores;
std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> core_threads;
std::size_t active_core{}; ///< Active core, only used in single thread mode
/// Map of guest threads to CPU cores
std::map<std::thread::id, Cpu*> thread_to_cpu;
};
} // namespace Core

View File

@@ -246,7 +246,6 @@ std::vector<TicketRaw> GetTicketblob(const FileUtil::IOFile& ticket_save) {
}
std::vector<TicketRaw> out;
u32 magic{};
for (std::size_t offset = 0; offset + 0x4 < buffer.size(); ++offset) {
if (buffer[offset] == 0x4 && buffer[offset + 1] == 0x0 && buffer[offset + 2] == 0x1 &&
buffer[offset + 3] == 0x0) {
@@ -794,7 +793,7 @@ void KeyManager::DeriveBase() {
void KeyManager::DeriveETicket(PartitionDataManager& data) {
// ETicket keys
const auto es = Service::FileSystem::GetUnionContents()->GetEntry(
const auto es = Service::FileSystem::GetUnionContents().GetEntry(
0x0100000000000033, FileSys::ContentRecordType::Program);
if (es == nullptr)

View File

@@ -8,8 +8,9 @@
namespace FileSys {
BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_)
BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_, VirtualDir dump_root_)
: nand_root(std::move(nand_root_)), load_root(std::move(load_root_)),
dump_root(std::move(dump_root_)),
sysnand_cache(std::make_unique<RegisteredCache>(
GetOrCreateDirectoryRelative(nand_root, "/system/Contents/registered"))),
usrnand_cache(std::make_unique<RegisteredCache>(
@@ -32,4 +33,10 @@ VirtualDir BISFactory::GetModificationLoadRoot(u64 title_id) const {
return GetOrCreateDirectoryRelative(load_root, fmt::format("/{:016X}", title_id));
}
VirtualDir BISFactory::GetModificationDumpRoot(u64 title_id) const {
if (title_id == 0)
return nullptr;
return GetOrCreateDirectoryRelative(dump_root, fmt::format("/{:016X}", title_id));
}
} // namespace FileSys

View File

@@ -17,17 +17,19 @@ class RegisteredCache;
/// registered caches.
class BISFactory {
public:
explicit BISFactory(VirtualDir nand_root, VirtualDir load_root);
explicit BISFactory(VirtualDir nand_root, VirtualDir load_root, VirtualDir dump_root);
~BISFactory();
RegisteredCache* GetSystemNANDContents() const;
RegisteredCache* GetUserNANDContents() const;
VirtualDir GetModificationLoadRoot(u64 title_id) const;
VirtualDir GetModificationDumpRoot(u64 title_id) const;
private:
VirtualDir nand_root;
VirtualDir load_root;
VirtualDir dump_root;
std::unique_ptr<RegisteredCache> sysnand_cache;
std::unique_ptr<RegisteredCache> usrnand_cache;

View File

@@ -176,7 +176,7 @@ Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) {
for (const VirtualFile& file : partitions[static_cast<std::size_t>(part)]->GetFiles()) {
if (file->GetExtension() != "nca")
continue;
auto nca = std::make_shared<NCA>(file);
auto nca = std::make_shared<NCA>(file, nullptr, 0, keys);
// TODO(DarkLordZach): Add proper Rev1+ Support
if (nca->IsUpdate())
continue;

View File

@@ -9,6 +9,7 @@
#include <vector>
#include "common/common_types.h"
#include "common/swap.h"
#include "core/crypto/key_manager.h"
#include "core/file_sys/vfs.h"
namespace Loader {
@@ -31,7 +32,18 @@ enum class GamecardSize : u8 {
};
struct GamecardInfo {
std::array<u8, 0x70> data;
u64_le firmware_version;
u32_le access_control_flags;
u32_le read_wait_time1;
u32_le read_wait_time2;
u32_le write_wait_time1;
u32_le write_wait_time2;
u32_le firmware_mode;
u32_le cup_version;
std::array<u8, 4> reserved1;
u64_le update_partition_hash;
u64_le cup_id;
std::array<u8, 0x38> reserved2;
};
static_assert(sizeof(GamecardInfo) == 0x70, "GamecardInfo has incorrect size.");
@@ -107,5 +119,7 @@ private:
std::shared_ptr<NSP> secure_partition;
std::shared_ptr<NCA> program;
std::vector<std::shared_ptr<NCA>> ncas;
Core::Crypto::KeyManager keys;
};
} // namespace FileSys

View File

@@ -101,8 +101,9 @@ static bool IsValidNCA(const NCAHeader& header) {
return header.magic == Common::MakeMagic('N', 'C', 'A', '3');
}
NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_offset)
: file(std::move(file_)), bktr_base_romfs(std::move(bktr_base_romfs_)) {
NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_offset,
Core::Crypto::KeyManager keys_)
: file(std::move(file_)), bktr_base_romfs(std::move(bktr_base_romfs_)), keys(std::move(keys_)) {
if (file == nullptr) {
status = Loader::ResultStatus::ErrorNullFile;
return;

View File

@@ -79,7 +79,8 @@ inline bool IsDirectoryExeFS(const std::shared_ptr<VfsDirectory>& pfs) {
class NCA : public ReadOnlyVfsDirectory {
public:
explicit NCA(VirtualFile file, VirtualFile bktr_base_romfs = nullptr,
u64 bktr_base_ivfc_offset = 0);
u64 bktr_base_ivfc_offset = 0,
Core::Crypto::KeyManager keys = Core::Crypto::KeyManager());
~NCA() override;
Loader::ResultStatus GetStatus() const;

View File

@@ -8,13 +8,23 @@
namespace FileSys {
const std::array<const char*, 15> LANGUAGE_NAMES = {
"AmericanEnglish", "BritishEnglish", "Japanese",
"French", "German", "LatinAmericanSpanish",
"Spanish", "Italian", "Dutch",
"CanadianFrench", "Portugese", "Russian",
"Korean", "Taiwanese", "Chinese",
};
const std::array<const char*, 15> LANGUAGE_NAMES{{
"AmericanEnglish",
"BritishEnglish",
"Japanese",
"French",
"German",
"LatinAmericanSpanish",
"Spanish",
"Italian",
"Dutch",
"CanadianFrench",
"Portuguese",
"Russian",
"Korean",
"Taiwanese",
"Chinese",
}};
std::string LanguageEntry::GetApplicationName() const {
return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(),
@@ -26,18 +36,20 @@ std::string LanguageEntry::GetDeveloperName() const {
developer_name.size());
}
NACP::NACP(VirtualFile file) : raw(std::make_unique<RawNACP>()) {
file->ReadObject(raw.get());
NACP::NACP() = default;
NACP::NACP(VirtualFile file) {
file->ReadObject(&raw);
}
NACP::~NACP() = default;
const LanguageEntry& NACP::GetLanguageEntry(Language language) const {
if (language != Language::Default) {
return raw->language_entries.at(static_cast<u8>(language));
return raw.language_entries.at(static_cast<u8>(language));
}
for (const auto& language_entry : raw->language_entries) {
for (const auto& language_entry : raw.language_entries) {
if (!language_entry.GetApplicationName().empty())
return language_entry;
}
@@ -55,15 +67,29 @@ std::string NACP::GetDeveloperName(Language language) const {
}
u64 NACP::GetTitleId() const {
return raw->title_id;
return raw.title_id;
}
u64 NACP::GetDLCBaseTitleId() const {
return raw->dlc_base_title_id;
return raw.dlc_base_title_id;
}
std::string NACP::GetVersionString() const {
return Common::StringFromFixedZeroTerminatedBuffer(raw->version_string.data(),
raw->version_string.size());
return Common::StringFromFixedZeroTerminatedBuffer(raw.version_string.data(),
raw.version_string.size());
}
u64 NACP::GetDefaultNormalSaveSize() const {
return raw.normal_save_data_size;
}
u64 NACP::GetDefaultJournalSaveSize() const {
return raw.journal_sava_data_size;
}
std::vector<u8> NACP::GetRawBytes() const {
std::vector<u8> out(sizeof(RawNACP));
std::memcpy(out.data(), &raw, sizeof(RawNACP));
return out;
}
} // namespace FileSys

View File

@@ -28,17 +28,30 @@ static_assert(sizeof(LanguageEntry) == 0x300, "LanguageEntry has incorrect size.
// The raw file format of a NACP file.
struct RawNACP {
std::array<LanguageEntry, 16> language_entries;
INSERT_PADDING_BYTES(0x38);
std::array<u8, 0x25> isbn;
u8 startup_user_account;
INSERT_PADDING_BYTES(2);
u32_le application_attribute;
u32_le supported_languages;
u32_le parental_control;
bool screenshot_enabled;
u8 video_capture_mode;
bool data_loss_confirmation;
INSERT_PADDING_BYTES(1);
u64_le title_id;
INSERT_PADDING_BYTES(0x20);
std::array<u8, 0x20> rating_age;
std::array<char, 0x10> version_string;
u64_le dlc_base_title_id;
u64_le title_id_2;
INSERT_PADDING_BYTES(0x28);
u64_le normal_save_data_size;
u64_le journal_sava_data_size;
INSERT_PADDING_BYTES(0x18);
u64_le product_code;
u64_le title_id_3;
std::array<u64_le, 0x7> title_id_array;
INSERT_PADDING_BYTES(0x8);
std::array<u64_le, 0x8> local_communication;
u8 logo_type;
u8 logo_handling;
bool runtime_add_on_content_install;
INSERT_PADDING_BYTES(5);
u64_le title_id_update;
std::array<u8, 0x40> bcat_passphrase;
INSERT_PADDING_BYTES(0xEC0);
@@ -72,6 +85,7 @@ extern const std::array<const char*, 15> LANGUAGE_NAMES;
// These store application name, dev name, title id, and other miscellaneous data.
class NACP {
public:
explicit NACP();
explicit NACP(VirtualFile file);
~NACP();
@@ -81,9 +95,12 @@ public:
u64 GetTitleId() const;
u64 GetDLCBaseTitleId() const;
std::string GetVersionString() const;
u64 GetDefaultNormalSaveSize() const;
u64 GetDefaultJournalSaveSize() const;
std::vector<u8> GetRawBytes() const;
private:
std::unique_ptr<RawNACP> raw;
RawNACP raw{};
};
} // namespace FileSys

View File

@@ -29,8 +29,8 @@ struct Entry {
filename[copy_size] = '\0';
}
char filename[0x300];
INSERT_PADDING_BYTES(4);
char filename[0x301];
INSERT_PADDING_BYTES(3);
EntryType type;
INSERT_PADDING_BYTES(3);
u64 file_size;

View File

@@ -8,25 +8,10 @@
namespace FileSys {
namespace ErrCodes {
enum {
NotFound = 1,
TitleNotFound = 1002,
SdCardNotFound = 2001,
RomFSNotFound = 2520,
};
}
constexpr ResultCode ERROR_PATH_NOT_FOUND(ErrorModule::FS, ErrCodes::NotFound);
// TODO(bunnei): Replace these with correct errors for Switch OS
constexpr ResultCode ERROR_INVALID_PATH(-1);
constexpr ResultCode ERROR_UNSUPPORTED_OPEN_FLAGS(-1);
constexpr ResultCode ERROR_INVALID_OPEN_FLAGS(-1);
constexpr ResultCode ERROR_FILE_NOT_FOUND(-1);
constexpr ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY(-1);
constexpr ResultCode ERROR_DIRECTORY_ALREADY_EXISTS(-1);
constexpr ResultCode ERROR_FILE_ALREADY_EXISTS(-1);
constexpr ResultCode ERROR_DIRECTORY_NOT_EMPTY(-1);
constexpr ResultCode ERROR_PATH_NOT_FOUND{ErrorModule::FS, 1};
constexpr ResultCode ERROR_ENTITY_NOT_FOUND{ErrorModule::FS, 1002};
constexpr ResultCode ERROR_SD_CARD_NOT_FOUND{ErrorModule::FS, 2001};
constexpr ResultCode ERROR_INVALID_OFFSET{ErrorModule::FS, 6061};
constexpr ResultCode ERROR_INVALID_SIZE{ErrorModule::FS, 6062};
} // namespace FileSys

View File

@@ -19,12 +19,18 @@
#include "core/file_sys/vfs_vector.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h"
#include "core/settings.h"
namespace FileSys {
constexpr u64 SINGLE_BYTE_MODULUS = 0x100;
constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000;
constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{
"main", "main.npdm", "rtld", "sdk", "subsdk0", "subsdk1", "subsdk2",
"subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "subsdk8", "subsdk9",
};
struct NSOBuildHeader {
u32_le magic;
INSERT_PADDING_BYTES(0x3C);
@@ -50,33 +56,82 @@ PatchManager::PatchManager(u64 title_id) : title_id(title_id) {}
PatchManager::~PatchManager() = default;
u64 PatchManager::GetTitleID() const {
return title_id;
}
VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
LOG_INFO(Loader, "Patching ExeFS for title_id={:016X}", title_id);
if (exefs == nullptr)
return exefs;
if (Settings::values.dump_exefs) {
LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id);
const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id);
if (dump_dir != nullptr) {
const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs");
VfsRawCopyD(exefs, exefs_dir);
}
}
const auto installed = Service::FileSystem::GetUnionContents();
const auto& disabled = Settings::values.disabled_addons[title_id];
const auto update_disabled =
std::find(disabled.begin(), disabled.end(), "Update") != disabled.end();
// Game Updates
const auto update_tid = GetUpdateTitleID(title_id);
const auto update = installed->GetEntry(update_tid, ContentRecordType::Program);
const auto update = installed.GetEntry(update_tid, ContentRecordType::Program);
if (update != nullptr && update->GetExeFS() != nullptr &&
if (!update_disabled && update != nullptr && update->GetExeFS() != nullptr &&
update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully",
FormatTitleVersion(installed->GetEntryVersion(update_tid).value_or(0)));
FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0)));
exefs = update->GetExeFS();
}
// LayeredExeFS
const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
if (load_dir != nullptr && load_dir->GetSize() > 0) {
auto patch_dirs = load_dir->GetSubdirectories();
std::sort(
patch_dirs.begin(), patch_dirs.end(),
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
std::vector<VirtualDir> layers;
layers.reserve(patch_dirs.size() + 1);
for (const auto& subdir : patch_dirs) {
if (std::find(disabled.begin(), disabled.end(), subdir->GetName()) != disabled.end())
continue;
auto exefs_dir = subdir->GetSubdirectory("exefs");
if (exefs_dir != nullptr)
layers.push_back(std::move(exefs_dir));
}
layers.push_back(exefs);
auto layered = LayeredVfsDirectory::MakeLayeredDirectory(std::move(layers));
if (layered != nullptr) {
LOG_INFO(Loader, " ExeFS: LayeredExeFS patches applied successfully");
exefs = std::move(layered);
}
}
return exefs;
}
static std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs,
const std::string& build_id) {
std::vector<VirtualFile> PatchManager::CollectPatches(const std::vector<VirtualDir>& patch_dirs,
const std::string& build_id) const {
const auto& disabled = Settings::values.disabled_addons[title_id];
std::vector<VirtualFile> out;
out.reserve(patch_dirs.size());
for (const auto& subdir : patch_dirs) {
if (std::find(disabled.begin(), disabled.end(), subdir->GetName()) != disabled.end())
continue;
auto exefs_dir = subdir->GetSubdirectory("exefs");
if (exefs_dir != nullptr) {
for (const auto& file : exefs_dir->GetFiles()) {
@@ -119,6 +174,18 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso) const {
const auto build_id_raw = Common::HexArrayToString(header.build_id);
const auto build_id = build_id_raw.substr(0, build_id_raw.find_last_not_of('0') + 1);
if (Settings::values.dump_nso) {
LOG_INFO(Loader, "Dumping NSO for build_id={}, title_id={:016X}", build_id, title_id);
const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id);
if (dump_dir != nullptr) {
const auto nso_dir = GetOrCreateDirectoryRelative(dump_dir, "/nso");
const auto file = nso_dir->CreateFile(fmt::format("{}.nso", build_id));
file->Resize(nso.size());
file->WriteBytes(nso);
}
}
LOG_INFO(Loader, "Patching NSO for build_id={}", build_id);
const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
@@ -177,6 +244,7 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
return;
}
const auto& disabled = Settings::values.disabled_addons[title_id];
auto patch_dirs = load_dir->GetSubdirectories();
std::sort(patch_dirs.begin(), patch_dirs.end(),
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
@@ -186,6 +254,9 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
layers.reserve(patch_dirs.size() + 1);
layers_ext.reserve(patch_dirs.size() + 1);
for (const auto& subdir : patch_dirs) {
if (std::find(disabled.begin(), disabled.end(), subdir->GetName()) != disabled.end())
continue;
auto romfs_dir = subdir->GetSubdirectory("romfs");
if (romfs_dir != nullptr)
layers.push_back(std::move(romfs_dir));
@@ -215,13 +286,12 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, ContentRecordType type,
VirtualFile update_raw) const {
const auto log_string = fmt::format("Patching RomFS for title_id={:016X}, type={:02X}",
title_id, static_cast<u8>(type))
.c_str();
title_id, static_cast<u8>(type));
if (type == ContentRecordType::Program || type == ContentRecordType::Data)
LOG_INFO(Loader, log_string);
LOG_INFO(Loader, "{}", log_string);
else
LOG_DEBUG(Loader, log_string);
LOG_DEBUG(Loader, "{}", log_string);
if (romfs == nullptr)
return romfs;
@@ -230,16 +300,21 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
// Game Updates
const auto update_tid = GetUpdateTitleID(title_id);
const auto update = installed->GetEntryRaw(update_tid, type);
if (update != nullptr) {
const auto update = installed.GetEntryRaw(update_tid, type);
const auto& disabled = Settings::values.disabled_addons[title_id];
const auto update_disabled =
std::find(disabled.begin(), disabled.end(), "Update") != disabled.end();
if (!update_disabled && update != nullptr) {
const auto new_nca = std::make_shared<NCA>(update, romfs, ivfc_offset);
if (new_nca->GetStatus() == Loader::ResultStatus::Success &&
new_nca->GetRomFS() != nullptr) {
LOG_INFO(Loader, " RomFS: Update ({}) applied successfully",
FormatTitleVersion(installed->GetEntryVersion(update_tid).value_or(0)));
FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0)));
romfs = new_nca->GetRomFS();
}
} else if (update_raw != nullptr) {
} else if (!update_disabled && update_raw != nullptr) {
const auto new_nca = std::make_shared<NCA>(update_raw, romfs, ivfc_offset);
if (new_nca->GetStatus() == Loader::ResultStatus::Success &&
new_nca->GetRomFS() != nullptr) {
@@ -269,25 +344,30 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
VirtualFile update_raw) const {
std::map<std::string, std::string, std::less<>> out;
const auto installed = Service::FileSystem::GetUnionContents();
const auto& disabled = Settings::values.disabled_addons[title_id];
// Game Updates
const auto update_tid = GetUpdateTitleID(title_id);
PatchManager update{update_tid};
auto [nacp, discard_icon_file] = update.GetControlMetadata();
const auto update_disabled =
std::find(disabled.begin(), disabled.end(), "Update") != disabled.end();
const auto update_label = update_disabled ? "[D] Update" : "Update";
if (nacp != nullptr) {
out.insert_or_assign("Update", nacp->GetVersionString());
out.insert_or_assign(update_label, nacp->GetVersionString());
} else {
if (installed->HasEntry(update_tid, ContentRecordType::Program)) {
const auto meta_ver = installed->GetEntryVersion(update_tid);
if (installed.HasEntry(update_tid, ContentRecordType::Program)) {
const auto meta_ver = installed.GetEntryVersion(update_tid);
if (meta_ver.value_or(0) == 0) {
out.insert_or_assign("Update", "");
out.insert_or_assign(update_label, "");
} else {
out.insert_or_assign(
"Update", FormatTitleVersion(*meta_ver, TitleVersionFormat::ThreeElements));
update_label, FormatTitleVersion(*meta_ver, TitleVersionFormat::ThreeElements));
}
} else if (update_raw != nullptr) {
out.insert_or_assign("Update", "PACKED");
out.insert_or_assign(update_label, "PACKED");
}
}
@@ -301,18 +381,25 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
if (IsDirValidAndNonEmpty(exefs_dir)) {
bool ips = false;
bool ipswitch = false;
bool layeredfs = false;
for (const auto& file : exefs_dir->GetFiles()) {
if (file->GetExtension() == "ips")
if (file->GetExtension() == "ips") {
ips = true;
else if (file->GetExtension() == "pchtxt")
} else if (file->GetExtension() == "pchtxt") {
ipswitch = true;
} else if (std::find(EXEFS_FILE_NAMES.begin(), EXEFS_FILE_NAMES.end(),
file->GetName()) != EXEFS_FILE_NAMES.end()) {
layeredfs = true;
}
}
if (ips)
AppendCommaIfNotEmpty(types, "IPS");
if (ipswitch)
AppendCommaIfNotEmpty(types, "IPSwitch");
if (layeredfs)
AppendCommaIfNotEmpty(types, "LayeredExeFS");
}
if (IsDirValidAndNonEmpty(mod->GetSubdirectory("romfs")))
AppendCommaIfNotEmpty(types, "LayeredFS");
@@ -320,19 +407,20 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
if (types.empty())
continue;
out.insert_or_assign(mod->GetName(), types);
const auto mod_disabled =
std::find(disabled.begin(), disabled.end(), mod->GetName()) != disabled.end();
out.insert_or_assign(mod_disabled ? "[D] " + mod->GetName() : mod->GetName(), types);
}
}
// DLC
const auto dlc_entries = installed->ListEntriesFilter(TitleType::AOC, ContentRecordType::Data);
const auto dlc_entries = installed.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data);
std::vector<RegisteredCacheEntry> dlc_match;
dlc_match.reserve(dlc_entries.size());
std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match),
[this, &installed](const RegisteredCacheEntry& entry) {
return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == title_id &&
installed->GetEntry(entry)->GetStatus() ==
Loader::ResultStatus::Success;
installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success;
});
if (!dlc_match.empty()) {
// Ensure sorted so DLC IDs show in order.
@@ -344,7 +432,9 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
list += fmt::format("{}", dlc_match.back().title_id & 0x7FF);
out.insert_or_assign("DLC", std::move(list));
const auto dlc_disabled =
std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end();
out.insert_or_assign(dlc_disabled ? "[D] DLC" : "DLC", std::move(list));
}
return out;
@@ -353,7 +443,7 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const {
const auto installed{Service::FileSystem::GetUnionContents()};
const auto base_control_nca = installed->GetEntry(title_id, ContentRecordType::Control);
const auto base_control_nca = installed.GetEntry(title_id, ContentRecordType::Control);
if (base_control_nca == nullptr)
return {};

View File

@@ -30,6 +30,8 @@ public:
explicit PatchManager(u64 title_id);
~PatchManager();
u64 GetTitleID() const;
// Currently tracked ExeFS patches:
// - Game Updates
VirtualDir PatchExeFS(VirtualDir exefs) const;
@@ -63,6 +65,9 @@ public:
std::pair<std::unique_ptr<NACP>, VirtualFile> ParseControlNCA(const NCA& nca) const;
private:
std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs,
const std::string& build_id) const;
u64 title_id;
};

View File

@@ -40,6 +40,13 @@ Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
if (sizeof(FileAccessHeader) != file->ReadObject(&aci_file_access, aci_header.fah_offset))
return Loader::ResultStatus::ErrorBadFileAccessHeader;
aci_kernel_capabilities.resize(aci_header.kac_size / sizeof(u32));
const u64 read_size = aci_header.kac_size;
const u64 read_offset = npdm_header.aci_offset + aci_header.kac_offset;
if (file->ReadBytes(aci_kernel_capabilities.data(), read_size, read_offset) != read_size) {
return Loader::ResultStatus::ErrorBadKernelCapabilityDescriptors;
}
return Loader::ResultStatus::Success;
}
@@ -71,6 +78,10 @@ u64 ProgramMetadata::GetFilesystemPermissions() const {
return aci_file_access.permissions;
}
const ProgramMetadata::KernelCapabilityDescriptors& ProgramMetadata::GetKernelCapabilities() const {
return aci_kernel_capabilities;
}
void ProgramMetadata::Print() const {
LOG_DEBUG(Service_FS, "Magic: {:.4}", npdm_header.magic.data());
LOG_DEBUG(Service_FS, "Main thread priority: 0x{:02X}", npdm_header.main_thread_priority);
@@ -81,16 +92,20 @@ void ProgramMetadata::Print() const {
LOG_DEBUG(Service_FS, " > 64-bit instructions: {}",
npdm_header.has_64_bit_instructions ? "YES" : "NO");
auto address_space = "Unknown";
const char* address_space = "Unknown";
switch (npdm_header.address_space_type) {
case ProgramAddressSpaceType::Is36Bit:
address_space = "64-bit (36-bit address space)";
break;
case ProgramAddressSpaceType::Is39Bit:
address_space = "64-bit";
address_space = "64-bit (39-bit address space)";
break;
case ProgramAddressSpaceType::Is32Bit:
case ProgramAddressSpaceType::Is32BitNoMap:
address_space = "32-bit";
break;
case ProgramAddressSpaceType::Is32BitNoMap:
address_space = "32-bit (no map region)";
break;
}
LOG_DEBUG(Service_FS, " > Address space: {}\n", address_space);

View File

@@ -5,6 +5,7 @@
#pragma once
#include <array>
#include <vector>
#include "common/bit_field.h"
#include "common/common_types.h"
#include "common/swap.h"
@@ -38,6 +39,8 @@ enum class ProgramFilePermission : u64 {
*/
class ProgramMetadata {
public:
using KernelCapabilityDescriptors = std::vector<u32>;
ProgramMetadata();
~ProgramMetadata();
@@ -50,6 +53,7 @@ public:
u32 GetMainThreadStackSize() const;
u64 GetTitleID() const;
u64 GetFilesystemPermissions() const;
const KernelCapabilityDescriptors& GetKernelCapabilities() const;
void Print() const;
@@ -154,6 +158,8 @@ private:
FileAccessControl acid_file_access;
FileAccessHeader aci_file_access;
KernelCapabilityDescriptors aci_kernel_capabilities;
};
} // namespace FileSys

View File

@@ -106,40 +106,42 @@ static ContentRecordType GetCRTypeFromNCAType(NCAContentType type) {
VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
std::string_view path) const {
if (dir->GetFileRelative(path) != nullptr)
return dir->GetFileRelative(path);
if (dir->GetDirectoryRelative(path) != nullptr) {
const auto nca_dir = dir->GetDirectoryRelative(path);
VirtualFile file = nullptr;
const auto files = nca_dir->GetFiles();
if (files.size() == 1 && files[0]->GetName() == "00") {
file = files[0];
} else {
std::vector<VirtualFile> concat;
// Since the files are a two-digit hex number, max is FF.
for (std::size_t i = 0; i < 0x100; ++i) {
auto next = nca_dir->GetFile(fmt::format("{:02X}", i));
if (next != nullptr) {
concat.push_back(std::move(next));
} else {
next = nca_dir->GetFile(fmt::format("{:02x}", i));
if (next != nullptr)
concat.push_back(std::move(next));
else
break;
}
}
if (concat.empty())
return nullptr;
file = ConcatenatedVfsFile::MakeConcatenatedFile(concat, concat.front()->GetName());
}
const auto file = dir->GetFileRelative(path);
if (file != nullptr) {
return file;
}
return nullptr;
const auto nca_dir = dir->GetDirectoryRelative(path);
if (nca_dir == nullptr) {
return nullptr;
}
const auto files = nca_dir->GetFiles();
if (files.size() == 1 && files[0]->GetName() == "00") {
return files[0];
}
std::vector<VirtualFile> concat;
// Since the files are a two-digit hex number, max is FF.
for (std::size_t i = 0; i < 0x100; ++i) {
auto next = nca_dir->GetFile(fmt::format("{:02X}", i));
if (next != nullptr) {
concat.push_back(std::move(next));
} else {
next = nca_dir->GetFile(fmt::format("{:02x}", i));
if (next != nullptr) {
concat.push_back(std::move(next));
} else {
break;
}
}
}
if (concat.empty()) {
return nullptr;
}
return ConcatenatedVfsFile::MakeConcatenatedFile(concat, concat.front()->GetName());
}
VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
@@ -225,7 +227,7 @@ void RegisteredCache::ProcessFiles(const std::vector<NcaID>& ids) {
if (file == nullptr)
continue;
const auto nca = std::make_shared<NCA>(parser(file, id));
const auto nca = std::make_shared<NCA>(parser(file, id), nullptr, 0, keys);
if (nca->GetStatus() != Loader::ResultStatus::Success ||
nca->GetType() != NCAContentType::Meta) {
continue;
@@ -315,7 +317,7 @@ std::unique_ptr<NCA> RegisteredCache::GetEntry(u64 title_id, ContentRecordType t
const auto raw = GetEntryRaw(title_id, type);
if (raw == nullptr)
return nullptr;
return std::make_unique<NCA>(raw);
return std::make_unique<NCA>(raw, nullptr, 0, keys);
}
std::unique_ptr<NCA> RegisteredCache::GetEntry(RegisteredCacheEntry entry) const {
@@ -378,22 +380,22 @@ std::vector<RegisteredCacheEntry> RegisteredCache::ListEntriesFilter(
return out;
}
static std::shared_ptr<NCA> GetNCAFromNSPForID(std::shared_ptr<NSP> nsp, const NcaID& id) {
const auto file = nsp->GetFile(fmt::format("{}.nca", Common::HexArrayToString(id, false)));
static std::shared_ptr<NCA> GetNCAFromNSPForID(const NSP& nsp, const NcaID& id) {
const auto file = nsp.GetFile(fmt::format("{}.nca", Common::HexArrayToString(id, false)));
if (file == nullptr)
return nullptr;
return std::make_shared<NCA>(file);
}
InstallResult RegisteredCache::InstallEntry(std::shared_ptr<XCI> xci, bool overwrite_if_exists,
InstallResult RegisteredCache::InstallEntry(const XCI& xci, bool overwrite_if_exists,
const VfsCopyFunction& copy) {
return InstallEntry(xci->GetSecurePartitionNSP(), overwrite_if_exists, copy);
return InstallEntry(*xci.GetSecurePartitionNSP(), overwrite_if_exists, copy);
}
InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overwrite_if_exists,
InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_exists,
const VfsCopyFunction& copy) {
const auto& ncas = nsp->GetNCAsCollapsed();
const auto& meta_iter = std::find_if(ncas.begin(), ncas.end(), [](std::shared_ptr<NCA> nca) {
const auto ncas = nsp.GetNCAsCollapsed();
const auto meta_iter = std::find_if(ncas.begin(), ncas.end(), [](const auto& nca) {
return nca->GetType() == NCAContentType::Meta;
});
@@ -407,7 +409,7 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overw
const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32);
const auto meta_id = Common::HexStringToArray<16>(meta_id_raw);
const auto res = RawInstallNCA(*meta_iter, copy, overwrite_if_exists, meta_id);
const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id);
if (res != InstallResult::Success)
return res;
@@ -419,7 +421,7 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overw
const auto nca = GetNCAFromNSPForID(nsp, record.nca_id);
if (nca == nullptr)
return InstallResult::ErrorCopyFailed;
const auto res2 = RawInstallNCA(nca, copy, overwrite_if_exists, record.nca_id);
const auto res2 = RawInstallNCA(*nca, copy, overwrite_if_exists, record.nca_id);
if (res2 != InstallResult::Success)
return res2;
}
@@ -428,21 +430,21 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overw
return InstallResult::Success;
}
InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType type,
InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type,
bool overwrite_if_exists, const VfsCopyFunction& copy) {
CNMTHeader header{
nca->GetTitleId(), ///< Title ID
0, ///< Ignore/Default title version
type, ///< Type
{}, ///< Padding
0x10, ///< Default table offset
1, ///< 1 Content Entry
0, ///< No Meta Entries
{}, ///< Padding
nca.GetTitleId(), ///< Title ID
0, ///< Ignore/Default title version
type, ///< Type
{}, ///< Padding
0x10, ///< Default table offset
1, ///< 1 Content Entry
0, ///< No Meta Entries
{}, ///< Padding
};
OptionalHeader opt_header{0, 0};
ContentRecord c_rec{{}, {}, {}, GetCRTypeFromNCAType(nca->GetType()), {}};
const auto& data = nca->GetBaseFile()->ReadBytes(0x100000);
ContentRecord c_rec{{}, {}, {}, GetCRTypeFromNCAType(nca.GetType()), {}};
const auto& data = nca.GetBaseFile()->ReadBytes(0x100000);
mbedtls_sha256(data.data(), data.size(), c_rec.hash.data(), 0);
memcpy(&c_rec.nca_id, &c_rec.hash, 16);
const CNMT new_cnmt(header, opt_header, {c_rec}, {});
@@ -451,10 +453,10 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType
return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id);
}
InstallResult RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy,
InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy,
bool overwrite_if_exists,
std::optional<NcaID> override_id) {
const auto in = nca->GetBaseFile();
const auto in = nca.GetBaseFile();
Core::Crypto::SHA256Hash hash{};
// Calculate NcaID

View File

@@ -6,12 +6,12 @@
#include <array>
#include <functional>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include <boost/container/flat_map.hpp>
#include "common/common_types.h"
#include "core/crypto/key_manager.h"
#include "core/file_sys/vfs.h"
namespace FileSys {
@@ -103,17 +103,16 @@ public:
// Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure
// there is a meta NCA and all of them are accessible.
InstallResult InstallEntry(std::shared_ptr<XCI> xci, bool overwrite_if_exists = false,
InstallResult InstallEntry(const XCI& xci, bool overwrite_if_exists = false,
const VfsCopyFunction& copy = &VfsRawCopy);
InstallResult InstallEntry(std::shared_ptr<NSP> nsp, bool overwrite_if_exists = false,
InstallResult InstallEntry(const NSP& nsp, bool overwrite_if_exists = false,
const VfsCopyFunction& copy = &VfsRawCopy);
// Due to the fact that we must use Meta-type NCAs to determine the existance of files, this
// poses quite a challenge. Instead of creating a new meta NCA for this file, yuzu will create a
// dir inside the NAND called 'yuzu_meta' and store the raw CNMT there.
// TODO(DarkLordZach): Author real meta-type NCAs and install those.
InstallResult InstallEntry(std::shared_ptr<NCA> nca, TitleType type,
bool overwrite_if_exists = false,
InstallResult InstallEntry(const NCA& nca, TitleType type, bool overwrite_if_exists = false,
const VfsCopyFunction& copy = &VfsRawCopy);
private:
@@ -127,12 +126,14 @@ private:
std::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const;
VirtualFile GetFileAtID(NcaID id) const;
VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const;
InstallResult RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy,
InstallResult RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy,
bool overwrite_if_exists, std::optional<NcaID> override_id = {});
bool RawInstallYuzuMeta(const CNMT& cnmt);
VirtualDir dir;
RegisteredCacheParsingFunction parser;
Core::Crypto::KeyManager keys;
// maps tid -> NcaID of meta
boost::container::flat_map<u64, NcaID> meta_id;
// maps tid -> meta

View File

@@ -48,7 +48,7 @@ ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, Conte
switch (storage) {
case StorageId::None:
res = Service::FileSystem::GetUnionContents()->GetEntry(title_id, type);
res = Service::FileSystem::GetUnionContents().GetEntry(title_id, type);
break;
case StorageId::NandSystem:
res = Service::FileSystem::GetSystemNANDContents()->GetEntry(title_id, type);

View File

@@ -13,12 +13,18 @@
namespace FileSys {
constexpr char SAVE_DATA_SIZE_FILENAME[] = ".yuzu_save_size";
std::string SaveDataDescriptor::DebugInfo() const {
return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}]",
static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id);
}
SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {}
SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {
// Delete all temporary storages
// On hardware, it is expected that temporary storage be empty at first use.
dir->DeleteSubdirectoryRecursive("temp");
}
SaveDataFactory::~SaveDataFactory() = default;
@@ -83,6 +89,24 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, SaveDataDescr
return MakeResult<VirtualDir>(std::move(out));
}
VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) const {
return dir->GetDirectoryRelative(GetSaveDataSpaceIdPath(space));
}
std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) {
switch (space) {
case SaveDataSpaceId::NandSystem:
return "/system/";
case SaveDataSpaceId::NandUser:
return "/user/";
case SaveDataSpaceId::TemporaryStorage:
return "/temp/";
default:
ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space));
return "/unrecognized/"; ///< To prevent corruption when ignoring asserts.
}
}
std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id,
u128 user_id, u64 save_id) {
// According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
@@ -90,21 +114,7 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ
if (type == SaveDataType::SaveData && title_id == 0)
title_id = Core::CurrentProcess()->GetTitleID();
std::string out;
switch (space) {
case SaveDataSpaceId::NandSystem:
out = "/system/";
break;
case SaveDataSpaceId::NandUser:
out = "/user/";
break;
case SaveDataSpaceId::TemporaryStorage:
out = "/temp/";
break;
default:
ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space));
}
std::string out = GetSaveDataSpaceIdPath(space);
switch (type) {
case SaveDataType::SystemSaveData:
@@ -116,9 +126,40 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ
case SaveDataType::TemporaryStorage:
return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
title_id);
case SaveDataType::CacheStorage:
return fmt::format("{}save/cache/{:016X}", out, title_id);
default:
ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type));
return fmt::format("{}save/unknown_{:X}/{:016X}", out, static_cast<u8>(type), title_id);
}
}
SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
u128 user_id) const {
const auto path = GetFullPath(SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
const auto dir = GetOrCreateDirectoryRelative(this->dir, path);
const auto size_file = dir->GetFile(SAVE_DATA_SIZE_FILENAME);
if (size_file == nullptr || size_file->GetSize() < sizeof(SaveDataSize))
return {0, 0};
SaveDataSize out;
if (size_file->ReadObject(&out) != sizeof(SaveDataSize))
return {0, 0};
return out;
}
void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
SaveDataSize new_value) {
const auto path = GetFullPath(SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
const auto dir = GetOrCreateDirectoryRelative(this->dir, path);
const auto size_file = dir->CreateFile(SAVE_DATA_SIZE_FILENAME);
if (size_file == nullptr)
return;
size_file->Resize(sizeof(SaveDataSize));
size_file->WriteObject(new_value);
}
} // namespace FileSys

View File

@@ -17,8 +17,10 @@ namespace FileSys {
enum class SaveDataSpaceId : u8 {
NandSystem = 0,
NandUser = 1,
SdCard = 2,
SdCardSystem = 2,
TemporaryStorage = 3,
SdCardUser = 4,
ProperSystem = 100,
};
enum class SaveDataType : u8 {
@@ -44,6 +46,11 @@ struct SaveDataDescriptor {
};
static_assert(sizeof(SaveDataDescriptor) == 0x40, "SaveDataDescriptor has incorrect size.");
struct SaveDataSize {
u64 normal;
u64 journal;
};
/// File system interface to the SaveData archive
class SaveDataFactory {
public:
@@ -52,9 +59,15 @@ public:
ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta);
VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;
static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space);
static std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id,
u128 user_id, u64 save_id);
SaveDataSize ReadSaveDataSize(SaveDataType type, u64 title_id, u128 user_id) const;
void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, SaveDataSize new_value);
private:
VirtualDir dir;
};

View File

@@ -252,7 +252,7 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
continue;
}
auto next_nca = std::make_shared<NCA>(next_file);
auto next_nca = std::make_shared<NCA>(next_file, nullptr, 0, keys);
if (next_nca->GetType() == NCAContentType::Program)
program_status[cnmt.GetTitleID()] = next_nca->GetStatus();
if (next_nca->GetStatus() == Loader::ResultStatus::Success ||

View File

@@ -70,6 +70,8 @@ private:
std::map<u64, std::map<ContentRecordType, std::shared_ptr<NCA>>> ncas;
std::vector<VirtualFile> ticket_files;
Core::Crypto::KeyManager keys;
VirtualFile romfs;
VirtualDir exefs;
};

View File

@@ -0,0 +1,81 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <fmt/format.h>
#include "common/common_types.h"
#include "core/file_sys/system_archive/ng_word.h"
#include "core/file_sys/vfs_vector.h"
namespace FileSys::SystemArchive {
namespace NgWord1Data {
constexpr std::size_t NUMBER_WORD_TXT_FILES = 0x10;
// Should this archive replacement mysteriously not work on a future game, consider updating.
constexpr std::array<u8, 4> VERSION_DAT{0x0, 0x0, 0x0, 0x19}; // 5.1.0 System Version
constexpr std::array<u8, 30> WORD_TXT{
0xFE, 0xFF, 0x00, 0x5E, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x79, 0x00, 0x62, 0x00,
0x61, 0x00, 0x64, 0x00, 0x77, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x64, 0x00, 0x24, 0x00, 0x0A,
}; // "^verybadword$" in UTF-16
} // namespace NgWord1Data
VirtualDir NgWord1() {
std::vector<VirtualFile> files(NgWord1Data::NUMBER_WORD_TXT_FILES);
for (std::size_t i = 0; i < files.size(); ++i) {
files[i] = std::make_shared<ArrayVfsFile<NgWord1Data::WORD_TXT.size()>>(
NgWord1Data::WORD_TXT, fmt::format("{}.txt", i));
}
files.push_back(std::make_shared<ArrayVfsFile<NgWord1Data::WORD_TXT.size()>>(
NgWord1Data::WORD_TXT, "common.txt"));
files.push_back(std::make_shared<ArrayVfsFile<NgWord1Data::VERSION_DAT.size()>>(
NgWord1Data::VERSION_DAT, "version.dat"));
return std::make_shared<VectorVfsDirectory>(files, std::vector<VirtualDir>{}, "data");
}
namespace NgWord2Data {
constexpr std::size_t NUMBER_AC_NX_FILES = 0x10;
// Should this archive replacement mysteriously not work on a future game, consider updating.
constexpr std::array<u8, 4> VERSION_DAT{0x0, 0x0, 0x0, 0x15}; // 5.1.0 System Version
constexpr std::array<u8, 0x2C> AC_NX_DATA{
0x1F, 0x8B, 0x08, 0x08, 0xD5, 0x2C, 0x09, 0x5C, 0x04, 0x00, 0x61, 0x63, 0x72, 0x61, 0x77,
0x00, 0xED, 0xC1, 0x01, 0x0D, 0x00, 0x00, 0x00, 0xC2, 0x20, 0xFB, 0xA7, 0xB6, 0xC7, 0x07,
0x0C, 0x00, 0x00, 0x00, 0xC8, 0x3B, 0x11, 0x00, 0x1C, 0xC7, 0x00, 0x10, 0x00, 0x00,
}; // Deserializes to no bad words
} // namespace NgWord2Data
VirtualDir NgWord2() {
std::vector<VirtualFile> files(NgWord2Data::NUMBER_AC_NX_FILES * 3);
for (std::size_t i = 0; i < NgWord2Data::NUMBER_AC_NX_FILES; ++i) {
files[3 * i] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b1_nx", i));
files[3 * i + 1] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b2_nx", i));
files[3 * i + 2] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_not_b_nx", i));
}
files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
NgWord2Data::AC_NX_DATA, "ac_common_b1_nx"));
files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
NgWord2Data::AC_NX_DATA, "ac_common_b2_nx"));
files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
NgWord2Data::AC_NX_DATA, "ac_common_not_b_nx"));
files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::VERSION_DAT.size()>>(
NgWord2Data::VERSION_DAT, "version.dat"));
return std::make_shared<VectorVfsDirectory>(files, std::vector<VirtualDir>{}, "data");
}
} // namespace FileSys::SystemArchive

View File

@@ -0,0 +1,14 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/file_sys/vfs_types.h"
namespace FileSys::SystemArchive {
VirtualDir NgWord1();
VirtualDir NgWord2();
} // namespace FileSys::SystemArchive

View File

@@ -0,0 +1,90 @@
// 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/file_sys/romfs.h"
#include "core/file_sys/system_archive/ng_word.h"
#include "core/file_sys/system_archive/system_archive.h"
namespace FileSys::SystemArchive {
constexpr u64 SYSTEM_ARCHIVE_BASE_TITLE_ID = 0x0100000000000800;
constexpr std::size_t SYSTEM_ARCHIVE_COUNT = 0x28;
using SystemArchiveSupplier = VirtualDir (*)();
struct SystemArchiveDescriptor {
u64 title_id;
const char* name;
SystemArchiveSupplier supplier;
};
constexpr std::array<SystemArchiveDescriptor, SYSTEM_ARCHIVE_COUNT> SYSTEM_ARCHIVES{{
{0x0100000000000800, "CertStore", nullptr},
{0x0100000000000801, "ErrorMessage", nullptr},
{0x0100000000000802, "MiiModel", nullptr},
{0x0100000000000803, "BrowserDll", nullptr},
{0x0100000000000804, "Help", nullptr},
{0x0100000000000805, "SharedFont", nullptr},
{0x0100000000000806, "NgWord", &NgWord1},
{0x0100000000000807, "SsidList", nullptr},
{0x0100000000000808, "Dictionary", nullptr},
{0x0100000000000809, "SystemVersion", nullptr},
{0x010000000000080A, "AvatarImage", nullptr},
{0x010000000000080B, "LocalNews", nullptr},
{0x010000000000080C, "Eula", nullptr},
{0x010000000000080D, "UrlBlackList", nullptr},
{0x010000000000080E, "TimeZoneBinary", nullptr},
{0x010000000000080F, "CertStoreCruiser", nullptr},
{0x0100000000000810, "FontNintendoExtension", nullptr},
{0x0100000000000811, "FontStandard", nullptr},
{0x0100000000000812, "FontKorean", nullptr},
{0x0100000000000813, "FontChineseTraditional", nullptr},
{0x0100000000000814, "FontChineseSimple", nullptr},
{0x0100000000000815, "FontBfcpx", nullptr},
{0x0100000000000816, "SystemUpdate", nullptr},
{0x0100000000000817, "0100000000000817", nullptr},
{0x0100000000000818, "FirmwareDebugSettings", nullptr},
{0x0100000000000819, "BootImagePackage", nullptr},
{0x010000000000081A, "BootImagePackageSafe", nullptr},
{0x010000000000081B, "BootImagePackageExFat", nullptr},
{0x010000000000081C, "BootImagePackageExFatSafe", nullptr},
{0x010000000000081D, "FatalMessage", nullptr},
{0x010000000000081E, "ControllerIcon", nullptr},
{0x010000000000081F, "PlatformConfigIcosa", nullptr},
{0x0100000000000820, "PlatformConfigCopper", nullptr},
{0x0100000000000821, "PlatformConfigHoag", nullptr},
{0x0100000000000822, "ControllerFirmware", nullptr},
{0x0100000000000823, "NgWord2", &NgWord2},
{0x0100000000000824, "PlatformConfigIcosaMariko", nullptr},
{0x0100000000000825, "ApplicationBlackList", nullptr},
{0x0100000000000826, "RebootlessSystemUpdateVersion", nullptr},
{0x0100000000000827, "ContentActionTable", nullptr},
}};
VirtualFile SynthesizeSystemArchive(const u64 title_id) {
if (title_id < SYSTEM_ARCHIVES.front().title_id || title_id > SYSTEM_ARCHIVES.back().title_id)
return nullptr;
const auto& desc = SYSTEM_ARCHIVES[title_id - SYSTEM_ARCHIVE_BASE_TITLE_ID];
LOG_INFO(Service_FS, "Synthesizing system archive '{}' (0x{:016X}).", desc.name, desc.title_id);
if (desc.supplier == nullptr)
return nullptr;
const auto dir = desc.supplier();
if (dir == nullptr)
return nullptr;
const auto romfs = CreateRomFS(dir);
if (romfs == nullptr)
return nullptr;
LOG_INFO(Service_FS, " - System archive generation successful!");
return romfs;
}
} // namespace FileSys::SystemArchive

View File

@@ -0,0 +1,14 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/common_types.h"
#include "core/file_sys/vfs_types.h"
namespace FileSys::SystemArchive {
VirtualFile SynthesizeSystemArchive(u64 title_id);
} // namespace FileSys::SystemArchive

View File

@@ -384,6 +384,28 @@ bool VfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
return success;
}
bool VfsDirectory::CleanSubdirectoryRecursive(std::string_view name) {
auto dir = GetSubdirectory(name);
if (dir == nullptr) {
return false;
}
bool success = true;
for (const auto& file : dir->GetFiles()) {
if (!dir->DeleteFile(file->GetName())) {
success = false;
}
}
for (const auto& sdir : dir->GetSubdirectories()) {
if (!dir->DeleteSubdirectoryRecursive(sdir->GetName())) {
success = false;
}
}
return success;
}
bool VfsDirectory::Copy(std::string_view src, std::string_view dest) {
const auto f1 = GetFile(src);
auto f2 = CreateFile(dest);
@@ -431,10 +453,34 @@ std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFile(std::string_view name)
return nullptr;
}
std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFileAbsolute(std::string_view path) {
return nullptr;
}
std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFileRelative(std::string_view path) {
return nullptr;
}
std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateDirectoryAbsolute(std::string_view path) {
return nullptr;
}
std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateDirectoryRelative(std::string_view path) {
return nullptr;
}
bool ReadOnlyVfsDirectory::DeleteSubdirectory(std::string_view name) {
return false;
}
bool ReadOnlyVfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
return false;
}
bool ReadOnlyVfsDirectory::CleanSubdirectoryRecursive(std::string_view name) {
return false;
}
bool ReadOnlyVfsDirectory::DeleteFile(std::string_view name) {
return false;
}

View File

@@ -150,7 +150,7 @@ public:
template <typename T>
std::size_t WriteArray(const T* data, std::size_t number_elements, std::size_t offset = 0) {
static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
return Write(data, number_elements * sizeof(T), offset);
return Write(reinterpret_cast<const u8*>(data), number_elements * sizeof(T), offset);
}
// Writes size bytes starting at memory location data to offset in file.
@@ -166,7 +166,7 @@ public:
template <typename T>
std::size_t WriteObject(const T& data, std::size_t offset = 0) {
static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
return Write(&data, sizeof(T), offset);
return Write(reinterpret_cast<const u8*>(&data), sizeof(T), offset);
}
// Renames the file to name. Returns whether or not the operation was successsful.
@@ -245,12 +245,18 @@ public:
// any failure.
virtual std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path);
// Deletes the subdirectory with name and returns true on success.
// Deletes the subdirectory with the given name and returns true on success.
virtual bool DeleteSubdirectory(std::string_view name) = 0;
// Deletes all subdirectories and files of subdirectory with name recirsively and then deletes
// the subdirectory. Returns true on success.
// Deletes all subdirectories and files within the provided directory and then deletes
// the directory itself. Returns true on success.
virtual bool DeleteSubdirectoryRecursive(std::string_view name);
// Returnes whether or not the file with name name was deleted successfully.
// Deletes all subdirectories and files within the provided directory.
// Unlike DeleteSubdirectoryRecursive, this does not delete the provided directory.
virtual bool CleanSubdirectoryRecursive(std::string_view name);
// Returns whether or not the file with name name was deleted successfully.
virtual bool DeleteFile(std::string_view name) = 0;
// Returns whether or not this directory was renamed to name.
@@ -276,7 +282,13 @@ public:
bool IsReadable() const override;
std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override;
std::shared_ptr<VfsFile> CreateFile(std::string_view name) override;
std::shared_ptr<VfsFile> CreateFileAbsolute(std::string_view path) override;
std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path) override;
std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path) override;
std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path) override;
bool DeleteSubdirectory(std::string_view name) override;
bool DeleteSubdirectoryRecursive(std::string_view name) override;
bool CleanSubdirectoryRecursive(std::string_view name) override;
bool DeleteFile(std::string_view name) override;
bool Rename(std::string_view name) override;
};

View File

@@ -3,7 +3,6 @@
// Refer to the license.txt file included.
#include <algorithm>
#include <cstring>
#include <utility>
#include "core/file_sys/vfs_vector.h"

View File

@@ -4,10 +4,63 @@
#pragma once
#include <cstring>
#include "core/file_sys/vfs.h"
namespace FileSys {
// An implementation of VfsFile that is backed by a statically-sized array
template <std::size_t size>
class ArrayVfsFile : public VfsFile {
public:
ArrayVfsFile(std::array<u8, size> data, std::string name = "", VirtualDir parent = nullptr)
: data(data), name(std::move(name)), parent(std::move(parent)) {}
std::string GetName() const override {
return name;
}
std::size_t GetSize() const override {
return size;
}
bool Resize(std::size_t new_size) override {
return false;
}
std::shared_ptr<VfsDirectory> GetContainingDirectory() const override {
return parent;
}
bool IsWritable() const override {
return false;
}
bool IsReadable() const override {
return true;
}
std::size_t Read(u8* data_, std::size_t length, std::size_t offset) const override {
const auto read = std::min(length, size - offset);
std::memcpy(data_, data.data() + offset, read);
return read;
}
std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override {
return 0;
}
bool Rename(std::string_view name) override {
this->name = name;
return true;
}
private:
std::array<u8, size> data;
std::string name;
VirtualDir parent;
};
// An implementation of VfsFile that is backed by a vector optionally supplied upon construction
class VectorVfsFile : public VfsFile {
public:

View File

@@ -0,0 +1,19 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/frontend/applets/profile_select.h"
#include "core/settings.h"
namespace Core::Frontend {
ProfileSelectApplet::~ProfileSelectApplet() = default;
void DefaultProfileSelectApplet::SelectProfile(
std::function<void(std::optional<Service::Account::UUID>)> callback) const {
Service::Account::ProfileManager manager;
callback(manager.GetUser(Settings::values.current_user).value_or(Service::Account::UUID{}));
LOG_INFO(Service_ACC, "called, selecting current user instead of prompting...");
}
} // namespace Core::Frontend

View File

@@ -0,0 +1,27 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <functional>
#include <optional>
#include "core/hle/service/acc/profile_manager.h"
namespace Core::Frontend {
class ProfileSelectApplet {
public:
virtual ~ProfileSelectApplet();
virtual void SelectProfile(
std::function<void(std::optional<Service::Account::UUID>)> callback) const = 0;
};
class DefaultProfileSelectApplet final : public ProfileSelectApplet {
public:
void SelectProfile(
std::function<void(std::optional<Service::Account::UUID>)> callback) const override;
};
} // namespace Core::Frontend

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/backend.h"
#include "common/string_util.h"
#include "core/frontend/applets/software_keyboard.h"
namespace Core::Frontend {
SoftwareKeyboardApplet::~SoftwareKeyboardApplet() = default;
void DefaultSoftwareKeyboardApplet::RequestText(
std::function<void(std::optional<std::u16string>)> out,
SoftwareKeyboardParameters parameters) const {
if (parameters.initial_text.empty())
out(u"yuzu");
out(parameters.initial_text);
}
void DefaultSoftwareKeyboardApplet::SendTextCheckDialog(
std::u16string error_message, std::function<void()> finished_check) const {
LOG_WARNING(Service_AM,
"(STUBBED) called - Default fallback software keyboard does not support text "
"check! (error_message={})",
Common::UTF16ToUTF8(error_message));
finished_check();
}
} // namespace Core::Frontend

View File

@@ -0,0 +1,54 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <functional>
#include <optional>
#include <string>
#include "common/bit_field.h"
#include "common/common_types.h"
namespace Core::Frontend {
struct SoftwareKeyboardParameters {
std::u16string submit_text;
std::u16string header_text;
std::u16string sub_text;
std::u16string guide_text;
std::u16string initial_text;
std::size_t max_length;
bool password;
bool cursor_at_beginning;
union {
u8 value;
BitField<1, 1, u8> disable_space;
BitField<2, 1, u8> disable_address;
BitField<3, 1, u8> disable_percent;
BitField<4, 1, u8> disable_slash;
BitField<6, 1, u8> disable_number;
BitField<7, 1, u8> disable_download_code;
};
};
class SoftwareKeyboardApplet {
public:
virtual ~SoftwareKeyboardApplet();
virtual void RequestText(std::function<void(std::optional<std::u16string>)> out,
SoftwareKeyboardParameters parameters) const = 0;
virtual void SendTextCheckDialog(std::u16string error_message,
std::function<void()> finished_check) const = 0;
};
class DefaultSoftwareKeyboardApplet final : public SoftwareKeyboardApplet {
public:
void RequestText(std::function<void(std::optional<std::u16string>)> out,
SoftwareKeyboardParameters parameters) const override;
void SendTextCheckDialog(std::u16string error_message,
std::function<void()> finished_check) const override;
};
} // namespace Core::Frontend

View File

@@ -6,6 +6,7 @@
#include "common/assert.h"
#include "core/frontend/framebuffer_layout.h"
#include "core/settings.h"
namespace Layout {
@@ -42,4 +43,18 @@ FramebufferLayout DefaultFrameLayout(unsigned width, unsigned height) {
return res;
}
FramebufferLayout FrameLayoutFromResolutionScale(u16 res_scale) {
int width, height;
if (Settings::values.use_docked_mode) {
width = ScreenDocked::WidthDocked * res_scale;
height = ScreenDocked::HeightDocked * res_scale;
} else {
width = ScreenUndocked::Width * res_scale;
height = ScreenUndocked::Height * res_scale;
}
return DefaultFrameLayout(width, height);
}
} // namespace Layout

View File

@@ -9,6 +9,7 @@
namespace Layout {
enum ScreenUndocked : unsigned { Width = 1280, Height = 720 };
enum ScreenDocked : unsigned { WidthDocked = 1920, HeightDocked = 1080 };
/// Describes the layout of the window framebuffer
struct FramebufferLayout {
@@ -34,4 +35,10 @@ struct FramebufferLayout {
*/
FramebufferLayout DefaultFrameLayout(unsigned width, unsigned height);
/**
* Convenience method to get frame layout by resolution scale
* @param res_scale resolution scale factor
*/
FramebufferLayout FrameLayoutFromResolutionScale(u16 res_scale);
} // namespace Layout

View File

@@ -132,4 +132,11 @@ using MotionDevice = InputDevice<std::tuple<Math::Vec3<float>, Math::Vec3<float>
*/
using TouchDevice = InputDevice<std::tuple<float, float, bool>>;
/**
* A mouse device is an input device that returns a tuple of two floats and four ints.
* The first two floats are X and Y device coordinates of the mouse (from 0-1).
* The s32s are the mouse wheel.
*/
using MouseDevice = InputDevice<std::tuple<float, float, s32, s32>>;
} // namespace Input

View File

@@ -71,10 +71,6 @@ constexpr u32 PSTATE_REGISTER = 33;
constexpr u32 UC_ARM64_REG_Q0 = 34;
constexpr u32 FPCR_REGISTER = 66;
// TODO/WiP - Used while working on support for FPU
constexpr u32 TODO_DUMMY_REG_997 = 997;
constexpr 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
// This XML defines what the registers are for this specific ARM device
@@ -205,11 +201,11 @@ void RegisterModule(std::string name, VAddr beg, VAddr end, bool add_elf_ext) {
modules.push_back(std::move(module));
}
static Kernel::Thread* FindThreadById(int id) {
static Kernel::Thread* FindThreadById(s64 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() == static_cast<u32>(id)) {
if (thread->GetThreadID() == static_cast<u64>(id)) {
current_core = core;
return thread.get();
}
@@ -260,6 +256,36 @@ static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr)
}
}
static u128 FpuRead(std::size_t id, Kernel::Thread* thread = nullptr) {
if (!thread) {
return u128{0};
}
auto& thread_context = thread->GetContext();
if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
return thread_context.vector_registers[id - UC_ARM64_REG_Q0];
} else if (id == FPCR_REGISTER) {
return u128{thread_context.fpcr, 0};
} else {
return u128{0};
}
}
static void FpuWrite(std::size_t id, u128 val, Kernel::Thread* thread = nullptr) {
if (!thread) {
return;
}
auto& thread_context = thread->GetContext();
if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
thread_context.vector_registers[id - UC_ARM64_REG_Q0] = val;
} else if (id == FPCR_REGISTER) {
thread_context.fpcr = static_cast<u32>(val[0]);
}
}
/**
* Turns hex string character into the equivalent byte.
*
@@ -409,6 +435,27 @@ static u64 GdbHexToLong(const u8* src) {
return output;
}
/**
* Convert a gdb-formatted hex string into a u128.
*
* @param src Pointer to hex string.
*/
static u128 GdbHexToU128(const u8* src) {
u128 output;
for (int i = 0; i < 16; i += 2) {
output[0] = (output[0] << 4) | HexCharToValue(src[15 - i - 1]);
output[0] = (output[0] << 4) | HexCharToValue(src[15 - i]);
}
for (int i = 0; i < 16; i += 2) {
output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i - 1]);
output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i]);
}
return output;
}
/// Read a byte from the gdb client.
static u8 ReadByte() {
u8 c;
@@ -599,8 +646,7 @@ static void HandleQuery() {
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 += fmt::format("{:x},", thread->GetThreadID());
}
}
val.pop_back();
@@ -791,11 +837,15 @@ static void ReadRegister() {
} else if (id == PSTATE_REGISTER) {
IntToGdbHex(reply, static_cast<u32>(RegRead(id, current_thread)));
} else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
LongToGdbHex(reply, RegRead(id, current_thread));
u128 r = FpuRead(id, current_thread);
LongToGdbHex(reply, r[0]);
LongToGdbHex(reply + 16, r[1]);
} else if (id == FPCR_REGISTER) {
LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_998, current_thread));
} else {
LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_997, current_thread));
u128 r = FpuRead(id, current_thread);
IntToGdbHex(reply, static_cast<u32>(r[0]));
} else if (id == FPCR_REGISTER + 1) {
u128 r = FpuRead(id, current_thread);
IntToGdbHex(reply, static_cast<u32>(r[0] >> 32));
}
SendReply(reinterpret_cast<char*>(reply));
@@ -822,13 +872,18 @@ static void ReadRegisters() {
bufptr += 8;
for (u32 reg = UC_ARM64_REG_Q0; reg <= UC_ARM64_REG_Q0 + 31; reg++) {
LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread));
u128 r;
for (u32 reg = UC_ARM64_REG_Q0; reg < FPCR_REGISTER; reg++) {
r = FpuRead(reg, current_thread);
LongToGdbHex(bufptr + reg * 32, r[0]);
LongToGdbHex(bufptr + reg * 32 + 16, r[1]);
}
bufptr += 32 * 32;
LongToGdbHex(bufptr, RegRead(TODO_DUMMY_REG_998, current_thread));
r = FpuRead(FPCR_REGISTER, current_thread);
IntToGdbHex(bufptr, static_cast<u32>(r[0]));
bufptr += 8;
@@ -853,14 +908,12 @@ static void WriteRegister() {
} else if (id == PSTATE_REGISTER) {
RegWrite(id, GdbHexToInt(buffer_ptr), current_thread);
} else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
RegWrite(id, GdbHexToLong(buffer_ptr), current_thread);
FpuWrite(id, GdbHexToU128(buffer_ptr), current_thread);
} else if (id == FPCR_REGISTER) {
RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr), current_thread);
} else {
RegWrite(TODO_DUMMY_REG_997, GdbHexToLong(buffer_ptr), current_thread);
} else if (id == FPCR_REGISTER + 1) {
}
// Update Unicorn context skipping scheduler, no running threads at this point
// Update ARM context, skipping scheduler - no running threads at this point
Core::System::GetInstance()
.ArmInterface(current_core)
.LoadContext(current_thread->GetContext());
@@ -885,13 +938,13 @@ static void WriteRegisters() {
} else if (reg >= UC_ARM64_REG_Q0 && reg < FPCR_REGISTER) {
RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread);
} else if (reg == FPCR_REGISTER) {
RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr + i * 16), current_thread);
} else {
UNIMPLEMENTED();
RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread);
} else if (reg == FPCR_REGISTER + 1) {
RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread);
}
}
// Update Unicorn context skipping scheduler, no running threads at this point
// Update ARM context, skipping scheduler - no running threads at this point
Core::System::GetInstance()
.ArmInterface(current_core)
.LoadContext(current_thread->GetContext());
@@ -917,12 +970,6 @@ static void ReadMemory() {
SendReply("E01");
}
const auto& vm_manager = Core::CurrentProcess()->VMManager();
if (addr < vm_manager.GetCodeRegionBaseAddress() ||
addr >= vm_manager.GetMapRegionEndAddress()) {
return SendReply("E00");
}
if (!Memory::IsValidVirtualAddress(addr)) {
return SendReply("E00");
}
@@ -967,7 +1014,7 @@ void Break(bool is_memory_break) {
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
// Update ARM context, skipping scheduler - no running threads at this point
Core::System::GetInstance()
.ArmInterface(current_core)
.LoadContext(current_thread->GetContext());
@@ -1010,7 +1057,7 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) {
breakpoint.addr = addr;
breakpoint.len = len;
Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size());
static constexpr std::array<u8, 4> btrap{{0x00, 0x7d, 0x20, 0xd4}};
static constexpr std::array<u8, 4> btrap{0x00, 0x7d, 0x20, 0xd4};
Memory::WriteBlock(addr, btrap.data(), btrap.size());
Core::System::GetInstance().InvalidateCpuInstructionCaches();
p.insert({addr, breakpoint});
@@ -1321,13 +1368,15 @@ void SetCpuStepFlag(bool 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;
if (!send_trap) {
return;
}
if (!halt_loop || current_thread == thread) {
current_thread = thread;
SendSignal(thread, trap);
}
halt_loop = true;
send_trap = false;
}
}; // namespace GDBStub

View File

@@ -8,58 +8,30 @@
namespace Kernel {
namespace ErrCodes {
enum {
// Confirmed Switch OS error codes
MaxConnectionsReached = 7,
InvalidSize = 101,
InvalidAddress = 102,
HandleTableFull = 105,
InvalidMemoryState = 106,
InvalidMemoryPermissions = 108,
InvalidMemoryRange = 110,
InvalidThreadPriority = 112,
InvalidProcessorId = 113,
InvalidHandle = 114,
InvalidPointer = 115,
InvalidCombination = 116,
Timeout = 117,
SynchronizationCanceled = 118,
TooLarge = 119,
InvalidEnumValue = 120,
NoSuchEntry = 121,
AlreadyRegistered = 122,
SessionClosed = 123,
InvalidState = 125,
ResourceLimitExceeded = 132,
};
}
// Confirmed Switch kernel error codes
// WARNING: The kernel is quite inconsistent in it's usage of errors code. Make sure to always
// double check that the code matches before re-using the constant.
constexpr ResultCode ERR_HANDLE_TABLE_FULL(ErrorModule::Kernel, ErrCodes::HandleTableFull);
constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE(ErrorModule::Kernel, ErrCodes::SessionClosed);
constexpr ResultCode ERR_PORT_NAME_TOO_LONG(ErrorModule::Kernel, ErrCodes::TooLarge);
constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(ErrorModule::Kernel,
ErrCodes::MaxConnectionsReached);
constexpr ResultCode ERR_INVALID_ENUM_VALUE(ErrorModule::Kernel, ErrCodes::InvalidEnumValue);
constexpr ResultCode ERR_INVALID_COMBINATION_KERNEL(ErrorModule::Kernel,
ErrCodes::InvalidCombination);
constexpr ResultCode ERR_INVALID_ADDRESS(ErrorModule::Kernel, ErrCodes::InvalidAddress);
constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::InvalidMemoryState);
constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel,
ErrCodes::InvalidMemoryPermissions);
constexpr ResultCode ERR_INVALID_MEMORY_RANGE(ErrorModule::Kernel, ErrCodes::InvalidMemoryRange);
constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle);
constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId);
constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize);
constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::Kernel, ErrCodes::AlreadyRegistered);
constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState);
constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel,
ErrCodes::InvalidThreadPriority);
constexpr ResultCode ERR_INVALID_POINTER(ErrorModule::Kernel, ErrCodes::InvalidPointer);
constexpr ResultCode ERR_NOT_FOUND(ErrorModule::Kernel, ErrCodes::NoSuchEntry);
constexpr ResultCode RESULT_TIMEOUT(ErrorModule::Kernel, ErrCodes::Timeout);
constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED{ErrorModule::Kernel, 7};
constexpr ResultCode ERR_INVALID_CAPABILITY_DESCRIPTOR{ErrorModule::Kernel, 14};
constexpr ResultCode ERR_INVALID_SIZE{ErrorModule::Kernel, 101};
constexpr ResultCode ERR_INVALID_ADDRESS{ErrorModule::Kernel, 102};
constexpr ResultCode ERR_HANDLE_TABLE_FULL{ErrorModule::Kernel, 105};
constexpr ResultCode ERR_INVALID_ADDRESS_STATE{ErrorModule::Kernel, 106};
constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS{ErrorModule::Kernel, 108};
constexpr ResultCode ERR_INVALID_MEMORY_RANGE{ErrorModule::Kernel, 110};
constexpr ResultCode ERR_INVALID_PROCESSOR_ID{ErrorModule::Kernel, 113};
constexpr ResultCode ERR_INVALID_THREAD_PRIORITY{ErrorModule::Kernel, 112};
constexpr ResultCode ERR_INVALID_HANDLE{ErrorModule::Kernel, 114};
constexpr ResultCode ERR_INVALID_POINTER{ErrorModule::Kernel, 115};
constexpr ResultCode ERR_INVALID_COMBINATION{ErrorModule::Kernel, 116};
constexpr ResultCode RESULT_TIMEOUT{ErrorModule::Kernel, 117};
constexpr ResultCode ERR_SYNCHRONIZATION_CANCELED{ErrorModule::Kernel, 118};
constexpr ResultCode ERR_OUT_OF_RANGE{ErrorModule::Kernel, 119};
constexpr ResultCode ERR_INVALID_ENUM_VALUE{ErrorModule::Kernel, 120};
constexpr ResultCode ERR_NOT_FOUND{ErrorModule::Kernel, 121};
constexpr ResultCode ERR_BUSY{ErrorModule::Kernel, 122};
constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE{ErrorModule::Kernel, 123};
constexpr ResultCode ERR_INVALID_STATE{ErrorModule::Kernel, 125};
constexpr ResultCode ERR_RESERVED_VALUE{ErrorModule::Kernel, 126};
constexpr ResultCode ERR_RESOURCE_LIMIT_EXCEEDED{ErrorModule::Kernel, 132};
} // namespace Kernel

View File

@@ -12,12 +12,23 @@
#include "core/hle/kernel/thread.h"
namespace Kernel {
namespace {
constexpr u16 GetSlot(Handle handle) {
return handle >> 15;
}
constexpr u16 GetGeneration(Handle handle) {
return handle & 0x7FFF;
}
} // Anonymous namespace
HandleTable::HandleTable() {
next_generation = 1;
Clear();
}
HandleTable::~HandleTable() = default;
ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
DEBUG_ASSERT(obj != nullptr);
@@ -31,9 +42,10 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
u16 generation = next_generation++;
// Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
// CTR-OS doesn't use generation 0, so skip straight to 1.
if (next_generation >= (1 << 15))
// Horizon OS uses zero to represent an invalid handle, so skip to 1.
if (next_generation >= (1 << 15)) {
next_generation = 1;
}
generations[slot] = generation;
objects[slot] = std::move(obj);

View File

@@ -13,6 +13,7 @@
namespace Kernel {
enum KernelHandle : Handle {
InvalidHandle = 0,
CurrentThread = 0xFFFF8000,
CurrentProcess = 0xFFFF8001,
};
@@ -42,7 +43,11 @@ enum KernelHandle : Handle {
*/
class HandleTable final : NonCopyable {
public:
/// This is the maximum limit of handles allowed per process in Horizon
static constexpr std::size_t MAX_COUNT = 1024;
HandleTable();
~HandleTable();
/**
* Allocates a handle for the given object.
@@ -89,19 +94,6 @@ public:
void Clear();
private:
/**
* This is the maximum limit of handles allowed per process in CTR-OS. It can be further
* reduced by ExHeader values, but this is not emulated here.
*/
static const std::size_t MAX_COUNT = 4096;
static u16 GetSlot(Handle handle) {
return handle >> 15;
}
static u16 GetGeneration(Handle handle) {
return handle & 0x7FFF;
}
/// Stores the Object referenced by the handle or null if the slot is empty.
std::array<SharedPtr<Object>, MAX_COUNT> objects;

View File

@@ -15,13 +15,14 @@
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/readable_event.h"
#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/writable_event.h"
#include "core/memory.h"
namespace Kernel {
@@ -36,11 +37,9 @@ void SessionRequestHandler::ClientDisconnected(const SharedPtr<ServerSession>& s
boost::range::remove_erase(connected_sessions, server_session);
}
SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
const std::string& reason, u64 timeout,
WakeupCallback&& callback,
Kernel::SharedPtr<Kernel::Event> event) {
SharedPtr<WritableEvent> HLERequestContext::SleepClientThread(
SharedPtr<Thread> thread, const std::string& reason, u64 timeout, WakeupCallback&& callback,
SharedPtr<WritableEvent> writable_event) {
// Put the client thread to sleep until the wait event is signaled or the timeout expires.
thread->SetWakeupCallback([context = *this, callback](
ThreadWakeupReason reason, SharedPtr<Thread> thread,
@@ -51,23 +50,25 @@ SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
return true;
});
if (!event) {
auto& kernel = Core::System::GetInstance().Kernel();
if (!writable_event) {
// Create event if not provided
auto& kernel = Core::System::GetInstance().Kernel();
event =
Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "HLE Pause Event: " + reason);
const auto pair = WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
"HLE Pause Event: " + reason);
writable_event = pair.writable;
}
event->Clear();
const auto readable_event{writable_event->GetReadableEvent()};
writable_event->Clear();
thread->SetStatus(ThreadStatus::WaitHLEEvent);
thread->SetWaitObjects({event});
event->AddWaitingThread(thread);
thread->SetWaitObjects({readable_event});
readable_event->AddWaitingThread(thread);
if (timeout > 0) {
thread->WakeAfterDelay(timeout);
}
return event;
return writable_event;
}
HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session)

View File

@@ -24,10 +24,11 @@ class ServiceFrameworkBase;
namespace Kernel {
class Domain;
class Event;
class HandleTable;
class HLERequestContext;
class Process;
class ReadableEvent;
class WritableEvent;
/**
* Interface implemented by HLE Session handlers.
@@ -119,12 +120,13 @@ 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.
* @param writable_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,
Kernel::SharedPtr<Kernel::Event> event = nullptr);
SharedPtr<WritableEvent> SleepClientThread(SharedPtr<Thread> thread, const std::string& reason,
u64 timeout, WakeupCallback&& callback,
SharedPtr<WritableEvent> writable_event = nullptr);
/// Populates this context with data from the requesting process/thread.
ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table,

View File

@@ -105,20 +105,20 @@ struct KernelCore::Impl {
void Initialize(KernelCore& kernel) {
Shutdown();
InitializeResourceLimits(kernel);
InitializeSystemResourceLimit(kernel);
InitializeThreads();
InitializeTimers();
}
void Shutdown() {
next_object_id = 0;
next_process_id = 10;
next_process_id = Process::ProcessIDMin;
next_thread_id = 1;
process_list.clear();
current_process = nullptr;
resource_limits.fill(nullptr);
system_resource_limit = nullptr;
thread_wakeup_callback_handle_table.Clear();
thread_wakeup_event_type = nullptr;
@@ -129,63 +129,17 @@ struct KernelCore::Impl {
named_ports.clear();
}
void InitializeResourceLimits(KernelCore& kernel) {
// Create the four resource limits that the system uses
// Create the APPLICATION resource limit
SharedPtr<ResourceLimit> resource_limit = ResourceLimit::Create(kernel, "Applications");
resource_limit->max_priority = 0x18;
resource_limit->max_commit = 0x4000000;
resource_limit->max_threads = 0x20;
resource_limit->max_events = 0x20;
resource_limit->max_mutexes = 0x20;
resource_limit->max_semaphores = 0x8;
resource_limit->max_timers = 0x8;
resource_limit->max_shared_mems = 0x10;
resource_limit->max_address_arbiters = 0x2;
resource_limit->max_cpu_time = 0x1E;
resource_limits[static_cast<u8>(ResourceLimitCategory::APPLICATION)] = resource_limit;
// Creates the default system resource limit
void InitializeSystemResourceLimit(KernelCore& kernel) {
system_resource_limit = ResourceLimit::Create(kernel, "System");
// Create the SYS_APPLET resource limit
resource_limit = ResourceLimit::Create(kernel, "System Applets");
resource_limit->max_priority = 0x4;
resource_limit->max_commit = 0x5E00000;
resource_limit->max_threads = 0x1D;
resource_limit->max_events = 0xB;
resource_limit->max_mutexes = 0x8;
resource_limit->max_semaphores = 0x4;
resource_limit->max_timers = 0x4;
resource_limit->max_shared_mems = 0x8;
resource_limit->max_address_arbiters = 0x3;
resource_limit->max_cpu_time = 0x2710;
resource_limits[static_cast<u8>(ResourceLimitCategory::SYS_APPLET)] = resource_limit;
// Create the LIB_APPLET resource limit
resource_limit = ResourceLimit::Create(kernel, "Library Applets");
resource_limit->max_priority = 0x4;
resource_limit->max_commit = 0x600000;
resource_limit->max_threads = 0xE;
resource_limit->max_events = 0x8;
resource_limit->max_mutexes = 0x8;
resource_limit->max_semaphores = 0x4;
resource_limit->max_timers = 0x4;
resource_limit->max_shared_mems = 0x8;
resource_limit->max_address_arbiters = 0x1;
resource_limit->max_cpu_time = 0x2710;
resource_limits[static_cast<u8>(ResourceLimitCategory::LIB_APPLET)] = resource_limit;
// Create the OTHER resource limit
resource_limit = ResourceLimit::Create(kernel, "Others");
resource_limit->max_priority = 0x4;
resource_limit->max_commit = 0x2180000;
resource_limit->max_threads = 0xE1;
resource_limit->max_events = 0x108;
resource_limit->max_mutexes = 0x25;
resource_limit->max_semaphores = 0x43;
resource_limit->max_timers = 0x2C;
resource_limit->max_shared_mems = 0x1F;
resource_limit->max_address_arbiters = 0x2D;
resource_limit->max_cpu_time = 0x3E8;
resource_limits[static_cast<u8>(ResourceLimitCategory::OTHER)] = resource_limit;
// If setting the default system values fails, then something seriously wrong has occurred.
ASSERT(system_resource_limit->SetLimitValue(ResourceType::PhysicalMemory, 0x200000000)
.IsSuccess());
ASSERT(system_resource_limit->SetLimitValue(ResourceType::Threads, 800).IsSuccess());
ASSERT(system_resource_limit->SetLimitValue(ResourceType::Events, 700).IsSuccess());
ASSERT(system_resource_limit->SetLimitValue(ResourceType::TransferMemory, 200).IsSuccess());
ASSERT(system_resource_limit->SetLimitValue(ResourceType::Sessions, 900).IsSuccess());
}
void InitializeThreads() {
@@ -199,16 +153,14 @@ struct KernelCore::Impl {
}
std::atomic<u32> next_object_id{0};
// TODO(Subv): Start the process ids from 10 for now, as lower PIDs are
// reserved for low-level services
std::atomic<u32> next_process_id{10};
std::atomic<u32> next_thread_id{1};
std::atomic<u64> next_process_id{Process::ProcessIDMin};
std::atomic<u64> next_thread_id{1};
// Lists all processes that exist in the current session.
std::vector<SharedPtr<Process>> process_list;
Process* current_process = nullptr;
std::array<SharedPtr<ResourceLimit>, 4> resource_limits;
SharedPtr<ResourceLimit> system_resource_limit;
/// The event type of the generic timer callback event
CoreTiming::EventType* timer_callback_event_type = nullptr;
@@ -239,9 +191,8 @@ void KernelCore::Shutdown() {
impl->Shutdown();
}
SharedPtr<ResourceLimit> KernelCore::ResourceLimitForCategory(
ResourceLimitCategory category) const {
return impl->resource_limits.at(static_cast<std::size_t>(category));
SharedPtr<ResourceLimit> KernelCore::GetSystemResourceLimit() const {
return impl->system_resource_limit;
}
SharedPtr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const {
@@ -289,11 +240,11 @@ u32 KernelCore::CreateNewObjectID() {
return impl->next_object_id++;
}
u32 KernelCore::CreateNewThreadID() {
u64 KernelCore::CreateNewThreadID() {
return impl->next_thread_id++;
}
u32 KernelCore::CreateNewProcessID() {
u64 KernelCore::CreateNewProcessID() {
return impl->next_process_id++;
}

View File

@@ -24,8 +24,6 @@ class ResourceLimit;
class Thread;
class Timer;
enum class ResourceLimitCategory : u8;
/// Represents a single instance of the kernel.
class KernelCore {
private:
@@ -47,8 +45,8 @@ public:
/// Clears all resources in use by the kernel instance.
void Shutdown();
/// Retrieves a shared pointer to a ResourceLimit identified by the given category.
SharedPtr<ResourceLimit> ResourceLimitForCategory(ResourceLimitCategory category) const;
/// Retrieves a shared pointer to the system resource limit instance.
SharedPtr<ResourceLimit> GetSystemResourceLimit() const;
/// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
SharedPtr<Thread> RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const;
@@ -90,10 +88,10 @@ private:
u32 CreateNewObjectID();
/// Creates a new process ID, incrementing the internal process ID counter;
u32 CreateNewProcessID();
u64 CreateNewProcessID();
/// Creates a new thread ID, incrementing the internal thread ID counter.
u32 CreateNewThreadID();
u64 CreateNewThreadID();
/// Creates a timer callback handle for the given timer.
ResultVal<Handle> CreateTimerCallbackHandle(const SharedPtr<Timer>& timer);

View File

@@ -13,16 +13,17 @@ Object::~Object() = default;
bool Object::IsWaitable() const {
switch (GetHandleType()) {
case HandleType::Event:
case HandleType::ReadableEvent:
case HandleType::Thread:
case HandleType::Process:
case HandleType::Timer:
case HandleType::ServerPort:
case HandleType::ServerSession:
return true;
case HandleType::Unknown:
case HandleType::WritableEvent:
case HandleType::SharedMemory:
case HandleType::Process:
case HandleType::AddressArbiter:
case HandleType::ResourceLimit:
case HandleType::ClientPort:
@@ -31,6 +32,7 @@ bool Object::IsWaitable() const {
}
UNREACHABLE();
return false;
}
} // namespace Kernel

View File

@@ -19,7 +19,8 @@ using Handle = u32;
enum class HandleType : u32 {
Unknown,
Event,
WritableEvent,
ReadableEvent,
SharedMemory,
Thread,
Process,
@@ -33,9 +34,9 @@ enum class HandleType : u32 {
};
enum class ResetType {
OneShot,
Sticky,
Pulse,
OneShot, ///< Reset automatically on object acquisition
Sticky, ///< Never reset automatically
Pulse, ///< Reset automatically on wakeup
};
class Object : NonCopyable {

View File

@@ -4,8 +4,8 @@
#include <algorithm>
#include <memory>
#include <random>
#include "common/assert.h"
#include "common/common_funcs.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/file_sys/program_metadata.h"
@@ -17,6 +17,7 @@
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/vm_manager.h"
#include "core/memory.h"
#include "core/settings.h"
namespace Kernel {
@@ -27,94 +28,49 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) {
SharedPtr<Process> process(new Process(kernel));
process->name = std::move(name);
process->flags.raw = 0;
process->flags.memory_region.Assign(MemoryRegion::APPLICATION);
process->resource_limit = kernel.ResourceLimitForCategory(ResourceLimitCategory::APPLICATION);
process->resource_limit = kernel.GetSystemResourceLimit();
process->status = ProcessStatus::Created;
process->program_id = 0;
process->process_id = kernel.CreateNewProcessID();
process->svc_access_mask.set();
process->capabilities.InitializeForMetadatalessProcess();
std::mt19937 rng(Settings::values.rng_seed.value_or(0));
std::uniform_int_distribution<u64> distribution;
std::generate(process->random_entropy.begin(), process->random_entropy.end(),
[&] { return distribution(rng); });
kernel.AppendNewProcess(process);
return process;
}
void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
program_id = metadata.GetTitleID();
is_64bit_process = metadata.Is64BitProgram();
vm_manager.Reset(metadata.GetAddressSpaceType());
SharedPtr<ResourceLimit> Process::GetResourceLimit() const {
return resource_limit;
}
void Process::ParseKernelCaps(const u32* kernel_caps, std::size_t len) {
for (std::size_t i = 0; i < len; ++i) {
u32 descriptor = kernel_caps[i];
u32 type = descriptor >> 20;
if (descriptor == 0xFFFFFFFF) {
// Unused descriptor entry
continue;
} else if ((type & 0xF00) == 0xE00) { // 0x0FFF
// Allowed interrupts list
LOG_WARNING(Loader, "ExHeader allowed interrupts list ignored");
} else if ((type & 0xF80) == 0xF00) { // 0x07FF
// Allowed syscalls mask
unsigned int index = ((descriptor >> 24) & 7) * 24;
u32 bits = descriptor & 0xFFFFFF;
while (bits && index < svc_access_mask.size()) {
svc_access_mask.set(index, bits & 1);
++index;
bits >>= 1;
}
} else if ((type & 0xFF0) == 0xFE0) { // 0x00FF
// Handle table size
handle_table_size = descriptor & 0x3FF;
} else if ((type & 0xFF8) == 0xFF0) { // 0x007F
// Misc. flags
flags.raw = descriptor & 0xFFFF;
} else if ((type & 0xFFE) == 0xFF8) { // 0x001F
// Mapped memory range
if (i + 1 >= len || ((kernel_caps[i + 1] >> 20) & 0xFFE) != 0xFF8) {
LOG_WARNING(Loader, "Incomplete exheader memory range descriptor ignored.");
continue;
}
u32 end_desc = kernel_caps[i + 1];
++i; // Skip over the second descriptor on the next iteration
AddressMapping mapping;
mapping.address = descriptor << 12;
VAddr end_address = end_desc << 12;
if (mapping.address < end_address) {
mapping.size = end_address - mapping.address;
} else {
mapping.size = 0;
}
mapping.read_only = (descriptor & (1 << 20)) != 0;
mapping.unk_flag = (end_desc & (1 << 20)) != 0;
address_mappings.push_back(mapping);
} else if ((type & 0xFFF) == 0xFFE) { // 0x000F
// Mapped memory page
AddressMapping mapping;
mapping.address = descriptor << 12;
mapping.size = Memory::PAGE_SIZE;
mapping.read_only = false;
mapping.unk_flag = false;
address_mappings.push_back(mapping);
} else if ((type & 0xFE0) == 0xFC0) { // 0x01FF
// Kernel version
kernel_version = descriptor & 0xFFFF;
int minor = kernel_version & 0xFF;
int major = (kernel_version >> 8) & 0xFF;
LOG_INFO(Loader, "ExHeader kernel version: {}.{}", major, minor);
} else {
LOG_ERROR(Loader, "Unhandled kernel caps descriptor: 0x{:08X}", descriptor);
}
ResultCode Process::ClearSignalState() {
if (status == ProcessStatus::Exited) {
LOG_ERROR(Kernel, "called on a terminated process instance.");
return ERR_INVALID_STATE;
}
if (!is_signaled) {
LOG_ERROR(Kernel, "called on a process instance that isn't signaled.");
return ERR_INVALID_STATE;
}
is_signaled = false;
return RESULT_SUCCESS;
}
ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
program_id = metadata.GetTitleID();
ideal_processor = metadata.GetMainThreadCore();
is_64bit_process = metadata.Is64BitProgram();
vm_manager.Reset(metadata.GetAddressSpaceType());
const auto& caps = metadata.GetKernelCapabilities();
return capabilities.InitializeForUserProcess(caps.data(), caps.size(), vm_manager);
}
void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
@@ -124,17 +80,17 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
vm_manager
.MapMemoryBlock(vm_manager.GetTLSIORegionEndAddress() - stack_size,
std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size,
MemoryState::Mapped)
MemoryState::Stack)
.Unwrap();
vm_manager.LogLayout();
status = ProcessStatus::Running;
ChangeStatus(ProcessStatus::Running);
Kernel::SetupMainThread(kernel, entry_point, main_thread_priority, *this);
}
void Process::PrepareForTermination() {
status = ProcessStatus::Exited;
ChangeStatus(ProcessStatus::Exiting);
const auto stop_threads = [this](const std::vector<SharedPtr<Thread>>& thread_list) {
for (auto& thread : thread_list) {
@@ -158,6 +114,8 @@ void Process::PrepareForTermination() {
stop_threads(system.Scheduler(1).GetThreadList());
stop_threads(system.Scheduler(2).GetThreadList());
stop_threads(system.Scheduler(3).GetThreadList());
ChangeStatus(ProcessStatus::Exited);
}
/**
@@ -240,91 +198,25 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) {
Core::System::GetInstance().ArmInterface(3).ClearInstructionCache();
}
ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
if (target < vm_manager.GetHeapRegionBaseAddress() ||
target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) {
return ERR_INVALID_ADDRESS;
}
if (heap_memory == nullptr) {
// Initialize heap
heap_memory = std::make_shared<std::vector<u8>>();
heap_start = heap_end = target;
} else {
vm_manager.UnmapRange(heap_start, heap_end - heap_start);
}
// If necessary, expand backing vector to cover new heap extents.
if (target < heap_start) {
heap_memory->insert(begin(*heap_memory), heap_start - target, 0);
heap_start = target;
vm_manager.RefreshMemoryBlockMappings(heap_memory.get());
}
if (target + size > heap_end) {
heap_memory->insert(end(*heap_memory), (target + size) - heap_end, 0);
heap_end = target + size;
vm_manager.RefreshMemoryBlockMappings(heap_memory.get());
}
ASSERT(heap_end - heap_start == heap_memory->size());
CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, heap_memory, target - heap_start,
size, MemoryState::Heap));
vm_manager.Reprotect(vma, perms);
heap_used = size;
return MakeResult<VAddr>(heap_end - size);
}
ResultCode Process::HeapFree(VAddr target, u32 size) {
if (target < vm_manager.GetHeapRegionBaseAddress() ||
target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) {
return ERR_INVALID_ADDRESS;
}
if (size == 0) {
return RESULT_SUCCESS;
}
ResultCode result = vm_manager.UnmapRange(target, size);
if (result.IsError())
return result;
heap_used -= size;
return RESULT_SUCCESS;
}
ResultCode Process::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
auto vma = vm_manager.FindVMA(src_addr);
ASSERT_MSG(vma != vm_manager.vma_map.end(), "Invalid memory address");
ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address");
// The returned VMA might be a bigger one encompassing the desired address.
auto vma_offset = src_addr - vma->first;
ASSERT_MSG(vma_offset + size <= vma->second.size,
"Shared memory exceeds bounds of mapped block");
const std::shared_ptr<std::vector<u8>>& backing_block = vma->second.backing_block;
std::size_t backing_block_offset = vma->second.offset + vma_offset;
CASCADE_RESULT(auto new_vma,
vm_manager.MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size,
MemoryState::Mapped));
// Protect mirror with permissions from old region
vm_manager.Reprotect(new_vma, vma->second.permissions);
// Remove permissions from old region
vm_manager.Reprotect(vma, VMAPermission::None);
return RESULT_SUCCESS;
}
ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) {
return vm_manager.UnmapRange(dst_addr, size);
}
Kernel::Process::Process(KernelCore& kernel) : Object{kernel} {}
Kernel::Process::Process(KernelCore& kernel) : WaitObject{kernel} {}
Kernel::Process::~Process() {}
void Process::Acquire(Thread* thread) {
ASSERT_MSG(!ShouldWait(thread), "Object unavailable!");
}
bool Process::ShouldWait(Thread* thread) const {
return !is_signaled;
}
void Process::ChangeStatus(ProcessStatus new_status) {
if (status == new_status) {
return;
}
status = new_status;
is_signaled = true;
WakeupAllWaitingThreads();
}
} // namespace Kernel

View File

@@ -11,12 +11,13 @@
#include <string>
#include <vector>
#include <boost/container/static_vector.hpp>
#include "common/bit_field.h"
#include "common/common_types.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/process_capability.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/vm_manager.h"
#include "core/hle/kernel/wait_object.h"
#include "core/hle/result.h"
namespace FileSys {
class ProgramMetadata;
@@ -41,24 +42,6 @@ enum class MemoryRegion : u16 {
BASE = 3,
};
union ProcessFlags {
u16 raw;
BitField<0, 1, u16>
allow_debug; ///< Allows other processes to attach to and debug this process.
BitField<1, 1, u16> force_debug; ///< Allows this process to attach to processes even if they
/// don't have allow_debug set.
BitField<2, 1, u16> allow_nonalphanum;
BitField<3, 1, u16> shared_page_writable; ///< Shared page is mapped with write permissions.
BitField<4, 1, u16> privileged_priority; ///< Can use priority levels higher than 24.
BitField<5, 1, u16> allow_main_args;
BitField<6, 1, u16> shared_device_mem;
BitField<7, 1, u16> runnable_on_sleep;
BitField<8, 4, MemoryRegion>
memory_region; ///< Default region for memory allocations for this process
BitField<12, 1, u16> loaded_high; ///< Application loaded high (not at 0x00100000).
};
/**
* Indicates the status of a Process instance.
*
@@ -117,8 +100,22 @@ struct CodeSet final {
VAddr entrypoint = 0;
};
class Process final : public Object {
class Process final : public WaitObject {
public:
enum : u64 {
/// Lowest allowed process ID for a kernel initial process.
InitialKIPIDMin = 1,
/// Highest allowed process ID for a kernel initial process.
InitialKIPIDMax = 80,
/// Lowest allowed process ID for a userland process.
ProcessIDMin = 81,
/// Highest allowed process ID for a userland process.
ProcessIDMax = 0xFFFFFFFFFFFFFFFF,
};
static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4;
static SharedPtr<Process> Create(KernelCore& kernel, std::string&& name);
std::string GetTypeName() const override {
@@ -159,7 +156,7 @@ public:
}
/// Gets the unique ID that identifies this particular process.
u32 GetProcessID() const {
u64 GetProcessID() const {
return process_id;
}
@@ -169,14 +166,7 @@ public:
}
/// Gets the resource limit descriptor for this process
ResourceLimit& GetResourceLimit() {
return *resource_limit;
}
/// Gets the resource limit descriptor for this process
const ResourceLimit& GetResourceLimit() const {
return *resource_limit;
}
SharedPtr<ResourceLimit> GetResourceLimit() const;
/// Gets the default CPU ID for this process
u8 GetDefaultProcessorID() const {
@@ -184,13 +174,13 @@ public:
}
/// Gets the bitmask of allowed CPUs that this process' threads can run on.
u32 GetAllowedProcessorMask() const {
return allowed_processor_mask;
u64 GetAllowedProcessorMask() const {
return capabilities.GetCoreMask();
}
/// Gets the bitmask of allowed thread priorities.
u32 GetAllowedThreadPriorityMask() const {
return allowed_thread_priority_mask;
u64 GetAllowedThreadPriorityMask() const {
return capabilities.GetPriorityMask();
}
u32 IsVirtualMemoryEnabled() const {
@@ -212,19 +202,31 @@ public:
total_process_running_time_ticks += ticks;
}
/// Gets 8 bytes of random data for svcGetInfo RandomEntropy
u64 GetRandomEntropy(std::size_t index) const {
return random_entropy.at(index);
}
/// Clears the signaled state of the process if and only if it's signaled.
///
/// @pre The process must not be already terminated. If this is called on a
/// terminated process, then ERR_INVALID_STATE will be returned.
///
/// @pre The process must be in a signaled state. If this is called on a
/// process instance that is not signaled, ERR_INVALID_STATE will be
/// returned.
ResultCode ClearSignalState();
/**
* Loads process-specifics configuration info with metadata provided
* by an executable.
*
* @param metadata The provided metadata to load process specific info.
* @param metadata The provided metadata to load process specific info from.
*
* @returns RESULT_SUCCESS if all relevant metadata was able to be
* loaded and parsed. Otherwise, an error code is returned.
*/
void LoadFromMetadata(const FileSys::ProgramMetadata& metadata);
/**
* Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them
* to this process.
*/
void ParseKernelCaps(const u32* kernel_caps, std::size_t len);
ResultCode LoadFromMetadata(const FileSys::ProgramMetadata& metadata);
/**
* Applies address space changes and launches the process main thread.
@@ -240,7 +242,7 @@ public:
void LoadModule(CodeSet module_, VAddr base_addr);
///////////////////////////////////////////////////////////////////////////////////////////////
// Memory Management
// Thread-local storage management
// Marks the next available region as used and returns the address of the slot.
VAddr MarkNextAvailableTLSSlotAsUsed(Thread& thread);
@@ -248,17 +250,21 @@ public:
// Frees a used TLS slot identified by the given address
void FreeTLSSlot(VAddr tls_address);
ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
ResultCode HeapFree(VAddr target, u32 size);
ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size);
ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
private:
explicit Process(KernelCore& kernel);
~Process() override;
/// Checks if the specified thread should wait until this process is available.
bool ShouldWait(Thread* thread) const override;
/// Acquires/locks this process for the specified thread if it's available.
void Acquire(Thread* thread) override;
/// Changes the process status. If the status is different
/// from the current process status, then this will trigger
/// a process signal.
void ChangeStatus(ProcessStatus new_status);
/// Memory manager for this process.
Kernel::VMManager vm_manager;
@@ -266,43 +272,18 @@ private:
ProcessStatus status;
/// The ID of this process
u32 process_id = 0;
u64 process_id = 0;
/// Title ID corresponding to the process
u64 program_id;
u64 program_id = 0;
/// Resource limit descriptor for this process
SharedPtr<ResourceLimit> resource_limit;
/// The process may only call SVCs which have the corresponding bit set.
std::bitset<0x80> svc_access_mask;
/// Maximum size of the handle table for the process.
u32 handle_table_size = 0x200;
/// Special memory ranges mapped into this processes address space. This is used to give
/// processes access to specific I/O regions and device memory.
boost::container::static_vector<AddressMapping, 8> address_mappings;
ProcessFlags flags;
/// Kernel compatibility version for this process
u16 kernel_version = 0;
/// The default CPU for this process, threads are scheduled on this cpu by default.
u8 ideal_processor = 0;
/// Bitmask of allowed CPUs that this process' threads can run on. TODO(Subv): Actually parse
/// this value from the process header.
u32 allowed_processor_mask = THREADPROCESSORID_DEFAULT_MASK;
u32 allowed_thread_priority_mask = 0xFFFFFFFF;
u32 is_virtual_address_memory_enabled = 0;
// Memory used to back the allocations in the regular heap. A single vector is used to cover
// the entire virtual address space extents that bound the allocations, including any holes.
// This makes deallocation and reallocation of holes fast and keeps process memory contiguous
// in the emulator address space, allowing Memory::GetPointer to be reasonably safe.
std::shared_ptr<std::vector<u8>> heap_memory;
// The left/right bounds of the address space covered by heap_memory.
VAddr heap_start = 0;
VAddr heap_end = 0;
u64 heap_used = 0;
/// The Thread Local Storage area is allocated as processes create threads,
/// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part
/// holds the TLS for a specific thread. This vector contains which parts are in use for each
@@ -310,17 +291,27 @@ private:
/// This vector will grow as more pages are allocated for new threads.
std::vector<std::bitset<8>> tls_slots;
/// Contains the parsed process capability descriptors.
ProcessCapabilities capabilities;
/// Whether or not this process is AArch64, or AArch32.
/// By default, we currently assume this is true, unless otherwise
/// specified by metadata provided to the process during loading.
bool is_64bit_process = true;
/// Whether or not this process is signaled. This occurs
/// upon the process changing to a different state.
bool is_signaled = false;
/// Total running time for the process in ticks.
u64 total_process_running_time_ticks = 0;
/// Per-process handle table for storing created object handles in.
HandleTable handle_table;
/// Random values for svcGetInfo RandomEntropy
std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy;
std::string name;
};

View File

@@ -0,0 +1,355 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/bit_util.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/process_capability.h"
#include "core/hle/kernel/vm_manager.h"
namespace Kernel {
namespace {
// clang-format off
// Shift offsets for kernel capability types.
enum : u32 {
CapabilityOffset_PriorityAndCoreNum = 3,
CapabilityOffset_Syscall = 4,
CapabilityOffset_MapPhysical = 6,
CapabilityOffset_MapIO = 7,
CapabilityOffset_Interrupt = 11,
CapabilityOffset_ProgramType = 13,
CapabilityOffset_KernelVersion = 14,
CapabilityOffset_HandleTableSize = 15,
CapabilityOffset_Debug = 16,
};
// Combined mask of all parameters that may be initialized only once.
constexpr u32 InitializeOnceMask = (1U << CapabilityOffset_PriorityAndCoreNum) |
(1U << CapabilityOffset_ProgramType) |
(1U << CapabilityOffset_KernelVersion) |
(1U << CapabilityOffset_HandleTableSize) |
(1U << CapabilityOffset_Debug);
// Packed kernel version indicating 10.4.0
constexpr u32 PackedKernelVersion = 0x520000;
// Indicates possible types of capabilities that can be specified.
enum class CapabilityType : u32 {
Unset = 0U,
PriorityAndCoreNum = (1U << CapabilityOffset_PriorityAndCoreNum) - 1,
Syscall = (1U << CapabilityOffset_Syscall) - 1,
MapPhysical = (1U << CapabilityOffset_MapPhysical) - 1,
MapIO = (1U << CapabilityOffset_MapIO) - 1,
Interrupt = (1U << CapabilityOffset_Interrupt) - 1,
ProgramType = (1U << CapabilityOffset_ProgramType) - 1,
KernelVersion = (1U << CapabilityOffset_KernelVersion) - 1,
HandleTableSize = (1U << CapabilityOffset_HandleTableSize) - 1,
Debug = (1U << CapabilityOffset_Debug) - 1,
Ignorable = 0xFFFFFFFFU,
};
// clang-format on
constexpr CapabilityType GetCapabilityType(u32 value) {
return static_cast<CapabilityType>((~value & (value + 1)) - 1);
}
u32 GetFlagBitOffset(CapabilityType type) {
const auto value = static_cast<u32>(type);
return static_cast<u32>(Common::BitSize<u32>() - Common::CountLeadingZeroes32(value));
}
} // Anonymous namespace
ResultCode ProcessCapabilities::InitializeForKernelProcess(const u32* capabilities,
std::size_t num_capabilities,
VMManager& vm_manager) {
Clear();
// Allow all cores and priorities.
core_mask = 0xF;
priority_mask = 0xFFFFFFFFFFFFFFFF;
kernel_version = PackedKernelVersion;
return ParseCapabilities(capabilities, num_capabilities, vm_manager);
}
ResultCode ProcessCapabilities::InitializeForUserProcess(const u32* capabilities,
std::size_t num_capabilities,
VMManager& vm_manager) {
Clear();
return ParseCapabilities(capabilities, num_capabilities, vm_manager);
}
void ProcessCapabilities::InitializeForMetadatalessProcess() {
// Allow all cores and priorities
core_mask = 0xF;
priority_mask = 0xFFFFFFFFFFFFFFFF;
kernel_version = PackedKernelVersion;
// Allow all system calls and interrupts.
svc_capabilities.set();
interrupt_capabilities.set();
// Allow using the maximum possible amount of handles
handle_table_size = static_cast<u32>(HandleTable::MAX_COUNT);
// Allow all debugging capabilities.
is_debuggable = true;
can_force_debug = true;
}
ResultCode ProcessCapabilities::ParseCapabilities(const u32* capabilities,
std::size_t num_capabilities,
VMManager& vm_manager) {
u32 set_flags = 0;
u32 set_svc_bits = 0;
for (std::size_t i = 0; i < num_capabilities; ++i) {
const u32 descriptor = capabilities[i];
const auto type = GetCapabilityType(descriptor);
if (type == CapabilityType::MapPhysical) {
i++;
// The MapPhysical type uses two descriptor flags for its parameters.
// If there's only one, then there's a problem.
if (i >= num_capabilities) {
return ERR_INVALID_COMBINATION;
}
const auto size_flags = capabilities[i];
if (GetCapabilityType(size_flags) != CapabilityType::MapPhysical) {
return ERR_INVALID_COMBINATION;
}
const auto result = HandleMapPhysicalFlags(descriptor, size_flags, vm_manager);
if (result.IsError()) {
return result;
}
} else {
const auto result =
ParseSingleFlagCapability(set_flags, set_svc_bits, descriptor, vm_manager);
if (result.IsError()) {
return result;
}
}
}
return RESULT_SUCCESS;
}
ResultCode ProcessCapabilities::ParseSingleFlagCapability(u32& set_flags, u32& set_svc_bits,
u32 flag, VMManager& vm_manager) {
const auto type = GetCapabilityType(flag);
if (type == CapabilityType::Unset) {
return ERR_INVALID_CAPABILITY_DESCRIPTOR;
}
// Bail early on ignorable entries, as one would expect,
// ignorable descriptors can be ignored.
if (type == CapabilityType::Ignorable) {
return RESULT_SUCCESS;
}
// Ensure that the give flag hasn't already been initialized before.
// If it has been, then bail.
const u32 flag_length = GetFlagBitOffset(type);
const u32 set_flag = 1U << flag_length;
if ((set_flag & set_flags & InitializeOnceMask) != 0) {
return ERR_INVALID_COMBINATION;
}
set_flags |= set_flag;
switch (type) {
case CapabilityType::PriorityAndCoreNum:
return HandlePriorityCoreNumFlags(flag);
case CapabilityType::Syscall:
return HandleSyscallFlags(set_svc_bits, flag);
case CapabilityType::MapIO:
return HandleMapIOFlags(flag, vm_manager);
case CapabilityType::Interrupt:
return HandleInterruptFlags(flag);
case CapabilityType::ProgramType:
return HandleProgramTypeFlags(flag);
case CapabilityType::KernelVersion:
return HandleKernelVersionFlags(flag);
case CapabilityType::HandleTableSize:
return HandleHandleTableFlags(flag);
case CapabilityType::Debug:
return HandleDebugFlags(flag);
default:
break;
}
return ERR_INVALID_CAPABILITY_DESCRIPTOR;
}
void ProcessCapabilities::Clear() {
svc_capabilities.reset();
interrupt_capabilities.reset();
core_mask = 0;
priority_mask = 0;
handle_table_size = 0;
kernel_version = 0;
program_type = ProgramType::SysModule;
is_debuggable = false;
can_force_debug = false;
}
ResultCode ProcessCapabilities::HandlePriorityCoreNumFlags(u32 flags) {
if (priority_mask != 0 || core_mask != 0) {
return ERR_INVALID_CAPABILITY_DESCRIPTOR;
}
const u32 core_num_min = (flags >> 16) & 0xFF;
const u32 core_num_max = (flags >> 24) & 0xFF;
if (core_num_min > core_num_max) {
return ERR_INVALID_COMBINATION;
}
const u32 priority_min = (flags >> 10) & 0x3F;
const u32 priority_max = (flags >> 4) & 0x3F;
if (priority_min > priority_max) {
return ERR_INVALID_COMBINATION;
}
// The switch only has 4 usable cores.
if (core_num_max >= 4) {
return ERR_INVALID_PROCESSOR_ID;
}
const auto make_mask = [](u64 min, u64 max) {
const u64 range = max - min + 1;
const u64 mask = (1ULL << range) - 1;
return mask << min;
};
core_mask = make_mask(core_num_min, core_num_max);
priority_mask = make_mask(priority_min, priority_max);
return RESULT_SUCCESS;
}
ResultCode ProcessCapabilities::HandleSyscallFlags(u32& set_svc_bits, u32 flags) {
const u32 index = flags >> 29;
const u32 svc_bit = 1U << index;
// If we've already set this svc before, bail.
if ((set_svc_bits & svc_bit) != 0) {
return ERR_INVALID_COMBINATION;
}
set_svc_bits |= svc_bit;
const u32 svc_mask = (flags >> 5) & 0xFFFFFF;
for (u32 i = 0; i < 24; ++i) {
const u32 svc_number = index * 24 + i;
if ((svc_mask & (1U << i)) == 0) {
continue;
}
if (svc_number >= svc_capabilities.size()) {
return ERR_OUT_OF_RANGE;
}
svc_capabilities[svc_number] = true;
}
return RESULT_SUCCESS;
}
ResultCode ProcessCapabilities::HandleMapPhysicalFlags(u32 flags, u32 size_flags,
VMManager& vm_manager) {
// TODO(Lioncache): Implement once the memory manager can handle this.
return RESULT_SUCCESS;
}
ResultCode ProcessCapabilities::HandleMapIOFlags(u32 flags, VMManager& vm_manager) {
// TODO(Lioncache): Implement once the memory manager can handle this.
return RESULT_SUCCESS;
}
ResultCode ProcessCapabilities::HandleInterruptFlags(u32 flags) {
constexpr u32 interrupt_ignore_value = 0x3FF;
const u32 interrupt0 = (flags >> 12) & 0x3FF;
const u32 interrupt1 = (flags >> 22) & 0x3FF;
for (u32 interrupt : {interrupt0, interrupt1}) {
if (interrupt == interrupt_ignore_value) {
continue;
}
// NOTE:
// This should be checking a generic interrupt controller value
// as part of the calculation, however, given we don't currently
// emulate that, it's sufficient to mark every interrupt as defined.
if (interrupt >= interrupt_capabilities.size()) {
return ERR_OUT_OF_RANGE;
}
interrupt_capabilities[interrupt] = true;
}
return RESULT_SUCCESS;
}
ResultCode ProcessCapabilities::HandleProgramTypeFlags(u32 flags) {
const u32 reserved = flags >> 17;
if (reserved != 0) {
return ERR_RESERVED_VALUE;
}
program_type = static_cast<ProgramType>((flags >> 14) & 0b111);
return RESULT_SUCCESS;
}
ResultCode ProcessCapabilities::HandleKernelVersionFlags(u32 flags) {
// Yes, the internal member variable is checked in the actual kernel here.
// This might look odd for options that are only allowed to be initialized
// just once, however the kernel has a separate initialization function for
// kernel processes and userland processes. The kernel variant sets this
// member variable ahead of time.
const u32 major_version = kernel_version >> 19;
if (major_version != 0 || flags < 0x80000) {
return ERR_INVALID_CAPABILITY_DESCRIPTOR;
}
kernel_version = flags;
return RESULT_SUCCESS;
}
ResultCode ProcessCapabilities::HandleHandleTableFlags(u32 flags) {
const u32 reserved = flags >> 26;
if (reserved != 0) {
return ERR_RESERVED_VALUE;
}
handle_table_size = (flags >> 16) & 0x3FF;
return RESULT_SUCCESS;
}
ResultCode ProcessCapabilities::HandleDebugFlags(u32 flags) {
const u32 reserved = flags >> 19;
if (reserved != 0) {
return ERR_RESERVED_VALUE;
}
is_debuggable = (flags & 0x20000) != 0;
can_force_debug = (flags & 0x40000) != 0;
return RESULT_SUCCESS;
}
} // namespace Kernel

View File

@@ -0,0 +1,264 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <bitset>
#include "common/common_types.h"
union ResultCode;
namespace Kernel {
class VMManager;
/// The possible types of programs that may be indicated
/// by the program type capability descriptor.
enum class ProgramType {
SysModule,
Application,
Applet,
};
/// Handles kernel capability descriptors that are provided by
/// application metadata. These descriptors provide information
/// that alters certain parameters for kernel process instance
/// that will run said application (or applet).
///
/// Capabilities are a sequence of flag descriptors, that indicate various
/// configurations and constraints for a particular process.
///
/// Flag types are indicated by a sequence of set low bits. E.g. the
/// types are indicated with the low bits as follows (where x indicates "don't care"):
///
/// - Priority and core mask : 0bxxxxxxxxxxxx0111
/// - Allowed service call mask: 0bxxxxxxxxxxx01111
/// - Map physical memory : 0bxxxxxxxxx0111111
/// - Map IO memory : 0bxxxxxxxx01111111
/// - Interrupts : 0bxxxx011111111111
/// - Application type : 0bxx01111111111111
/// - Kernel version : 0bx011111111111111
/// - Handle table size : 0b0111111111111111
/// - Debugger flags : 0b1111111111111111
///
/// These are essentially a bit offset subtracted by 1 to create a mask.
/// e.g. The first entry in the above list is simply bit 3 (value 8 -> 0b1000)
/// subtracted by one (7 -> 0b0111)
///
/// An example of a bit layout (using the map physical layout):
/// <example>
/// The MapPhysical type indicates a sequence entry pair of:
///
/// [initial, memory_flags], where:
///
/// initial:
/// bits:
/// 7-24: Starting page to map memory at.
/// 25 : Indicates if the memory should be mapped as read only.
///
/// memory_flags:
/// bits:
/// 7-20 : Number of pages to map
/// 21-25: Seems to be reserved (still checked against though)
/// 26 : Whether or not the memory being mapped is IO memory, or physical memory
/// </example>
///
class ProcessCapabilities {
public:
using InterruptCapabilities = std::bitset<1024>;
using SyscallCapabilities = std::bitset<128>;
ProcessCapabilities() = default;
ProcessCapabilities(const ProcessCapabilities&) = delete;
ProcessCapabilities(ProcessCapabilities&&) = default;
ProcessCapabilities& operator=(const ProcessCapabilities&) = delete;
ProcessCapabilities& operator=(ProcessCapabilities&&) = default;
/// Initializes this process capabilities instance for a kernel process.
///
/// @param capabilities The capabilities to parse
/// @param num_capabilities The number of capabilities to parse.
/// @param vm_manager The memory manager to use for handling any mapping-related
/// operations (such as mapping IO memory, etc).
///
/// @returns RESULT_SUCCESS if this capabilities instance was able to be initialized,
/// otherwise, an error code upon failure.
///
ResultCode InitializeForKernelProcess(const u32* capabilities, std::size_t num_capabilities,
VMManager& vm_manager);
/// Initializes this process capabilities instance for a userland process.
///
/// @param capabilities The capabilities to parse.
/// @param num_capabilities The total number of capabilities to parse.
/// @param vm_manager The memory manager to use for handling any mapping-related
/// operations (such as mapping IO memory, etc).
///
/// @returns RESULT_SUCCESS if this capabilities instance was able to be initialized,
/// otherwise, an error code upon failure.
///
ResultCode InitializeForUserProcess(const u32* capabilities, std::size_t num_capabilities,
VMManager& vm_manager);
/// Initializes this process capabilities instance for a process that does not
/// have any metadata to parse.
///
/// This is necessary, as we allow running raw executables, and the internal
/// kernel process capabilities also determine what CPU cores the process is
/// allowed to run on, and what priorities are allowed for threads. It also
/// determines the max handle table size, what the program type is, whether or
/// not the process can be debugged, or whether it's possible for a process to
/// forcibly debug another process.
///
/// Given the above, this essentially enables all capabilities across the board
/// for the process. It allows the process to:
///
/// - Run on any core
/// - Use any thread priority
/// - Use the maximum amount of handles a process is allowed to.
/// - Be debuggable
/// - Forcibly debug other processes.
///
/// Note that this is not a behavior that the kernel allows a process to do via
/// a single function like this. This is yuzu-specific behavior to handle
/// executables with no capability descriptors whatsoever to derive behavior from.
/// It being yuzu-specific is why this is also not the default behavior and not
/// done by default in the constructor.
///
void InitializeForMetadatalessProcess();
/// Gets the allowable core mask
u64 GetCoreMask() const {
return core_mask;
}
/// Gets the allowable priority mask
u64 GetPriorityMask() const {
return priority_mask;
}
/// Gets the SVC access permission bits
const SyscallCapabilities& GetServiceCapabilities() const {
return svc_capabilities;
}
/// Gets the valid interrupt bits.
const InterruptCapabilities& GetInterruptCapabilities() const {
return interrupt_capabilities;
}
/// Gets the program type for this process.
ProgramType GetProgramType() const {
return program_type;
}
/// Gets the number of total allowable handles for the process' handle table.
u32 GetHandleTableSize() const {
return handle_table_size;
}
/// Gets the kernel version value.
u32 GetKernelVersion() const {
return kernel_version;
}
/// Whether or not this process can be debugged.
bool IsDebuggable() const {
return is_debuggable;
}
/// Whether or not this process can forcibly debug another
/// process, even if that process is not considered debuggable.
bool CanForceDebug() const {
return can_force_debug;
}
private:
/// Attempts to parse a given sequence of capability descriptors.
///
/// @param capabilities The sequence of capability descriptors to parse.
/// @param num_capabilities The number of descriptors within the given sequence.
/// @param vm_manager The memory manager that will perform any memory
/// mapping if necessary.
///
/// @return RESULT_SUCCESS if no errors occur, otherwise an error code.
///
ResultCode ParseCapabilities(const u32* capabilities, std::size_t num_capabilities,
VMManager& vm_manager);
/// Attempts to parse a capability descriptor that is only represented by a
/// single flag set.
///
/// @param set_flags Running set of flags that are used to catch
/// flags being initialized more than once when they shouldn't be.
/// @param set_svc_bits Running set of bits representing the allowed supervisor calls mask.
/// @param flag The flag to attempt to parse.
/// @param vm_manager The memory manager that will perform any memory
/// mapping if necessary.
///
/// @return RESULT_SUCCESS if no errors occurred, otherwise an error code.
///
ResultCode ParseSingleFlagCapability(u32& set_flags, u32& set_svc_bits, u32 flag,
VMManager& vm_manager);
/// Clears the internal state of this process capability instance. Necessary,
/// to have a sane starting point due to us allowing running executables without
/// configuration metadata. We assume a process is not going to have metadata,
/// and if it turns out that the process does, in fact, have metadata, then
/// we attempt to parse it. Thus, we need this to reset data members back to
/// a good state.
///
/// DO NOT ever make this a public member function. This isn't an invariant
/// anything external should depend upon (and if anything comes to rely on it,
/// you should immediately be questioning the design of that thing, not this
/// class. If the kernel itself can run without depending on behavior like that,
/// then so can yuzu).
///
void Clear();
/// Handles flags related to the priority and core number capability flags.
ResultCode HandlePriorityCoreNumFlags(u32 flags);
/// Handles flags related to determining the allowable SVC mask.
ResultCode HandleSyscallFlags(u32& set_svc_bits, u32 flags);
/// Handles flags related to mapping physical memory pages.
ResultCode HandleMapPhysicalFlags(u32 flags, u32 size_flags, VMManager& vm_manager);
/// Handles flags related to mapping IO pages.
ResultCode HandleMapIOFlags(u32 flags, VMManager& vm_manager);
/// Handles flags related to the interrupt capability flags.
ResultCode HandleInterruptFlags(u32 flags);
/// Handles flags related to the program type.
ResultCode HandleProgramTypeFlags(u32 flags);
/// Handles flags related to the handle table size.
ResultCode HandleHandleTableFlags(u32 flags);
/// Handles flags related to the kernel version capability flags.
ResultCode HandleKernelVersionFlags(u32 flags);
/// Handles flags related to debug-specific capabilities.
ResultCode HandleDebugFlags(u32 flags);
SyscallCapabilities svc_capabilities;
InterruptCapabilities interrupt_capabilities;
u64 core_mask = 0;
u64 priority_mask = 0;
u32 handle_table_size = 0;
u32 kernel_version = 0;
ProgramType program_type = ProgramType::SysModule;
bool is_debuggable = false;
bool can_force_debug = false;
};
} // namespace Kernel

View File

@@ -4,46 +4,47 @@
#include <algorithm>
#include "common/assert.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/readable_event.h"
#include "core/hle/kernel/thread.h"
namespace Kernel {
Event::Event(KernelCore& kernel) : WaitObject{kernel} {}
Event::~Event() = default;
ReadableEvent::ReadableEvent(KernelCore& kernel) : WaitObject{kernel} {}
ReadableEvent::~ReadableEvent() = default;
SharedPtr<Event> Event::Create(KernelCore& kernel, ResetType reset_type, std::string name) {
SharedPtr<Event> evt(new Event(kernel));
evt->signaled = false;
evt->reset_type = reset_type;
evt->name = std::move(name);
return evt;
}
bool Event::ShouldWait(Thread* thread) const {
bool ReadableEvent::ShouldWait(Thread* thread) const {
return !signaled;
}
void Event::Acquire(Thread* thread) {
void ReadableEvent::Acquire(Thread* thread) {
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
if (reset_type == ResetType::OneShot)
signaled = false;
}
void Event::Signal() {
void ReadableEvent::Signal() {
signaled = true;
WakeupAllWaitingThreads();
}
void Event::Clear() {
void ReadableEvent::Clear() {
signaled = false;
}
void Event::WakeupAllWaitingThreads() {
ResultCode ReadableEvent::Reset() {
if (!signaled) {
return ERR_INVALID_STATE;
}
Clear();
return RESULT_SUCCESS;
}
void ReadableEvent::WakeupAllWaitingThreads() {
WaitObject::WakeupAllWaitingThreads();
if (reset_type == ResetType::Pulse)

View File

@@ -0,0 +1,66 @@
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/wait_object.h"
union ResultCode;
namespace Kernel {
class KernelCore;
class WritableEvent;
class ReadableEvent final : public WaitObject {
friend class WritableEvent;
public:
~ReadableEvent() override;
std::string GetTypeName() const override {
return "ReadableEvent";
}
std::string GetName() const override {
return name;
}
ResetType GetResetType() const {
return reset_type;
}
static const HandleType HANDLE_TYPE = HandleType::ReadableEvent;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
bool ShouldWait(Thread* thread) const override;
void Acquire(Thread* thread) override;
void WakeupAllWaitingThreads() override;
/// Unconditionally clears the readable event's state.
void Clear();
/// Clears the readable event's state if and only if it
/// has already been signaled.
///
/// @pre The event must be in a signaled state. If this event
/// is in an unsignaled state and this function is called,
/// then ERR_INVALID_STATE will be returned.
ResultCode Reset();
private:
explicit ReadableEvent(KernelCore& kernel);
void Signal();
ResetType reset_type;
bool signaled;
std::string name; ///< Name of event (optional)
};
} // namespace Kernel

View File

@@ -2,12 +2,16 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <cstring>
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/resource_limit.h"
#include "core/hle/result.h"
namespace Kernel {
namespace {
constexpr std::size_t ResourceTypeToIndex(ResourceType type) {
return static_cast<std::size_t>(type);
}
} // Anonymous namespace
ResourceLimit::ResourceLimit(KernelCore& kernel) : Object{kernel} {}
ResourceLimit::~ResourceLimit() = default;
@@ -19,59 +23,22 @@ SharedPtr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel, std::string n
return resource_limit;
}
s32 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const {
switch (resource) {
case ResourceType::Commit:
return current_commit;
case ResourceType::Thread:
return current_threads;
case ResourceType::Event:
return current_events;
case ResourceType::Mutex:
return current_mutexes;
case ResourceType::Semaphore:
return current_semaphores;
case ResourceType::Timer:
return current_timers;
case ResourceType::SharedMemory:
return current_shared_mems;
case ResourceType::AddressArbiter:
return current_address_arbiters;
case ResourceType::CPUTime:
return current_cpu_time;
default:
LOG_ERROR(Kernel, "Unknown resource type={:08X}", static_cast<u32>(resource));
UNIMPLEMENTED();
return 0;
}
s64 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const {
return values.at(ResourceTypeToIndex(resource));
}
u32 ResourceLimit::GetMaxResourceValue(ResourceType resource) const {
switch (resource) {
case ResourceType::Priority:
return max_priority;
case ResourceType::Commit:
return max_commit;
case ResourceType::Thread:
return max_threads;
case ResourceType::Event:
return max_events;
case ResourceType::Mutex:
return max_mutexes;
case ResourceType::Semaphore:
return max_semaphores;
case ResourceType::Timer:
return max_timers;
case ResourceType::SharedMemory:
return max_shared_mems;
case ResourceType::AddressArbiter:
return max_address_arbiters;
case ResourceType::CPUTime:
return max_cpu_time;
default:
LOG_ERROR(Kernel, "Unknown resource type={:08X}", static_cast<u32>(resource));
UNIMPLEMENTED();
return 0;
s64 ResourceLimit::GetMaxResourceValue(ResourceType resource) const {
return limits.at(ResourceTypeToIndex(resource));
}
ResultCode ResourceLimit::SetLimitValue(ResourceType resource, s64 value) {
const auto index = ResourceTypeToIndex(resource);
if (value < values[index]) {
return ERR_INVALID_STATE;
}
values[index] = value;
return RESULT_SUCCESS;
}
} // namespace Kernel

View File

@@ -4,32 +4,30 @@
#pragma once
#include <array>
#include "common/common_types.h"
#include "core/hle/kernel/object.h"
union ResultCode;
namespace Kernel {
class KernelCore;
enum class ResourceLimitCategory : u8 {
APPLICATION = 0,
SYS_APPLET = 1,
LIB_APPLET = 2,
OTHER = 3
enum class ResourceType : u32 {
PhysicalMemory,
Threads,
Events,
TransferMemory,
Sessions,
// Used as a count, not an actual type.
ResourceTypeCount
};
enum class ResourceType {
Priority = 0,
Commit = 1,
Thread = 2,
Event = 3,
Mutex = 4,
Semaphore = 5,
Timer = 6,
SharedMemory = 7,
AddressArbiter = 8,
CPUTime = 9,
};
constexpr bool IsValidResourceType(ResourceType type) {
return type < ResourceType::ResourceTypeCount;
}
class ResourceLimit final : public Object {
public:
@@ -55,61 +53,51 @@ public:
* @param resource Requested resource type
* @returns The current value of the resource type
*/
s32 GetCurrentResourceValue(ResourceType resource) const;
s64 GetCurrentResourceValue(ResourceType resource) const;
/**
* Gets the max value for the specified resource.
* @param resource Requested resource type
* @returns The max value of the resource type
*/
u32 GetMaxResourceValue(ResourceType resource) const;
s64 GetMaxResourceValue(ResourceType resource) const;
/// Name of resource limit object.
std::string name;
/// Max thread priority that a process in this category can create
s32 max_priority = 0;
/// Max memory that processes in this category can use
s32 max_commit = 0;
///< Max number of objects that can be collectively created by the processes in this category
s32 max_threads = 0;
s32 max_events = 0;
s32 max_mutexes = 0;
s32 max_semaphores = 0;
s32 max_timers = 0;
s32 max_shared_mems = 0;
s32 max_address_arbiters = 0;
/// Max CPU time that the processes in this category can utilize
s32 max_cpu_time = 0;
// TODO(Subv): Increment these in their respective Kernel::T::Create functions, keeping in mind
// that APPLICATION resource limits should not be affected by the objects created by service
// modules.
// Currently we have no way of distinguishing if a Create was called by the running application,
// or by a service module. Approach this once we have separated the service modules into their
// own processes
/// Current memory that the processes in this category are using
s32 current_commit = 0;
///< Current number of objects among all processes in this category
s32 current_threads = 0;
s32 current_events = 0;
s32 current_mutexes = 0;
s32 current_semaphores = 0;
s32 current_timers = 0;
s32 current_shared_mems = 0;
s32 current_address_arbiters = 0;
/// Current CPU time that the processes in this category are utilizing
s32 current_cpu_time = 0;
/**
* Sets the limit value for a given resource type.
*
* @param resource The resource type to apply the limit to.
* @param value The limit to apply to the given resource type.
*
* @return A result code indicating if setting the limit value
* was successful or not.
*
* @note The supplied limit value *must* be greater than or equal to
* the current resource value for the given resource type,
* otherwise ERR_INVALID_STATE will be returned.
*/
ResultCode SetLimitValue(ResourceType resource, s64 value);
private:
explicit ResourceLimit(KernelCore& kernel);
~ResourceLimit() override;
// TODO(Subv): Increment resource limit current values in their respective Kernel::T::Create
// functions
//
// Currently we have no way of distinguishing if a Create was called by the running application,
// or by a service module. Approach this once we have separated the service modules into their
// own processes
using ResourceArray =
std::array<s64, static_cast<std::size_t>(ResourceType::ResourceTypeCount)>;
/// Maximum values a resource type may reach.
ResourceArray limits{};
/// Current resource limit values.
ResourceArray values{};
/// Name of resource limit object.
std::string name;
};
} // namespace Kernel

View File

@@ -9,6 +9,7 @@
#include "common/logging/log.h"
#include "core/arm/arm_interface.h"
#include "core/core.h"
#include "core/core_cpu.h"
#include "core/core_timing.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
@@ -179,4 +180,69 @@ void Scheduler::SetThreadPriority(Thread* thread, u32 priority) {
ready_queue.prepare(priority);
}
Thread* Scheduler::GetNextSuggestedThread(u32 core, u32 maximum_priority) const {
std::lock_guard<std::mutex> lock(scheduler_mutex);
const u32 mask = 1U << core;
return ready_queue.get_first_filter([mask, maximum_priority](Thread const* thread) {
return (thread->GetAffinityMask() & mask) != 0 && thread->GetPriority() < maximum_priority;
});
}
void Scheduler::YieldWithoutLoadBalancing(Thread* thread) {
ASSERT(thread != nullptr);
// Avoid yielding if the thread isn't even running.
ASSERT(thread->GetStatus() == ThreadStatus::Running);
// Sanity check that the priority is valid
ASSERT(thread->GetPriority() < THREADPRIO_COUNT);
// Yield this thread -- sleep for zero time and force reschedule to different thread
WaitCurrentThread_Sleep();
GetCurrentThread()->WakeAfterDelay(0);
}
void Scheduler::YieldWithLoadBalancing(Thread* thread) {
ASSERT(thread != nullptr);
const auto priority = thread->GetPriority();
const auto core = static_cast<u32>(thread->GetProcessorID());
// Avoid yielding if the thread isn't even running.
ASSERT(thread->GetStatus() == ThreadStatus::Running);
// Sanity check that the priority is valid
ASSERT(priority < THREADPRIO_COUNT);
// Sleep for zero time to be able to force reschedule to different thread
WaitCurrentThread_Sleep();
GetCurrentThread()->WakeAfterDelay(0);
Thread* suggested_thread = nullptr;
// Search through all of the cpu cores (except this one) for a suggested thread.
// Take the first non-nullptr one
for (unsigned cur_core = 0; cur_core < Core::NUM_CPU_CORES; ++cur_core) {
const auto res =
Core::System::GetInstance().CpuCore(cur_core).Scheduler().GetNextSuggestedThread(
core, priority);
// If scheduler provides a suggested thread
if (res != nullptr) {
// And its better than the current suggested thread (or is the first valid one)
if (suggested_thread == nullptr ||
suggested_thread->GetPriority() > res->GetPriority()) {
suggested_thread = res;
}
}
}
// If a suggested thread was found, queue that for this core
if (suggested_thread != nullptr)
suggested_thread->ChangeCore(core, suggested_thread->GetAffinityMask());
}
void Scheduler::YieldAndWaitForLoadBalancing(Thread* thread) {
UNIMPLEMENTED_MSG("Wait for load balancing thread yield type is not implemented!");
}
} // namespace Kernel

View File

@@ -51,6 +51,75 @@ public:
/// Sets the priority of a thread in the scheduler
void SetThreadPriority(Thread* thread, u32 priority);
/// Gets the next suggested thread for load balancing
Thread* GetNextSuggestedThread(u32 core, u32 minimum_priority) const;
/**
* YieldWithoutLoadBalancing -- analogous to normal yield on a system
* Moves the thread to the end of the ready queue for its priority, and then reschedules the
* system to the new head of the queue.
*
* Example (Single Core -- but can be extrapolated to multi):
* ready_queue[prio=0]: ThreadA, ThreadB, ThreadC (->exec order->)
* Currently Running: ThreadR
*
* ThreadR calls YieldWithoutLoadBalancing
*
* ThreadR is moved to the end of ready_queue[prio=0]:
* ready_queue[prio=0]: ThreadA, ThreadB, ThreadC, ThreadR (->exec order->)
* Currently Running: Nothing
*
* System is rescheduled (ThreadA is popped off of queue):
* ready_queue[prio=0]: ThreadB, ThreadC, ThreadR (->exec order->)
* Currently Running: ThreadA
*
* If the queue is empty at time of call, no yielding occurs. This does not cross between cores
* or priorities at all.
*/
void YieldWithoutLoadBalancing(Thread* thread);
/**
* YieldWithLoadBalancing -- yield but with better selection of the new running thread
* Moves the current thread to the end of the ready queue for its priority, then selects a
* 'suggested thread' (a thread on a different core that could run on this core) from the
* scheduler, changes its core, and reschedules the current core to that thread.
*
* Example (Dual Core -- can be extrapolated to Quad Core, this is just normal yield if it were
* single core):
* ready_queue[core=0][prio=0]: ThreadA, ThreadB (affinities not pictured as irrelevant
* ready_queue[core=1][prio=0]: ThreadC[affinity=both], ThreadD[affinity=core1only]
* Currently Running: ThreadQ on Core 0 || ThreadP on Core 1
*
* ThreadQ calls YieldWithLoadBalancing
*
* ThreadQ is moved to the end of ready_queue[core=0][prio=0]:
* ready_queue[core=0][prio=0]: ThreadA, ThreadB
* ready_queue[core=1][prio=0]: ThreadC[affinity=both], ThreadD[affinity=core1only]
* Currently Running: ThreadQ on Core 0 || ThreadP on Core 1
*
* A list of suggested threads for each core is compiled
* Suggested Threads: {ThreadC on Core 1}
* If this were quad core (as the switch is), there could be between 0 and 3 threads in this
* list. If there are more than one, the thread is selected by highest prio.
*
* ThreadC is core changed to Core 0:
* ready_queue[core=0][prio=0]: ThreadC, ThreadA, ThreadB, ThreadQ
* ready_queue[core=1][prio=0]: ThreadD
* Currently Running: None on Core 0 || ThreadP on Core 1
*
* System is rescheduled (ThreadC is popped off of queue):
* ready_queue[core=0][prio=0]: ThreadA, ThreadB, ThreadQ
* ready_queue[core=1][prio=0]: ThreadD
* Currently Running: ThreadC on Core 0 || ThreadP on Core 1
*
* If no suggested threads can be found this will behave just as normal yield. If there are
* multiple candidates for the suggested thread on a core, the highest prio is taken.
*/
void YieldWithLoadBalancing(Thread* thread);
/// Currently unknown -- asserts as unimplemented on call
void YieldAndWaitForLoadBalancing(Thread* thread);
/// Returns a list of all threads managed by the scheduler
const std::vector<SharedPtr<Thread>>& GetThreadList() const {
return thread_list;

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