Compare commits

..

291 Commits

Author SHA1 Message Date
Wunkolo d9b1199ffb cpu_detect: Revert __cpuid{ex} array-type argument
Restores compatibility with MSVC's `__cpuid` intrinsic.
2022-03-09 19:50:01 -08:00
bunnei 9a97ef4647 Merge pull request #7936 from Wunkolo/cpu_detect
cpu_detect: Refactor detection of processor features
2022-03-09 15:34:42 -08:00
Wunkolo 873a9fa7e5 cpu_detect: Add missing lzcnt detection 2022-03-09 13:57:47 -08:00
Wunkolo ec5f3351b6 cpu_detect: Refactor cpu/manufacturer identification
Set the zero-enum value to Unknown
Move the Manufacterer enum into the CPUCaps structure namespace
Add "ParseManufacturer" utility-function
Fix cpu/brand string buffer sizes(!)
2022-03-09 13:57:47 -08:00
Wunkolo 86e9e60f07 cpu_detect: Update array-types to span and array
Update some uses of `int` into some more explicitly sized types as well
2022-03-09 13:57:47 -08:00
Wunkolo 3c33ba7f18 cpu_detect: Utilize Bit<N> utility function 2022-03-09 13:57:47 -08:00
Wunkolo d233de8194 cpu_detect: Compact capability fields
As this structure gets more explicit, bools can be bitfields and
small enums can use smaller types for their span of values.
2022-03-09 13:57:47 -08:00
Wunkolo add2cfcb96 bit_util: Add bit utility function
Extracts a singular bit, as a bool, from the specified compile-time index.
2022-03-09 13:57:47 -08:00
bunnei 6f670381cf Merge pull request #7975 from bunnei/ldr-fix
hle: service: ldr: Use deterministic addresses when mapping NROs.
2022-03-08 17:39:03 -08:00
bunnei 853e58e593 hle: service: ldr: Use deterministic addresses when mapping NROs.
- Instead of randomization, choose in-order addresses for where to map NROs into memory.
- This results in predictable behavior when debugging and consistent behavior when reproducing issues.
2022-03-08 17:38:20 -08:00
bunnei f2743b41b0 Merge pull request #7986 from lat9nq/vk-callback
core, video_core: Fix two crashes when failing to create the emulated GPU instance
2022-03-08 12:36:57 -08:00
Fernando S 35309f27ed Merge pull request #7989 from degasus/maxwell_LUT3
shader_recompiler/LOP3: Use brute force python results within switch/case.
2022-03-08 15:40:31 +01:00
Markus Wick c78c8190d5 shader_recompiler/LOP3: Use brute force python results within switch/case.
Thanks to @asLody for optimizing this function. This raised the focus that this function should be optimized more.

The current table assumes that the host GPU is able to invert for free, so only AND,OR,XOR are accumulated in the performance metrik.

Performance results:

Instructions
0: 8
1: 30
2: 114
3: 80
4: 24

Latency
0: 8
1: 30
2: 194
3: 24
2022-03-08 09:44:28 +01:00
bunnei 1f37896066 Merge pull request #7974 from bunnei/improve-code-mem
Kernel Memory Updates (Part 5): Revamp MapCodeMemory and UnmapCodeMemory.
2022-03-07 20:28:39 -08:00
bunnei 749f76e6fe hle: kernel: KPageTable: Improve implementations of MapCodeMemory and UnmapCodeMemory.
- This makes these functions more accurate to the real HOS implementations.
- Fixes memory access issues in Super Smash Bros. Ultimate that occur when un/mapping NROs.
2022-03-07 17:18:20 -08:00
lat9nq b5e60ae1b0 video_core: Cancel Scoped's exit call on GPU failure
When CreateRenderer fails, the GraphicsContext that was std::move'd into
it is destroyed before the Scoped that was created to manage its
currency. In that case, the GraphicsContext::Scoped will still call its
destructor at the ending of the function. And because the context is
destroyed, the Scoped will cause a crash as it attempts to call a
destroyed object's DoneCurrent function.

Since we know when the call would be invalid, call the Scoped's Cancel
method. This prevents it from calling a method on a destroyed object.
2022-03-07 18:21:56 -05:00
lat9nq 1f24a4e520 emu_window: Create a way to Cancel the exit of a Scoped
If a GraphicsContext is destroyed before its Scoped is destroyed, this
causes a crash as the Scoped tries to call a method in the destroyed
context on exit.

Add a way to Cancel the call when we know that calling the
GraphicsContext will not work.
2022-03-07 18:21:56 -05:00
Fernando S 58b52f4884 Merge pull request #7930 from asLody/dma-semaphore
MaxwellDMA: Implement semaphore operations
2022-03-07 21:53:38 +01:00
lat9nq 381f1dd2c9 core: Don't shutdown a null GPU
When CreateGPU fails, yuzu would try and shutdown the GPU instance
regardless of whether any instance was actually created.

Check for nullptr before calling its methods to prevent a crash.
2022-03-07 15:25:20 -05:00
Lody 4498908e72 MaxwellDMA: Implement semaphore operations 2022-03-07 13:46:18 +08:00
Ameer J 370e480c8c gl_graphics_pipeline: Improve shader builder synchronization using fences (#7969)
* gl_graphics_pipeline: Improve shader builder synchronization

Make use of GLsync objects to ensure better synchronization between shader builder threads and the main context

* gl_graphics_pipeline: Make built_fence access threadsafe

* gl_graphics_pipeline: Use GLsync objects only when building in parallel

* gl_graphics_pipeline: Replace GetSync calls with non-blocking waits

The spec states that a ClientWait on a Fence object ensures the changes propagate to the calling context
2022-03-06 16:46:49 +01:00
Fernando S 5192c64991 Merge pull request #7973 from Morph1984/debug-crash
host_memory: Fix fastmem crashes in debug builds
2022-03-06 04:49:27 +01:00
bunnei a31c195749 Merge pull request #7935 from Wunkolo/logging-join-fix
logging: Convert `backend_thread` into an `std::jthread`
2022-03-02 19:09:26 -08:00
bunnei 3ab82e7582 Merge pull request #7956 from bunnei/improve-mem-manager
Kernel Memory Updates (Part 4): Revamp KMemoryManager & other fixes
2022-03-02 17:55:51 -08:00
Morph b33f23cc46 host_memory: Fix fastmem crashes in debug builds
It is possible for virtual_offset to not be 0 when the iterator is at the beginning, and thus, std::prev(it) may be evaluated, leading to a crash in debug mode.

Co-Authored-By: Fernando S. <1731197+FernandoS27@users.noreply.github.com>
2022-03-02 18:36:59 -05:00
Fernando S e06a133717 Merge pull request #7959 from merryhime/cmpxchg
dynarmic: Inline exclusive memory accesses
2022-03-01 22:50:52 +01:00
Mai M 3c47570563 Merge pull request #7967 from zhaobot/tx-update-20220301023432
Update translations (2022-03-01)
2022-03-01 00:50:28 -05:00
The yuzu Community b4c919eba8 Update translations (2022-03-01) 2022-03-01 02:34:54 +00:00
Mai M 96dbb9233a Merge pull request #7963 from ameerj/gl_fence_nit
gl_fence_manager: Minor optimization to signal querying
2022-02-28 19:53:24 -05:00
Mai M fdf81cd112 Merge pull request #7966 from merryhime/cmake-ffmpeg-endif
ffmpeg: Fix mis-maching argument warning for endif
2022-02-28 19:51:10 -05:00
Merry c4df0d8cdc ffmpeg: Fix mis-maching argument warning for endif 2022-02-28 21:08:12 +00:00
merry ec9689f200 dynarmic: Update to latest master 2022-02-28 20:10:13 +00:00
bunnei 14d28a043d hle: kernel: Re-create memory layout at initialization.
- As this can only be derived once.
2022-02-27 18:00:09 -08:00
bunnei 16e5954fcb hle: kernel: Remove unused pool locals. 2022-02-27 18:00:09 -08:00
bunnei f87f076162 hle: kernel: k_memory_manager: Rework for latest kernel behavior.
- Updates the KMemoryManager implementation against latest documentation.
- Reworks KMemoryLayout to be accessed throughout the kernel.
- Fixes an issue with pool sizes being incorrectly reported.
2022-02-27 18:00:09 -08:00
Wunkolo 913c2bd2cb logging: Convert backend_thread into an std::jthread
Was getting an unhandled `invalid_argument` [exception](https://en.cppreference.com/w/cpp/thread/thread/join) during
shutdown on my linux machine. This removes the need for a `StopBackendThread` function entirely since `jthread`
[automatically handles both checking if the thread is joinable and stopping the token before attempting to join](https://en.cppreference.com/w/cpp/thread/jthread/~jthread) in the case that `StartBackendThread` was never called.
2022-02-27 16:23:52 -08:00
ameerj 7f7df43da2 gl_fence_manager: Minor optimization to signal querying
Per the spec, bufSize is the number of integers that will be written, in this case, 1.

Also, the length argument is optional if the information of the number of elements written is not needed.
2022-02-27 17:57:33 -05:00
merry 16784e5bb3 dynarmic: Inline exclusive memory accesses
Inlines implementation of exclusive instructions into JITted code,
improving performance of applications relying heavily on these
instructions.

We also fastmem these instructions for additional speed, with
support for appropriate recompilation on fastmem failure.

An unsafe optimization to disable the intercore global_monitor is also
provided, should one wish to rely solely on cmpxchg semantics for
safety.

See also: merryhime/dynarmic#664
2022-02-27 19:40:05 +00:00
bunnei adbb9c2b00 hle: kernel: k_page_heap: GetPhysicalAddr can be const. 2022-02-27 10:34:02 -08:00
bunnei f7e65eb971 hle: kernel: k_page_heap: Remove superfluous consexpr. 2022-02-27 10:34:02 -08:00
bunnei 06e2b76c75 hle: kernel: k_page_heap: Various updates and improvements.
- KPageHeap tracks physical addresses, not virtual addresses.
- Various updates and improvements to match latest documentation for this type.
2022-02-27 10:34:02 -08:00
bunnei 5d1a81520c hle: kernel: Add initial_process.h header. 2022-02-27 10:34:02 -08:00
bunnei a6496deeed hle: kernel: board: nx: Add k_memory_layout.h header. 2022-02-27 10:34:02 -08:00
bunnei 9b5e7971dc hle: kernel: k_system_control: Add GetRealMemorySize and update GetKernelPhysicalBaseAddress. 2022-02-27 10:34:02 -08:00
bunnei 18e77a54c3 hle: kernel: k_memory_layout: Add GetPhysicalLinearRegion. 2022-02-27 10:34:02 -08:00
bunnei 06a21ac229 hle: kernel: k_memory_region_types: Update for new regions. 2022-02-27 10:34:02 -08:00
bunnei 96d90be59f Merge pull request #7955 from bunnei/update-dynarmic
externals: Dynarmic: Update to latest rev.
2022-02-26 10:52:47 -08:00
bunnei ce46aa4721 externals: Dynarmic: Update to latest rev.
- Fixes inaccurate size reporting in SpaceRemaining, which caused crashes in yuzu with SSBU.
2022-02-26 09:51:41 -08:00
bunnei 20e9501b0d Merge pull request #7932 from bunnei/extended-mem-layout
Add extended memory layout (6GB) support and improve KResourceLimit management
2022-02-26 01:41:08 -08:00
bunnei 56d9052b73 Merge pull request #7953 from ameerj/radv-rdna2-crash
vulkan_device: Blacklist RADV on RDNA2 from VK_EXT_vertex_input_dynamic_state
2022-02-26 01:19:13 -08:00
Mai M 91d802f68d Merge pull request #7948 from Morph1984/11-11-10-float
maxwell_to_(gl/vk): Add 11_11_10 float vertex format
2022-02-26 00:09:44 -05:00
Ameer J 5f8d6bc504 vulkan_device: Blacklist RADV on RDNA2 from VK_EXT_vertex_input_dynamic_state
RDNA2 devices running under the RADV driver were crashing when VK_EXT_vertex_input_dynamic_state was enabled.

Blacklisting these devices until a proper fix is established.
2022-02-25 23:09:03 -05:00
Morph e292b2d991 maxwell_to_(gl/vk): Add 11_11_10 float vertex format
- Used by パワプロクンポケットR
2022-02-25 17:11:17 -05:00
bunnei 6c9b9b72da Merge pull request #7939 from asLody/fb-format-gbra8
vk_blit_screen: Add missing framebuffer format
2022-02-25 00:58:28 -08:00
bunnei f582a4482d Merge pull request #7927 from german77/amiibo
yuzu: Disconnect amiibos on drag and drop
2022-02-24 23:13:32 -08:00
bunnei 1079215871 Merge pull request #7859 from german77/battery_again
input_common: Remove battery duplicated struct and update every button press
2022-02-24 11:42:51 -08:00
Lody 6978093404 vk_blit_screen: Add missing format bgra8 2022-02-24 19:25:39 +08:00
Mai M 2f45e999d8 Merge pull request #7933 from german77/am_update
service: am: Update enum names to match documentation
2022-02-21 20:42:01 -05:00
Narr the Reg d44464829b service: am: Update enum names to match documentation 2022-02-21 18:00:50 -06:00
bunnei efe50d88ec Merge pull request #7913 from voidanix/anv-fix
vulkan_device: fix missing format in ANV
2022-02-21 14:34:27 -07:00
bunnei 71f62a346d hle: kernel: KSystemControl: Use 6GB memory layout when "use_extended_memory_layout" setting is enabled.
- This uses a larger 6GB DRAM memory layout, which is useful for some mods that require more memory.
2022-02-21 13:07:19 -08:00
bunnei c0e45a3c78 core: device_memory: Use memory size reported by KSystemControl.
- That way, we can consolidate the memory layout to one place.
2022-02-21 13:07:19 -08:00
bunnei 70482e6b26 settings: Add a new "use_extended_memory_layout" setting.
- This will be used to enable emulation of a larger memory arrangement.
2022-02-21 13:07:19 -08:00
bunnei ca5e843bf6 core: hle: kernel: Remove resource limit hack for PhysicalMemory.
- With prior changes, we now report the correct amount of physical memory available to the emulated process.
2022-02-21 12:41:31 -08:00
bunnei a74fddc98f core: hle: kernel: KProcess: Pass in KResourceLimit on process creation.
- This allows us to have a resource limit per process, rather than use the global system resource limit.
2022-02-21 12:41:31 -08:00
bunnei 57ebcbf2c4 core: hle: kernel: KEvent: Pass in owner KProcess on event creation.
- This is necessary to ensure resource limits are freed from the right process.
2022-02-21 12:41:06 -08:00
bunnei c7019db6f4 core: hle: kernel: KResourceLimit: Add a helper function for creating a KResourceLimit for a process. 2022-02-21 12:40:09 -08:00
bunnei 21f5912ec9 Merge pull request #7919 from bunnei/phys-mem-updates
core: hle: kernel: KPageTable: Improve Un/MapPhysicalMemory.
2022-02-21 13:39:05 -07:00
bunnei 8d46c3cc66 Merge pull request #7920 from bunnei/fix-unmap-pages
core: hle: kernel: KPageTable: Fix UnmapPages.
2022-02-21 13:38:52 -07:00
voidanix 7712e46d64 vulkan_device: fix missing format in ANV
Currently Mesa's ANV driver does not support
VK_FORMAT_B5G6R5_UNORM_PACK16, implement an alternative for it.
2022-02-21 09:21:41 +01:00
german77 b504df9d02 yuzu: Remove amiibos on drag and drop 2022-02-20 14:28:21 -06:00
bunnei 92b2e92620 fixup! core: hle: kernel: KPageTable: Improve Un/MapPhysicalMemory. 2022-02-19 00:14:27 -08:00
bunnei 2984695265 Merge pull request #7867 from german77/amiibo
nfp: Improve amiibo support
2022-02-19 00:57:47 -07:00
bunnei c9260a75f6 core: hle: kernel: KPageTable: Fix UnmapPages.
- Fixes a logic bug in KPageTable::UnmapPages.
2022-02-18 23:48:16 -08:00
bunnei 1a16d055df core: hle: kernel: KPageTable: Improve Un/MapPhysicalMemory.
- Improves the implementations of MapPhysicalMemory and UnmapPhysicalMemory to more closely reflect latest HOS.
2022-02-18 23:42:27 -08:00
bunnei 83a84f1c2d Merge pull request #7900 from german77/enter
yuzu: config: Fix mapping issues with the enter key
2022-02-18 15:47:34 -07:00
Mai M 90a4591563 Merge pull request #7909 from Wunkolo/null-visit-ctor
common: Add NullVisitor default constructor
2022-02-18 17:44:02 -05:00
Wunkolo 768fdb269e common: Add NullVisitor default constructor
Addresses https://github.com/yuzu-emu/yuzu/issues/7881 to fix linux
builds.

`YUZU_NON_COPYABLE` deletes the `T(const T&)` constructor which will
cause the implicitly defined default ctor/dtor to no-longer generate.
2022-02-17 06:28:19 -08:00
Mai M c48b9668f0 Merge pull request #7866 from xerpi/svc-OutputDebugString32-CreateCodeMemory32-ControlCodeMemory32
kernel: svc: Add OutputDebugString32, CreateCodeMemory32, ControlCodeMemory32
2022-02-16 22:49:56 -05:00
bunnei 027ff7847c Merge pull request #7878 from german77/mnpp
service/mnpp: Stub mnpp_app
2022-02-16 18:42:49 -07:00
Morph 4514325b9c Merge pull request #7899 from Kelebek1/test
file_sys: Dump patched exefs rather than base
2022-02-16 16:37:09 -05:00
bunnei b5fd9c58cd Merge pull request #7877 from lat9nq/upd_rev
audio_core: Update current process revision
2022-02-15 13:08:40 -07:00
bunnei 910a0fa58e Merge pull request #7891 from Morph1984/buffer_to_string_view
common: fs_util: Add buffer to string view utility functions
2022-02-15 12:02:23 -07:00
Narr the Reg 1e21f5f872 yuzu: config: Fix mapping issues with the enter key 2022-02-15 11:08:11 -06:00
Kelebek1 e1201abc1e Dump patched exefs rather than base 2022-02-15 04:52:28 +00:00
Sergi Granell c3242abe95 kernel: svc: Add OutputDebugString32, CreateCodeMemory32, ControlCodeMemory32
Very straightforward, they are just wrappers to the 64-bit version of
the SVC.
2022-02-15 00:45:19 +01:00
bunnei d81cdd9114 Merge pull request #7871 from german77/svc2
svc: Set unique names for function tables
2022-02-14 16:32:54 -07:00
Mai M 45bcd7f9b8 Merge pull request #7890 from Morph1984/utf8-console
debugger: console: Set console output codepage to UTF-8
2022-02-13 19:54:05 -05:00
Morph 4390370a19 common: fs_util: Add buffer to string view utility functions
These functions allow to construct a string view from an input buffer, avoiding the copy done by the non string view counterparts. However, callers must be cognizant of the viewed buffer's lifetime to avoid a use-after-free.
2022-02-13 18:53:21 -05:00
Morph 54c7af9902 debugger: console: Set console output codepage to UTF-8
This allows the console to display multi-byte encoded characters.
2022-02-13 18:18:05 -05:00
german77 b57d61010f nfp: Allow files without password data 2022-02-13 13:52:34 -06:00
Narr the Reg eaca010ee9 Merge pull request #7887 from lat9nq/stub-is-usb-full-key
hid: Stub IsUsbFullKeyControllerEnabled
2022-02-12 22:22:38 -06:00
lat9nq c5d22952bf hid: Stub IsUsbFullKeyControllerEnabled
Used by Splatoon 2, when opening the inventory from a LAN battle lobby.

Reference: https://switchbrew.org/wiki/HID_services
2022-02-12 15:42:50 -05:00
lat9nq 81806603eb audio_core: Update current process revision
Update CURRENT_PROCESS_REVISION from REV9 to REVA.

Used by Nintendo Entertainment System - Nintendo Switch Online 6.0.0 and
Super Nintendo Entertainment System - Nintendo Switch Online 3.0.0.
2022-02-11 00:56:13 -05:00
bunnei ca9da569ce Merge pull request #7852 from Morph1984/new-uuid
common: Revise and fix the UUID implementation
2022-02-10 21:52:13 -07:00
Narr the Reg 6705439cf3 service/mnpp: Stub mnpp_app
Used in Super Nintendo Entertainment System™ - Nintendo Switch Online
2022-02-10 21:55:28 -06:00
Morph 3799c820ca common: uuid: Use sizeof(u64) instead of 8 in Hash() 2022-02-10 15:03:49 -05:00
bunnei 1105614b86 Merge pull request #7861 from german77/user_features
yuzu: New hotkeys and mute audio on background
2022-02-10 10:06:58 -07:00
Narr the Reg 6a1ad03153 nfp: Separate nfc tag from amiibo data 2022-02-10 10:58:37 -06:00
bunnei fc01074f89 Merge pull request #7860 from german77/no-more-drift
yuzu: Add auto center on right click
2022-02-09 17:52:39 -07:00
bunnei bcd666b86b Merge pull request #7870 from yuzu-emu/fix-codememory-size
hle: kernel: KCodeMemory: Correct m_page_group number of pages.
2022-02-09 11:29:32 -07:00
Narr the Reg d0c7c3f64f svc: Set unique names for function tables 2022-02-08 21:03:31 -06:00
bunnei 862dddf8c9 hle: kernel: KCodeMemory: Remove unused QueryMemory. 2022-02-08 18:49:41 -08:00
bunnei d134ca68c6 hle: kernel: KCodeMemory: Correct m_page_group number of pages.
Credits to @xerpi for finding this issue and pointing it out on #7519.
2022-02-08 18:47:11 -08:00
german77 e35c2fd5d0 nfp: Address compiler issues 2022-02-08 18:52:44 -06:00
Narr the Reg 29f9a454eb nfp: Validate amiibo files 2022-02-08 14:09:30 -06:00
german77 41b65d38fa yuzu: Allow to open and remove the amiibo 2022-02-08 10:08:04 -06:00
german77 fc9abd3c62 nfp: Improve implementation 2022-02-08 10:08:04 -06:00
german77 c001a2af25 nfp: Move IUser class to header and add missing enum and structs 2022-02-07 09:18:22 -06:00
german77 3d24eb54ec nfp: Sort functions by command number 2022-02-07 09:18:22 -06:00
german77 ab93b4c66d yuzu: Mute audio when in background 2022-02-06 20:46:58 -06:00
german77 49eb78497b yuzu: Add docked, GPU accuracy and adapting filter hotkeys 2022-02-06 20:46:58 -06:00
german77 6a4ab3e0d2 yuzu: Add auto center on right click 2022-02-06 19:56:03 -06:00
german77 21742f0096 input_common: Remove battery duplicated struct and update every button press 2022-02-06 18:33:55 -06:00
Morph b720009dc0 Merge pull request #7847 from tech-ticks/master
service: pm: Implement AtmosphereGetProcessInfo
2022-02-05 19:22:45 -05:00
Morph 36910e9020 Merge pull request #7851 from lat9nq/cmd-add-motion
yuzu-cmd: config: Support motion inputs
2022-02-05 19:22:18 -05:00
bunnei 0456ed6b4e Merge pull request #7849 from Morph1984/qt-frameless-window
main: Always remove the frameless window flag when restoring UI state
2022-02-05 15:18:48 -07:00
Morph ec4d7f71fe common: uuid: Return an invalid UUID if conversion from string fails
The string constructor of UUID states:
Should the input string not meet the above requirements, an assert will be triggered and an invalid UUID is set instead.
2022-02-05 13:56:21 -05:00
Morph 25db62ce15 general: Rename NewUUID to UUID, and remove the previous UUID impl
This completes the removal of the old UUID implementation.
2022-02-05 13:56:21 -05:00
Morph dfe11d72e3 profile: Migrate to the new UUID implementation 2022-02-05 13:56:21 -05:00
Morph d94dcaefa0 common: uuid: Add AsU128()
This copies the internal bytes of the UUID into a u128 for backwards compatibility. This should not be used.
2022-02-05 13:56:21 -05:00
Morph f0340b8d22 hle: ipc_helpers: Ignore -Wclass-memaccess
This warning is triggered by GCC when copying into non-trivially default constructible types, as it uses the more restrictive std::is_trivial (which includes std::is_trivially_default_constructible) to determine whether memcpy is safe instead of std::is_trivially_copyable.
2022-02-05 13:56:20 -05:00
Morph ee0547e4c4 service: Migrate to the new UUID implementation 2022-02-05 13:18:46 -05:00
Morph cb30fe50cd input/hid: Migrate to the new UUID implementation 2022-02-05 13:18:41 -05:00
Morph 3271099fea common: Implement NewUUID
This is a fixed and revised implementation of UUID that uses an array of bytes as its internal representation of a UUID instead of a u128 (which was an array of 2 u64s).
In addition to this, the generation of RFC 4122 Version 4 compliant UUIDs is also implemented.
2022-02-05 13:18:31 -05:00
bunnei 5cb1c2ad84 Merge pull request #7842 from german77/vibration_test
yuzu: config: Vibrate the controller while configuring vibration strength
2022-02-05 02:57:26 -07:00
lat9nq 928380ebf9 config: Support motion inputs
Motion inputs were not being read in by the config when yuzu-cmd boots
up. This adds support for those.

While we're at it, make a reference to the current player controls to
improve readability. Also updates the if statements in the Analog and
Button loops with curly braces to keep the style consistent.
2022-02-05 02:31:55 -05:00
bunnei 0ec5b9bff2 Merge pull request #7839 from german77/battery
yuzu: ui: Improve battery symbols
2022-02-04 18:23:35 -07:00
Mai M 7ad17ae397 Merge pull request #7848 from Morph1984/unused-core-include
input_common: Remove unused core include
2022-02-03 23:21:32 -05:00
Morph edbfbf2f2f main: Always remove the frameless window flag when restoring UI state
For unknown reasons, this flag may persist after the application has been closed.
Removing this flag when restoring the UI state ensures that a frameless window will not be shown on startup.
2022-02-03 23:12:49 -05:00
Morph fbefcf7280 input_common: Remove unused core include 2022-02-03 22:44:28 -05:00
tech-ticks 16bf50e610 service: pm: Implement AtmosphereGetProcessInfo 2022-02-04 01:41:36 +01:00
bunnei fc8aef7323 Merge pull request #7811 from german77/analog-mod
input_common: Use attributes for analog range modifiers
2022-02-03 12:21:11 -07:00
bunnei 8ec32e9755 Merge pull request #7814 from FernandoS27/another-bug-in-my-schedule
Vulkan: Fix Scheduler Chunks when their FuncType is 0.
2022-02-02 19:15:06 -07:00
bunnei 03186af6a1 Merge pull request #7835 from bunnei/page-table-lock
hle: kernel: KPageTable: Migrate locks to KScopedLightLock.
2022-02-02 17:58:55 -07:00
Morph d68eb751c5 Merge pull request #7838 from lioncash/noncopy
common_types: Remove NonCopyable struct
2022-02-02 16:04:26 -05:00
Narr the Reg 694c078655 yuzu: config: Vibrate the controller while configuring vibration strength 2022-02-02 14:54:24 -06:00
bunnei 9484519ec3 Merge pull request #7834 from german77/repeat
yuzu: Disable auto repeat on hotkeys again
2022-02-02 13:20:18 -07:00
Narr the Reg 064aa3de11 yuzu: ui: Improve battery symbols 2022-02-02 13:18:06 -06:00
Lioncash ade44ac2ea common_types: Remove NonCopyable struct
Now that we're moved over to the YUZU_ defines, we can get rid of this
struct.
2022-02-02 13:19:01 -05:00
Lioncash f785f73e92 general: Replace NonCopyable struct with equivalents 2022-02-02 13:17:12 -05:00
bunnei 09400e4f4e Merge pull request #7806 from ameerj/atomic64-fallbacks
shaders: Implement U32x2 atomic fallbacks when device does not support int64
2022-02-02 10:57:22 -07:00
Lioncash 76d83ffbec general: Move deleted copy/move constructor/assignment operators to public interface
This allows for better compiler errors, where the compiler will state a
copy or move couldn't occur due to the relevant function being deleted.

Previously a compiler would warn about the relevant function not being
accessible (which, while true, isn't as informative as it could be).
2022-02-02 12:17:08 -05:00
bunnei 72add82ee9 Merge pull request #7807 from german77/moar-buttons
input_common: Add home and hard touch press buttons to UDP controllers
2022-02-01 22:37:13 -07:00
bunnei 995e27e9b7 hle: kernel: KPageTable: Migrate locks to KScopedLightLock.
- More accurately reflects real kernel behavior by using guest locks.
2022-02-01 19:34:24 -08:00
Morph 79e8f4abe8 Merge pull request #7833 from lioncash/file-sys
configure_filesystem: Add missing changeEvent() override
2022-02-01 22:15:37 -05:00
bunnei 404a94a199 Merge pull request #7792 from german77/translate
hotkeys: Don't translate hotkey buttons
2022-02-01 20:07:52 -07:00
Lioncash 40d31b8b8a configure_filesystem: Add missing changeEvent() override
This allows the dialog to be retranslated during runtime if the language
is changed.
2022-02-01 22:03:12 -05:00
Lioncash b9f06bd599 configure_filesystem: Normalize member function casing
All other dialog types we have use CamelCase naming.
2022-02-01 22:01:22 -05:00
Narr the Reg 330b31ae2e yuzu: Disable auto repeat on hotkeys again 2022-02-01 21:00:37 -06:00
bunnei 50e9ba34b4 Merge pull request #7809 from Morph1984/clock-constants
common: wall_clock: Utilize constants for ms, us, and ns ratios
2022-02-01 18:34:31 -07:00
Morph a28a10bc54 Merge pull request #7831 from lioncash/motion
configure_motion_touch: Use functor versions of invokeMethod
2022-02-01 14:48:52 -05:00
Morph cd9345e10c Merge pull request #7830 from lioncash/player-copy
configure_input_player: Avoid unnecessary ParamPackage copies
2022-02-01 14:48:33 -05:00
Lioncash 5c4ed30c21 configure_motion_touch: Use functor versions of invokeMethod
Same behavior, but ensures that the functions we're calling exist, since
they can be checked at compile-time.
2022-02-01 13:22:42 -05:00
Lioncash e2a86e2c8a configure_input_player: Eliminate variable shadowing 2022-02-01 12:54:00 -05:00
Lioncash 2dba59d1ff configure_input_player: std::move input setters in HandleClick 2022-02-01 12:51:03 -05:00
Lioncash 9ba6bab920 configure_input_player: Avoid unnecessary ParamPackage copies
Avoids churning allocations.
2022-02-01 12:20:23 -05:00
Morph f56226e17f Merge pull request #7828 from lioncash/dep
yuzu/game_list: Use non-deprecated version of QString's split() function
2022-02-01 11:45:25 -05:00
Mai M 2ce0410f2c Merge pull request #7827 from FernandoS27/dynamite-costume-with-the-wick-outside
Update dynarmic.
2022-02-01 11:43:31 -05:00
Lioncash cd4aa50207 yuzu/game_list: Use non-deprecated version of QString's split() function
The previous overload of split() was deprecated in 5.14.
2022-02-01 11:41:31 -05:00
Fernando Sahmkow e5c83b5a3e Update dynarmic. 2022-02-01 15:31:02 +01:00
Morph 7432343214 Merge pull request #7825 from lioncash/nodisc2
common/file: Remove [[nodiscard]] from Open()
2022-02-01 02:29:36 -05:00
Lioncash 8f32bab4c9 common/file: Remove [[nodiscard]] from Open()
Since this has a void return value, there's nothing that can actually be
used.
2022-02-01 02:19:21 -05:00
Morph 26a9dc3f65 Merge pull request #7824 from lioncash/scache
video_core/shader_cache: Take std::span in RemoveShadersFromStorage()
2022-02-01 01:58:38 -05:00
Lioncash 360a97ab54 video_core/shader_cache: Remove unused algorithm include 2022-02-01 01:41:05 -05:00
Lioncash 540ed72e99 video_core/shader_cache: Take std::span in RemoveShadersFromStorage()
Same behavior, but without the need to move into the function to avoid
an allocation.
2022-02-01 01:40:41 -05:00
Mai M c81793029d Merge pull request #7822 from zhaobot/tx-update-20220201021425
Update translations (2022-02-01)
2022-01-31 22:15:09 -05:00
The yuzu Community 1e66eaf929 Update translations (2022-02-01) 2022-02-01 02:14:44 +00:00
bunnei 7ddccb55d2 Merge pull request #7821 from german77/espada_aguda
svc: Add 32 bit SynchronizePreemptionState
2022-01-31 19:13:46 -07:00
bunnei 34dc1c8bc2 Merge pull request #7805 from FernandoS27/rodrigo-failed-me
Inline2Memory: Flush before writing buffer.
2022-01-31 18:08:21 -07:00
Narr the Reg 1ed22b4613 svc: Add 32 bit SynchronizePreemptionState
Used by Espgaluda II
2022-01-31 19:02:41 -06:00
Fernando Sahmkow 8a6e6465a7 Rasterizer: Refactor inlineToMemory. 2022-02-01 01:47:28 +01:00
Fernando Sahmkow 35ed051742 Vulkan: Fix Scheduler Chunks when their FuncType is 0. 2022-01-31 17:08:08 +01:00
german77 5bd0c1517f input_common: Use attributes for analog range modifiers 2022-01-30 22:42:40 -06:00
Morph 6267110b69 common: wall_clock: Check precision against the emulated CPU and CNTFRQ
In addition to requiring nanosecond precision, using the native clock requires that the hardware TSC has a precision greater than the emulated CPU and its clock counter.
2022-01-30 12:57:23 -05:00
Morph 4e766280c4 common: wall_clock: Utilize constants for ms, us, and ns ratios 2022-01-30 12:36:56 -05:00
german77 3d2d77eb3f input_common: Add home and hard touch press buttons to UDP controllers 2022-01-30 09:17:22 -06:00
ameerj e394e1ecc4 emit_glsl_atomic: Implement 32x2 fallback atomic ops 2022-01-29 19:56:03 -05:00
ameerj 90a0506d56 lower_int64_to_int32: Add 64-bit atomic fallbacks 2022-01-29 19:56:02 -05:00
ameerj ad58d7eae7 shaders: Add U64->U32x2 Atomic fallback functions 2022-01-29 19:55:53 -05:00
Fernando Sahmkow d0a5a48948 GPU: Improve syncing. 2022-01-29 23:02:04 +01:00
Fernando Sahmkow 4258d515e6 Rasterizer: Implement Inline2Memory Acceleration. 2022-01-29 22:53:27 +01:00
Fernando Sahmkow f54280dafd Inline2Memory: Flush before writting buffer. 2022-01-29 17:42:28 +01:00
Morph 11099dda2e Merge pull request #7791 from german77/wall_clock
wall_clock: Use standard wall clock if rtsc frequency is too low
2022-01-28 20:04:24 -05:00
Morph 64a68ccbb4 Merge pull request #7800 from ameerj/spirv-int64-storage
spirv_atomic: Define U32x2 storage buffers for 64-bit storage atomics
2022-01-28 20:03:50 -05:00
ameerj 4790ba7839 spirv_atomic: Define U32x2 storage buffers for 64-bit storage atomics
Some drivers do not support 64-bit atomics, and fallback to atomically modifying U32x2 vectors. This change ensures that U32x2 storage vectors are defined in the spir-v shader when 64-bit atomics are used.

Fixes a hang on some devices, notably Intel GPUs, when booting Pokemon Legends Arceus
2022-01-28 19:00:04 -05:00
Morph 1900abde13 Merge pull request #7784 from german77/ds5
input_common: Add DS5 to HD rumble list
2022-01-28 18:36:28 -05:00
Morph 60b5670577 Merge pull request #7787 from bunnei/scheduler-deadlock-fix
hle: kernel: KScheduler: Fix deadlock with core waiting for a thread lock that has migrated.
2022-01-28 18:30:29 -05:00
Morph b00406c8e4 Merge pull request #7788 from ameerj/stream-buffer-begin
buffer_cache: Reduce stream buffer allocations when expanding from the left
2022-01-28 18:30:01 -05:00
Morph 8dea7fa129 Merge pull request #7786 from ameerj/vmnmx-sel
video_minimum_maximum: Implement src operand selectors
2022-01-28 18:24:56 -05:00
Morph 2241d8c971 Merge pull request #7799 from ameerj/amd-xfb
emit_spirv: Add Xfb execution mode when transform feedback is used
2022-01-28 17:55:17 -05:00
ameerj beaf7654bb emit_spirv: Add Xfb execution mode when transform feedback is used
Fixes Transform Feedback on Vulkan AMD drivers.
2022-01-28 16:32:48 -05:00
bunnei 0dec42431f Merge pull request #7770 from german77/motion-threshold
input_common: Add option to configure gyro threshold
2022-01-27 15:44:04 -08:00
german77 fea05a17ea hotkeys: Don't translate hotkey buttons 2022-01-27 17:32:48 -06:00
german77 e4c63d432d wall_clock: use standard wall clock if rtsc frequency is too low 2022-01-27 17:07:52 -06:00
ameerj f300a1d54b buffer_cache: Reduce stream buffer allocations when expanding from the left
The existing stream buffer optimization accounts for size increases at the end of the allocated buffer.
This adds the same optimization, increasing the size from the beginning of the buffer as well to reduce buffer allocations when expanding the same buffer from the left.
2022-01-27 15:31:43 -05:00
bunnei 3a1a3dd0db hle: kernel: KScheduler: Fix deadlock with core waiting for a thread lock that has migrated.
- Previously, it was possible for a thread migration to occur from core A to core B.
- Next, core B waits on a guest lock that must be released by a thread queued for core A.
- Meanwhile, core A is still waiting on the core B's current thread lock - resulting in a deadlock.
- Fix this by try-locking the thread lock.
- Fixes softlocks in FF8 and Pokemon Legends Arceus.
2022-01-27 12:17:14 -08:00
ameerj 74e6e3623f video_minimum_maximum: Implement src operand selectors
Used by Pokemon Legends: Arceus
2022-01-27 14:55:08 -05:00
Morph 8a244dd3d3 Merge pull request #7783 from lioncash/abi-cexpr
common/xbyak_api: Make BuildRegSet() constexpr
2022-01-27 10:29:34 -05:00
Narr the Reg fd1cef5616 input_common: Add DS5 to HD rumble list 2022-01-26 21:49:32 -06:00
bunnei adcac857f8 Merge pull request #7762 from bunnei/un-map-improve
Kernel Memory Updates (Part 4): Improve Un/MapPages, and more.
2022-01-26 17:54:20 -08:00
Lioncash f6a049337e common/xbyak_api: Make BuildRegSet() constexpr
This allows us to eliminate any static constructors that would have been
emitted due to the function not being constexpr.
2022-01-26 16:29:15 -05:00
bunnei 40050c1188 Merge pull request #7780 from lioncash/macro
video_core/macro: Move impl classes into their cpp files
2022-01-26 12:39:59 -08:00
bunnei 9bf7ad97f5 Merge pull request #7769 from german77/no-control
yuzu: Add setting to disable controller navigation
2022-01-25 20:24:42 -08:00
bunnei 5723145165 Merge pull request #7768 from Moonlacer/fsr-1.0.2
Update AMD FidelityFX Super Resolution™ to 1.0.2
2022-01-25 17:32:44 -08:00
Morph 84cc22b21b Merge pull request #7777 from lioncash/nodisc
shader_recompiler: Remove unnecessary [[nodiscard]] specifier
2022-01-25 16:16:20 -05:00
Morph c93dd45997 Merge pull request #7779 from lioncash/gpu-iface
gpu: Remove obsoleted CDmaPusher() accessors
2022-01-25 16:16:04 -05:00
Morph a1c4bca908 Merge pull request #7778 from lioncash/comma
vk_fsr: Replace comma operator with semicolon
2022-01-25 16:15:53 -05:00
Morph 432f4441b9 Merge pull request #7774 from lioncash/mapping
input_common/main: Pass MappingData by const reference in callbacks
2022-01-25 16:15:45 -05:00
Morph 306b3491c4 Merge pull request #7773 from lioncash/udp-deprecated
input_common/udp_client: Replace deprecated from_string()/to_ulong() functions
2022-01-25 16:15:27 -05:00
Morph 8dbad556ec Merge pull request #7771 from lioncash/assert
kernel/k_affinity_mask: Remove duplicated assert
2022-01-25 16:15:18 -05:00
Lioncash a8a4f37628 video_core/macro: Add missing <cstring> header
Necessary since memcpy is used.
2022-01-25 14:10:02 -05:00
Lioncash 81d1a1133d video_core/macro_interpreter: Move impl class to the cpp file
Keeps the implementation hidden from the intended API and lessens the
header dependencies on the interpreter's header.
2022-01-25 14:03:48 -05:00
Lioncash cfd9f7d25b video_core/macro_hle: Return unique_ptr directly from GetHLEProgram()
Same behavior, but less code and header dependencies.
2022-01-25 13:50:14 -05:00
Lioncash a05d9405b9 video_core/macro: Remove unused parameter from Execute()
Simplifies the function interface.
2022-01-25 13:41:38 -05:00
Lioncash 74f80299b0 video_core/macro_jit_x64: Remove unused impl class member
Reduces the size of the impl class a tiny bit.
2022-01-25 13:33:09 -05:00
Lioncash f11eefed56 video_core/macro_jit_x64: Decouple PersistentCallerSavedRegs() from impl
This doesn't depend on class state and can just be a regular function.
2022-01-25 13:31:54 -05:00
Lioncash 6b873b72ae video_core/macro_jit_x64: Move impl class into cpp file
Keeps the implementation internalized and also reduces API-facing header
dependencies.

Notably, this fully internalizes all of the xbyak externals.
2022-01-25 13:31:46 -05:00
Lioncash a3c81745b1 video_core/macro_hle: Move impl class into cpp file
Given it's intended to be an internal implementation class, we can move
it into the cpp file to ensure that.

This also lets us move some header dependencies into the cpp file as
well.
2022-01-25 13:15:48 -05:00
Lioncash d8486a9968 gpu: Tidy up forward declarations
Over time a few forward declarations became unnecessary, so we can
remove these to tidy up the header a little bit.
2022-01-25 13:05:39 -05:00
Lioncash 9b38c8ef08 gpu: Remove obsoleted CDMAPusher() accessors
These were obsoleted in 2c47f8aa18 but
were accidentally overlooked.
2022-01-25 12:53:56 -05:00
Lioncash e7af84670d vk_fsr: Replace comma operator with semicolon
Generally, we should be ending statements with a semicolon not a comma

Resolves a clang diagnostic.
2022-01-25 12:42:27 -05:00
Lioncash b46ec4efea shader_recompiler: Remove unnecessary [[nodiscard]]
Since ConvertLegacyToGeneric has a void return value, there's nothing
that is actually returned by the function.
2022-01-25 12:16:09 -05:00
bunnei 4f9f55ec21 Merge pull request #7765 from bunnei/update-thread-count
hle: kernel: KThread: Improve Increment/Decrement RunningThreadCount.
2022-01-24 18:58:48 -08:00
bunnei 3442365127 Merge pull request #7760 from german77/inverted_keyboard
yuzu: Add modifiers for keyboard
2022-01-24 15:41:49 -08:00
Lioncash 651358d0b6 input_common/input_engine: Ensure PadIdentifier UUIDs have a valid initial state
The default constructor of a UUID instance doesn't initialize the
underlying array.
2022-01-24 11:57:48 -05:00
Lioncash 187c9d7e33 input_common/input_mapping: Simplify UUID validity checks
Makes the checks a little more intuitive to read and doesn't construct
an extra UUID instance
2022-01-24 11:49:52 -05:00
Lioncash 0849be094e input_common/input_mapping: Add missing includes
Ensures that the class always sees the types it needs.
2022-01-24 11:49:31 -05:00
Lioncash 8bb39750a1 input_common/input_mapping: Remove const from return value
Top-level const on a return by value can inhibit move semantics, and is
unnecessary.
2022-01-24 11:39:20 -05:00
Lioncash 12e7d3b254 input_common/input_mapping: Default constructor 2022-01-24 11:37:48 -05:00
Lioncash 51dd3da11c input_common/main: Pass MappingData by const reference in callbacks
Avoids creating unnecessary 168 byte copies per callback invocation.
2022-01-24 11:31:43 -05:00
Lioncash 87eb3cb083 input_common/udp_client: Replace deprecated from_string()/to_ulong() functions
These are deprecated and make_address variants and to_uint() should be used instead.
2022-01-24 11:14:30 -05:00
Lioncash b084a9bf0a input_common/udp_client: Prevent unnecessary string copies
We can also remove some redundant const on the return values, since
these don't do anything
2022-01-24 10:58:25 -05:00
Lioncash 2f12caccf9 kernel/k_affinity_mask: Remove duplicated assert
This is already checked inside GetCoreBit()
2022-01-24 10:35:22 -05:00
german77 ebf19616f4 input_common: Add option to configure gyro threshold 2022-01-23 21:54:33 -06:00
german77 b998aa5504 yuzu: Add setting to disable controller navigation 2022-01-23 21:08:49 -06:00
Moonlacer fdde08bd01 Update FSR to 1.0.2
Updates yuzu's FSR implementation to 1.0.2
2022-01-23 14:38:48 -06:00
bunnei 2136ebccd6 Merge pull request #7761 from v1993/patch-8
Improve FFmpeg cmake file
2022-01-22 23:43:14 -08:00
bunnei 59add00d4a hle: kernel: KThread: Improve Increment/Decrement RunningThreadCount.
- Previously implementation was incorrect, and would occasionally underflow.
2022-01-22 21:09:45 -08:00
bunnei e791da9791 core: hle: kernel: KPageTable: Various improvements to MapPages and UnmapPages. 2022-01-22 20:51:34 -08:00
bunnei 07add23251 core: hle: kernel: KPageTable: MapProcessCode: Various cleanup. 2022-01-22 20:51:34 -08:00
bunnei ee25e0a40b core: hle: kernel: KPageTable: ReserveTransferMemory: Various cleanup. 2022-01-22 20:51:34 -08:00
bunnei 0cee5e1af8 core: hle: kernel: KPageTable: ResetTransferMemory: Various cleanup. 2022-01-22 20:51:34 -08:00
bunnei ffcaf5af90 core: hle: kernel: KPageTable: SetMemoryAttribute: Various cleanup. 2022-01-22 20:51:34 -08:00
bunnei 5b57ee66ce Merge pull request #7716 from german77/volume
yuzu: Add volume hotkeys
2022-01-22 02:25:59 -08:00
Valeri f68be36159 Improve FFmpeg cmake file
* Fix compilation if CUDA_INCLUDE_DIRS is empty/contains multiple paths
* Pass CMAKE_{C,CXX}_COMPILER_LAUNCHER to ffmpeg compiler
2022-01-22 12:56:25 +03:00
bunnei 2935c9d8de core: hle: kernel: KPageTable: Assert valid address on GetPhysicalAddr. 2022-01-22 01:33:26 -08:00
bunnei 264bb5abf7 core: hle: kernel: KPageTable: Operate: Assert lock ownership. 2022-01-22 01:33:26 -08:00
bunnei 0137f2e6e1 core: hle: kernel: KPageTable: SetHeapSize: Cleanup & take physical memory lock. 2022-01-22 01:33:26 -08:00
bunnei 6d8e498f76 core: hle: kernel: Refactor Un/MapPhysicalMemory to remove unnecessary methods. 2022-01-22 01:33:26 -08:00
bunnei b8b1b58f36 core: hle: kernel: Rename Un/Map to Un/MapMeory. 2022-01-22 01:33:26 -08:00
bunnei 8433edacb3 Merge pull request #7735 from german77/udp_battery
input_common: Report battery for UDP controllers
2022-01-22 01:28:14 -08:00
bunnei 68c8a1b170 Merge pull request #7737 from bunnei/fix-dummy-thread-leak
Various fixes to HLE service thread management
2022-01-21 22:34:47 -08:00
Narr the Reg 7d133fd37e yuzu: Add modifiers for keyboard 2022-01-21 20:41:50 -06:00
bunnei cef7649bed Merge pull request #7752 from Morph1984/SetCpuOverclockEnabled
service: apm: Stub ISession SetCpuOverclockEnabled
2022-01-21 17:13:52 -08:00
bunnei 615fb40416 hle: kernel: KThread: Ensure host (dummy) threads block on locking.
- But do not enter the priority queue, as otherwise they will be scheduled.
- Allows dummy threads to use guest synchronization primitives.
2022-01-21 17:12:06 -08:00
bunnei d990f043bd Merge pull request #7756 from lioncash/service
service: Update function tables
2022-01-21 14:26:05 -08:00
Lioncash 12bf8ca929 service/wlan: Update function tables 2022-01-21 16:35:51 -05:00
Lioncash 8dd6dc9a29 service/usb: Update function tables 2022-01-21 16:31:57 -05:00
Lioncash 43039d95ac service/set: Update function tables 2022-01-21 16:26:12 -05:00
Lioncash 7ba6f68a8d service/ns: Update function tables 2022-01-21 16:21:35 -05:00
Lioncash 19c11e2fd2 service/nim: Update unknown function table entries 2022-01-21 16:17:40 -05:00
Lioncash 888bc10c17 service/friend: Update unknown function table entries 2022-01-21 16:08:46 -05:00
Lioncash 54150f5afa service/filsystem: Update fsp-srv function table 2022-01-21 16:07:01 -05:00
Lioncash 3da43ad2a9 service/btm: Update function tables 2022-01-21 15:59:41 -05:00
Lioncash 0f7337c522 service/audio: Update audctl unknown function names 2022-01-21 15:50:38 -05:00
Lioncash 29e3636e0a service/am: Update omm function tables 2022-01-21 15:40:08 -05:00
Lioncash a271cf89cf service/acc: Update unknown function names
Switchbrew has the function names now.
2022-01-21 15:33:22 -05:00
bunnei 88d9b55b14 Merge pull request #7755 from v1993/someone-in-here-lacks-system-wide-theming
Use Default Colorful theme by default outside of Windows
2022-01-21 11:51:29 -08:00
bunnei 03cf308c16 Merge pull request #7731 from v1993/xfb-varying-check-fix
shader_recompiler: fix potential OOB access
2022-01-21 10:45:56 -08:00
v1993 d63d8bf7f9 Use Default Colorful theme by default outside of Windows
On OSes with system-wide theming this allows yuzu to follow system style, regardless of its exact coloration, working well with both light and dark system themes. Dark /Colorful, on the other hand, forces dark theme regardless of user preferences set in system settings, making for a poor default.

Use Colorful variation to keep in line with icon style of patron-voted Dark Colorful.
2022-01-21 20:57:00 +03:00
bunnei ef7c50b276 Merge pull request #7695 from Morph1984/is-pow2
common: bit_util: Add IsPow2 helper function
2022-01-20 18:06:11 -08:00
bunnei f6815086a1 hle: kernel: Remove redundant tracking of dummy threads.
- These are already tracked by kernel's registered_objects member.
2022-01-20 17:08:00 -08:00
bunnei 91ff6d4cb3 hle: kernel: KThread: DummyThread can be waited, ensure wait_queue is not nullptr. 2022-01-20 17:08:00 -08:00
bunnei 46a620f9d7 hle: kernel: KThread: Decrease DummyThread priority to ensure it is never scheduled. 2022-01-20 17:08:00 -08:00
bunnei 0b37e7cb39 hle: kernel: service_thread: Ensure dummy thread is closed & destroyed on thread exit. 2022-01-20 17:08:00 -08:00
bunnei 384e24d3e9 hle: kernel: KServerSession: Remove hack for CompleteSyncRequest.
- This does not appear to be necessary anymore.
2022-01-20 17:08:00 -08:00
bunnei ad53dc22fd hle: kernel: KServerSession: Simplify CompleteSyncRequest EndWait.
- Considering is_thread_waiting is never set, so we can remove IsThreadWaiting.
- KThread::EndWait will take the scheduler lock, so we can remove the redundant lock.
2022-01-20 17:08:00 -08:00
bunnei 5ffec69dc7 hle: kernel: KThread: Ensure dummy threads never call EndWait.
- These are only used by host threads for locking and will never have a wait_queue.
2022-01-20 17:08:00 -08:00
bunnei 11a380c3da hle: kernel: KScheduler: Ensure dummy threads are never scheduled.
- These are only used by host threads for locking.
2022-01-20 17:08:00 -08:00
bunnei f6cbb14dce hle: kernel: KThread: Rename thread_type_for_debugging -> thread_type.
- This will be used to ensure that we do not schedule dummy threads.
2022-01-20 17:08:00 -08:00
bunnei e781f6e767 Merge pull request #7710 from german77/just-shake-it
core/hid: Increment shake force
2022-01-20 16:53:22 -08:00
Mai M 55ef89a9c7 Merge pull request #7749 from jbeich/ffmpeg5
video_core: unbreak build with FFmpeg 5.0
2022-01-20 13:56:32 -05:00
Jan Beich d24a4b79d4 video_core: constify AVCodec for ffmpeg >= 5.0
src/video_core/command_classes/codecs/codec.cpp:177:16: error: assigning to 'AVCodec *' from 'const AVCodec *' discards qualifiers
    av_codec = avcodec_find_decoder(codec);
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~
2022-01-20 11:09:21 +00:00
Narr the Reg 36144a5690 input_common: Report battery for UDP controllers 2022-01-17 13:30:15 -06:00
v1993 a943600019 shader_recompiler: fix potential OOB access
Found by static analysis with PVS-Studio. Original check wasn't actually checking for OOB and would segfault in case of it.
2022-01-17 21:50:51 +03:00
german77 850896a52b audio/stream: Adjust volume scale factor 2022-01-15 20:28:37 -06:00
german77 c8b3a12856 yuzu: Add volume up/down hotkeys 2022-01-15 20:28:37 -06:00
german77 419f427a01 yuzu: Remove speed limit hotkeys 2022-01-15 13:44:45 -06:00
Narr the Reg 5ce5432830 core/hid: Increment shake force
With the current settings 2p mode in pokemon let's go wasn't showing up.  By making the shake more violent we can make it appear without any effort using the keyboard
2022-01-14 11:11:20 -06:00
Morph d92b5fc435 common: bit_util: Add IsPow2 helper function
Makes use of std::has_single_bit() to check whether the value is a power of 2.
2022-01-11 16:01:12 -05:00
267 changed files with 36576 additions and 11556 deletions
+510 -395
View File
File diff suppressed because it is too large Load Diff
+540 -425
View File
File diff suppressed because it is too large Load Diff
+553 -438
View File
File diff suppressed because it is too large Load Diff
+537 -422
View File
File diff suppressed because it is too large Load Diff
+501 -386
View File
File diff suppressed because it is too large Load Diff
+6190
View File
File diff suppressed because it is too large Load Diff
+569 -454
View File
File diff suppressed because it is too large Load Diff
+6187
View File
File diff suppressed because it is too large Load Diff
+530 -415
View File
File diff suppressed because it is too large Load Diff
+615 -486
View File
File diff suppressed because it is too large Load Diff
+615 -500
View File
File diff suppressed because it is too large Load Diff
+604 -489
View File
File diff suppressed because it is too large Load Diff
+594 -478
View File
File diff suppressed because it is too large Load Diff
+765 -634
View File
File diff suppressed because it is too large Load Diff
+508 -393
View File
File diff suppressed because it is too large Load Diff
+816 -676
View File
File diff suppressed because it is too large Load Diff
+506 -391
View File
File diff suppressed because it is too large Load Diff
+603 -488
View File
File diff suppressed because it is too large Load Diff
+506 -391
View File
File diff suppressed because it is too large Load Diff
+6202
View File
File diff suppressed because it is too large Load Diff
+608 -493
View File
File diff suppressed because it is too large Load Diff
+501 -386
View File
File diff suppressed because it is too large Load Diff
+508 -393
View File
File diff suppressed because it is too large Load Diff
+18 -18
View File
@@ -747,12 +747,12 @@ AF1 sharpness){
// Immediate constants for peak range.
AF2 peakC=AF2(1.0,-1.0*4.0);
// Limiters, these need to be high precision RCPs.
AF1 hitMinR=mn4R*ARcpF1(AF1_(4.0)*mx4R);
AF1 hitMinG=mn4G*ARcpF1(AF1_(4.0)*mx4G);
AF1 hitMinB=mn4B*ARcpF1(AF1_(4.0)*mx4B);
AF1 hitMaxR=(peakC.x-mx4R)*ARcpF1(AF1_(4.0)*mn4R+peakC.y);
AF1 hitMaxG=(peakC.x-mx4G)*ARcpF1(AF1_(4.0)*mn4G+peakC.y);
AF1 hitMaxB=(peakC.x-mx4B)*ARcpF1(AF1_(4.0)*mn4B+peakC.y);
AF1 hitMinR=min(mn4R,eR)*ARcpF1(AF1_(4.0)*mx4R);
AF1 hitMinG=min(mn4G,eG)*ARcpF1(AF1_(4.0)*mx4G);
AF1 hitMinB=min(mn4B,eB)*ARcpF1(AF1_(4.0)*mx4B);
AF1 hitMaxR=(peakC.x-max(mx4R,eR))*ARcpF1(AF1_(4.0)*mn4R+peakC.y);
AF1 hitMaxG=(peakC.x-max(mx4G,eG))*ARcpF1(AF1_(4.0)*mn4G+peakC.y);
AF1 hitMaxB=(peakC.x-max(mx4B,eB))*ARcpF1(AF1_(4.0)*mn4B+peakC.y);
AF1 lobeR=max(-hitMinR,hitMaxR);
AF1 lobeG=max(-hitMinG,hitMaxG);
AF1 lobeB=max(-hitMinB,hitMaxB);
@@ -845,12 +845,12 @@ AF1 sharpness){
// Immediate constants for peak range.
AH2 peakC=AH2(1.0,-1.0*4.0);
// Limiters, these need to be high precision RCPs.
AH1 hitMinR=mn4R*ARcpH1(AH1_(4.0)*mx4R);
AH1 hitMinG=mn4G*ARcpH1(AH1_(4.0)*mx4G);
AH1 hitMinB=mn4B*ARcpH1(AH1_(4.0)*mx4B);
AH1 hitMaxR=(peakC.x-mx4R)*ARcpH1(AH1_(4.0)*mn4R+peakC.y);
AH1 hitMaxG=(peakC.x-mx4G)*ARcpH1(AH1_(4.0)*mn4G+peakC.y);
AH1 hitMaxB=(peakC.x-mx4B)*ARcpH1(AH1_(4.0)*mn4B+peakC.y);
AH1 hitMinR=min(mn4R,eR)*ARcpH1(AH1_(4.0)*mx4R);
AH1 hitMinG=min(mn4G,eG)*ARcpH1(AH1_(4.0)*mx4G);
AH1 hitMinB=min(mn4B,eB)*ARcpH1(AH1_(4.0)*mx4B);
AH1 hitMaxR=(peakC.x-max(mx4R,eR))*ARcpH1(AH1_(4.0)*mn4R+peakC.y);
AH1 hitMaxG=(peakC.x-max(mx4G,eG))*ARcpH1(AH1_(4.0)*mn4G+peakC.y);
AH1 hitMaxB=(peakC.x-max(mx4B,eB))*ARcpH1(AH1_(4.0)*mn4B+peakC.y);
AH1 lobeR=max(-hitMinR,hitMaxR);
AH1 lobeG=max(-hitMinG,hitMaxG);
AH1 lobeB=max(-hitMinB,hitMaxB);
@@ -963,12 +963,12 @@ AF1 sharpness){
// Immediate constants for peak range.
AH2 peakC=AH2(1.0,-1.0*4.0);
// Limiters, these need to be high precision RCPs.
AH2 hitMinR=mn4R*ARcpH2(AH2_(4.0)*mx4R);
AH2 hitMinG=mn4G*ARcpH2(AH2_(4.0)*mx4G);
AH2 hitMinB=mn4B*ARcpH2(AH2_(4.0)*mx4B);
AH2 hitMaxR=(peakC.x-mx4R)*ARcpH2(AH2_(4.0)*mn4R+peakC.y);
AH2 hitMaxG=(peakC.x-mx4G)*ARcpH2(AH2_(4.0)*mn4G+peakC.y);
AH2 hitMaxB=(peakC.x-mx4B)*ARcpH2(AH2_(4.0)*mn4B+peakC.y);
AH2 hitMinR=min(mn4R,eR)*ARcpH2(AH2_(4.0)*mx4R);
AH2 hitMinG=min(mn4G,eG)*ARcpH2(AH2_(4.0)*mx4G);
AH2 hitMinB=min(mn4B,eB)*ARcpH2(AH2_(4.0)*mx4B);
AH2 hitMaxR=(peakC.x-max(mx4R,eR))*ARcpH2(AH2_(4.0)*mn4R+peakC.y);
AH2 hitMaxG=(peakC.x-max(mx4G,eG))*ARcpH2(AH2_(4.0)*mn4G+peakC.y);
AH2 hitMaxB=(peakC.x-max(mx4B,eB))*ARcpH2(AH2_(4.0)*mn4B+peakC.y);
AH2 lobeR=max(-hitMinR,hitMaxR);
AH2 lobeG=max(-hitMinG,hitMaxG);
AH2 lobeB=max(-hitMinB,hitMaxB);
+9 -4
View File
@@ -95,7 +95,8 @@ if (NOT WIN32)
# ffnvenc could load CUDA libraries at the runtime using dlopen/dlsym or LoadLibrary/GetProcAddress
# here we handle the hard-linking senario where CUDA is linked during compilation
if (CUDA_FOUND)
list(APPEND FFmpeg_HWACCEL_FLAGS --extra-cflags=-I${CUDA_INCLUDE_DIRS})
# This line causes build error if CUDA_INCLUDE_DIRS is anything but a single non-empty value
#list(APPEND FFmpeg_HWACCEL_FLAGS --extra-cflags=-I${CUDA_INCLUDE_DIRS})
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${CUDA_LIBRARIES})
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${CUDA_INCLUDE_DIRS})
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${CUDA_LDFLAGS})
@@ -119,6 +120,8 @@ if (NOT WIN32)
# `configure` parameters builds only exactly what yuzu needs from FFmpeg
# `--disable-vdpau` is needed to avoid linking issues
set(FFmpeg_CC ${CMAKE_C_COMPILER_LAUNCHER} ${CMAKE_C_COMPILER})
set(FFmpeg_CXX ${CMAKE_CXX_COMPILER_LAUNCHER} ${CMAKE_CXX_COMPILER})
add_custom_command(
OUTPUT
${FFmpeg_MAKEFILE}
@@ -137,12 +140,14 @@ if (NOT WIN32)
--enable-decoder=h264
--enable-decoder=vp8
--enable-decoder=vp9
--cc="${CMAKE_C_COMPILER}"
--cxx="${CMAKE_CXX_COMPILER}"
--cc="${FFmpeg_CC}"
--cxx="${FFmpeg_CXX}"
${FFmpeg_HWACCEL_FLAGS}
WORKING_DIRECTORY
${FFmpeg_BUILD_DIR}
)
unset(FFmpeg_CC)
unset(FFmpeg_CXX)
unset(FFmpeg_HWACCEL_FLAGS)
# Workaround for Ubuntu 18.04's older version of make not being able to call make as a child
@@ -209,6 +214,6 @@ else(WIN32)
set(FFmpeg_LDFLAGS "${FFmpeg_LDFLAGS}" PARENT_SCOPE)
set(FFmpeg_LIBRARIES "${FFmpeg_LIBRARIES}" PARENT_SCOPE)
set(FFmpeg_INCLUDE_DIR "${FFmpeg_INCLUDE_DIR}" PARENT_SCOPE)
endif(WIN32)
endif()
unset(FFmpeg_COMPONENTS)
+3 -1
View File
@@ -15,7 +15,9 @@ constexpr ResultCode ERR_INVALID_PARAMETERS{ErrorModule::Audio, 41};
constexpr ResultCode ERR_SPLITTER_SORT_FAILED{ErrorModule::Audio, 43};
} // namespace Audren
constexpr u32_le CURRENT_PROCESS_REVISION = Common::MakeMagic('R', 'E', 'V', '9');
constexpr u8 BASE_REVISION = '0';
constexpr u32_le CURRENT_PROCESS_REVISION =
Common::MakeMagic('R', 'E', 'V', static_cast<u8>(BASE_REVISION + 0xA));
constexpr std::size_t MAX_MIX_BUFFERS = 24;
constexpr std::size_t MAX_BIQUAD_FILTERS = 2;
constexpr std::size_t MAX_CHANNEL_COUNT = 6;
+2 -2
View File
@@ -79,8 +79,8 @@ static void VolumeAdjustSamples(std::vector<s16>& samples, float game_volume) {
return;
}
// Implementation of a volume slider with a dynamic range of 60 dB
const float volume_scale_factor = volume == 0 ? 0 : std::exp(6.90775f * volume) * 0.001f;
// Perceived volume is not the same as the volume level
const float volume_scale_factor = (0.85f * ((volume * volume) - volume)) + volume;
for (auto& sample : samples) {
sample = static_cast<s16>(sample * volume_scale_factor);
}
+13
View File
@@ -45,10 +45,23 @@ template <typename T>
return static_cast<u32>(log2_f + static_cast<u64>((value ^ (1ULL << log2_f)) != 0ULL));
}
template <typename T>
requires std::is_unsigned_v<T>
[[nodiscard]] constexpr bool IsPow2(T value) {
return std::has_single_bit(value);
}
template <typename T>
requires std::is_integral_v<T>
[[nodiscard]] T NextPow2(T value) {
return static_cast<T>(1ULL << ((8U * sizeof(T)) - std::countl_zero(value - 1U)));
}
template <size_t bit_index, typename T>
requires std::is_integral_v<T>
[[nodiscard]] constexpr bool Bit(const T value) {
static_assert(bit_index < BitSize<T>(), "bit_index must be smaller than size of T");
return ((value >> bit_index) & T(1)) == T(1);
}
} // namespace Common
-10
View File
@@ -46,13 +46,3 @@ using GPUVAddr = u64; ///< Represents a pointer in the GPU virtual address space
using u128 = std::array<std::uint64_t, 2>;
static_assert(sizeof(u128) == 16, "u128 must be 128 bits wide");
// An inheritable class to disallow the copy constructor and operator= functions
class NonCopyable {
protected:
constexpr NonCopyable() = default;
~NonCopyable() = default;
NonCopyable(const NonCopyable&) = delete;
NonCopyable& operator=(const NonCopyable&) = delete;
};
+2 -3
View File
@@ -188,9 +188,8 @@ public:
#ifdef _WIN32
template <typename Path>
[[nodiscard]] void Open(const Path& path, FileAccessMode mode,
FileType type = FileType::BinaryFile,
FileShareFlag flag = FileShareFlag::ShareReadOnly) {
void Open(const Path& path, FileAccessMode mode, FileType type = FileType::BinaryFile,
FileShareFlag flag = FileShareFlag::ShareReadOnly) {
using ValueType = typename Path::value_type;
if constexpr (IsChar<ValueType>) {
Open(ToU8String(path), mode, type, flag);
+8
View File
@@ -16,6 +16,10 @@ std::u8string BufferToU8String(std::span<const u8> buffer) {
return std::u8string{buffer.begin(), std::ranges::find(buffer, u8{0})};
}
std::u8string_view BufferToU8StringView(std::span<const u8> buffer) {
return std::u8string_view{reinterpret_cast<const char8_t*>(buffer.data())};
}
std::string ToUTF8String(std::u8string_view u8_string) {
return std::string{u8_string.begin(), u8_string.end()};
}
@@ -24,6 +28,10 @@ std::string BufferToUTF8String(std::span<const u8> buffer) {
return std::string{buffer.begin(), std::ranges::find(buffer, u8{0})};
}
std::string_view BufferToUTF8StringView(std::span<const u8> buffer) {
return std::string_view{reinterpret_cast<const char*>(buffer.data())};
}
std::string PathToUTF8String(const std::filesystem::path& path) {
return ToUTF8String(path.u8string());
}
+18
View File
@@ -37,6 +37,15 @@ concept IsChar = std::same_as<T, char>;
*/
[[nodiscard]] std::u8string BufferToU8String(std::span<const u8> buffer);
/**
* Same as BufferToU8String, but returns a string view of the buffer.
*
* @param buffer Buffer of bytes
*
* @returns UTF-8 encoded std::u8string_view.
*/
[[nodiscard]] std::u8string_view BufferToU8StringView(std::span<const u8> buffer);
/**
* Converts a std::u8string or std::u8string_view to a UTF-8 encoded std::string.
*
@@ -57,6 +66,15 @@ concept IsChar = std::same_as<T, char>;
*/
[[nodiscard]] std::string BufferToUTF8String(std::span<const u8> buffer);
/**
* Same as BufferToUTF8String, but returns a string view of the buffer.
*
* @param buffer Buffer of bytes
*
* @returns UTF-8 encoded std::string_view.
*/
[[nodiscard]] std::string_view BufferToUTF8StringView(std::span<const u8> buffer);
/**
* Converts a filesystem path to a UTF-8 encoded std::string.
*
+2 -2
View File
@@ -327,8 +327,8 @@ private:
bool IsNiechePlaceholder(size_t virtual_offset, size_t length) const {
const auto it = placeholders.upper_bound({virtual_offset, virtual_offset + length});
if (it != placeholders.end() && it->lower() == virtual_offset + length) {
const bool is_root = it == placeholders.begin() && virtual_offset == 0;
return is_root || std::prev(it)->upper() == virtual_offset;
return it == placeholders.begin() ? virtual_offset == 0
: std::prev(it)->upper() == virtual_offset;
}
return false;
}
+2
View File
@@ -209,6 +209,8 @@ enum class ButtonNames {
Triangle,
Share,
Options,
Home,
Touch,
// Mouse buttons
ButtonMouseWheel,
+5 -13
View File
@@ -218,19 +218,17 @@ private:
Impl(const std::filesystem::path& file_backend_filename, const Filter& filter_)
: filter{filter_}, file_backend{file_backend_filename} {}
~Impl() {
StopBackendThread();
}
~Impl() = default;
void StartBackendThread() {
backend_thread = std::thread([this] {
backend_thread = std::jthread([this](std::stop_token stop_token) {
Common::SetCurrentThreadName("yuzu:Log");
Entry entry;
const auto write_logs = [this, &entry]() {
ForEachBackend([&entry](Backend& backend) { backend.Write(entry); });
};
while (!stop.stop_requested()) {
entry = message_queue.PopWait(stop.get_token());
while (!stop_token.stop_requested()) {
entry = message_queue.PopWait(stop_token);
if (entry.filename != nullptr) {
write_logs();
}
@@ -244,11 +242,6 @@ private:
});
}
void StopBackendThread() {
stop.request_stop();
backend_thread.join();
}
Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
const char* function, std::string&& message) const {
using std::chrono::duration_cast;
@@ -283,8 +276,7 @@ private:
ColorConsoleBackend color_console_backend{};
FileBackend file_backend;
std::stop_source stop;
std::thread backend_thread;
std::jthread backend_thread;
MPSCQueue<Entry, true> message_queue{};
std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()};
};
+1
View File
@@ -108,6 +108,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
SUB(Service, Migration) \
SUB(Service, Mii) \
SUB(Service, MM) \
SUB(Service, MNPP) \
SUB(Service, NCM) \
SUB(Service, NFC) \
SUB(Service, NFP) \
+1
View File
@@ -76,6 +76,7 @@ enum class Class : u8 {
Service_Migration, ///< The migration service
Service_Mii, ///< The Mii service
Service_MM, ///< The MM (Multimedia) service
Service_MNPP, ///< The MNPP service
Service_NCM, ///< The NCM service
Service_NFC, ///< The NFC (Near-field communication) service
Service_NFP, ///< The NFP service
+56 -2
View File
@@ -10,11 +10,65 @@ PageTable::PageTable() = default;
PageTable::~PageTable() noexcept = default;
void PageTable::Resize(size_t address_space_width_in_bits, size_t page_size_in_bits) {
const size_t num_page_table_entries{1ULL << (address_space_width_in_bits - page_size_in_bits)};
bool PageTable::BeginTraversal(TraversalEntry& out_entry, TraversalContext& out_context,
u64 address) const {
// Setup invalid defaults.
out_entry.phys_addr = 0;
out_entry.block_size = page_size;
out_context.next_page = 0;
// Validate that we can read the actual entry.
const auto page = address / page_size;
if (page >= backing_addr.size()) {
return false;
}
// Validate that the entry is mapped.
const auto phys_addr = backing_addr[page];
if (phys_addr == 0) {
return false;
}
// Populate the results.
out_entry.phys_addr = phys_addr + address;
out_context.next_page = page + 1;
out_context.next_offset = address + page_size;
return true;
}
bool PageTable::ContinueTraversal(TraversalEntry& out_entry, TraversalContext& context) const {
// Setup invalid defaults.
out_entry.phys_addr = 0;
out_entry.block_size = page_size;
// Validate that we can read the actual entry.
const auto page = context.next_page;
if (page >= backing_addr.size()) {
return false;
}
// Validate that the entry is mapped.
const auto phys_addr = backing_addr[page];
if (phys_addr == 0) {
return false;
}
// Populate the results.
out_entry.phys_addr = phys_addr + context.next_offset;
context.next_page = page + 1;
context.next_offset += page_size;
return true;
}
void PageTable::Resize(std::size_t address_space_width_in_bits, std::size_t page_size_in_bits) {
const std::size_t num_page_table_entries{1ULL
<< (address_space_width_in_bits - page_size_in_bits)};
pointers.resize(num_page_table_entries);
backing_addr.resize(num_page_table_entries);
current_address_space_width_in_bits = address_space_width_in_bits;
page_size = 1ULL << page_size_in_bits;
}
} // namespace Common
+20 -4
View File
@@ -27,6 +27,16 @@ enum class PageType : u8 {
* mimics the way a real CPU page table works.
*/
struct PageTable {
struct TraversalEntry {
u64 phys_addr{};
std::size_t block_size{};
};
struct TraversalContext {
u64 next_page{};
u64 next_offset{};
};
/// Number of bits reserved for attribute tagging.
/// This can be at most the guaranteed alignment of the pointers in the page table.
static constexpr int ATTRIBUTE_BITS = 2;
@@ -89,6 +99,10 @@ struct PageTable {
PageTable(PageTable&&) noexcept = default;
PageTable& operator=(PageTable&&) noexcept = default;
bool BeginTraversal(TraversalEntry& out_entry, TraversalContext& out_context,
u64 address) const;
bool ContinueTraversal(TraversalEntry& out_entry, TraversalContext& context) const;
/**
* Resizes the page table to be able to accommodate enough pages within
* a given address space.
@@ -96,9 +110,9 @@ struct PageTable {
* @param address_space_width_in_bits The address size width in bits.
* @param page_size_in_bits The page size in bits.
*/
void Resize(size_t address_space_width_in_bits, size_t page_size_in_bits);
void Resize(std::size_t address_space_width_in_bits, std::size_t page_size_in_bits);
size_t GetAddressSpaceBits() const {
std::size_t GetAddressSpaceBits() const {
return current_address_space_width_in_bits;
}
@@ -110,9 +124,11 @@ struct PageTable {
VirtualBuffer<u64> backing_addr;
size_t current_address_space_width_in_bits;
std::size_t current_address_space_width_in_bits{};
u8* fastmem_arena;
u8* fastmem_arena{};
std::size_t page_size{};
};
} // namespace Common
+2
View File
@@ -167,6 +167,7 @@ void RestoreGlobalState(bool is_powered_on) {
// Core
values.use_multi_core.SetGlobal(true);
values.use_extended_memory_layout.SetGlobal(true);
// CPU
values.cpu_accuracy.SetGlobal(true);
@@ -175,6 +176,7 @@ void RestoreGlobalState(bool is_powered_on) {
values.cpuopt_unsafe_ignore_standard_fpcr.SetGlobal(true);
values.cpuopt_unsafe_inaccurate_nan.SetGlobal(true);
values.cpuopt_unsafe_fastmem_check.SetGlobal(true);
values.cpuopt_unsafe_ignore_global_monitor.SetGlobal(true);
// Renderer
values.renderer_backend.SetGlobal(true);
+5
View File
@@ -466,6 +466,7 @@ struct Values {
// Core
Setting<bool> use_multi_core{true, "use_multi_core"};
Setting<bool> use_extended_memory_layout{false, "use_extended_memory_layout"};
// Cpu
RangedSetting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto,
@@ -483,12 +484,15 @@ struct Values {
BasicSetting<bool> cpuopt_misc_ir{true, "cpuopt_misc_ir"};
BasicSetting<bool> cpuopt_reduce_misalign_checks{true, "cpuopt_reduce_misalign_checks"};
BasicSetting<bool> cpuopt_fastmem{true, "cpuopt_fastmem"};
BasicSetting<bool> cpuopt_fastmem_exclusives{true, "cpuopt_fastmem_exclusives"};
BasicSetting<bool> cpuopt_recompile_exclusives{true, "cpuopt_recompile_exclusives"};
Setting<bool> cpuopt_unsafe_unfuse_fma{true, "cpuopt_unsafe_unfuse_fma"};
Setting<bool> cpuopt_unsafe_reduce_fp_error{true, "cpuopt_unsafe_reduce_fp_error"};
Setting<bool> cpuopt_unsafe_ignore_standard_fpcr{true, "cpuopt_unsafe_ignore_standard_fpcr"};
Setting<bool> cpuopt_unsafe_inaccurate_nan{true, "cpuopt_unsafe_inaccurate_nan"};
Setting<bool> cpuopt_unsafe_fastmem_check{true, "cpuopt_unsafe_fastmem_check"};
Setting<bool> cpuopt_unsafe_ignore_global_monitor{true, "cpuopt_unsafe_ignore_global_monitor"};
// Renderer
RangedSetting<RendererBackend> renderer_backend{
@@ -554,6 +558,7 @@ struct Values {
Setting<bool> use_docked_mode{true, "use_docked_mode"};
BasicSetting<bool> enable_raw_input{false, "enable_raw_input"};
BasicSetting<bool> controller_navigation{true, "controller_navigation"};
Setting<bool> vibration_enabled{true, "vibration_enabled"};
Setting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"};
+20 -9
View File
@@ -8,6 +8,7 @@
#include <map>
#include <memory>
#include <string>
#include "common/common_funcs.h"
#include "common/common_types.h"
namespace Common::Telemetry {
@@ -28,7 +29,7 @@ struct VisitorInterface;
/**
* Interface class for telemetry data fields.
*/
class FieldInterface : NonCopyable {
class FieldInterface {
public:
virtual ~FieldInterface() = default;
@@ -52,14 +53,15 @@ public:
template <typename T>
class Field : public FieldInterface {
public:
YUZU_NON_COPYABLE(Field);
Field(FieldType type_, std::string name_, T value_)
: name(std::move(name_)), type(type_), value(std::move(value_)) {}
Field(const Field&) = default;
Field& operator=(const Field&) = default;
~Field() override = default;
Field(Field&&) = default;
Field& operator=(Field&& other) = default;
Field(Field&&) noexcept = default;
Field& operator=(Field&& other) noexcept = default;
void Accept(VisitorInterface& visitor) const override;
@@ -98,9 +100,15 @@ private:
/**
* Collection of data fields that have been logged.
*/
class FieldCollection final : NonCopyable {
class FieldCollection final {
public:
YUZU_NON_COPYABLE(FieldCollection);
FieldCollection() = default;
~FieldCollection() = default;
FieldCollection(FieldCollection&&) noexcept = default;
FieldCollection& operator=(FieldCollection&&) noexcept = default;
/**
* Accept method for the visitor pattern, visits each field in the collection.
@@ -133,7 +141,7 @@ private:
* Telemetry fields visitor interface class. A backend to log to a web service should implement
* this interface.
*/
struct VisitorInterface : NonCopyable {
struct VisitorInterface {
virtual ~VisitorInterface() = default;
virtual void Visit(const Field<bool>& field) = 0;
@@ -160,8 +168,11 @@ struct VisitorInterface : NonCopyable {
* Empty implementation of VisitorInterface that drops all fields. Used when a functional
* backend implementation is not available.
*/
struct NullVisitor : public VisitorInterface {
~NullVisitor() = default;
struct NullVisitor final : public VisitorInterface {
YUZU_NON_COPYABLE(NullVisitor);
NullVisitor() = default;
~NullVisitor() override = default;
void Visit(const Field<bool>& /*field*/) override {}
void Visit(const Field<double>& /*field*/) override {}
+173 -47
View File
@@ -1,23 +1,25 @@
// Copyright 2018 yuzu Emulator Project
// Copyright 2022 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <bit>
#include <optional>
#include <random>
#include <fmt/format.h>
#include "common/assert.h"
#include "common/tiny_mt.h"
#include "common/uuid.h"
namespace Common {
namespace {
bool IsHexDigit(char c) {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
constexpr size_t RawStringSize = sizeof(UUID) * 2;
constexpr size_t FormattedStringSize = RawStringSize + 4;
u8 HexCharToByte(char c) {
std::optional<u8> HexCharToByte(char c) {
if (c >= '0' && c <= '9') {
return static_cast<u8>(c - '0');
}
@@ -28,60 +30,184 @@ u8 HexCharToByte(char c) {
return static_cast<u8>(c - 'A' + 10);
}
ASSERT_MSG(false, "{} is not a hexadecimal digit!", c);
return u8{0};
return std::nullopt;
}
std::array<u8, 0x10> ConstructFromRawString(std::string_view raw_string) {
std::array<u8, 0x10> uuid;
for (size_t i = 0; i < RawStringSize; i += 2) {
const auto upper = HexCharToByte(raw_string[i]);
const auto lower = HexCharToByte(raw_string[i + 1]);
if (!upper || !lower) {
return {};
}
uuid[i / 2] = static_cast<u8>((*upper << 4) | *lower);
}
return uuid;
}
std::array<u8, 0x10> ConstructFromFormattedString(std::string_view formatted_string) {
std::array<u8, 0x10> uuid;
size_t i = 0;
// Process the first 8 characters.
const auto* str = formatted_string.data();
for (; i < 4; ++i) {
const auto upper = HexCharToByte(*(str++));
const auto lower = HexCharToByte(*(str++));
if (!upper || !lower) {
return {};
}
uuid[i] = static_cast<u8>((*upper << 4) | *lower);
}
// Process the next 4 characters.
++str;
for (; i < 6; ++i) {
const auto upper = HexCharToByte(*(str++));
const auto lower = HexCharToByte(*(str++));
if (!upper || !lower) {
return {};
}
uuid[i] = static_cast<u8>((*upper << 4) | *lower);
}
// Process the next 4 characters.
++str;
for (; i < 8; ++i) {
const auto upper = HexCharToByte(*(str++));
const auto lower = HexCharToByte(*(str++));
if (!upper || !lower) {
return {};
}
uuid[i] = static_cast<u8>((*upper << 4) | *lower);
}
// Process the next 4 characters.
++str;
for (; i < 10; ++i) {
const auto upper = HexCharToByte(*(str++));
const auto lower = HexCharToByte(*(str++));
if (!upper || !lower) {
return {};
}
uuid[i] = static_cast<u8>((*upper << 4) | *lower);
}
// Process the last 12 characters.
++str;
for (; i < 16; ++i) {
const auto upper = HexCharToByte(*(str++));
const auto lower = HexCharToByte(*(str++));
if (!upper || !lower) {
return {};
}
uuid[i] = static_cast<u8>((*upper << 4) | *lower);
}
return uuid;
}
std::array<u8, 0x10> ConstructUUID(std::string_view uuid_string) {
const auto length = uuid_string.length();
if (length == 0) {
return {};
}
// Check if the input string contains 32 hexadecimal characters.
if (length == RawStringSize) {
return ConstructFromRawString(uuid_string);
}
// Check if the input string has the length of a RFC 4122 formatted UUID string.
if (length == FormattedStringSize) {
return ConstructFromFormattedString(uuid_string);
}
ASSERT_MSG(false, "UUID string has an invalid length of {} characters!", length);
return {};
}
} // Anonymous namespace
u128 HexStringToU128(std::string_view hex_string) {
const size_t length = hex_string.length();
UUID::UUID(std::string_view uuid_string) : uuid{ConstructUUID(uuid_string)} {}
// Detect "0x" prefix.
const bool has_0x_prefix = length > 2 && hex_string[0] == '0' && hex_string[1] == 'x';
const size_t offset = has_0x_prefix ? 2 : 0;
// Check length.
if (length > 32 + offset) {
ASSERT_MSG(false, "hex_string has more than 32 hexadecimal characters!");
return INVALID_UUID;
}
u64 lo = 0;
u64 hi = 0;
for (size_t i = 0; i < length - offset; ++i) {
const char c = hex_string[length - 1 - i];
if (!IsHexDigit(c)) {
ASSERT_MSG(false, "{} is not a hexadecimal digit!", c);
return INVALID_UUID;
}
if (i < 16) {
lo |= u64{HexCharToByte(c)} << (i * 4);
}
if (i >= 16) {
hi |= u64{HexCharToByte(c)} << ((i - 16) * 4);
}
}
return u128{lo, hi};
std::string UUID::RawString() const {
return fmt::format("{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}"
"{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],
uuid[15]);
}
UUID UUID::Generate() {
std::string UUID::FormattedString() const {
return fmt::format("{:02x}{:02x}{:02x}{:02x}"
"-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-"
"{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],
uuid[15]);
}
size_t UUID::Hash() const noexcept {
u64 upper_hash;
u64 lower_hash;
std::memcpy(&upper_hash, uuid.data(), sizeof(u64));
std::memcpy(&lower_hash, uuid.data() + sizeof(u64), sizeof(u64));
return upper_hash ^ std::rotl(lower_hash, 1);
}
u128 UUID::AsU128() const {
u128 uuid_old;
std::memcpy(&uuid_old, uuid.data(), sizeof(UUID));
return uuid_old;
}
UUID UUID::MakeRandom() {
std::random_device device;
std::mt19937 gen(device());
std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
return UUID{distribution(gen), distribution(gen)};
return MakeRandomWithSeed(device());
}
std::string UUID::Format() const {
return fmt::format("{:016x}{:016x}", uuid[1], uuid[0]);
UUID UUID::MakeRandomWithSeed(u32 seed) {
// Create and initialize our RNG.
TinyMT rng;
rng.Initialize(seed);
UUID uuid;
// Populate the UUID with random bytes.
rng.GenerateRandomBytes(uuid.uuid.data(), sizeof(UUID));
return uuid;
}
std::string UUID::FormatSwitch() const {
std::array<u8, 16> s{};
std::memcpy(s.data(), uuid.data(), sizeof(u128));
return fmt::format("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{"
":02x}{:02x}{:02x}{:02x}{:02x}",
s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11],
s[12], s[13], s[14], s[15]);
UUID UUID::MakeRandomRFC4122V4() {
auto uuid = MakeRandom();
// According to Proposed Standard RFC 4122 Section 4.4, we must:
// 1. Set the two most significant bits (bits 6 and 7) of the
// clock_seq_hi_and_reserved to zero and one, respectively.
uuid.uuid[8] = 0x80 | (uuid.uuid[8] & 0x3F);
// 2. Set the four most significant bits (bits 12 through 15) of the
// time_hi_and_version field to the 4-bit version number from Section 4.1.3.
uuid.uuid[6] = 0x40 | (uuid.uuid[6] & 0xF);
return uuid;
}
} // namespace Common
+106 -54
View File
@@ -1,9 +1,11 @@
// Copyright 2018 yuzu Emulator Project
// Copyright 2022 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <functional>
#include <string>
#include <string_view>
@@ -11,69 +13,119 @@
namespace Common {
constexpr u128 INVALID_UUID{{0, 0}};
/**
* Converts a hex string to a 128-bit unsigned integer.
*
* The hex string can be formatted in lowercase or uppercase, with or without the "0x" prefix.
*
* This function will assert and return INVALID_UUID under the following conditions:
* - If the hex string is more than 32 characters long
* - If the hex string contains non-hexadecimal characters
*
* @param hex_string Hexadecimal string
*
* @returns A 128-bit unsigned integer if successfully converted, INVALID_UUID otherwise.
*/
[[nodiscard]] u128 HexStringToU128(std::string_view hex_string);
struct UUID {
// UUIDs which are 0 are considered invalid!
u128 uuid;
UUID() = default;
constexpr explicit UUID(const u128& id) : uuid{id} {}
constexpr explicit UUID(const u64 lo, const u64 hi) : uuid{{lo, hi}} {}
explicit UUID(std::string_view hex_string) {
uuid = HexStringToU128(hex_string);
std::array<u8, 0x10> uuid{};
/// Constructs an invalid UUID.
constexpr UUID() = default;
/// Constructs a UUID from a reference to a 128 bit array.
constexpr explicit UUID(const std::array<u8, 16>& uuid_) : uuid{uuid_} {}
/**
* Constructs a UUID from either:
* 1. A 32 hexadecimal character string representing the bytes of the UUID
* 2. A RFC 4122 formatted UUID string, in the format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
*
* The input string may contain uppercase or lowercase characters, but they must:
* 1. Contain valid hexadecimal characters (0-9, a-f, A-F)
* 2. Not contain the "0x" hexadecimal prefix
*
* Should the input string not meet the above requirements,
* an assert will be triggered and an invalid UUID is set instead.
*/
explicit UUID(std::string_view uuid_string);
~UUID() = default;
constexpr UUID(const UUID&) noexcept = default;
constexpr UUID(UUID&&) noexcept = default;
constexpr UUID& operator=(const UUID&) noexcept = default;
constexpr UUID& operator=(UUID&&) noexcept = default;
/**
* Returns whether the stored UUID is valid or not.
*
* @returns True if the stored UUID is valid, false otherwise.
*/
constexpr bool IsValid() const {
return uuid != std::array<u8, 0x10>{};
}
[[nodiscard]] constexpr explicit operator bool() const {
return uuid != INVALID_UUID;
/**
* Returns whether the stored UUID is invalid or not.
*
* @returns True if the stored UUID is invalid, false otherwise.
*/
constexpr bool IsInvalid() const {
return !IsValid();
}
[[nodiscard]] constexpr bool operator==(const UUID& rhs) const {
return uuid == rhs.uuid;
/**
* Returns a 32 hexadecimal character string representing the bytes of the UUID.
*
* @returns A 32 hexadecimal character string of the UUID.
*/
std::string RawString() const;
/**
* Returns a RFC 4122 formatted UUID string in the format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
*
* @returns A RFC 4122 formatted UUID string.
*/
std::string FormattedString() const;
/**
* Returns a 64-bit hash of the UUID for use in hash table data structures.
*
* @returns A 64-bit hash of the UUID.
*/
size_t Hash() const noexcept;
/// DO NOT USE. Copies the contents of the UUID into a u128.
u128 AsU128() const;
/**
* Creates a default UUID "yuzu Default UID".
*
* @returns A UUID with its bytes set to the ASCII values of "yuzu Default UID".
*/
static constexpr UUID MakeDefault() {
return UUID{
{'y', 'u', 'z', 'u', ' ', 'D', 'e', 'f', 'a', 'u', 'l', 't', ' ', 'U', 'I', 'D'},
};
}
[[nodiscard]] constexpr bool operator!=(const UUID& rhs) const {
return !operator==(rhs);
}
/**
* Creates a random UUID.
*
* @returns A random UUID.
*/
static UUID MakeRandom();
// TODO(ogniK): Properly generate uuids based on RFC-4122
[[nodiscard]] static UUID Generate();
/**
* Creates a random UUID with a seed.
*
* @param seed A seed to initialize the Mersenne-Twister RNG
*
* @returns A random UUID.
*/
static UUID MakeRandomWithSeed(u32 seed);
// Set the UUID to {0,0} to be considered an invalid user
constexpr void Invalidate() {
uuid = INVALID_UUID;
}
/**
* Creates a random UUID. The generated UUID is RFC 4122 Version 4 compliant.
*
* @returns A random UUID that is RFC 4122 Version 4 compliant.
*/
static UUID MakeRandomRFC4122V4();
[[nodiscard]] constexpr bool IsInvalid() const {
return uuid == INVALID_UUID;
}
[[nodiscard]] constexpr bool IsValid() const {
return !IsInvalid();
}
// TODO(ogniK): Properly generate a Nintendo ID
[[nodiscard]] constexpr u64 GetNintendoID() const {
return uuid[0];
}
[[nodiscard]] std::string Format() const;
[[nodiscard]] std::string FormatSwitch() const;
friend constexpr bool operator==(const UUID& lhs, const UUID& rhs) = default;
};
static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
static_assert(sizeof(UUID) == 0x10, "UUID has incorrect size.");
/// An invalid UUID. This UUID has all its bytes set to 0.
constexpr UUID InvalidUUID = {};
} // namespace Common
@@ -82,7 +134,7 @@ namespace std {
template <>
struct hash<Common::UUID> {
size_t operator()(const Common::UUID& uuid) const noexcept {
return uuid.uuid[1] ^ uuid.uuid[0];
return uuid.Hash();
}
};
+11 -5
View File
@@ -65,14 +65,20 @@ private:
#ifdef ARCHITECTURE_x86_64
std::unique_ptr<WallClock> CreateBestMatchingClock(u32 emulated_cpu_frequency,
u32 emulated_clock_frequency) {
std::unique_ptr<WallClock> CreateBestMatchingClock(u64 emulated_cpu_frequency,
u64 emulated_clock_frequency) {
const auto& caps = GetCPUCaps();
u64 rtsc_frequency = 0;
if (caps.invariant_tsc) {
rtsc_frequency = EstimateRDTSCFrequency();
}
if (rtsc_frequency == 0) {
// Fallback to StandardWallClock if the hardware TSC does not have the precision greater than:
// - A nanosecond
// - The emulated CPU frequency
// - The emulated clock counter frequency (CNTFRQ)
if (rtsc_frequency <= WallClock::NS_RATIO || rtsc_frequency <= emulated_cpu_frequency ||
rtsc_frequency <= emulated_clock_frequency) {
return std::make_unique<StandardWallClock>(emulated_cpu_frequency,
emulated_clock_frequency);
} else {
@@ -83,8 +89,8 @@ std::unique_ptr<WallClock> CreateBestMatchingClock(u32 emulated_cpu_frequency,
#else
std::unique_ptr<WallClock> CreateBestMatchingClock(u32 emulated_cpu_frequency,
u32 emulated_clock_frequency) {
std::unique_ptr<WallClock> CreateBestMatchingClock(u64 emulated_cpu_frequency,
u64 emulated_clock_frequency) {
return std::make_unique<StandardWallClock>(emulated_cpu_frequency, emulated_clock_frequency);
}
+6 -2
View File
@@ -13,6 +13,10 @@ namespace Common {
class WallClock {
public:
static constexpr u64 NS_RATIO = 1'000'000'000;
static constexpr u64 US_RATIO = 1'000'000;
static constexpr u64 MS_RATIO = 1'000;
virtual ~WallClock() = default;
/// Returns current wall time in nanoseconds
@@ -49,7 +53,7 @@ private:
bool is_native;
};
[[nodiscard]] std::unique_ptr<WallClock> CreateBestMatchingClock(u32 emulated_cpu_frequency,
u32 emulated_clock_frequency);
[[nodiscard]] std::unique_ptr<WallClock> CreateBestMatchingClock(u64 emulated_cpu_frequency,
u64 emulated_clock_frequency);
} // namespace Common
+50 -52
View File
@@ -1,8 +1,12 @@
// Copyright 2013 Dolphin Emulator Project / 2015 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
// Copyright 2013 Dolphin Emulator Project / 2015 Citra Emulator Project / 2022 Yuzu Emulator
// Project Licensed under GPLv2 or any later version Refer to the license.txt file included.
#include <array>
#include <cstring>
#include <iterator>
#include <span>
#include <string_view>
#include "common/bit_util.h"
#include "common/common_types.h"
#include "common/x64/cpu_detect.h"
@@ -17,7 +21,7 @@
// clang-format on
#endif
static inline void __cpuidex(int info[4], int function_id, int subfunction_id) {
static inline void __cpuidex(int info[4], u32 function_id, u32 subfunction_id) {
#if defined(__DragonFly__) || defined(__FreeBSD__)
// Despite the name, this is just do_cpuid() with ECX as second input.
cpuid_count((u_int)function_id, (u_int)subfunction_id, (u_int*)info);
@@ -30,7 +34,7 @@ static inline void __cpuidex(int info[4], int function_id, int subfunction_id) {
#endif
}
static inline void __cpuid(int info[4], int function_id) {
static inline void __cpuid(int info[4], u32 function_id) {
return __cpuidex(info, function_id, 0);
}
@@ -45,6 +49,17 @@ static inline u64 _xgetbv(u32 index) {
namespace Common {
CPUCaps::Manufacturer CPUCaps::ParseManufacturer(std::string_view brand_string) {
if (brand_string == "GenuineIntel") {
return Manufacturer::Intel;
} else if (brand_string == "AuthenticAMD") {
return Manufacturer::AMD;
} else if (brand_string == "HygonGenuine") {
return Manufacturer::Hygon;
}
return Manufacturer::Unknown;
}
// Detects the various CPU features
static CPUCaps Detect() {
CPUCaps caps = {};
@@ -53,57 +68,44 @@ static CPUCaps Detect() {
// yuzu at all anyway
int cpu_id[4];
memset(caps.brand_string, 0, sizeof(caps.brand_string));
// Detect CPU's CPUID capabilities and grab CPU string
// Detect CPU's CPUID capabilities and grab manufacturer string
__cpuid(cpu_id, 0x00000000);
u32 max_std_fn = cpu_id[0]; // EAX
const u32 max_std_fn = cpu_id[0]; // EAX
std::memcpy(&caps.brand_string[0], &cpu_id[1], sizeof(int));
std::memcpy(&caps.brand_string[4], &cpu_id[3], sizeof(int));
std::memcpy(&caps.brand_string[8], &cpu_id[2], sizeof(int));
if (cpu_id[1] == 0x756e6547 && cpu_id[2] == 0x6c65746e && cpu_id[3] == 0x49656e69)
caps.manufacturer = Manufacturer::Intel;
else if (cpu_id[1] == 0x68747541 && cpu_id[2] == 0x444d4163 && cpu_id[3] == 0x69746e65)
caps.manufacturer = Manufacturer::AMD;
else if (cpu_id[1] == 0x6f677948 && cpu_id[2] == 0x656e6975 && cpu_id[3] == 0x6e65476e)
caps.manufacturer = Manufacturer::Hygon;
else
caps.manufacturer = Manufacturer::Unknown;
std::memset(caps.brand_string, 0, std::size(caps.brand_string));
std::memcpy(&caps.brand_string[0], &cpu_id[1], sizeof(u32));
std::memcpy(&caps.brand_string[4], &cpu_id[3], sizeof(u32));
std::memcpy(&caps.brand_string[8], &cpu_id[2], sizeof(u32));
caps.manufacturer = CPUCaps::ParseManufacturer(caps.brand_string);
// Set reasonable default cpu string even if brand string not available
std::strncpy(caps.cpu_string, caps.brand_string, std::size(caps.brand_string));
__cpuid(cpu_id, 0x80000000);
u32 max_ex_fn = cpu_id[0];
// Set reasonable default brand string even if brand string not available
strcpy(caps.cpu_string, caps.brand_string);
const u32 max_ex_fn = cpu_id[0];
// Detect family and other miscellaneous features
if (max_std_fn >= 1) {
__cpuid(cpu_id, 0x00000001);
if ((cpu_id[3] >> 25) & 1)
caps.sse = true;
if ((cpu_id[3] >> 26) & 1)
caps.sse2 = true;
if ((cpu_id[2]) & 1)
caps.sse3 = true;
if ((cpu_id[2] >> 9) & 1)
caps.ssse3 = true;
if ((cpu_id[2] >> 19) & 1)
caps.sse4_1 = true;
if ((cpu_id[2] >> 20) & 1)
caps.sse4_2 = true;
if ((cpu_id[2] >> 25) & 1)
caps.aes = true;
caps.sse = Common::Bit<25>(cpu_id[3]);
caps.sse2 = Common::Bit<26>(cpu_id[3]);
caps.sse3 = Common::Bit<0>(cpu_id[2]);
caps.ssse3 = Common::Bit<9>(cpu_id[2]);
caps.sse4_1 = Common::Bit<19>(cpu_id[2]);
caps.sse4_2 = Common::Bit<20>(cpu_id[2]);
caps.aes = Common::Bit<25>(cpu_id[2]);
// AVX support requires 3 separate checks:
// - Is the AVX bit set in CPUID?
// - Is the XSAVE bit set in CPUID?
// - XGETBV result has the XCR bit set.
if (((cpu_id[2] >> 28) & 1) && ((cpu_id[2] >> 27) & 1)) {
if (Common::Bit<28>(cpu_id[2]) && Common::Bit<27>(cpu_id[2])) {
if ((_xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) == 0x6) {
caps.avx = true;
if ((cpu_id[2] >> 12) & 1)
if (Common::Bit<12>(cpu_id[2]))
caps.fma = true;
}
}
@@ -111,15 +113,13 @@ static CPUCaps Detect() {
if (max_std_fn >= 7) {
__cpuidex(cpu_id, 0x00000007, 0x00000000);
// Can't enable AVX2 unless the XSAVE/XGETBV checks above passed
if ((cpu_id[1] >> 5) & 1)
caps.avx2 = caps.avx;
if ((cpu_id[1] >> 3) & 1)
caps.bmi1 = true;
if ((cpu_id[1] >> 8) & 1)
caps.bmi2 = true;
caps.avx2 = caps.avx && Common::Bit<5>(cpu_id[1]);
caps.bmi1 = Common::Bit<3>(cpu_id[1]);
caps.bmi2 = Common::Bit<8>(cpu_id[1]);
// Checks for AVX512F, AVX512CD, AVX512VL, AVX512DQ, AVX512BW (Intel Skylake-X/SP)
if ((cpu_id[1] >> 16) & 1 && (cpu_id[1] >> 28) & 1 && (cpu_id[1] >> 31) & 1 &&
(cpu_id[1] >> 17) & 1 && (cpu_id[1] >> 30) & 1) {
if (Common::Bit<16>(cpu_id[1]) && Common::Bit<28>(cpu_id[1]) &&
Common::Bit<31>(cpu_id[1]) && Common::Bit<17>(cpu_id[1]) &&
Common::Bit<30>(cpu_id[1])) {
caps.avx512 = caps.avx2;
}
}
@@ -138,15 +138,13 @@ static CPUCaps Detect() {
if (max_ex_fn >= 0x80000001) {
// Check for more features
__cpuid(cpu_id, 0x80000001);
if ((cpu_id[2] >> 16) & 1)
caps.fma4 = true;
caps.lzcnt = Common::Bit<5>(cpu_id[2]);
caps.fma4 = Common::Bit<16>(cpu_id[2]);
}
if (max_ex_fn >= 0x80000007) {
__cpuid(cpu_id, 0x80000007);
if (cpu_id[3] & (1 << 8)) {
caps.invariant_tsc = true;
}
caps.invariant_tsc = Common::Bit<8>(cpu_id[3]);
}
if (max_std_fn >= 0x16) {
+36 -28
View File
@@ -1,42 +1,50 @@
// Copyright 2013 Dolphin Emulator Project / 2015 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
// Copyright 2013 Dolphin Emulator Project / 2015 Citra Emulator Project / 2022 Yuzu Emulator
// Project Project Licensed under GPLv2 or any later version Refer to the license.txt file included.
#pragma once
namespace Common {
#include <string_view>
#include "common/common_types.h"
enum class Manufacturer : u32 {
Intel = 0,
AMD = 1,
Hygon = 2,
Unknown = 3,
};
namespace Common {
/// x86/x64 CPU capabilities that may be detected by this module
struct CPUCaps {
enum class Manufacturer : u8 {
Unknown = 0,
Intel = 1,
AMD = 2,
Hygon = 3,
};
static Manufacturer ParseManufacturer(std::string_view brand_string);
Manufacturer manufacturer;
char cpu_string[0x21];
char brand_string[0x41];
bool sse;
bool sse2;
bool sse3;
bool ssse3;
bool sse4_1;
bool sse4_2;
bool lzcnt;
bool avx;
bool avx2;
bool avx512;
bool bmi1;
bool bmi2;
bool fma;
bool fma4;
bool aes;
bool invariant_tsc;
char brand_string[13];
char cpu_string[48];
u32 base_frequency;
u32 max_frequency;
u32 bus_frequency;
bool sse : 1;
bool sse2 : 1;
bool sse3 : 1;
bool ssse3 : 1;
bool sse4_1 : 1;
bool sse4_2 : 1;
bool lzcnt : 1;
bool avx : 1;
bool avx2 : 1;
bool avx512 : 1;
bool bmi1 : 1;
bool bmi2 : 1;
bool fma : 1;
bool fma4 : 1;
bool aes : 1;
bool invariant_tsc : 1;
};
/**
+3 -3
View File
@@ -47,9 +47,9 @@ NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequen
_mm_mfence();
time_point.inner.last_measure = __rdtsc();
time_point.inner.accumulated_ticks = 0U;
ns_rtsc_factor = GetFixedPoint64Factor(1000000000, rtsc_frequency);
us_rtsc_factor = GetFixedPoint64Factor(1000000, rtsc_frequency);
ms_rtsc_factor = GetFixedPoint64Factor(1000, rtsc_frequency);
ns_rtsc_factor = GetFixedPoint64Factor(NS_RATIO, rtsc_frequency);
us_rtsc_factor = GetFixedPoint64Factor(US_RATIO, rtsc_frequency);
ms_rtsc_factor = GetFixedPoint64Factor(MS_RATIO, rtsc_frequency);
clock_rtsc_factor = GetFixedPoint64Factor(emulated_clock_frequency, rtsc_frequency);
cpu_rtsc_factor = GetFixedPoint64Factor(emulated_cpu_frequency, rtsc_frequency);
}
+8 -8
View File
@@ -37,12 +37,12 @@ constexpr Xbyak::Reg IndexToReg(size_t reg_index) {
}
}
inline std::bitset<32> BuildRegSet(std::initializer_list<Xbyak::Reg> regs) {
std::bitset<32> bits;
constexpr std::bitset<32> BuildRegSet(std::initializer_list<Xbyak::Reg> regs) {
size_t bits = 0;
for (const Xbyak::Reg& reg : regs) {
bits[RegToIndex(reg)] = true;
bits |= size_t{1} << RegToIndex(reg);
}
return bits;
return {bits};
}
constexpr inline std::bitset<32> ABI_ALL_GPRS(0x0000FFFF);
@@ -57,7 +57,7 @@ constexpr inline Xbyak::Reg ABI_PARAM2 = Xbyak::util::rdx;
constexpr inline Xbyak::Reg ABI_PARAM3 = Xbyak::util::r8;
constexpr inline Xbyak::Reg ABI_PARAM4 = Xbyak::util::r9;
const std::bitset<32> ABI_ALL_CALLER_SAVED = BuildRegSet({
constexpr inline std::bitset<32> ABI_ALL_CALLER_SAVED = BuildRegSet({
// GPRs
Xbyak::util::rcx,
Xbyak::util::rdx,
@@ -74,7 +74,7 @@ const std::bitset<32> ABI_ALL_CALLER_SAVED = BuildRegSet({
Xbyak::util::xmm5,
});
const std::bitset<32> ABI_ALL_CALLEE_SAVED = BuildRegSet({
constexpr inline std::bitset<32> ABI_ALL_CALLEE_SAVED = BuildRegSet({
// GPRs
Xbyak::util::rbx,
Xbyak::util::rsi,
@@ -108,7 +108,7 @@ constexpr inline Xbyak::Reg ABI_PARAM2 = Xbyak::util::rsi;
constexpr inline Xbyak::Reg ABI_PARAM3 = Xbyak::util::rdx;
constexpr inline Xbyak::Reg ABI_PARAM4 = Xbyak::util::rcx;
const std::bitset<32> ABI_ALL_CALLER_SAVED = BuildRegSet({
constexpr inline std::bitset<32> ABI_ALL_CALLER_SAVED = BuildRegSet({
// GPRs
Xbyak::util::rcx,
Xbyak::util::rdx,
@@ -137,7 +137,7 @@ const std::bitset<32> ABI_ALL_CALLER_SAVED = BuildRegSet({
Xbyak::util::xmm15,
});
const std::bitset<32> ABI_ALL_CALLEE_SAVED = BuildRegSet({
constexpr inline std::bitset<32> ABI_ALL_CALLEE_SAVED = BuildRegSet({
// GPRs
Xbyak::util::rbx,
Xbyak::util::rbp,
+4
View File
@@ -152,6 +152,7 @@ add_library(core STATIC
hle/api_version.h
hle/ipc.h
hle/ipc_helpers.h
hle/kernel/board/nintendo/nx/k_memory_layout.h
hle/kernel/board/nintendo/nx/k_system_control.cpp
hle/kernel/board/nintendo/nx/k_system_control.h
hle/kernel/board/nintendo/nx/secure_monitor.h
@@ -164,6 +165,7 @@ add_library(core STATIC
hle/kernel/hle_ipc.h
hle/kernel/init/init_slab_setup.cpp
hle/kernel/init/init_slab_setup.h
hle/kernel/initial_process.h
hle/kernel/k_address_arbiter.cpp
hle/kernel/k_address_arbiter.h
hle/kernel/k_address_space_info.cpp
@@ -467,6 +469,8 @@ add_library(core STATIC
hle/service/mii/types.h
hle/service/mm/mm_u.cpp
hle/service/mm/mm_u.h
hle/service/mnpp/mnpp_app.cpp
hle/service/mnpp/mnpp_app.h
hle/service/ncm/ncm.cpp
hle/service/ncm/ncm.h
hle/service/nfc/nfc.cpp
+5 -1
View File
@@ -6,6 +6,7 @@
#include <array>
#include <vector>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hardware_properties.h"
@@ -24,8 +25,11 @@ class CPUInterruptHandler;
using CPUInterrupts = std::array<CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>;
/// Generic ARMv8 CPU interface
class ARM_Interface : NonCopyable {
class ARM_Interface {
public:
YUZU_NON_COPYABLE(ARM_Interface);
YUZU_NON_MOVEABLE(ARM_Interface);
explicit ARM_Interface(System& system_, CPUInterrupts& interrupt_handlers_,
bool uses_wall_clock_)
: system{system_}, interrupt_handlers{interrupt_handlers_}, uses_wall_clock{
+12
View File
@@ -137,6 +137,8 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
config.only_detect_misalignment_via_page_table_on_page_boundary = true;
config.fastmem_exclusive_access = true;
config.recompile_on_exclusive_fastmem_failure = true;
// Multi-process state
config.processor_id = core_index;
@@ -178,6 +180,12 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
if (!Settings::values.cpuopt_fastmem) {
config.fastmem_pointer = nullptr;
}
if (!Settings::values.cpuopt_fastmem_exclusives) {
config.fastmem_exclusive_access = false;
}
if (!Settings::values.cpuopt_recompile_exclusives) {
config.recompile_on_exclusive_fastmem_failure = false;
}
}
// Unsafe optimizations
@@ -195,6 +203,9 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
if (Settings::values.cpuopt_unsafe_inaccurate_nan) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
}
if (Settings::values.cpuopt_unsafe_ignore_global_monitor) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor;
}
}
// Curated optimizations
@@ -203,6 +214,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue;
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor;
}
return std::make_unique<Dynarmic::A32::Jit>(config);
+13
View File
@@ -185,6 +185,9 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
config.fastmem_pointer = page_table->fastmem_arena;
config.fastmem_address_space_bits = address_space_bits;
config.silently_mirror_fastmem = false;
config.fastmem_exclusive_access = true;
config.recompile_on_exclusive_fastmem_failure = true;
}
// Multi-process state
@@ -237,6 +240,12 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
if (!Settings::values.cpuopt_fastmem) {
config.fastmem_pointer = nullptr;
}
if (!Settings::values.cpuopt_fastmem_exclusives) {
config.fastmem_exclusive_access = false;
}
if (!Settings::values.cpuopt_recompile_exclusives) {
config.recompile_on_exclusive_fastmem_failure = false;
}
}
// Unsafe optimizations
@@ -254,6 +263,9 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
if (Settings::values.cpuopt_unsafe_fastmem_check) {
config.fastmem_address_space_bits = 64;
}
if (Settings::values.cpuopt_unsafe_ignore_global_monitor) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor;
}
}
// Curated optimizations
@@ -262,6 +274,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
config.fastmem_address_space_bits = 64;
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor;
}
return std::make_shared<Dynarmic::A64::Jit>(config);
@@ -37,8 +37,8 @@ u128 DynarmicExclusiveMonitor::ExclusiveRead128(std::size_t core_index, VAddr ad
});
}
void DynarmicExclusiveMonitor::ClearExclusive() {
monitor.Clear();
void DynarmicExclusiveMonitor::ClearExclusive(std::size_t core_index) {
monitor.ClearProcessor(core_index);
}
bool DynarmicExclusiveMonitor::ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) {
@@ -29,7 +29,7 @@ public:
u32 ExclusiveRead32(std::size_t core_index, VAddr addr) override;
u64 ExclusiveRead64(std::size_t core_index, VAddr addr) override;
u128 ExclusiveRead128(std::size_t core_index, VAddr addr) override;
void ClearExclusive() override;
void ClearExclusive(std::size_t core_index) override;
bool ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) override;
bool ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) override;
+1 -1
View File
@@ -23,7 +23,7 @@ public:
virtual u32 ExclusiveRead32(std::size_t core_index, VAddr addr) = 0;
virtual u64 ExclusiveRead64(std::size_t core_index, VAddr addr) = 0;
virtual u128 ExclusiveRead128(std::size_t core_index, VAddr addr) = 0;
virtual void ClearExclusive() = 0;
virtual void ClearExclusive(std::size_t core_index) = 0;
virtual bool ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) = 0;
virtual bool ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) = 0;
+13 -2
View File
@@ -28,7 +28,9 @@
#include "core/file_sys/vfs_real.h"
#include "core/hardware_interrupt_manager.h"
#include "core/hid/hid_core.h"
#include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/physical_core.h"
@@ -252,9 +254,16 @@ struct System::Impl {
}
telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);
// Create a resource limit for the process.
const auto physical_memory_size =
kernel.MemoryManager().GetSize(Kernel::KMemoryManager::Pool::Application);
auto* resource_limit = Kernel::CreateResourceLimitForProcess(system, physical_memory_size);
// Create the process.
auto main_process = Kernel::KProcess::Create(system.Kernel());
ASSERT(Kernel::KProcess::Initialize(main_process, system, "main",
Kernel::KProcess::ProcessType::Userland)
Kernel::KProcess::ProcessType::Userland, resource_limit)
.IsSuccess());
const auto [load_result, load_parameters] = app_loader->Load(*main_process, system);
if (load_result != Loader::ResultStatus::Success) {
@@ -317,7 +326,9 @@ struct System::Impl {
is_powered_on = false;
exit_lock = false;
gpu_core->NotifyShutdown();
if (gpu_core != nullptr) {
gpu_core->NotifyShutdown();
}
services.reset();
service_manager.reset();
+4 -1
View File
@@ -3,10 +3,13 @@
// Refer to the license.txt file included.
#include "core/device_memory.h"
#include "hle/kernel/board/nintendo/nx/k_system_control.h"
namespace Core {
DeviceMemory::DeviceMemory() : buffer{DramMemoryMap::Size, 1ULL << 39} {}
DeviceMemory::DeviceMemory()
: buffer{Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetIntendedMemorySize(),
1ULL << 39} {}
DeviceMemory::~DeviceMemory() = default;
} // namespace Core
-4
View File
@@ -12,12 +12,8 @@ namespace Core {
namespace DramMemoryMap {
enum : u64 {
Base = 0x80000000ULL,
Size = 0x100000000ULL,
End = Base + Size,
KernelReserveBase = Base + 0x60000,
SlabHeapBase = KernelReserveBase + 0x85000,
SlapHeapSize = 0xa21000,
SlabHeapEnd = SlabHeapBase + SlapHeapSize,
};
}; // namespace DramMemoryMap
+9 -9
View File
@@ -128,15 +128,6 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
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 = fs_controller.GetModificationDumpRoot(title_id);
if (dump_dir != nullptr) {
const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs");
VfsRawCopyD(exefs, exefs_dir);
}
}
const auto& disabled = Settings::values.disabled_addons[title_id];
const auto update_disabled =
std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend();
@@ -179,6 +170,15 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
}
}
if (Settings::values.dump_exefs) {
LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id);
const auto dump_dir = fs_controller.GetModificationDumpRoot(title_id);
if (dump_dir != nullptr) {
const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs");
VfsRawCopyD(exefs, exefs_dir);
}
}
return exefs;
}
+15 -3
View File
@@ -12,6 +12,7 @@
#include <type_traits>
#include <vector>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/file_sys/vfs_types.h"
@@ -29,8 +30,11 @@ enum class VfsEntryType {
// A class representing an abstract filesystem. A default implementation given the root VirtualDir
// is provided for convenience, but if the Vfs implementation has any additional state or
// functionality, they will need to override.
class VfsFilesystem : NonCopyable {
class VfsFilesystem {
public:
YUZU_NON_COPYABLE(VfsFilesystem);
YUZU_NON_MOVEABLE(VfsFilesystem);
explicit VfsFilesystem(VirtualDir root);
virtual ~VfsFilesystem();
@@ -77,8 +81,12 @@ protected:
};
// A class representing a file in an abstract filesystem.
class VfsFile : NonCopyable {
class VfsFile {
public:
YUZU_NON_COPYABLE(VfsFile);
YUZU_NON_MOVEABLE(VfsFile);
VfsFile() = default;
virtual ~VfsFile();
// Retrieves the file name.
@@ -176,8 +184,12 @@ public:
};
// A class representing a directory in an abstract filesystem.
class VfsDirectory : NonCopyable {
class VfsDirectory {
public:
YUZU_NON_COPYABLE(VfsDirectory);
YUZU_NON_MOVEABLE(VfsDirectory);
VfsDirectory() = default;
virtual ~VfsDirectory();
// Retrives the file located at path as if the current directory was root. Returns nullptr if
+1 -2
View File
@@ -13,8 +13,7 @@ ProfileSelectApplet::~ProfileSelectApplet() = default;
void DefaultProfileSelectApplet::SelectProfile(
std::function<void(std::optional<Common::UUID>)> callback) const {
Service::Account::ProfileManager manager;
callback(manager.GetUser(Settings::values.current_user.GetValue())
.value_or(Common::UUID{Common::INVALID_UUID}));
callback(manager.GetUser(Settings::values.current_user.GetValue()).value_or(Common::UUID{}));
LOG_INFO(Service_ACC, "called, selecting current user instead of prompting...");
}
+10 -1
View File
@@ -42,11 +42,20 @@ public:
context.MakeCurrent();
}
~Scoped() {
context.DoneCurrent();
if (active) {
context.DoneCurrent();
}
}
/// In the event that context was destroyed before the Scoped is destroyed, this provides a
/// mechanism to prevent calling a destroyed object's method during the deconstructor
void Cancel() {
active = false;
}
private:
GraphicsContext& context;
bool active{true};
};
/// Calls MakeCurrent on the context and calls DoneCurrent when the scope for the returned value
+1
View File
@@ -10,6 +10,7 @@
#include <mutex>
#include <unordered_map>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/input.h"
#include "common/param_package.h"
+13 -5
View File
@@ -269,7 +269,8 @@ void EmulatedController::ReloadInput() {
}
// Use a common UUID for TAS
const auto tas_uuid = Common::UUID{0x0, 0x7A5};
static constexpr Common::UUID TAS_UUID = Common::UUID{
{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xA5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
// Register TAS devices. No need to force update
for (std::size_t index = 0; index < tas_button_devices.size(); ++index) {
@@ -278,8 +279,8 @@ void EmulatedController::ReloadInput() {
}
tas_button_devices[index]->SetCallback({
.on_change =
[this, index, tas_uuid](const Common::Input::CallbackStatus& callback) {
SetButton(callback, index, tas_uuid);
[this, index](const Common::Input::CallbackStatus& callback) {
SetButton(callback, index, TAS_UUID);
},
});
}
@@ -290,8 +291,8 @@ void EmulatedController::ReloadInput() {
}
tas_stick_devices[index]->SetCallback({
.on_change =
[this, index, tas_uuid](const Common::Input::CallbackStatus& callback) {
SetStick(callback, index, tas_uuid);
[this, index](const Common::Input::CallbackStatus& callback) {
SetStick(callback, index, TAS_UUID);
},
});
}
@@ -749,6 +750,7 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
raw_status.gyro.y.value,
raw_status.gyro.z.value,
});
emulated.SetGyroThreshold(raw_status.gyro.x.properties.threshold);
emulated.UpdateRotation(raw_status.delta_timestamp);
emulated.UpdateOrientation(raw_status.delta_timestamp);
force_update_motion = raw_status.force_update;
@@ -883,6 +885,12 @@ bool EmulatedController::TestVibration(std::size_t device_index) {
return SetVibration(device_index, DEFAULT_VIBRATION_VALUE);
}
bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) {
LOG_INFO(Service_HID, "Set polling mode {}", polling_mode);
auto& output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
return output_device->SetPollingMode(polling_mode) == Common::Input::PollingError::None;
}
void EmulatedController::SetLedPattern() {
for (auto& device : output_devices) {
if (!device) {
+9 -4
View File
@@ -13,8 +13,6 @@
#include "common/common_types.h"
#include "common/input.h"
#include "common/param_package.h"
#include "common/point.h"
#include "common/quaternion.h"
#include "common/settings.h"
#include "common/vector_math.h"
#include "core/hid/hid_types.h"
@@ -301,16 +299,23 @@ public:
/**
* Sends a specific vibration to the output device
* @return returns true if vibration had no errors
* @return true if vibration had no errors
*/
bool SetVibration(std::size_t device_index, VibrationValue vibration);
/**
* Sends a small vibration to the output device
* @return returns true if SetVibration was successfull
* @return true if SetVibration was successfull
*/
bool TestVibration(std::size_t device_index);
/**
* Sets the desired data to be polled from a controller
* @param polling_mode type of input desired buttons, gyro, nfc, ir, etc.
* @return true if SetPollingMode was successfull
*/
bool SetPollingMode(Common::Input::PollingMode polling_mode);
/// Returns the led pattern corresponding to this emulated controller
LedPattern GetLedPattern() const;
+1
View File
@@ -6,6 +6,7 @@
#include <memory>
#include "common/common_funcs.h"
#include "core/hid/hid_types.h"
namespace Core::HID {
+2 -2
View File
@@ -28,7 +28,7 @@ Common::Input::BatteryStatus TransformToBattery(const Common::Input::CallbackSta
if (value > 0.8f) {
battery = Common::Input::BatteryLevel::Full;
}
if (value >= 1.0f) {
if (value >= 0.95f) {
battery = Common::Input::BatteryLevel::Charging;
}
break;
@@ -114,7 +114,7 @@ Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatu
if (TransformToButton(callback).value) {
std::random_device device;
std::mt19937 gen(device());
std::uniform_int_distribution<s16> distribution(-1000, 1000);
std::uniform_int_distribution<s16> distribution(-5000, 5000);
status.accel.x.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
status.accel.y.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
status.accel.z.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
+2 -2
View File
@@ -10,7 +10,7 @@ namespace Core::HID {
MotionInput::MotionInput() {
// Initialize PID constants with default values
SetPID(0.3f, 0.005f, 0.0f);
SetGyroThreshold(0.00005f);
SetGyroThreshold(0.007f);
}
void MotionInput::SetPID(f32 new_kp, f32 new_ki, f32 new_kd) {
@@ -31,7 +31,7 @@ void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) {
gyro_bias = (gyro_bias * 0.9999f) + (gyroscope * 0.0001f);
}
if (gyro.Length2() < gyro_threshold) {
if (gyro.Length() < gyro_threshold) {
gyro = {};
} else {
only_accelerometer = false;
+8
View File
@@ -404,6 +404,11 @@ inline s32 RequestParser::Pop() {
return static_cast<s32>(Pop<u32>());
}
// Ignore the -Wclass-memaccess warning on memcpy for non-trivially default constructible objects.
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wclass-memaccess"
#endif
template <typename T>
void RequestParser::PopRaw(T& value) {
static_assert(std::is_trivially_copyable_v<T>,
@@ -411,6 +416,9 @@ void RequestParser::PopRaw(T& value) {
std::memcpy(&value, cmdbuf + index, sizeof(T));
index += (sizeof(T) + 3) / 4; // round up to word length
}
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
template <typename T>
T RequestParser::PopRaw() {
@@ -0,0 +1,13 @@
// Copyright 2022 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/common_types.h"
namespace Kernel {
constexpr inline PAddr MainMemoryAddress = 0x80000000;
} // namespace Kernel
@@ -5,6 +5,7 @@
#include <random>
#include "common/literals.h"
#include "common/settings.h"
#include "core/hle/kernel/board/nintendo/nx/k_system_control.h"
#include "core/hle/kernel/board/nintendo/nx/secure_monitor.h"
@@ -28,33 +29,20 @@ namespace {
using namespace Common::Literals;
u32 GetMemoryModeForInit() {
return 0x01;
}
u32 GetMemorySizeForInit() {
return 0;
return Settings::values.use_extended_memory_layout ? Smc::MemorySize_6GB : Smc::MemorySize_4GB;
}
Smc::MemoryArrangement GetMemoryArrangeForInit() {
switch (GetMemoryModeForInit() & 0x3F) {
case 0x01:
default:
return Smc::MemoryArrangement_4GB;
case 0x02:
return Smc::MemoryArrangement_4GBForAppletDev;
case 0x03:
return Smc::MemoryArrangement_4GBForSystemDev;
case 0x11:
return Smc::MemoryArrangement_6GB;
case 0x12:
return Smc::MemoryArrangement_6GBForAppletDev;
case 0x21:
return Smc::MemoryArrangement_8GB;
}
return Settings::values.use_extended_memory_layout ? Smc::MemoryArrangement_6GB
: Smc::MemoryArrangement_4GB;
}
} // namespace
size_t KSystemControl::Init::GetRealMemorySize() {
return GetIntendedMemorySize();
}
// Initialization.
size_t KSystemControl::Init::GetIntendedMemorySize() {
switch (GetMemorySizeForInit()) {
@@ -69,7 +57,13 @@ size_t KSystemControl::Init::GetIntendedMemorySize() {
}
PAddr KSystemControl::Init::GetKernelPhysicalBaseAddress(u64 base_address) {
return base_address;
const size_t real_dram_size = KSystemControl::Init::GetRealMemorySize();
const size_t intended_dram_size = KSystemControl::Init::GetIntendedMemorySize();
if (intended_dram_size * 2 < real_dram_size) {
return base_address;
} else {
return base_address + ((real_dram_size - intended_dram_size) / 2);
}
}
bool KSystemControl::Init::ShouldIncreaseThreadResourceLimit() {
@@ -13,6 +13,7 @@ public:
class Init {
public:
// Initialization.
static std::size_t GetRealMemorySize();
static std::size_t GetIntendedMemorySize();
static PAddr GetKernelPhysicalBaseAddress(u64 base_address);
static bool ShouldIncreaseThreadResourceLimit();
-5
View File
@@ -341,10 +341,6 @@ public:
return *thread;
}
bool IsThreadWaiting() const {
return is_thread_waiting;
}
private:
friend class IPC::ResponseBuilder;
@@ -379,7 +375,6 @@ private:
u32 domain_offset{};
std::shared_ptr<SessionRequestManager> manager;
bool is_thread_waiting{};
KernelCore& kernel;
Core::Memory::Memory& memory;
+23
View File
@@ -0,0 +1,23 @@
// Copyright 2022 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/common_types.h"
#include "common/literals.h"
#include "core/hle/kernel/board/nintendo/nx/k_memory_layout.h"
#include "core/hle/kernel/board/nintendo/nx/k_system_control.h"
namespace Kernel {
using namespace Common::Literals;
constexpr std::size_t InitialProcessBinarySizeMax = 12_MiB;
static inline PAddr GetInitialProcessBinaryPhysicalAddress() {
return Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetKernelPhysicalBaseAddress(
MainMemoryAddress);
}
} // namespace Kernel
+2 -2
View File
@@ -49,7 +49,7 @@ bool DecrementIfLessThan(Core::System& system, s32* out, VAddr address, s32 valu
}
} else {
// Otherwise, clear our exclusive hold and finish
monitor.ClearExclusive();
monitor.ClearExclusive(current_core);
}
// We're done.
@@ -78,7 +78,7 @@ bool UpdateIfEqual(Core::System& system, s32* out, VAddr address, s32 value, s32
}
} else {
// Otherwise, clear our exclusive hold and finish.
monitor.ClearExclusive();
monitor.ClearExclusive(current_core);
}
// We're done.
-2
View File
@@ -31,8 +31,6 @@ public:
}
constexpr void SetAffinity(s32 core, bool set) {
ASSERT(0 <= core && core < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
if (set) {
this->mask |= GetCoreBit(core);
} else {
+4 -3
View File
@@ -20,8 +20,6 @@ class KernelCore;
class KProcess;
#define KERNEL_AUTOOBJECT_TRAITS(CLASS, BASE_CLASS) \
YUZU_NON_COPYABLE(CLASS); \
YUZU_NON_MOVEABLE(CLASS); \
\
private: \
friend class ::Kernel::KClassTokenGenerator; \
@@ -32,6 +30,9 @@ private:
} \
\
public: \
YUZU_NON_COPYABLE(CLASS); \
YUZU_NON_MOVEABLE(CLASS); \
\
using BaseClass = BASE_CLASS; \
static constexpr TypeObj GetStaticTypeObj() { \
constexpr ClassTokenType Token = ClassToken(); \
@@ -224,9 +225,9 @@ private:
template <typename T>
class KScopedAutoObject {
public:
YUZU_NON_COPYABLE(KScopedAutoObject);
public:
constexpr KScopedAutoObject() = default;
constexpr KScopedAutoObject(T* o) : m_obj(o) {
@@ -16,13 +16,12 @@ class KernelCore;
class KProcess;
class KAutoObjectWithListContainer {
public:
YUZU_NON_COPYABLE(KAutoObjectWithListContainer);
YUZU_NON_MOVEABLE(KAutoObjectWithListContainer);
public:
using ListType = boost::intrusive::rbtree<KAutoObjectWithList>;
public:
class ListAccessor : public KScopedLightLock {
public:
explicit ListAccessor(KAutoObjectWithListContainer* container)
@@ -48,7 +47,6 @@ public:
friend class ListAccessor;
public:
KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(kernel), m_object_list() {}
void Initialize() {}
+3 -3
View File
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/alignment.h"
#include "common/common_types.h"
#include "core/device_memory.h"
#include "core/hle/kernel/k_auto_object.h"
@@ -28,8 +29,7 @@ ResultCode KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr
auto& page_table = m_owner->PageTable();
// Construct the page group.
KMemoryInfo kBlockInfo = page_table.QueryInfo(addr);
m_page_group = KPageLinkedList(kBlockInfo.GetAddress(), kBlockInfo.GetNumPages());
m_page_group = KPageLinkedList(addr, Common::DivideUp(size, PageSize));
// Lock the memory.
R_TRY(page_table.LockForCodeMemory(addr, size))
@@ -143,4 +143,4 @@ ResultCode KCodeMemory::UnmapFromOwner(VAddr address, size_t size) {
return ResultSuccess;
}
} // namespace Kernel
} // namespace Kernel
+5 -9
View File
@@ -14,7 +14,7 @@ KEvent::KEvent(KernelCore& kernel_)
KEvent::~KEvent() = default;
void KEvent::Initialize(std::string&& name_) {
void KEvent::Initialize(std::string&& name_, KProcess* owner_) {
// Increment reference count.
// Because reference count is one on creation, this will result
// in a reference count of two. Thus, when both readable and
@@ -30,10 +30,8 @@ void KEvent::Initialize(std::string&& name_) {
writable_event.Initialize(this, name_ + ":Writable");
// Set our owner process.
owner = kernel.CurrentProcess();
if (owner) {
owner->Open();
}
owner = owner_;
owner->Open();
// Mark initialized.
name = std::move(name_);
@@ -47,10 +45,8 @@ void KEvent::Finalize() {
void KEvent::PostDestroy(uintptr_t arg) {
// Release the event count resource the owner process holds.
KProcess* owner = reinterpret_cast<KProcess*>(arg);
if (owner) {
owner->GetResourceLimit()->Release(LimitableResource::Events, 1);
owner->Close();
}
owner->GetResourceLimit()->Release(LimitableResource::Events, 1);
owner->Close();
}
} // namespace Kernel
+1 -1
View File
@@ -22,7 +22,7 @@ public:
explicit KEvent(KernelCore& kernel_);
~KEvent() override;
void Initialize(std::string&& name);
void Initialize(std::string&& name, KProcess* owner_);
void Finalize() override;
+1 -2
View File
@@ -22,13 +22,12 @@ namespace Kernel {
class KernelCore;
class KHandleTable {
public:
YUZU_NON_COPYABLE(KHandleTable);
YUZU_NON_MOVEABLE(KHandleTable);
public:
static constexpr size_t MaxTableSize = 1024;
public:
explicit KHandleTable(KernelCore& kernel_);
~KHandleTable();
+4
View File
@@ -173,6 +173,10 @@ public:
return Dereference(FindVirtualLinear(address));
}
const KMemoryRegion& GetPhysicalLinearRegion(PAddr address) const {
return Dereference(FindPhysicalLinear(address));
}
const KMemoryRegion* GetPhysicalKernelTraceBufferRegion() const {
return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_KernelTraceBuffer);
}
+354 -131
View File
@@ -10,189 +10,412 @@
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/device_memory.h"
#include "core/hle/kernel/initial_process.h"
#include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/kernel/k_page_linked_list.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/svc_results.h"
#include "core/memory.h"
namespace Kernel {
KMemoryManager::KMemoryManager(Core::System& system_) : system{system_} {}
namespace {
std::size_t KMemoryManager::Impl::Initialize(Pool new_pool, u64 start_address, u64 end_address) {
const auto size{end_address - start_address};
// Calculate metadata sizes
const auto ref_count_size{(size / PageSize) * sizeof(u16)};
const auto optimize_map_size{(Common::AlignUp((size / PageSize), 64) / 64) * sizeof(u64)};
const auto manager_size{Common::AlignUp(optimize_map_size + ref_count_size, PageSize)};
const auto page_heap_size{KPageHeap::CalculateManagementOverheadSize(size)};
const auto total_metadata_size{manager_size + page_heap_size};
ASSERT(manager_size <= total_metadata_size);
ASSERT(Common::IsAligned(total_metadata_size, PageSize));
// Setup region
pool = new_pool;
// Initialize the manager's KPageHeap
heap.Initialize(start_address, size, page_heap_size);
// Free the memory to the heap
heap.Free(start_address, size / PageSize);
// Update the heap's used size
heap.UpdateUsedSize();
return total_metadata_size;
constexpr KMemoryManager::Pool GetPoolFromMemoryRegionType(u32 type) {
if ((type | KMemoryRegionType_DramApplicationPool) == type) {
return KMemoryManager::Pool::Application;
} else if ((type | KMemoryRegionType_DramAppletPool) == type) {
return KMemoryManager::Pool::Applet;
} else if ((type | KMemoryRegionType_DramSystemPool) == type) {
return KMemoryManager::Pool::System;
} else if ((type | KMemoryRegionType_DramSystemNonSecurePool) == type) {
return KMemoryManager::Pool::SystemNonSecure;
} else {
UNREACHABLE_MSG("InvalidMemoryRegionType for conversion to Pool");
return {};
}
}
void KMemoryManager::InitializeManager(Pool pool, u64 start_address, u64 end_address) {
ASSERT(pool < Pool::Count);
managers[static_cast<std::size_t>(pool)].Initialize(pool, start_address, end_address);
} // namespace
KMemoryManager::KMemoryManager(Core::System& system_)
: system{system_}, pool_locks{
KLightLock{system_.Kernel()},
KLightLock{system_.Kernel()},
KLightLock{system_.Kernel()},
KLightLock{system_.Kernel()},
} {}
void KMemoryManager::Initialize(VAddr management_region, size_t management_region_size) {
// Clear the management region to zero.
const VAddr management_region_end = management_region + management_region_size;
// Reset our manager count.
num_managers = 0;
// Traverse the virtual memory layout tree, initializing each manager as appropriate.
while (num_managers != MaxManagerCount) {
// Locate the region that should initialize the current manager.
PAddr region_address = 0;
size_t region_size = 0;
Pool region_pool = Pool::Count;
for (const auto& it : system.Kernel().MemoryLayout().GetPhysicalMemoryRegionTree()) {
// We only care about regions that we need to create managers for.
if (!it.IsDerivedFrom(KMemoryRegionType_DramUserPool)) {
continue;
}
// We want to initialize the managers in order.
if (it.GetAttributes() != num_managers) {
continue;
}
const PAddr cur_start = it.GetAddress();
const PAddr cur_end = it.GetEndAddress();
// Validate the region.
ASSERT(cur_end != 0);
ASSERT(cur_start != 0);
ASSERT(it.GetSize() > 0);
// Update the region's extents.
if (region_address == 0) {
region_address = cur_start;
region_size = it.GetSize();
region_pool = GetPoolFromMemoryRegionType(it.GetType());
} else {
ASSERT(cur_start == region_address + region_size);
// Update the size.
region_size = cur_end - region_address;
ASSERT(GetPoolFromMemoryRegionType(it.GetType()) == region_pool);
}
}
// If we didn't find a region, we're done.
if (region_size == 0) {
break;
}
// Initialize a new manager for the region.
Impl* manager = std::addressof(managers[num_managers++]);
ASSERT(num_managers <= managers.size());
const size_t cur_size = manager->Initialize(region_address, region_size, management_region,
management_region_end, region_pool);
management_region += cur_size;
ASSERT(management_region <= management_region_end);
// Insert the manager into the pool list.
const auto region_pool_index = static_cast<u32>(region_pool);
if (pool_managers_tail[region_pool_index] == nullptr) {
pool_managers_head[region_pool_index] = manager;
} else {
pool_managers_tail[region_pool_index]->SetNext(manager);
manager->SetPrev(pool_managers_tail[region_pool_index]);
}
pool_managers_tail[region_pool_index] = manager;
}
// Free each region to its corresponding heap.
size_t reserved_sizes[MaxManagerCount] = {};
const PAddr ini_start = GetInitialProcessBinaryPhysicalAddress();
const PAddr ini_end = ini_start + InitialProcessBinarySizeMax;
const PAddr ini_last = ini_end - 1;
for (const auto& it : system.Kernel().MemoryLayout().GetPhysicalMemoryRegionTree()) {
if (it.IsDerivedFrom(KMemoryRegionType_DramUserPool)) {
// Get the manager for the region.
auto index = it.GetAttributes();
auto& manager = managers[index];
const PAddr cur_start = it.GetAddress();
const PAddr cur_last = it.GetLastAddress();
const PAddr cur_end = it.GetEndAddress();
if (cur_start <= ini_start && ini_last <= cur_last) {
// Free memory before the ini to the heap.
if (cur_start != ini_start) {
manager.Free(cur_start, (ini_start - cur_start) / PageSize);
}
// Open/reserve the ini memory.
manager.OpenFirst(ini_start, InitialProcessBinarySizeMax / PageSize);
reserved_sizes[it.GetAttributes()] += InitialProcessBinarySizeMax;
// Free memory after the ini to the heap.
if (ini_last != cur_last) {
ASSERT(cur_end != 0);
manager.Free(ini_end, cur_end - ini_end);
}
} else {
// Ensure there's no partial overlap with the ini image.
if (cur_start <= ini_last) {
ASSERT(cur_last < ini_start);
} else {
// Otherwise, check the region for general validity.
ASSERT(cur_end != 0);
}
// Free the memory to the heap.
manager.Free(cur_start, it.GetSize() / PageSize);
}
}
}
// Update the used size for all managers.
for (size_t i = 0; i < num_managers; ++i) {
managers[i].SetInitialUsedHeapSize(reserved_sizes[i]);
}
}
VAddr KMemoryManager::AllocateAndOpenContinuous(std::size_t num_pages, std::size_t align_pages,
u32 option) {
// Early return if we're allocating no pages
PAddr KMemoryManager::AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option) {
// Early return if we're allocating no pages.
if (num_pages == 0) {
return {};
return 0;
}
// Lock the pool that we're allocating from
// Lock the pool that we're allocating from.
const auto [pool, dir] = DecodeOption(option);
const auto pool_index{static_cast<std::size_t>(pool)};
std::lock_guard lock{pool_locks[pool_index]};
KScopedLightLock lk(pool_locks[static_cast<std::size_t>(pool)]);
// Choose a heap based on our page size request
const s32 heap_index{KPageHeap::GetAlignedBlockIndex(num_pages, align_pages)};
// Choose a heap based on our page size request.
const s32 heap_index = KPageHeap::GetAlignedBlockIndex(num_pages, align_pages);
// Loop, trying to iterate from each block
// TODO (bunnei): Support multiple managers
Impl& chosen_manager{managers[pool_index]};
VAddr allocated_block{chosen_manager.AllocateBlock(heap_index, false)};
// If we failed to allocate, quit now
if (!allocated_block) {
return {};
// Loop, trying to iterate from each block.
Impl* chosen_manager = nullptr;
PAddr allocated_block = 0;
for (chosen_manager = this->GetFirstManager(pool, dir); chosen_manager != nullptr;
chosen_manager = this->GetNextManager(chosen_manager, dir)) {
allocated_block = chosen_manager->AllocateBlock(heap_index, true);
if (allocated_block != 0) {
break;
}
}
// If we allocated more than we need, free some
const auto allocated_pages{KPageHeap::GetBlockNumPages(heap_index)};
// If we failed to allocate, quit now.
if (allocated_block == 0) {
return 0;
}
// If we allocated more than we need, free some.
const size_t allocated_pages = KPageHeap::GetBlockNumPages(heap_index);
if (allocated_pages > num_pages) {
chosen_manager.Free(allocated_block + num_pages * PageSize, allocated_pages - num_pages);
chosen_manager->Free(allocated_block + num_pages * PageSize, allocated_pages - num_pages);
}
// Open the first reference to the pages.
chosen_manager->OpenFirst(allocated_block, num_pages);
return allocated_block;
}
ResultCode KMemoryManager::Allocate(KPageLinkedList& page_list, std::size_t num_pages, Pool pool,
Direction dir, u32 heap_fill_value) {
ASSERT(page_list.GetNumPages() == 0);
ResultCode KMemoryManager::AllocatePageGroupImpl(KPageLinkedList* out, size_t num_pages, Pool pool,
Direction dir, bool random) {
// Choose a heap based on our page size request.
const s32 heap_index = KPageHeap::GetBlockIndex(num_pages);
R_UNLESS(0 <= heap_index, ResultOutOfMemory);
// Early return if we're allocating no pages
if (num_pages == 0) {
return ResultSuccess;
}
// Lock the pool that we're allocating from
const auto pool_index{static_cast<std::size_t>(pool)};
std::lock_guard lock{pool_locks[pool_index]};
// Choose a heap based on our page size request
const s32 heap_index{KPageHeap::GetBlockIndex(num_pages)};
if (heap_index < 0) {
return ResultOutOfMemory;
}
// TODO (bunnei): Support multiple managers
Impl& chosen_manager{managers[pool_index]};
// Ensure that we don't leave anything un-freed
auto group_guard = detail::ScopeExit([&] {
for (const auto& it : page_list.Nodes()) {
const auto min_num_pages{std::min<size_t>(
it.GetNumPages(), (chosen_manager.GetEndAddress() - it.GetAddress()) / PageSize)};
chosen_manager.Free(it.GetAddress(), min_num_pages);
// Ensure that we don't leave anything un-freed.
auto group_guard = SCOPE_GUARD({
for (const auto& it : out->Nodes()) {
auto& manager = this->GetManager(system.Kernel().MemoryLayout(), it.GetAddress());
const size_t num_pages_to_free =
std::min(it.GetNumPages(), (manager.GetEndAddress() - it.GetAddress()) / PageSize);
manager.Free(it.GetAddress(), num_pages_to_free);
}
});
// Keep allocating until we've allocated all our pages
for (s32 index{heap_index}; index >= 0 && num_pages > 0; index--) {
const auto pages_per_alloc{KPageHeap::GetBlockNumPages(index)};
while (num_pages >= pages_per_alloc) {
// Allocate a block
VAddr allocated_block{chosen_manager.AllocateBlock(index, false)};
if (!allocated_block) {
break;
}
// Safely add it to our group
{
auto block_guard = detail::ScopeExit(
[&] { chosen_manager.Free(allocated_block, pages_per_alloc); });
if (const ResultCode result{page_list.AddBlock(allocated_block, pages_per_alloc)};
result.IsError()) {
return result;
// Keep allocating until we've allocated all our pages.
for (s32 index = heap_index; index >= 0 && num_pages > 0; index--) {
const size_t pages_per_alloc = KPageHeap::GetBlockNumPages(index);
for (Impl* cur_manager = this->GetFirstManager(pool, dir); cur_manager != nullptr;
cur_manager = this->GetNextManager(cur_manager, dir)) {
while (num_pages >= pages_per_alloc) {
// Allocate a block.
PAddr allocated_block = cur_manager->AllocateBlock(index, random);
if (allocated_block == 0) {
break;
}
block_guard.Cancel();
}
// Safely add it to our group.
{
auto block_guard =
SCOPE_GUARD({ cur_manager->Free(allocated_block, pages_per_alloc); });
R_TRY(out->AddBlock(allocated_block, pages_per_alloc));
block_guard.Cancel();
}
num_pages -= pages_per_alloc;
num_pages -= pages_per_alloc;
}
}
}
// Clear allocated memory.
for (const auto& it : page_list.Nodes()) {
std::memset(system.DeviceMemory().GetPointer(it.GetAddress()), heap_fill_value,
it.GetSize());
}
// Only succeed if we allocated as many pages as we wanted
if (num_pages) {
return ResultOutOfMemory;
}
// Only succeed if we allocated as many pages as we wanted.
R_UNLESS(num_pages == 0, ResultOutOfMemory);
// We succeeded!
group_guard.Cancel();
return ResultSuccess;
}
ResultCode KMemoryManager::Free(KPageLinkedList& page_list, std::size_t num_pages, Pool pool,
Direction dir, u32 heap_fill_value) {
// Early return if we're freeing no pages
if (!num_pages) {
return ResultSuccess;
}
ResultCode KMemoryManager::AllocateAndOpen(KPageLinkedList* out, size_t num_pages, u32 option) {
ASSERT(out != nullptr);
ASSERT(out->GetNumPages() == 0);
// Lock the pool that we're freeing from
const auto pool_index{static_cast<std::size_t>(pool)};
std::lock_guard lock{pool_locks[pool_index]};
// Early return if we're allocating no pages.
R_SUCCEED_IF(num_pages == 0);
// TODO (bunnei): Support multiple managers
Impl& chosen_manager{managers[pool_index]};
// Lock the pool that we're allocating from.
const auto [pool, dir] = DecodeOption(option);
KScopedLightLock lk(pool_locks[static_cast<size_t>(pool)]);
// Free all of the pages
for (const auto& it : page_list.Nodes()) {
const auto min_num_pages{std::min<size_t>(
it.GetNumPages(), (chosen_manager.GetEndAddress() - it.GetAddress()) / PageSize)};
chosen_manager.Free(it.GetAddress(), min_num_pages);
// Allocate the page group.
R_TRY(this->AllocatePageGroupImpl(out, num_pages, pool, dir, false));
// Open the first reference to the pages.
for (const auto& block : out->Nodes()) {
PAddr cur_address = block.GetAddress();
size_t remaining_pages = block.GetNumPages();
while (remaining_pages > 0) {
// Get the manager for the current address.
auto& manager = this->GetManager(system.Kernel().MemoryLayout(), cur_address);
// Process part or all of the block.
const size_t cur_pages =
std::min(remaining_pages, manager.GetPageOffsetToEnd(cur_address));
manager.OpenFirst(cur_address, cur_pages);
// Advance.
cur_address += cur_pages * PageSize;
remaining_pages -= cur_pages;
}
}
return ResultSuccess;
}
std::size_t KMemoryManager::Impl::CalculateManagementOverheadSize(std::size_t region_size) {
const std::size_t ref_count_size = (region_size / PageSize) * sizeof(u16);
const std::size_t optimize_map_size =
ResultCode KMemoryManager::AllocateAndOpenForProcess(KPageLinkedList* out, size_t num_pages,
u32 option, u64 process_id, u8 fill_pattern) {
ASSERT(out != nullptr);
ASSERT(out->GetNumPages() == 0);
// Decode the option.
const auto [pool, dir] = DecodeOption(option);
// Allocate the memory.
{
// Lock the pool that we're allocating from.
KScopedLightLock lk(pool_locks[static_cast<size_t>(pool)]);
// Allocate the page group.
R_TRY(this->AllocatePageGroupImpl(out, num_pages, pool, dir, false));
// Open the first reference to the pages.
for (const auto& block : out->Nodes()) {
PAddr cur_address = block.GetAddress();
size_t remaining_pages = block.GetNumPages();
while (remaining_pages > 0) {
// Get the manager for the current address.
auto& manager = this->GetManager(system.Kernel().MemoryLayout(), cur_address);
// Process part or all of the block.
const size_t cur_pages =
std::min(remaining_pages, manager.GetPageOffsetToEnd(cur_address));
manager.OpenFirst(cur_address, cur_pages);
// Advance.
cur_address += cur_pages * PageSize;
remaining_pages -= cur_pages;
}
}
}
// Set all the allocated memory.
for (const auto& block : out->Nodes()) {
std::memset(system.DeviceMemory().GetPointer(block.GetAddress()), fill_pattern,
block.GetSize());
}
return ResultSuccess;
}
void KMemoryManager::Open(PAddr address, size_t num_pages) {
// Repeatedly open references until we've done so for all pages.
while (num_pages) {
auto& manager = this->GetManager(system.Kernel().MemoryLayout(), address);
const size_t cur_pages = std::min(num_pages, manager.GetPageOffsetToEnd(address));
{
KScopedLightLock lk(pool_locks[static_cast<size_t>(manager.GetPool())]);
manager.Open(address, cur_pages);
}
num_pages -= cur_pages;
address += cur_pages * PageSize;
}
}
void KMemoryManager::Close(PAddr address, size_t num_pages) {
// Repeatedly close references until we've done so for all pages.
while (num_pages) {
auto& manager = this->GetManager(system.Kernel().MemoryLayout(), address);
const size_t cur_pages = std::min(num_pages, manager.GetPageOffsetToEnd(address));
{
KScopedLightLock lk(pool_locks[static_cast<size_t>(manager.GetPool())]);
manager.Close(address, cur_pages);
}
num_pages -= cur_pages;
address += cur_pages * PageSize;
}
}
void KMemoryManager::Close(const KPageLinkedList& pg) {
for (const auto& node : pg.Nodes()) {
Close(node.GetAddress(), node.GetNumPages());
}
}
void KMemoryManager::Open(const KPageLinkedList& pg) {
for (const auto& node : pg.Nodes()) {
Open(node.GetAddress(), node.GetNumPages());
}
}
size_t KMemoryManager::Impl::Initialize(PAddr address, size_t size, VAddr management,
VAddr management_end, Pool p) {
// Calculate management sizes.
const size_t ref_count_size = (size / PageSize) * sizeof(u16);
const size_t optimize_map_size = CalculateOptimizedProcessOverheadSize(size);
const size_t manager_size = Common::AlignUp(optimize_map_size + ref_count_size, PageSize);
const size_t page_heap_size = KPageHeap::CalculateManagementOverheadSize(size);
const size_t total_management_size = manager_size + page_heap_size;
ASSERT(manager_size <= total_management_size);
ASSERT(management + total_management_size <= management_end);
ASSERT(Common::IsAligned(total_management_size, PageSize));
// Setup region.
pool = p;
management_region = management;
page_reference_counts.resize(
Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetIntendedMemorySize() / PageSize);
ASSERT(Common::IsAligned(management_region, PageSize));
// Initialize the manager's KPageHeap.
heap.Initialize(address, size, management + manager_size, page_heap_size);
return total_management_size;
}
size_t KMemoryManager::Impl::CalculateManagementOverheadSize(size_t region_size) {
const size_t ref_count_size = (region_size / PageSize) * sizeof(u16);
const size_t optimize_map_size =
(Common::AlignUp((region_size / PageSize), Common::BitSize<u64>()) /
Common::BitSize<u64>()) *
sizeof(u64);
const std::size_t manager_meta_size =
Common::AlignUp(optimize_map_size + ref_count_size, PageSize);
const std::size_t page_heap_size = KPageHeap::CalculateManagementOverheadSize(region_size);
const size_t manager_meta_size = Common::AlignUp(optimize_map_size + ref_count_size, PageSize);
const size_t page_heap_size = KPageHeap::CalculateManagementOverheadSize(region_size);
return manager_meta_size + page_heap_size;
}
+170 -33
View File
@@ -5,10 +5,12 @@
#pragma once
#include <array>
#include <mutex>
#include <tuple>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hle/kernel/k_light_lock.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_page_heap.h"
#include "core/hle/result.h"
@@ -20,8 +22,11 @@ namespace Kernel {
class KPageLinkedList;
class KMemoryManager final : NonCopyable {
class KMemoryManager final {
public:
YUZU_NON_COPYABLE(KMemoryManager);
YUZU_NON_MOVEABLE(KMemoryManager);
enum class Pool : u32 {
Application = 0,
Applet = 1,
@@ -48,22 +53,33 @@ public:
explicit KMemoryManager(Core::System& system_);
constexpr std::size_t GetSize(Pool pool) const {
return managers[static_cast<std::size_t>(pool)].GetSize();
void Initialize(VAddr management_region, size_t management_region_size);
constexpr size_t GetSize(Pool pool) const {
constexpr Direction GetSizeDirection = Direction::FromFront;
size_t total = 0;
for (auto* manager = this->GetFirstManager(pool, GetSizeDirection); manager != nullptr;
manager = this->GetNextManager(manager, GetSizeDirection)) {
total += manager->GetSize();
}
return total;
}
void InitializeManager(Pool pool, u64 start_address, u64 end_address);
PAddr AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option);
ResultCode AllocateAndOpen(KPageLinkedList* out, size_t num_pages, u32 option);
ResultCode AllocateAndOpenForProcess(KPageLinkedList* out, size_t num_pages, u32 option,
u64 process_id, u8 fill_pattern);
VAddr AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option);
ResultCode Allocate(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, Direction dir,
u32 heap_fill_value = 0);
ResultCode Free(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, Direction dir,
u32 heap_fill_value = 0);
static constexpr size_t MaxManagerCount = 10;
static constexpr std::size_t MaxManagerCount = 10;
void Close(PAddr address, size_t num_pages);
void Close(const KPageLinkedList& pg);
void Open(PAddr address, size_t num_pages);
void Open(const KPageLinkedList& pg);
public:
static std::size_t CalculateManagementOverheadSize(std::size_t region_size) {
static size_t CalculateManagementOverheadSize(size_t region_size) {
return Impl::CalculateManagementOverheadSize(region_size);
}
@@ -88,38 +104,34 @@ public:
}
private:
class Impl final : NonCopyable {
private:
using RefCount = u16;
private:
KPageHeap heap;
Pool pool{};
class Impl final {
public:
static std::size_t CalculateManagementOverheadSize(std::size_t region_size);
YUZU_NON_COPYABLE(Impl);
YUZU_NON_MOVEABLE(Impl);
static constexpr std::size_t CalculateOptimizedProcessOverheadSize(
std::size_t region_size) {
return (Common::AlignUp((region_size / PageSize), Common::BitSize<u64>()) /
Common::BitSize<u64>()) *
sizeof(u64);
}
public:
Impl() = default;
~Impl() = default;
std::size_t Initialize(Pool new_pool, u64 start_address, u64 end_address);
size_t Initialize(PAddr address, size_t size, VAddr management, VAddr management_end,
Pool p);
VAddr AllocateBlock(s32 index, bool random) {
return heap.AllocateBlock(index, random);
}
void Free(VAddr addr, std::size_t num_pages) {
void Free(VAddr addr, size_t num_pages) {
heap.Free(addr, num_pages);
}
constexpr std::size_t GetSize() const {
void SetInitialUsedHeapSize(size_t reserved_size) {
heap.SetInitialUsedSize(reserved_size);
}
constexpr Pool GetPool() const {
return pool;
}
constexpr size_t GetSize() const {
return heap.GetSize();
}
@@ -130,12 +142,137 @@ private:
constexpr VAddr GetEndAddress() const {
return heap.GetEndAddress();
}
constexpr size_t GetPageOffset(PAddr address) const {
return heap.GetPageOffset(address);
}
constexpr size_t GetPageOffsetToEnd(PAddr address) const {
return heap.GetPageOffsetToEnd(address);
}
constexpr void SetNext(Impl* n) {
next = n;
}
constexpr void SetPrev(Impl* n) {
prev = n;
}
constexpr Impl* GetNext() const {
return next;
}
constexpr Impl* GetPrev() const {
return prev;
}
void OpenFirst(PAddr address, size_t num_pages) {
size_t index = this->GetPageOffset(address);
const size_t end = index + num_pages;
while (index < end) {
const RefCount ref_count = (++page_reference_counts[index]);
ASSERT(ref_count == 1);
index++;
}
}
void Open(PAddr address, size_t num_pages) {
size_t index = this->GetPageOffset(address);
const size_t end = index + num_pages;
while (index < end) {
const RefCount ref_count = (++page_reference_counts[index]);
ASSERT(ref_count > 1);
index++;
}
}
void Close(PAddr address, size_t num_pages) {
size_t index = this->GetPageOffset(address);
const size_t end = index + num_pages;
size_t free_start = 0;
size_t free_count = 0;
while (index < end) {
ASSERT(page_reference_counts[index] > 0);
const RefCount ref_count = (--page_reference_counts[index]);
// Keep track of how many zero refcounts we see in a row, to minimize calls to free.
if (ref_count == 0) {
if (free_count > 0) {
free_count++;
} else {
free_start = index;
free_count = 1;
}
} else {
if (free_count > 0) {
this->Free(heap.GetAddress() + free_start * PageSize, free_count);
free_count = 0;
}
}
index++;
}
if (free_count > 0) {
this->Free(heap.GetAddress() + free_start * PageSize, free_count);
}
}
static size_t CalculateManagementOverheadSize(size_t region_size);
static constexpr size_t CalculateOptimizedProcessOverheadSize(size_t region_size) {
return (Common::AlignUp((region_size / PageSize), Common::BitSize<u64>()) /
Common::BitSize<u64>()) *
sizeof(u64);
}
private:
using RefCount = u16;
KPageHeap heap;
std::vector<RefCount> page_reference_counts;
VAddr management_region{};
Pool pool{};
Impl* next{};
Impl* prev{};
};
private:
Impl& GetManager(const KMemoryLayout& memory_layout, PAddr address) {
return managers[memory_layout.GetPhysicalLinearRegion(address).GetAttributes()];
}
const Impl& GetManager(const KMemoryLayout& memory_layout, PAddr address) const {
return managers[memory_layout.GetPhysicalLinearRegion(address).GetAttributes()];
}
constexpr Impl* GetFirstManager(Pool pool, Direction dir) const {
return dir == Direction::FromBack ? pool_managers_tail[static_cast<size_t>(pool)]
: pool_managers_head[static_cast<size_t>(pool)];
}
constexpr Impl* GetNextManager(Impl* cur, Direction dir) const {
if (dir == Direction::FromBack) {
return cur->GetPrev();
} else {
return cur->GetNext();
}
}
ResultCode AllocatePageGroupImpl(KPageLinkedList* out, size_t num_pages, Pool pool,
Direction dir, bool random);
private:
Core::System& system;
std::array<std::mutex, static_cast<std::size_t>(Pool::Count)> pool_locks;
std::array<KLightLock, static_cast<size_t>(Pool::Count)> pool_locks;
std::array<Impl*, MaxManagerCount> pool_managers_head{};
std::array<Impl*, MaxManagerCount> pool_managers_tail{};
std::array<Impl, MaxManagerCount> managers;
size_t num_managers{};
};
} // namespace Kernel
+43 -37
View File
@@ -5,6 +5,7 @@
#pragma once
#include "common/assert.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/intrusive_red_black_tree.h"
#include "core/hle/kernel/k_memory_region_type.h"
@@ -13,11 +14,13 @@ namespace Kernel {
class KMemoryRegionAllocator;
class KMemoryRegion final : public Common::IntrusiveRedBlackTreeBaseNode<KMemoryRegion>,
NonCopyable {
class KMemoryRegion final : public Common::IntrusiveRedBlackTreeBaseNode<KMemoryRegion> {
friend class KMemoryRegionTree;
public:
YUZU_NON_COPYABLE(KMemoryRegion);
YUZU_NON_MOVEABLE(KMemoryRegion);
constexpr KMemoryRegion() = default;
constexpr KMemoryRegion(u64 address_, u64 last_address_)
: address{address_}, last_address{last_address_} {}
@@ -29,6 +32,8 @@ public:
: KMemoryRegion(address_, last_address_, std::numeric_limits<u64>::max(), attributes_,
type_id_) {}
~KMemoryRegion() = default;
static constexpr int Compare(const KMemoryRegion& lhs, const KMemoryRegion& rhs) {
if (lhs.GetAddress() < rhs.GetAddress()) {
return -1;
@@ -39,16 +44,6 @@ public:
}
}
private:
constexpr void Reset(u64 a, u64 la, u64 p, u32 r, u32 t) {
address = a;
pair_address = p;
last_address = la;
attributes = r;
type_id = t;
}
public:
constexpr u64 GetAddress() const {
return address;
}
@@ -108,6 +103,14 @@ public:
}
private:
constexpr void Reset(u64 a, u64 la, u64 p, u32 r, u32 t) {
address = a;
pair_address = p;
last_address = la;
attributes = r;
type_id = t;
}
u64 address{};
u64 last_address{};
u64 pair_address{};
@@ -115,8 +118,25 @@ private:
u32 type_id{};
};
class KMemoryRegionTree final : NonCopyable {
class KMemoryRegionTree final {
private:
using TreeType =
Common::IntrusiveRedBlackTreeBaseTraits<KMemoryRegion>::TreeType<KMemoryRegion>;
public:
YUZU_NON_COPYABLE(KMemoryRegionTree);
YUZU_NON_MOVEABLE(KMemoryRegionTree);
using value_type = TreeType::value_type;
using size_type = TreeType::size_type;
using difference_type = TreeType::difference_type;
using pointer = TreeType::pointer;
using const_pointer = TreeType::const_pointer;
using reference = TreeType::reference;
using const_reference = TreeType::const_reference;
using iterator = TreeType::iterator;
using const_iterator = TreeType::const_iterator;
struct DerivedRegionExtents {
const KMemoryRegion* first_region{};
const KMemoryRegion* last_region{};
@@ -140,29 +160,9 @@ public:
}
};
private:
using TreeType =
Common::IntrusiveRedBlackTreeBaseTraits<KMemoryRegion>::TreeType<KMemoryRegion>;
public:
using value_type = TreeType::value_type;
using size_type = TreeType::size_type;
using difference_type = TreeType::difference_type;
using pointer = TreeType::pointer;
using const_pointer = TreeType::const_pointer;
using reference = TreeType::reference;
using const_reference = TreeType::const_reference;
using iterator = TreeType::iterator;
using const_iterator = TreeType::const_iterator;
private:
TreeType m_tree{};
KMemoryRegionAllocator& memory_region_allocator;
public:
explicit KMemoryRegionTree(KMemoryRegionAllocator& memory_region_allocator_);
~KMemoryRegionTree() = default;
public:
KMemoryRegion* FindModifiable(u64 address) {
if (auto it = this->find(KMemoryRegion(address, address, 0, 0)); it != this->end()) {
return std::addressof(*it);
@@ -241,7 +241,6 @@ public:
return GetDerivedRegionExtents(static_cast<KMemoryRegionType>(type_id));
}
public:
void InsertDirectly(u64 address, u64 last_address, u32 attr = 0, u32 type_id = 0);
bool Insert(u64 address, size_t size, u32 type_id, u32 new_attr = 0, u32 old_attr = 0);
@@ -252,7 +251,6 @@ public:
return this->GetRandomAlignedRegion(size + 2 * guard_size, alignment, type_id) + guard_size;
}
public:
// Iterator accessors.
iterator begin() {
return m_tree.begin();
@@ -322,13 +320,21 @@ public:
iterator nfind(const_reference ref) const {
return m_tree.nfind(ref);
}
private:
TreeType m_tree{};
KMemoryRegionAllocator& memory_region_allocator;
};
class KMemoryRegionAllocator final : NonCopyable {
class KMemoryRegionAllocator final {
public:
YUZU_NON_COPYABLE(KMemoryRegionAllocator);
YUZU_NON_MOVEABLE(KMemoryRegionAllocator);
static constexpr size_t MaxMemoryRegions = 200;
constexpr KMemoryRegionAllocator() = default;
constexpr ~KMemoryRegionAllocator() = default;
template <typename... Args>
KMemoryRegion* Allocate(Args&&... args) {
+9 -1
View File
@@ -14,7 +14,8 @@
namespace Kernel {
enum KMemoryRegionType : u32 {
KMemoryRegionAttr_CarveoutProtected = 0x04000000,
KMemoryRegionAttr_CarveoutProtected = 0x02000000,
KMemoryRegionAttr_Uncached = 0x04000000,
KMemoryRegionAttr_DidKernelMap = 0x08000000,
KMemoryRegionAttr_ShouldKernelMap = 0x10000000,
KMemoryRegionAttr_UserReadOnly = 0x20000000,
@@ -239,6 +240,11 @@ static_assert(KMemoryRegionType_VirtualDramHeapBase.GetValue() == 0x1A);
static_assert(KMemoryRegionType_VirtualDramKernelPtHeap.GetValue() == 0x2A);
static_assert(KMemoryRegionType_VirtualDramKernelTraceBuffer.GetValue() == 0x4A);
// UNUSED: .DeriveSparse(2, 2, 0);
constexpr auto KMemoryRegionType_VirtualDramUnknownDebug =
KMemoryRegionType_Dram.DeriveSparse(2, 2, 1);
static_assert(KMemoryRegionType_VirtualDramUnknownDebug.GetValue() == (0x52));
constexpr auto KMemoryRegionType_VirtualDramKernelInitPt =
KMemoryRegionType_VirtualDramHeapBase.Derive(3, 0);
constexpr auto KMemoryRegionType_VirtualDramPoolManagement =
@@ -330,6 +336,8 @@ constexpr KMemoryRegionType GetTypeForVirtualLinearMapping(u32 type_id) {
return KMemoryRegionType_VirtualDramKernelTraceBuffer;
} else if (KMemoryRegionType_DramKernelPtHeap.IsAncestorOf(type_id)) {
return KMemoryRegionType_VirtualDramKernelPtHeap;
} else if ((type_id | KMemoryRegionAttr_ShouldKernelMap) == type_id) {
return KMemoryRegionType_VirtualDramUnknownDebug;
} else {
return KMemoryRegionType_Dram;
}
+70 -54
View File
@@ -7,35 +7,51 @@
namespace Kernel {
void KPageHeap::Initialize(VAddr address, std::size_t size, std::size_t metadata_size) {
// Check our assumptions
ASSERT(Common::IsAligned((address), PageSize));
void KPageHeap::Initialize(PAddr address, size_t size, VAddr management_address,
size_t management_size, const size_t* block_shifts,
size_t num_block_shifts) {
// Check our assumptions.
ASSERT(Common::IsAligned(address, PageSize));
ASSERT(Common::IsAligned(size, PageSize));
ASSERT(0 < num_block_shifts && num_block_shifts <= NumMemoryBlockPageShifts);
const VAddr management_end = management_address + management_size;
// Set our members
heap_address = address;
heap_size = size;
// Set our members.
m_heap_address = address;
m_heap_size = size;
m_num_blocks = num_block_shifts;
// Setup bitmaps
metadata.resize(metadata_size / sizeof(u64));
u64* cur_bitmap_storage{metadata.data()};
for (std::size_t i = 0; i < MemoryBlockPageShifts.size(); i++) {
const std::size_t cur_block_shift{MemoryBlockPageShifts[i]};
const std::size_t next_block_shift{
(i != MemoryBlockPageShifts.size() - 1) ? MemoryBlockPageShifts[i + 1] : 0};
cur_bitmap_storage = blocks[i].Initialize(heap_address, heap_size, cur_block_shift,
next_block_shift, cur_bitmap_storage);
// Setup bitmaps.
m_management_data.resize(management_size / sizeof(u64));
u64* cur_bitmap_storage{m_management_data.data()};
for (size_t i = 0; i < num_block_shifts; i++) {
const size_t cur_block_shift = block_shifts[i];
const size_t next_block_shift = (i != num_block_shifts - 1) ? block_shifts[i + 1] : 0;
cur_bitmap_storage = m_blocks[i].Initialize(m_heap_address, m_heap_size, cur_block_shift,
next_block_shift, cur_bitmap_storage);
}
// Ensure we didn't overextend our bounds.
ASSERT(VAddr(cur_bitmap_storage) <= management_end);
}
VAddr KPageHeap::AllocateBlock(s32 index, bool random) {
const std::size_t needed_size{blocks[index].GetSize()};
size_t KPageHeap::GetNumFreePages() const {
size_t num_free = 0;
for (s32 i{index}; i < static_cast<s32>(MemoryBlockPageShifts.size()); i++) {
if (const VAddr addr{blocks[i].PopBlock(random)}; addr) {
if (const std::size_t allocated_size{blocks[i].GetSize()};
allocated_size > needed_size) {
Free(addr + needed_size, (allocated_size - needed_size) / PageSize);
for (size_t i = 0; i < m_num_blocks; i++) {
num_free += m_blocks[i].GetNumFreePages();
}
return num_free;
}
PAddr KPageHeap::AllocateBlock(s32 index, bool random) {
const size_t needed_size = m_blocks[index].GetSize();
for (s32 i = index; i < static_cast<s32>(m_num_blocks); i++) {
if (const PAddr addr = m_blocks[i].PopBlock(random); addr != 0) {
if (const size_t allocated_size = m_blocks[i].GetSize(); allocated_size > needed_size) {
this->Free(addr + needed_size, (allocated_size - needed_size) / PageSize);
}
return addr;
}
@@ -44,34 +60,34 @@ VAddr KPageHeap::AllocateBlock(s32 index, bool random) {
return 0;
}
void KPageHeap::FreeBlock(VAddr block, s32 index) {
void KPageHeap::FreeBlock(PAddr block, s32 index) {
do {
block = blocks[index++].PushBlock(block);
block = m_blocks[index++].PushBlock(block);
} while (block != 0);
}
void KPageHeap::Free(VAddr addr, std::size_t num_pages) {
// Freeing no pages is a no-op
void KPageHeap::Free(PAddr addr, size_t num_pages) {
// Freeing no pages is a no-op.
if (num_pages == 0) {
return;
}
// Find the largest block size that we can free, and free as many as possible
s32 big_index{static_cast<s32>(MemoryBlockPageShifts.size()) - 1};
const VAddr start{addr};
const VAddr end{(num_pages * PageSize) + addr};
VAddr before_start{start};
VAddr before_end{start};
VAddr after_start{end};
VAddr after_end{end};
// Find the largest block size that we can free, and free as many as possible.
s32 big_index = static_cast<s32>(m_num_blocks) - 1;
const PAddr start = addr;
const PAddr end = addr + num_pages * PageSize;
PAddr before_start = start;
PAddr before_end = start;
PAddr after_start = end;
PAddr after_end = end;
while (big_index >= 0) {
const std::size_t block_size{blocks[big_index].GetSize()};
const VAddr big_start{Common::AlignUp((start), block_size)};
const VAddr big_end{Common::AlignDown((end), block_size)};
const size_t block_size = m_blocks[big_index].GetSize();
const PAddr big_start = Common::AlignUp(start, block_size);
const PAddr big_end = Common::AlignDown(end, block_size);
if (big_start < big_end) {
// Free as many big blocks as we can
for (auto block{big_start}; block < big_end; block += block_size) {
FreeBlock(block, big_index);
// Free as many big blocks as we can.
for (auto block = big_start; block < big_end; block += block_size) {
this->FreeBlock(block, big_index);
}
before_end = big_start;
after_start = big_end;
@@ -81,31 +97,31 @@ void KPageHeap::Free(VAddr addr, std::size_t num_pages) {
}
ASSERT(big_index >= 0);
// Free space before the big blocks
for (s32 i{big_index - 1}; i >= 0; i--) {
const std::size_t block_size{blocks[i].GetSize()};
// Free space before the big blocks.
for (s32 i = big_index - 1; i >= 0; i--) {
const size_t block_size = m_blocks[i].GetSize();
while (before_start + block_size <= before_end) {
before_end -= block_size;
FreeBlock(before_end, i);
this->FreeBlock(before_end, i);
}
}
// Free space after the big blocks
for (s32 i{big_index - 1}; i >= 0; i--) {
const std::size_t block_size{blocks[i].GetSize()};
// Free space after the big blocks.
for (s32 i = big_index - 1; i >= 0; i--) {
const size_t block_size = m_blocks[i].GetSize();
while (after_start + block_size <= after_end) {
FreeBlock(after_start, i);
this->FreeBlock(after_start, i);
after_start += block_size;
}
}
}
std::size_t KPageHeap::CalculateManagementOverheadSize(std::size_t region_size) {
std::size_t overhead_size = 0;
for (std::size_t i = 0; i < MemoryBlockPageShifts.size(); i++) {
const std::size_t cur_block_shift{MemoryBlockPageShifts[i]};
const std::size_t next_block_shift{
(i != MemoryBlockPageShifts.size() - 1) ? MemoryBlockPageShifts[i + 1] : 0};
size_t KPageHeap::CalculateManagementOverheadSize(size_t region_size, const size_t* block_shifts,
size_t num_block_shifts) {
size_t overhead_size = 0;
for (size_t i = 0; i < num_block_shifts; i++) {
const size_t cur_block_shift = block_shifts[i];
const size_t next_block_shift = (i != num_block_shifts - 1) ? block_shifts[i + 1] : 0;
overhead_size += KPageHeap::Block::CalculateManagementOverheadSize(
region_size, cur_block_shift, next_block_shift);
}
+142 -115
View File
@@ -8,183 +8,210 @@
#include <vector>
#include "common/alignment.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hle/kernel/k_page_bitmap.h"
#include "core/hle/kernel/memory_types.h"
namespace Kernel {
class KPageHeap final : NonCopyable {
class KPageHeap final {
public:
static constexpr s32 GetAlignedBlockIndex(std::size_t num_pages, std::size_t align_pages) {
const auto target_pages{std::max(num_pages, align_pages)};
for (std::size_t i = 0; i < NumMemoryBlockPageShifts; i++) {
if (target_pages <=
(static_cast<std::size_t>(1) << MemoryBlockPageShifts[i]) / PageSize) {
YUZU_NON_COPYABLE(KPageHeap);
YUZU_NON_MOVEABLE(KPageHeap);
KPageHeap() = default;
~KPageHeap() = default;
constexpr PAddr GetAddress() const {
return m_heap_address;
}
constexpr size_t GetSize() const {
return m_heap_size;
}
constexpr PAddr GetEndAddress() const {
return this->GetAddress() + this->GetSize();
}
constexpr size_t GetPageOffset(PAddr block) const {
return (block - this->GetAddress()) / PageSize;
}
constexpr size_t GetPageOffsetToEnd(PAddr block) const {
return (this->GetEndAddress() - block) / PageSize;
}
void Initialize(PAddr heap_address, size_t heap_size, VAddr management_address,
size_t management_size) {
return this->Initialize(heap_address, heap_size, management_address, management_size,
MemoryBlockPageShifts.data(), NumMemoryBlockPageShifts);
}
size_t GetFreeSize() const {
return this->GetNumFreePages() * PageSize;
}
void SetInitialUsedSize(size_t reserved_size) {
// Check that the reserved size is valid.
const size_t free_size = this->GetNumFreePages() * PageSize;
ASSERT(m_heap_size >= free_size + reserved_size);
// Set the initial used size.
m_initial_used_size = m_heap_size - free_size - reserved_size;
}
PAddr AllocateBlock(s32 index, bool random);
void Free(PAddr addr, size_t num_pages);
static size_t CalculateManagementOverheadSize(size_t region_size) {
return CalculateManagementOverheadSize(region_size, MemoryBlockPageShifts.data(),
NumMemoryBlockPageShifts);
}
static constexpr s32 GetAlignedBlockIndex(size_t num_pages, size_t align_pages) {
const size_t target_pages = std::max(num_pages, align_pages);
for (size_t i = 0; i < NumMemoryBlockPageShifts; i++) {
if (target_pages <= (size_t(1) << MemoryBlockPageShifts[i]) / PageSize) {
return static_cast<s32>(i);
}
}
return -1;
}
static constexpr s32 GetBlockIndex(std::size_t num_pages) {
for (s32 i{static_cast<s32>(NumMemoryBlockPageShifts) - 1}; i >= 0; i--) {
if (num_pages >= (static_cast<std::size_t>(1) << MemoryBlockPageShifts[i]) / PageSize) {
static constexpr s32 GetBlockIndex(size_t num_pages) {
for (s32 i = static_cast<s32>(NumMemoryBlockPageShifts) - 1; i >= 0; i--) {
if (num_pages >= (size_t(1) << MemoryBlockPageShifts[i]) / PageSize) {
return i;
}
}
return -1;
}
static constexpr std::size_t GetBlockSize(std::size_t index) {
return static_cast<std::size_t>(1) << MemoryBlockPageShifts[index];
static constexpr size_t GetBlockSize(size_t index) {
return size_t(1) << MemoryBlockPageShifts[index];
}
static constexpr std::size_t GetBlockNumPages(std::size_t index) {
static constexpr size_t GetBlockNumPages(size_t index) {
return GetBlockSize(index) / PageSize;
}
private:
static constexpr std::size_t NumMemoryBlockPageShifts{7};
static constexpr std::array<std::size_t, NumMemoryBlockPageShifts> MemoryBlockPageShifts{
0xC, 0x10, 0x15, 0x16, 0x19, 0x1D, 0x1E,
};
class Block final : NonCopyable {
private:
KPageBitmap bitmap;
VAddr heap_address{};
uintptr_t end_offset{};
std::size_t block_shift{};
std::size_t next_block_shift{};
class Block final {
public:
YUZU_NON_COPYABLE(Block);
YUZU_NON_MOVEABLE(Block);
Block() = default;
~Block() = default;
constexpr std::size_t GetShift() const {
return block_shift;
constexpr size_t GetShift() const {
return m_block_shift;
}
constexpr std::size_t GetNextShift() const {
return next_block_shift;
constexpr size_t GetNextShift() const {
return m_next_block_shift;
}
constexpr std::size_t GetSize() const {
return static_cast<std::size_t>(1) << GetShift();
constexpr size_t GetSize() const {
return u64(1) << this->GetShift();
}
constexpr std::size_t GetNumPages() const {
return GetSize() / PageSize;
constexpr size_t GetNumPages() const {
return this->GetSize() / PageSize;
}
constexpr std::size_t GetNumFreeBlocks() const {
return bitmap.GetNumBits();
constexpr size_t GetNumFreeBlocks() const {
return m_bitmap.GetNumBits();
}
constexpr std::size_t GetNumFreePages() const {
return GetNumFreeBlocks() * GetNumPages();
constexpr size_t GetNumFreePages() const {
return this->GetNumFreeBlocks() * this->GetNumPages();
}
u64* Initialize(VAddr addr, std::size_t size, std::size_t bs, std::size_t nbs,
u64* bit_storage) {
// Set shifts
block_shift = bs;
next_block_shift = nbs;
u64* Initialize(PAddr addr, size_t size, size_t bs, size_t nbs, u64* bit_storage) {
// Set shifts.
m_block_shift = bs;
m_next_block_shift = nbs;
// Align up the address
VAddr end{addr + size};
const auto align{(next_block_shift != 0) ? (1ULL << next_block_shift)
: (1ULL << block_shift)};
addr = Common::AlignDown((addr), align);
end = Common::AlignUp((end), align);
// Align up the address.
PAddr end = addr + size;
const size_t align = (m_next_block_shift != 0) ? (u64(1) << m_next_block_shift)
: (u64(1) << m_block_shift);
addr = Common::AlignDown(addr, align);
end = Common::AlignUp(end, align);
heap_address = addr;
end_offset = (end - addr) / (1ULL << block_shift);
return bitmap.Initialize(bit_storage, end_offset);
m_heap_address = addr;
m_end_offset = (end - addr) / (u64(1) << m_block_shift);
return m_bitmap.Initialize(bit_storage, m_end_offset);
}
VAddr PushBlock(VAddr address) {
// Set the bit for the free block
std::size_t offset{(address - heap_address) >> GetShift()};
bitmap.SetBit(offset);
PAddr PushBlock(PAddr address) {
// Set the bit for the free block.
size_t offset = (address - m_heap_address) >> this->GetShift();
m_bitmap.SetBit(offset);
// If we have a next shift, try to clear the blocks below and return the address
if (GetNextShift()) {
const auto diff{1ULL << (GetNextShift() - GetShift())};
// If we have a next shift, try to clear the blocks below this one and return the new
// address.
if (this->GetNextShift()) {
const size_t diff = u64(1) << (this->GetNextShift() - this->GetShift());
offset = Common::AlignDown(offset, diff);
if (bitmap.ClearRange(offset, diff)) {
return heap_address + (offset << GetShift());
if (m_bitmap.ClearRange(offset, diff)) {
return m_heap_address + (offset << this->GetShift());
}
}
// We couldn't coalesce, or we're already as big as possible
return 0;
// We couldn't coalesce, or we're already as big as possible.
return {};
}
VAddr PopBlock(bool random) {
// Find a free block
const s64 soffset{bitmap.FindFreeBlock(random)};
PAddr PopBlock(bool random) {
// Find a free block.
s64 soffset = m_bitmap.FindFreeBlock(random);
if (soffset < 0) {
return 0;
return {};
}
const auto offset{static_cast<std::size_t>(soffset)};
const size_t offset = static_cast<size_t>(soffset);
// Update our tracking and return it
bitmap.ClearBit(offset);
return heap_address + (offset << GetShift());
// Update our tracking and return it.
m_bitmap.ClearBit(offset);
return m_heap_address + (offset << this->GetShift());
}
public:
static constexpr std::size_t CalculateManagementOverheadSize(std::size_t region_size,
std::size_t cur_block_shift,
std::size_t next_block_shift) {
const auto cur_block_size{(1ULL << cur_block_shift)};
const auto next_block_size{(1ULL << next_block_shift)};
const auto align{(next_block_shift != 0) ? next_block_size : cur_block_size};
static constexpr size_t CalculateManagementOverheadSize(size_t region_size,
size_t cur_block_shift,
size_t next_block_shift) {
const size_t cur_block_size = (u64(1) << cur_block_shift);
const size_t next_block_size = (u64(1) << next_block_shift);
const size_t align = (next_block_shift != 0) ? next_block_size : cur_block_size;
return KPageBitmap::CalculateManagementOverheadSize(
(align * 2 + Common::AlignUp(region_size, align)) / cur_block_size);
}
private:
KPageBitmap m_bitmap;
PAddr m_heap_address{};
uintptr_t m_end_offset{};
size_t m_block_shift{};
size_t m_next_block_shift{};
};
public:
KPageHeap() = default;
private:
void Initialize(PAddr heap_address, size_t heap_size, VAddr management_address,
size_t management_size, const size_t* block_shifts, size_t num_block_shifts);
size_t GetNumFreePages() const;
constexpr VAddr GetAddress() const {
return heap_address;
}
constexpr std::size_t GetSize() const {
return heap_size;
}
constexpr VAddr GetEndAddress() const {
return GetAddress() + GetSize();
}
constexpr std::size_t GetPageOffset(VAddr block) const {
return (block - GetAddress()) / PageSize;
}
void FreeBlock(PAddr block, s32 index);
void Initialize(VAddr heap_address, std::size_t heap_size, std::size_t metadata_size);
VAddr AllocateBlock(s32 index, bool random);
void Free(VAddr addr, std::size_t num_pages);
void UpdateUsedSize() {
used_size = heap_size - (GetNumFreePages() * PageSize);
}
static std::size_t CalculateManagementOverheadSize(std::size_t region_size);
static constexpr size_t NumMemoryBlockPageShifts{7};
static constexpr std::array<size_t, NumMemoryBlockPageShifts> MemoryBlockPageShifts{
0xC, 0x10, 0x15, 0x16, 0x19, 0x1D, 0x1E,
};
private:
constexpr std::size_t GetNumFreePages() const {
std::size_t num_free{};
static size_t CalculateManagementOverheadSize(size_t region_size, const size_t* block_shifts,
size_t num_block_shifts);
for (const auto& block : blocks) {
num_free += block.GetNumFreePages();
}
return num_free;
}
void FreeBlock(VAddr block, s32 index);
VAddr heap_address{};
std::size_t heap_size{};
std::size_t used_size{};
std::array<Block, NumMemoryBlockPageShifts> blocks{};
std::vector<u64> metadata;
private:
PAddr m_heap_address{};
size_t m_heap_size{};
size_t m_initial_used_size{};
size_t m_num_blocks{};
std::array<Block, NumMemoryBlockPageShifts> m_blocks{};
std::vector<u64> m_management_data;
};
} // namespace Kernel
File diff suppressed because it is too large Load Diff
+27 -19
View File
@@ -5,11 +5,12 @@
#pragma once
#include <memory>
#include <mutex>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/page_table.h"
#include "core/file_sys/program_metadata.h"
#include "core/hle/kernel/k_light_lock.h"
#include "core/hle/kernel/k_memory_block.h"
#include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/result.h"
@@ -22,24 +23,27 @@ namespace Kernel {
class KMemoryBlockManager;
class KPageTable final : NonCopyable {
class KPageTable final {
public:
YUZU_NON_COPYABLE(KPageTable);
YUZU_NON_MOVEABLE(KPageTable);
explicit KPageTable(Core::System& system_);
~KPageTable();
ResultCode InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr,
VAddr code_addr, std::size_t code_size,
KMemoryManager::Pool pool);
ResultCode MapProcessCode(VAddr addr, std::size_t pages_count, KMemoryState state,
KMemoryPermission perm);
ResultCode MapCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
ResultCode UnmapCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
ResultCode MapCodeMemory(VAddr dst_address, VAddr src_address, std::size_t size);
ResultCode UnmapCodeMemory(VAddr dst_address, VAddr src_address, std::size_t size);
ResultCode UnmapProcessMemory(VAddr dst_addr, std::size_t size, KPageTable& src_page_table,
VAddr src_addr);
ResultCode MapPhysicalMemory(VAddr addr, std::size_t size);
ResultCode UnmapPhysicalMemory(VAddr addr, std::size_t size);
ResultCode UnmapMemory(VAddr addr, std::size_t size);
ResultCode Map(VAddr dst_addr, VAddr src_addr, std::size_t size);
ResultCode Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size);
ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state,
KMemoryPermission perm);
ResultCode UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state);
@@ -88,7 +92,6 @@ private:
ResultCode MapPages(VAddr addr, const KPageLinkedList& page_linked_list,
KMemoryPermission perm);
ResultCode UnmapPages(VAddr addr, const KPageLinkedList& page_linked_list);
void MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end);
bool IsRegionMapped(VAddr address, u64 size);
bool IsRegionContiguous(VAddr addr, u64 size) const;
void AddRegionToPages(VAddr start, std::size_t num_pages, KPageLinkedList& page_linked_list);
@@ -99,8 +102,8 @@ private:
OperationType operation);
ResultCode Operate(VAddr addr, std::size_t num_pages, KMemoryPermission perm,
OperationType operation, PAddr map_addr = 0);
constexpr VAddr GetRegionAddress(KMemoryState state) const;
constexpr std::size_t GetRegionSize(KMemoryState state) const;
VAddr GetRegionAddress(KMemoryState state) const;
std::size_t GetRegionSize(KMemoryState state) const;
ResultCode CheckMemoryStateContiguous(std::size_t* out_blocks_needed, VAddr addr,
std::size_t size, KMemoryState state_mask,
@@ -144,10 +147,12 @@ private:
}
bool IsLockedByCurrentThread() const {
return true;
return general_lock.IsLockedByCurrentThread();
}
std::recursive_mutex page_table_lock;
mutable KLightLock general_lock;
mutable KLightLock map_physical_memory_lock;
std::unique_ptr<KMemoryBlockManager> block_manager;
public:
@@ -206,7 +211,7 @@ public:
return alias_code_region_end - alias_code_region_start;
}
size_t GetNormalMemorySize() {
std::lock_guard lk(page_table_lock);
KScopedLightLock lk(general_lock);
return GetHeapSize() + mapped_physical_memory_size;
}
constexpr std::size_t GetAddressSpaceWidth() const {
@@ -248,8 +253,13 @@ public:
constexpr bool IsInsideASLRRegion(VAddr address, std::size_t size) const {
return !IsOutsideASLRRegion(address, size);
}
constexpr PAddr GetPhysicalAddr(VAddr addr) {
return page_table_impl.backing_addr[addr >> PageBits] + addr;
constexpr std::size_t GetNumGuardPages() const {
return IsKernel() ? 1 : 4;
}
PAddr GetPhysicalAddr(VAddr addr) const {
const auto backing_addr = page_table_impl.backing_addr[addr >> PageBits];
ASSERT(backing_addr);
return backing_addr + addr;
}
constexpr bool Contains(VAddr addr) const {
return address_space_start <= addr && addr <= address_space_end - 1;
@@ -267,10 +277,6 @@ private:
return is_aslr_enabled;
}
constexpr std::size_t GetNumGuardPages() const {
return IsKernel() ? 1 : 4;
}
constexpr bool ContainsPages(VAddr addr, std::size_t num_pages) const {
return (address_space_start <= addr) &&
(num_pages <= (address_space_end - address_space_start) / PageSize) &&
@@ -302,6 +308,8 @@ private:
bool is_kernel{};
bool is_aslr_enabled{};
u32 heap_fill_value{};
KMemoryManager::Pool memory_pool{KMemoryManager::Pool::Application};
KMemoryManager::Direction allocation_option{KMemoryManager::Direction::FromFront};
+37 -1
View File
@@ -45,6 +45,7 @@ concept KPriorityQueueMember = !std::is_reference_v<T> && requires(T & t) {
{ t.GetActiveCore() } -> Common::ConvertibleTo<s32>;
{ t.GetPriority() } -> Common::ConvertibleTo<s32>;
{ t.IsDummyThread() } -> Common::ConvertibleTo<bool>;
};
template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority>
@@ -257,7 +258,7 @@ private:
private:
constexpr void ClearAffinityBit(u64& affinity, s32 core) {
affinity &= ~(u64(1) << core);
affinity &= ~(UINT64_C(1) << core);
}
constexpr s32 GetNextCore(u64& affinity) {
@@ -349,24 +350,49 @@ public:
// Mutators.
constexpr void PushBack(Member* member) {
// This is for host (dummy) threads that we do not want to enter the priority queue.
if (member->IsDummyThread()) {
return;
}
this->PushBack(member->GetPriority(), member);
}
constexpr void Remove(Member* member) {
// This is for host (dummy) threads that we do not want to enter the priority queue.
if (member->IsDummyThread()) {
return;
}
this->Remove(member->GetPriority(), member);
}
constexpr void MoveToScheduledFront(Member* member) {
// This is for host (dummy) threads that we do not want to enter the priority queue.
if (member->IsDummyThread()) {
return;
}
this->scheduled_queue.MoveToFront(member->GetPriority(), member->GetActiveCore(), member);
}
constexpr KThread* MoveToScheduledBack(Member* member) {
// This is for host (dummy) threads that we do not want to enter the priority queue.
if (member->IsDummyThread()) {
return {};
}
return this->scheduled_queue.MoveToBack(member->GetPriority(), member->GetActiveCore(),
member);
}
// First class fancy operations.
constexpr void ChangePriority(s32 prev_priority, bool is_running, Member* member) {
// This is for host (dummy) threads that we do not want to enter the priority queue.
if (member->IsDummyThread()) {
return;
}
ASSERT(IsValidPriority(prev_priority));
// Remove the member from the queues.
@@ -383,6 +409,11 @@ public:
constexpr void ChangeAffinityMask(s32 prev_core, const AffinityMaskType& prev_affinity,
Member* member) {
// This is for host (dummy) threads that we do not want to enter the priority queue.
if (member->IsDummyThread()) {
return;
}
// Get the new information.
const s32 priority = member->GetPriority();
const AffinityMaskType& new_affinity = member->GetAffinityMask();
@@ -412,6 +443,11 @@ public:
}
constexpr void ChangeCore(s32 prev_core, Member* member, bool to_front = false) {
// This is for host (dummy) threads that we do not want to enter the priority queue.
if (member->IsDummyThread()) {
return;
}
// Get the new information.
const s32 new_core = member->GetActiveCore();
const s32 priority = member->GetPriority();
+17 -14
View File
@@ -123,12 +123,11 @@ private:
};
ResultCode KProcess::Initialize(KProcess* process, Core::System& system, std::string process_name,
ProcessType type) {
ProcessType type, KResourceLimit* res_limit) {
auto& kernel = system.Kernel();
process->name = std::move(process_name);
process->resource_limit = kernel.GetSystemResourceLimit();
process->resource_limit = res_limit;
process->status = ProcessStatus::Created;
process->program_id = 0;
process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID()
@@ -143,6 +142,13 @@ ResultCode KProcess::Initialize(KProcess* process, Core::System& system, std::st
kernel.AppendNewProcess(process);
// Clear remaining fields.
process->num_running_threads = 0;
process->is_signaled = false;
process->exception_thread = nullptr;
process->is_suspended = false;
process->schedule_count = 0;
// Open a reference to the resource limit.
process->resource_limit->Open();
@@ -157,20 +163,17 @@ KResourceLimit* KProcess::GetResourceLimit() const {
return resource_limit;
}
void KProcess::IncrementThreadCount() {
ASSERT(num_threads >= 0);
num_created_threads++;
if (const auto count = ++num_threads; count > peak_num_threads) {
peak_num_threads = count;
}
void KProcess::IncrementRunningThreadCount() {
ASSERT(num_running_threads.load() >= 0);
++num_running_threads;
}
void KProcess::DecrementThreadCount() {
ASSERT(num_threads > 0);
void KProcess::DecrementRunningThreadCount() {
ASSERT(num_running_threads.load() > 0);
if (const auto count = --num_threads; count == 0) {
LOG_WARNING(Kernel, "Process termination is not fully implemented.");
if (const auto prev = num_running_threads--; prev == 1) {
// TODO(bunnei): Process termination to be implemented when multiprocess is supported.
UNIMPLEMENTED_MSG("KProcess termination is not implemennted!");
}
}
+4 -6
View File
@@ -91,7 +91,7 @@ public:
static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4;
static ResultCode Initialize(KProcess* process, Core::System& system, std::string process_name,
ProcessType type);
ProcessType type, KResourceLimit* res_limit);
/// Gets a reference to the process' page table.
KPageTable& PageTable() {
@@ -235,8 +235,8 @@ public:
++schedule_count;
}
void IncrementThreadCount();
void DecrementThreadCount();
void IncrementRunningThreadCount();
void DecrementRunningThreadCount();
void SetRunningThread(s32 core, KThread* thread, u64 idle_count) {
running_threads[core] = thread;
@@ -473,9 +473,7 @@ private:
bool is_suspended{};
bool is_initialized{};
std::atomic<s32> num_created_threads{};
std::atomic<u16> num_threads{};
u16 peak_num_threads{};
std::atomic<u16> num_running_threads{};
std::array<KThread*, Core::Hardware::NUM_CPU_CORES> running_threads{};
std::array<u64, Core::Hardware::NUM_CPU_CORES> running_thread_idle_counts{};
+19
View File
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include "common/assert.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/svc_results.h"
@@ -151,4 +152,22 @@ void KResourceLimit::Release(LimitableResource which, s64 value, s64 hint) {
}
}
KResourceLimit* CreateResourceLimitForProcess(Core::System& system, s64 physical_memory_size) {
auto* resource_limit = KResourceLimit::Create(system.Kernel());
resource_limit->Initialize(&system.CoreTiming());
// Initialize default resource limit values.
// TODO(bunnei): These values are the system defaults, the limits for service processes are
// lower. These should use the correct limit values.
ASSERT(resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, physical_memory_size)
.IsSuccess());
ASSERT(resource_limit->SetLimitValue(LimitableResource::Threads, 800).IsSuccess());
ASSERT(resource_limit->SetLimitValue(LimitableResource::Events, 900).IsSuccess());
ASSERT(resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200).IsSuccess());
ASSERT(resource_limit->SetLimitValue(LimitableResource::Sessions, 1133).IsSuccess());
return resource_limit;
}
} // namespace Kernel
+3
View File
@@ -67,4 +67,7 @@ private:
KLightConditionVariable cond_var;
const Core::Timing::CoreTiming* core_timing{};
};
KResourceLimit* CreateResourceLimitForProcess(Core::System& system, s64 physical_memory_size);
} // namespace Kernel
+32 -22
View File
@@ -406,6 +406,9 @@ void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduli
} else {
RescheduleCores(kernel, cores_needing_scheduling);
}
// Special case to ensure dummy threads that are waiting block.
current_thread->IfDummyThreadTryWait();
}
u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) {
@@ -707,23 +710,19 @@ void KScheduler::Unload(KThread* thread) {
}
void KScheduler::Reload(KThread* thread) {
LOG_TRACE(Kernel, "core {}, reload thread {}", core_id, thread ? thread->GetName() : "nullptr");
LOG_TRACE(Kernel, "core {}, reload thread {}", core_id, thread->GetName());
if (thread) {
ASSERT_MSG(thread->GetState() == ThreadState::Runnable, "Thread must be runnable.");
Core::ARM_Interface& cpu_core = system.ArmInterface(core_id);
cpu_core.LoadContext(thread->GetContext32());
cpu_core.LoadContext(thread->GetContext64());
cpu_core.SetTlsAddress(thread->GetTLSAddress());
cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0());
cpu_core.ClearExclusiveState();
}
Core::ARM_Interface& cpu_core = system.ArmInterface(core_id);
cpu_core.LoadContext(thread->GetContext32());
cpu_core.LoadContext(thread->GetContext64());
cpu_core.SetTlsAddress(thread->GetTLSAddress());
cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0());
cpu_core.ClearExclusiveState();
}
void KScheduler::SwitchContextStep2() {
// Load context of new thread
Reload(current_thread.load());
Reload(GetCurrentThread());
RescheduleCurrentCore();
}
@@ -732,13 +731,23 @@ void KScheduler::ScheduleImpl() {
KThread* previous_thread = GetCurrentThread();
KThread* next_thread = state.highest_priority_thread;
state.needs_scheduling = false;
state.needs_scheduling.store(false);
// We never want to schedule a null thread, so use the idle thread if we don't have a next.
if (next_thread == nullptr) {
next_thread = idle_thread;
}
if (next_thread->GetCurrentCore() != core_id) {
next_thread->SetCurrentCore(core_id);
}
// We never want to schedule a dummy thread, as these are only used by host threads for locking.
if (next_thread->GetThreadType() == ThreadType::Dummy) {
ASSERT_MSG(false, "Dummy threads should never be scheduled!");
next_thread = idle_thread;
}
// If we're not actually switching thread, there's nothing to do.
if (next_thread == current_thread.load()) {
previous_thread->EnableDispatch();
@@ -746,14 +755,8 @@ void KScheduler::ScheduleImpl() {
return;
}
if (next_thread->GetCurrentCore() != core_id) {
next_thread->SetCurrentCore(core_id);
}
current_thread.store(next_thread);
// Update the CPU time tracking variables.
KProcess* const previous_process = system.Kernel().CurrentProcess();
UpdateLastContextSwitchTime(previous_thread, previous_process);
// Save context for previous thread
@@ -761,6 +764,10 @@ void KScheduler::ScheduleImpl() {
std::shared_ptr<Common::Fiber>* old_context;
old_context = &previous_thread->GetHostContext();
// Set the new thread.
current_thread.store(next_thread);
guard.Unlock();
Common::Fiber::YieldTo(*old_context, *switch_fiber);
@@ -788,8 +795,8 @@ void KScheduler::SwitchToCurrent() {
do {
auto next_thread = current_thread.load();
if (next_thread != nullptr) {
next_thread->context_guard.Lock();
if (next_thread->GetRawState() != ThreadState::Runnable) {
const auto locked = next_thread->context_guard.TryLock();
if (state.needs_scheduling.load()) {
next_thread->context_guard.Unlock();
break;
}
@@ -797,6 +804,9 @@ void KScheduler::SwitchToCurrent() {
next_thread->context_guard.Unlock();
break;
}
if (!locked) {
continue;
}
}
auto thread = next_thread ? next_thread : idle_thread;
Common::Fiber::YieldTo(switch_fiber, *thread->GetHostContext());

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