Compare commits

...

319 Commits

Author SHA1 Message Date
bunnei 71d4abcfd4 cmake: Remove use of bintray for externals.
- Bintray will be deprecated on May 1st 2021 (https://bintray.com/)
- We were previously using this for Qt (non-Windows) and SDL.
- I've moved to bundled SDL on Windows.
2021-04-15 23:12:23 -07:00
bunnei 0a5bc8ec14 Merge pull request #6119 from german77/SDLMapping
InputCommon: Address mapping and naming issues with SDL2
2021-04-15 21:40:35 -07:00
bunnei 60511976bb Merge pull request #6199 from lioncash/log-ns
common/log: Move Log namespace into the Common namespace
2021-04-14 21:29:44 -07:00
Lioncash 2a341c9969 log/backend: Correct order of const in copy constructor
Follows our predominant coding style. Also explicitly specifies the move
constructor/assignment operator as well.
2021-04-14 23:11:01 -04:00
Lioncash 64606aefcf common/log: Move Log namespace into the Common namespace
Forgot to move this over when I moved the rest of the source files with
lacking namespaces over.
2021-04-14 23:10:58 -04:00
bunnei de5bf640b7 Merge pull request #6196 from bunnei/asserts-setting
core: settings: Add setting for debug assertions and disable by default.
2021-04-14 17:47:18 -07:00
bunnei a4c6712a4b common: Move settings to common from core.
- Removes a dependency on core and input_common from common.
2021-04-14 16:24:03 -07:00
bunnei c6c0771b12 core: settings: Add setting for debug assertions and disable by default.
- This is a developer-only setting and no longer needs to be enabled by default.
- Also adds "use_auto_stub" setting to SDL frontend while we are here.
- Supersedes #1340.
2021-04-14 16:24:02 -07:00
bunnei eedbe8351c Merge pull request #6197 from ameerj/kreslimit-cleanup
k_resource_limit: Cleanup of member variables/headers
2021-04-14 14:25:51 -07:00
bunnei 62a8505345 Merge pull request #6195 from Morph1984/controller-applet-motion
applets/controller: Hook up the "Motion" button functionality
2021-04-13 21:53:34 -07:00
ameerj 2067115c78 k_resource_limit: Minor cleanup of member variables/headers 2021-04-14 00:40:33 -04:00
bunnei bb922d6ff6 Merge pull request #6185 from ameerj/process-reslimit
kernel/process: Replace process resource limit instance with the kernel's resource limit
2021-04-13 21:08:59 -07:00
bunnei 8146c8c5e7 Merge pull request #6191 from lioncash/vdtor
engine_interface: Add missing virtual destructor
2021-04-13 19:59:10 -07:00
bunnei 12a343ed8d Merge pull request #6190 from lioncash/constfn2
vk_master_semaphore: Add missing const qualifier for IsFree()
2021-04-13 17:52:38 -07:00
bunnei 62b560e8e3 Merge pull request #6188 from lioncash/bits
vk_texture_cache: Make use of bit_cast where applicable
2021-04-13 16:44:49 -07:00
bunnei 154eb3cfbe Merge pull request #6187 from lioncash/sign-conv
texure_cache/util: Resolve implicit sign conversions with std::reduce
2021-04-13 09:46:32 -07:00
Morph 10ca4c9490 applets/controller: Hook up the "Motion" button functionality
I forgot to hook this up during the development of the controller applet, this PR amends that.
2021-04-13 10:05:07 -04:00
bunnei 335a3cc115 Merge pull request #6186 from lioncash/cache-erase
query_cache: Make use of std::erase_if
2021-04-12 17:52:34 -07:00
bunnei 7f06276192 Merge pull request #6193 from lioncash/incguard
nvidia_flags: Add missing header guard
2021-04-12 16:59:02 -07:00
Lioncash ff6a83e0fe nvidia_flags: Add missing header guard
Prevents potential inclusion compilation errors.
2021-04-12 19:18:48 -04:00
ameerj 5e85bc3d23 kernel/process: Replace process resource limit instance with the kernel's resource limit
This commit addresses the inaccurate behavior of kernel processes creating their own resource limit, rather than utilizing the kernel's system-wide resource limit instance.
2021-04-12 16:14:19 -04:00
bunnei 8e7734bf40 Merge pull request #6192 from lioncash/discard
k_thread: Remove [[nodiscard]] attribute from ClearWaitCancelled()
2021-04-12 11:12:45 -07:00
Lioncash 0fb3773924 k_thread: Remove [[nodiscard]] attribute from ClearWaitCancelled()
This function has a void return value, so this attribute doesn't apply
to it.
2021-04-12 10:17:38 -04:00
Lioncash 31932904c5 engine_interface: Add missing virtual destructor
Eliminates a potential bug vector related to inheritance. Plus, we
should generally be specifying the destructor as virtual within purely
virtual interfaces to begin with.
2021-04-12 09:53:55 -04:00
Lioncash 9b331a5fb5 vk_master_semaphore: Deduplicate atomic access within IsFree()
We can just reuse the already existing KnownGpuTick() to deduplicate the
access.
2021-04-12 09:41:55 -04:00
Lioncash c5f5d6e7f6 vk_master_semaphore: Add missing const qualifier for IsFree()
This member function doesn't modify class state.
2021-04-12 09:41:23 -04:00
Lioncash 4198c92ed0 vk_texture_cache: Make use of Common::BitCast where applicable
Also clarify the TODO comment a little more on the lacking
implementations for std::bit_cast.
2021-04-12 09:17:36 -04:00
Lioncash fddb278aa3 texure_cache/util: Resolve implicit sign conversions with std::reduce
Amends implicit sign conversions occurring with usages of std::reduce
and also relocates it to its own utility function to reduce verbosity a
little bit.
2021-04-12 05:21:53 -04:00
Lioncash 4209588505 query_cache: Make use of std::erase_if
Same behavior, but much more straightforward to read.
2021-04-12 04:51:18 -04:00
bunnei 26d60014d0 Merge pull request #6135 from Morph1984/borderless-windowed-fullscreen
configure_graphics: Add Borderless Windowed fullscreen mode
2021-04-11 21:23:59 -07:00
Rodrigo Locatti ddbd1387aa Merge pull request #6181 from Joshua-Ashton/robustness_features
vulkan_device: Enable EXT_robustness2 features
2021-04-11 20:42:14 -03:00
Rodrigo Locatti 9f1cf99ea0 Merge pull request #6182 from Joshua-Ashton/null-offset
vk_buffer_cache: Fix offset for NULL vertex buffers
2021-04-11 20:41:48 -03:00
bunnei 0c19147e09 Merge pull request #6170 from Morph1984/more-time-fixes
service: time: Setup the network clock with the local clock context
2021-04-11 10:50:08 -07:00
LC 55b7d8e322 Merge pull request #6183 from MerryMage/dynarmic
externals: Update dynarmic to b2a4da5e
2021-04-11 11:16:34 -04:00
MerryMage a208c7b059 externals: Update dynarmic to b2a4da5e 2021-04-11 15:39:45 +01:00
Joshua Ashton 0ec6cb942d vk_buffer_cache: Fix offset for NULL vertex buffers
The Vulkan spec states:
If an element of pBuffers is VK_NULL_HANDLE, then the corresponding element of pOffsets must be zero.

https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkCmdBindVertexBuffers2EXT.html#VUID-vkCmdBindVertexBuffers2EXT-pBuffers-04112
2021-04-11 10:34:52 +01:00
Morph 9bd71f4064 Merge pull request #6180 from Joshua-Ashton/device_loss_fix
renderer_vulkan: Check return value of AcquireNextImage
2021-04-11 05:08:32 -04:00
Joshua Ashton 08337a492d vulkan_device: Enable EXT_robustness2 features
When this was being made mandatory, these enablement of these features was removed, but this is still needed.

Fixes: 757fd1e917 ("vulkan_device: Require VK_EXT_robustness2")
2021-04-11 09:48:38 +01:00
Joshua Ashton bcf58c8210 renderer_vulkan: Check return value of AcquireNextImage
We can get into a really bad state by ignoring this
leading to device loss and using incorrect resources.
2021-04-11 09:27:50 +01:00
bunnei 4f60818eae Merge pull request #6167 from Morph1984/time-fix
service: time: Fix CalculateStandardUserSystemClockDifferenceByUser
2021-04-10 22:11:53 -07:00
bunnei 290b452ea1 Merge pull request #6112 from ogniK5377/pctl
pctl: Rework how pctl works to be more accurate
2021-04-10 21:09:54 -07:00
bunnei 1063e0be48 Merge pull request #6172 from degasus/cmake_opus
externals: Search for shared opus installation.
2021-04-10 02:27:02 -07:00
bunnei b04877dd95 Merge pull request #6099 from bunnei/derive-mem
Kernel Rework: Derive memory regions from board layout.
2021-04-10 00:02:52 -07:00
bunnei 31c80b8c6f Merge pull request #6171 from german77/services
service: Update service function tables and use proper names
2021-04-09 22:47:34 -07:00
bunnei c6d2af16b5 Merge pull request #6156 from lioncash/lock-discard
kernel: Mark lock helper classes as [[nodiscard]]
2021-04-09 21:42:26 -07:00
bunnei 9cf8bcc75c Merge pull request #6113 from german77/playhistory
Friend: Stub GetPlayHistoryRegistrationKey
2021-04-09 20:50:13 -07:00
bunnei 96d07b4949 Merge pull request #6158 from german77/hidServiceTables
hid: Update service function tables
2021-04-09 16:10:06 -07:00
bunnei d6e5e053a6 Merge pull request #6162 from degasus/no_spin_loops
video_core: Avoid spin loops.
2021-04-09 11:52:18 -07:00
bunnei c34249559d Merge pull request #6164 from Morph1984/service-update-12.x
service: Update service function tables
2021-04-09 10:59:27 -07:00
Morph 9c85bcbecc ns: Update to 12.x 2021-04-09 00:49:47 -04:00
Morph 467ef54e2a aoc_u: Update to 12.x 2021-04-09 00:49:47 -04:00
Morph 8a9e834fc2 nim: Update to 12.x 2021-04-09 00:49:47 -04:00
Morph e0bddf8f07 npns: Update to 12.x 2021-04-09 00:49:47 -04:00
Morph 5ce0e127da bgtc: Update to 12.x and implement OpenTaskService 2021-04-09 00:49:47 -04:00
Morph 6af7bd02b2 vi: Update to 12.x 2021-04-09 00:49:47 -04:00
Morph 7e62452ac8 erpt: Update to 12.x 2021-04-09 00:49:46 -04:00
Morph 5ec2fdceca btm: Update to 12.x 2021-04-09 00:49:46 -04:00
Morph 214ef2dd8a btdrv: Update to 12.x 2021-04-09 00:49:46 -04:00
bunnei c1017efb4a Merge pull request #6168 from Morph1984/stub-SetNpadAnalogStickUseCenterClamp
service: hid: Stub SetAnalogStickUseCenterClamp
2021-04-08 21:16:47 -07:00
german77 09a8e08109 wlan: Update to 12.x 2021-04-08 19:40:25 -06:00
german77 ac14ef70b5 usb: Use proper names 2021-04-08 19:40:25 -06:00
german77 35abd560c4 ITimeZoneService: Update to 12.x 2021-04-08 19:40:25 -06:00
german77 e7530b341e spl: Update to 12.x 2021-04-08 19:40:25 -06:00
german77 01928b1d17 sfdnsres: Use proper names 2021-04-08 19:40:25 -06:00
german77 ff1201210c nsd: Update to 12.x 2021-04-08 19:40:25 -06:00
german77 f90041a2d4 ethc: Update to 12.x 2021-04-08 19:40:25 -06:00
german77 6c81332ca7 sm: Use proper names, update to 12.x 2021-04-08 19:40:25 -06:00
german77 7133bfdd2c set_sys: Update to 12.x 2021-04-08 19:40:25 -06:00
german77 556c5df745 pctl_module: Update to 12.x 2021-04-08 19:40:25 -06:00
german77 4530b58eb0 pcie: Use proper names 2021-04-08 19:40:25 -06:00
german77 53f1560a24 olsc: Update to 12.x 2021-04-08 19:40:25 -06:00
german77 c37b8a1028 pl_u: Update to 12.x 2021-04-08 19:40:25 -06:00
german77 278c38aa4a ldr: Use proper names 2021-04-08 19:40:25 -06:00
german77 a4e2821530 arp: Use proper names, update to 12.x 2021-04-08 19:40:25 -06:00
german77 a83f0f7154 caps_u: Update to 12.x 2021-04-08 19:40:25 -06:00
german77 dbc4c8e314 caps_a: Update to 12.x 2021-04-08 19:40:24 -06:00
german77 03790771a6 bpc: Use proper names 2021-04-08 19:40:24 -06:00
german77 0377618288 bcat_module: Update to 12.x 2021-04-08 19:40:24 -06:00
german77 247b1c14d2 codecctl: Use proper names 2021-04-08 19:40:24 -06:00
german77 ec0e644fb0 audren_u: Use proper names 2021-04-08 19:40:24 -06:00
german77 8f1300cd31 audren_a: Use proper names 2021-04-08 19:40:24 -06:00
german77 6219da627b audrec_u: Use proper names, update to 12.x 2021-04-08 19:40:24 -06:00
german77 5ce97bf0a0 audrec_a: Use proper names 2021-04-08 19:40:24 -06:00
german77 b059db74c5 audout_u: Use proper names 2021-04-08 19:40:24 -06:00
german77 c51d9e0b0a audout_a: Use proper names 2021-04-08 19:40:24 -06:00
german77 d7f2078e7b audin_u: Use proper names 2021-04-08 19:40:24 -06:00
german77 b6bbc0d483 audin_a: Use proper names 2021-04-08 19:40:24 -06:00
bunnei 701b6c2fb8 Merge pull request #6155 from ameerj/kernel-12-rescnt
kernel: Increase event and session counts
2021-04-08 18:21:00 -07:00
bunnei d894818bb3 Merge pull request #6157 from Morph1984/am-update-12.x
service: am: Update service function tables
2021-04-08 16:37:59 -07:00
bunnei 1744fa6ecf Merge pull request #6062 from ameerj/auto-stub
service: Add a toggle for auto stub fallback
2021-04-08 15:32:41 -07:00
Markus Wick 5096ed5e0a externals: Search for shared opus installation.
We had used conan for opus before, but there was a bug in the AVX detection.
However we still had the Findopus.cmake file within the repository, but not used.

This patch reenables the Findopus helper and prefer the system wide installation of opus.
2021-04-08 23:49:32 +02:00
bunnei dfac2e2d25 Merge pull request #6145 from lat9nq/nvhost_empty_memcpy
nvhost_nvdec_common: Avoid memcpy with null pointers
2021-04-08 13:23:05 -07:00
Morph 2283fccc1b service: time: Setup the network clock with the local clock context
Setting the network time allows some time based events using the network clock to not reset.
2021-04-08 13:26:38 -04:00
bunnei 415dfb6cd3 Merge pull request #6154 from lioncash/svcrange2
svc: Expand SVC tables
2021-04-08 09:21:55 -07:00
Morph 8e545deab9 service: hid: Stub SetAnalogStickUseCenterClamp
- Used by eBASEBALLパワフルプロ野球2020
2021-04-08 03:41:06 -04:00
bunnei 15a07f0282 Merge pull request #6160 from Morph1984/fs-update-12.x
service: fs: Update service function tables
2021-04-07 20:54:42 -07:00
Morph 28d3661a5c service: time: Fix CalculateStandardUserSystemClockDifferenceByUser
CalculateStandardUserSystemClockDifferenceByUser passes in the ClockSnapshots through 2 input buffers and not as raw arguments. Fix this by reading the 2 input buffers instead of popping raw arguments.
2021-04-07 23:34:14 -04:00
bunnei 262a70223f Merge pull request #6143 from lat9nq/nvhost_null_memcpy
nvhost_ctrl_gpu: Avoid sending null pointer to memcpy
2021-04-07 16:50:22 -07:00
bunnei 535e50db1c Merge pull request #6159 from Morph1984/acc-update-12.x
service: acc: Update service function tables
2021-04-07 14:37:59 -07:00
Markus Wick e8bd9aed8b video_core: Use a CV for blocking commands.
There is no need for a busy loop here. Let's just use a condition variable to save some power.
2021-04-07 22:38:52 +02:00
Markus Wick e6fb49fa4b video_core/gpu_thread: Keep the write lock for allocating the fence.
Else the fence might get submited out-of-order into the queue, which makes testing them pointless.
Overhead should be tiny as the mutex is just moved from the queue to the writing code.
2021-04-07 22:38:52 +02:00
Markus Wick 5145133a60 video_core/gpu_thread: Implement a ShutDown method.
This was implicitly done by `is_powered_on = false`, however the explicit method allows us to block until the GPU is actually gone.

This should fix a race condition while removing the other subsystems while the GPU is still active.
2021-04-07 22:38:52 +02:00
Markus Wick 4aec060f6d common/threadsafe_queue: Provide Wait() method.
It shall block until there is something to consume in the queue.

And use it for the GPU emulation instead of the spin loop.
This is only in booting the emulator, however in BOTW this is the case for about 1 second.
2021-04-07 22:38:52 +02:00
bunnei 3173a53db9 Merge pull request #6130 from degasus/better_assert_handling
common: Move assert failure handling into a cpp file.
2021-04-07 13:35:41 -07:00
bunnei d490f6dcf8 Merge pull request #6153 from lioncash/svcrange
process_capability: Handle extended SVC range
2021-04-07 13:01:40 -07:00
bunnei 6dc35caad1 Merge pull request #6161 from Morph1984/audio-update-12.x
service: audio: Update service function tables
2021-04-07 10:39:05 -07:00
Morph a2d40b8185 hwopus: Update to 12.x 2021-04-07 02:57:39 -04:00
Morph 1ad4c98a5c IFile: Update to 12.x 2021-04-07 02:49:19 -04:00
Morph c44db90ad1 fsp-srv: Update to 12.x 2021-04-07 02:46:29 -04:00
Morph 531e797795 dauth_o: Update to 11.x 2021-04-07 02:15:55 -04:00
Morph ded420cfeb acc_u1: Update to 12.x 2021-04-07 02:15:55 -04:00
Morph 63caeca6ba acc_su: Update to 12.x 2021-04-07 02:15:55 -04:00
german77 4fe05d7b42 hid: Update service function tables 2021-04-07 01:15:38 -05:00
Morph 63ebf2a328 ISelfController: Update to 11.x 2021-04-07 02:00:19 -04:00
Morph d04120169d IApplicationFunctions: Update to 11.x 2021-04-07 01:59:35 -04:00
Morph ad0d5818a6 IDebugFunctions: Update to 12.x 2021-04-07 01:53:04 -04:00
Morph 49ec5784b0 ICommonStateGetter: Update to 12.x 2021-04-07 01:53:04 -04:00
Morph 4cdc701fd3 IGlobalStateController: Update to 12.x 2021-04-07 01:53:04 -04:00
Morph 95fa89da27 IHomeMenuFunctions: Update to 12.x 2021-04-07 01:53:04 -04:00
Lioncash 530a5a1d09 Amend bizarre clang-format suggestions 2021-04-07 01:52:08 -04:00
Lioncash 1e964604bb k_scoped_scheduler_lock_and_sleep: Mark class as [[nodiscard]]
Prevents logic bugs from slipping through.
2021-04-07 01:45:04 -04:00
Lioncash c018769016 k_scoped_lock: delete copy and move assignment operators
If we delete the copy and move constructor, we should also be deleting
the copy and move assignment operators (and even if this were intended,
it would be pretty odd to not document why it's done this way).
2021-04-07 01:25:57 -04:00
Lioncash bc30aa8249 k_scoped_lock: Mark class as [[nodiscard]]
Prevents logic bugs of the kind described in the previous commit from
slipping through.
2021-04-07 01:23:08 -04:00
Lioncash 97e2604575 k_scheduler: Mark KScopedSchedulerLock as [[nodiscard]]
Prevents logic bugs like:

KScopedSchedulerLock{kernel};

instead of:

KScopedSchedulerLock lk{kernel};

from slipping through.
2021-04-07 01:19:29 -04:00
ameerj 24900674b7 kernel: Increase event and session counts
12.x increased the number of available sessions and event resource counts
2021-04-07 01:01:05 -04:00
bunnei 068b2ffbcc Merge pull request #6146 from lat9nq/vp9_empty_memcpy
vp9: Avoid memcpy with null pointers
2021-04-06 21:57:43 -07:00
Lioncash 55fc808d64 svc: Expand SVC tables
12.x expanded the range of SVC entries from 0x7F to 0xBF (with all new
entries being unused), so we can expand it to also match.
2021-04-07 00:55:33 -04:00
Lioncash 03dda80e2b process_capability: Handle extended SVC range
12.x extended the range of SVC IDs, so we need to expand the range of
bits that need to be tested.

The upside of this is that we can eliminate a range check, given the
whole range is used.
2021-04-07 00:35:49 -04:00
Morph 8ce31f1c8e config: Default to exclusive fullscreen mode on platforms other than Windows
Several issues have been reported with the borderless windowed fullscreen mode on *nix platforms. Default to exclusive fullscreen mode on these platforms for now.
2021-04-06 05:58:57 -04:00
Morph 01ea0f3c74 configure_graphics: Add Borderless Windowed fullscreen mode
The borderless windowed fullscreen mode solves several issues with the presentation of the overlay dialogs and on-screen keyboard in exclusive fullscreen mode, and also has other benefits such as smoother gameplay, lower latency and a significant reduction in screen tearing.

Co-authored-by: Its-Rei <kupfel@gmail.com>
2021-04-06 05:58:57 -04:00
lat9nq 2cc42e40c5 nvhost_nvdec_common: Avoid memcpy with null pointers
Avoid sending null pointer to memcpy as reported by Undefined Behavious
Sanitizer.

Co-authored-by: LC <mathew1800@gmail.com>
2021-04-05 16:40:03 -04:00
lat9nq 638c892edf nvhost_ctrl_gpu: Avoid sending null pointer to memcpy
Undefined Behaviour Sanitizer reports a null pointer is being sent to
memcpy, thought it's "guaranteed to never be null". Guard it with an if
statement, and log when the action has been averted.
2021-04-05 00:49:09 -04:00
lat9nq a60653dcd3 vp9: Avoid memcpy with null pointers
Avoid sending null pointer to memcpy as reported by Undefined Behaviour
Sanitizer. Replaces the std::memcpy calls in SpliceVectors with
std::copy calls. Opting to replace all the memcpy's with copy's.

Co-authored-by: LC <mathew1800@gmail.com>
2021-04-05 00:44:38 -04:00
LC 7feb490f83 Merge pull request #6141 from lat9nq/cfg_gphcs_stack_use
configure_graphics: Prevent stack-use-after-scope
2021-04-04 18:16:50 -04:00
Markus Wick 9be819faaf common: Move assert failure handling into a cpp file.
Advantage: Altering the handler does not need a full recompilation.
Disadvantage: noreturn is droped, so the caller is a bit slower.

We quite often run yuzu with a YOLO assertion handler. In fact, only very few
games run at all with asserts. This patch allows developers to patch the handler
without recompiling everything. The overhead of the missing "noreturn" attribute
shoul be negletable.
2021-04-04 21:19:33 +02:00
lat9nq 33ed02a239 configure_graphics: Prevent stack-use-after-scope
Address Sanitizer reports stack-use-after-scope on line 231
`vulkan_devices.push_back(QString::fromStdString(name));`. Instead of
using a pointer, copy the string into a std::string and use that,
instead.
2021-04-04 15:05:22 -04:00
Morph 69b2dbdffd Merge pull request #6139 from Morph1984/cmake-fix-build
ci: Fix MSVC build with CMake 3.20.0
2021-04-04 07:54:38 -04:00
Morph 17ad323b36 ci: Fix MSVC build with CMake 3.20.0 2021-04-04 07:49:21 -04:00
bunnei c92a211e7c Merge pull request #6127 from german77/udpSingleConnection
InputCommon: Improve UDP communications
2021-04-03 23:14:23 -07:00
bunnei c5ca8675c8 Merge pull request #6132 from MerryMage/code_size
arm_dynarmic: Increase size of code cache
2021-04-02 18:47:04 -07:00
Morph aca6ab6417 Merge pull request #6131 from german77/rightjoyconSLSR
HID: Fix SL and SR buttons for right joycon
2021-04-02 15:48:04 -04:00
MerryMage 0fbd7752c3 arm_dynarmic: Increase size of code cache 2021-04-02 18:09:15 +01:00
german77 eaf0c4af11 HID: Fix SL and SR buttons for right joycon 2021-04-02 09:03:11 -05:00
bunnei 94d77d0e39 Merge pull request #6129 from degasus/cmake_libzip
externals/cmake: Fix case spelling of libzip.
2021-04-01 23:06:36 -07:00
bunnei 824adb44fa Merge pull request #6128 from bunnei/update-dynarmic-2
externals: dynarmic: Update to latest rev. to increase code size.
2021-04-01 21:02:51 -07:00
Markus Wick d3e87d70ec externals: Fix case spelling of libzip.
CMake is case senstive, so Libzip vs LIBZIP was a bug.
Upstream calls themself libzip, so let's pick this naming.
2021-04-02 00:30:13 +02:00
bunnei 7ff7e65926 externals: dynarmic: Update to latest rev. to increase code size.
- The current limits are being hit in yuzu with some games.
- This should fix the slowdowns in newer updates for Super Smash Bros. Ultimate.
2021-04-01 13:23:12 -07:00
bunnei d69421b1db Merge pull request #6106 from MerryMage/nullptr-jit
[test] arm_dynarmic: Always have a 'valid' jit instance
2021-04-01 09:50:00 -07:00
bunnei e44622860a Merge pull request #6126 from Morph1984/stub-SetAlbumImageTakenNotificationEnabled
ISelfController: Stub SetAlbumImageTakenNotificationEnabled
2021-03-30 21:32:01 -07:00
german77 bb3dce9363 Use a single connection for UDP server, make connection test longer and check all pads instead of only the first one 2021-03-30 22:17:08 -05:00
german77 d9db1d125e InputCommon: Name properly xbox 360 and one controllers, Fix mappings for Nintendo Pro controllers 2021-03-30 21:40:36 -05:00
Rodrigo Locatti 5ee669466f Merge pull request #5927 from ameerj/astc-compute
video_core: Accelerate ASTC texture decoding using compute shaders
2021-03-30 19:31:52 -03:00
bunnei eeea426c74 Merge pull request #6116 from german77/userArgument
yuzu/main: Add user command line argument
2021-03-30 15:01:33 -07:00
Morph ca30190fad ISelfController: Stub SetAlbumImageTakenNotificationEnabled
This service call sets an internal flag whether a notification is shown when an image is captured.
Currently we do not support capturing images via the capture button, so this can be stubbed for now.
2021-03-30 13:45:00 -04:00
ameerj 54c1e0897d configuration: Add auto stub toggle that resets on boot
Auto-stub is an experimental debugging feature that may cause unforseen bugs. This adds a toggle to only allow auto-stubbing unimplemented functions when explicitly enabled when yuzu is launched.
2021-03-30 13:40:31 -04:00
ameerj e6e61424d4 service: Auto stub fallback
For simple services we can implement an automatic stub fallback to help with compatibility until a proper implementation is done.

Co-Authored-By: Chloe <25727384+ognik5377@users.noreply.github.com>
2021-03-30 13:40:31 -04:00
bunnei b3f68098d5 Merge pull request #6124 from jbeich/vulkan+opengl
vulkan_common: enable OpenGL interop on other Unices
2021-03-30 09:37:00 -07:00
Chloe Marcec 4930242c20 Addressed issues 2021-03-30 20:27:27 +11:00
bunnei f234531f92 Merge pull request #6109 from german77/gestureID
HID: Initialize correctly the gesture finger_id and filter invalid inputs
2021-03-29 18:00:47 -07:00
Jan Beich 9b50b23a50 vulkan_common: enable OpenGL interop on other Unices 2021-03-30 00:25:25 +00:00
bunnei fb7dcbf7af Merge pull request #6102 from ogniK5377/fd-pass
nvdrv: Pass device fd and handle device create methods for device opening and closing
2021-03-29 12:53:55 -07:00
bunnei a63dcb6d56 Merge pull request #6118 from MerryMage/dynarmic
externals: Update dynarmic to c28f13af
2021-03-28 13:59:05 -07:00
bunnei f8561c7a65 Merge pull request #6115 from bunnei/fix-kernel-init
hle: kernel: Initialize preemption task after schedulers.
2021-03-28 12:13:39 -07:00
MerryMage a527e5f0cd externals: Update dynarmic to c28f13af
AVX-512 bugfixes
2021-03-27 21:34:20 +00:00
german77 9cebde760f yuzu/main: Add user command line argument 2021-03-27 12:34:48 -05:00
bunnei 8a5794c4db Merge pull request #6114 from Morph1984/friend-log
service: friend: Change logging class from ACC to Friend
2021-03-27 10:29:43 -07:00
bunnei cb7f2e5616 hle: kernel: Initialize preemption task after schedulers.
- Fixes a startup crash that occurs if CoreTiming tries to preempt before kernel initialization completes.
2021-03-27 10:04:13 -07:00
Morph 3b98fab850 service: friend: Change logging class from ACC to Friend 2021-03-27 11:11:07 -04:00
german77 b2fb5c60e1 Friend: Stub GetPlayHistoryRegistrationKey 2021-03-27 08:25:36 -05:00
Narr the Reg 7c26a9aefe HID: Initialize correctly the gesture finger_id and filter invalid results 2021-03-26 11:13:18 -06:00
Chloe Marcec e9a1f29e93 pctl: Rework how pctl works to be more accurate
Introduces the usage of compatibilities to allow it the module to be closer to how it works on hardware.
2021-03-27 02:03:18 +11:00
ameerj 2f83d9a61b astc_decoder: Refactor for style and more efficient memory use 2021-03-25 16:53:51 -04:00
Chloe Marcec 99fdfa1fcd nvdrv: Pass device fd and handle device create methods for device opening and closing
We pass the fd to the ioctl as well as alert the device when it's opened or closed to allow for fd unique actions to take place
2021-03-25 12:56:42 +11:00
bunnei 65774084fd Merge pull request #6101 from ogniK5377/alloc-as-ex
nvdrv: Change InitializeEx to AllocAsEx
2021-03-24 17:37:01 -07:00
bunnei b83eb4dd18 Merge pull request #6108 from jbeich/freebsd-async-shaders
gl_device: unblock async shaders on other Unix systems
2021-03-24 16:52:27 -07:00
Jan Beich 8c016b02e7 gl_device: unblock async shaders on other Unix systems
Mesa is the primary OpenGL provider on all FreeDesktop systems.
For example, iris is used on Intel GPU + FreeBSD by default.
2021-03-24 19:59:20 +00:00
MerryMage 52dae41d7f arm_dynarmic: Always have a 'valid' jit instance 2021-03-24 18:47:17 +00:00
bunnei 10d6e9f32b hle: kernel: Breakup InitializeMemoryLayout. 2021-03-23 18:47:16 -07:00
bunnei fb91647bca hle: kernel: k_memory_region_type: Minor code cleanup. 2021-03-23 18:42:04 -07:00
bunnei 4eac8703d2 hle: kernel: k_memory_region: Minor code cleanup. 2021-03-23 18:37:39 -07:00
bunnei 9032d21365 hle: kernel: k_memory_layout: Use pair instead of tuple. 2021-03-23 18:35:01 -07:00
bunnei a32190d0c2 hle: kernel: k_system_control: Remove unnecessary inline. 2021-03-23 18:33:29 -07:00
bunnei ab5995c7ae common: common_sizes: Move sizes to the Common namespace. 2021-03-23 18:31:46 -07:00
bunnei 716285fab8 Merge pull request #6100 from bunnei/arm-fix
core: arm_dynarmic: Ensure JIT state is saved/restored on page table changes.
2021-03-23 17:08:37 -07:00
bunnei dde074eaab Merge pull request #6092 from ivan-boikov/cancel-dir-select
Fix cancelation of getExistingDirectory dialog
2021-03-22 17:55:18 -07:00
Chloe Marcec 875183e7c5 nvdrv: Change InitializeEx to AllocAsEx
Wee also report the correct "big page size" now in GetVARegions & fix up the struct for IoctlAllocAsEx
2021-03-22 19:59:30 +11:00
LC a50133fc5e Merge pull request #6095 from lat9nq/async-shader-block
gl_device: Block async shaders on AMD and Intel
2021-03-21 23:29:49 -04:00
LC e274e38205 Merge pull request #6078 from Morph1984/libusb-utf8
externals/libusb/CMakeLists: Add /utf-8 compile option for MSVC
2021-03-21 23:29:01 -04:00
bunnei 1d78190843 hle: kernel: Merge KMemoryRegionAttr and KMemoryRegionType.
- Fixes clang errors with mixed enum arithmetic.
2021-03-21 15:53:21 -07:00
bunnei 3ffbe50e7d hle: kernel: Remove unused variable. 2021-03-21 15:47:24 -07:00
bunnei fc5205fc84 hle: kernel: k_memory_region_type: Remove extra ". 2021-03-21 15:47:05 -07:00
bunnei a35717b245 core: arm_dynarmic: Ensure JIT state is saved/restored on page table changes.
- We re-create the JIT here without preserving any state.
2021-03-21 15:25:25 -07:00
bunnei 1996cae9cb hle: kernel: k_memory_layout: Move KMemoryRegionAllocator out of global. 2021-03-21 14:45:13 -07:00
bunnei 343eaecd38 hle: kernel: k_memory_layout: Derive memory regions based on board layout. 2021-03-21 14:45:13 -07:00
bunnei 8d0ba7ee49 common: common_sizes: Move Invalid to Size_* prefix and add missing values. 2021-03-21 14:45:03 -07:00
bunnei 80688362cf hle: kernel: k_memory_region: Refactor to simplify code. 2021-03-21 14:45:03 -07:00
bunnei edbc505e52 hle: kernel: board: k_system_control: Extend to include memory region sizes. 2021-03-21 14:45:03 -07:00
bunnei 10265ad0e4 hle: kernel: board: Add secure_monitor module. 2021-03-21 14:45:03 -07:00
bunnei 28be8aec9a common: Move common sizes to their own header for code reuse. 2021-03-21 14:45:03 -07:00
bunnei 01f04fee32 hle: kernel: k_address_space_info: Cleanup. 2021-03-21 14:45:02 -07:00
bunnei f2e1441567 hle: kernel: Add k_trace module. 2021-03-21 14:45:02 -07:00
bunnei 5762517728 hle: kernel: KSystemControl: Update to reflect board-specific behavior. 2021-03-21 14:45:02 -07:00
bunnei a439867f2c hle: kernel: KMemoryManager: Add CalculateManagementOverheadSize. 2021-03-21 14:45:02 -07:00
bunnei 43a29b5803 hle: kernel: KMemoryManager: Add aliases. 2021-03-21 14:45:02 -07:00
bunnei c17beefe3d hle: kernel: Add architecture and board specific memory regions. 2021-03-21 14:45:02 -07:00
bunnei 3fb64da452 hle: kernel: KMemoryRegion: Derive region values. 2021-03-21 14:45:02 -07:00
bunnei 5872561077 hle: kernel: Migrate some code from Common::SpinLock to KSpinLock. 2021-03-21 14:45:02 -07:00
bunnei 541b4353e4 hle: kernel: Add initial KMemoryRegionType module. 2021-03-21 14:45:02 -07:00
bunnei 778e0f8ec1 hle: kernel: Move KMemoryRegion to its own module and update. 2021-03-21 14:45:02 -07:00
lat9nq 538f097f97 gl_device: Block async shaders on AMD and Intel
Currently, the Windows versions of the Intel OpenGL driver and the AMD
proprietary OpenGL driver do not properly support (or in fact degrade)
when asynchronous shader compilation is enabled. This blocks
specifically those drivers from using this feature. This affects
AMDGPU-PRO on Linux, and AMD's and Intel's OpenGL drivers on Windows.
2021-03-21 01:25:45 -04:00
ivan-boikov afa4bcbb3b Fix cancelation of choose directory dialog 2021-03-20 15:52:22 +01:00
bunnei 2e85ee250d Merge pull request #6052 from Morph1984/vi-getindirectlayerimagemap
IApplicationDisplayService: Stub GetIndirectLayerImageMap
2021-03-19 22:59:25 -07:00
bunnei cb48ed2e1a Merge pull request #6056 from zkitX/spl-updates
service: Refactor spl
2021-03-18 15:49:41 -07:00
bunnei 4aa8189328 Merge pull request #6055 from MerryMage/exceed-the-limit
[testing] fiber: Double default stack size
2021-03-17 20:46:45 -07:00
Morph ec514a4d1b IApplicationDisplayService: Stub GetIndirectLayerImageMap
Used by games invoking the inline software keyboard such as GNOSIA
2021-03-17 03:25:12 -04:00
bunnei e1f7938a3b Merge pull request #6070 from Morph1984/sysver-11.0.1
system_version: Update to 11.0.1
2021-03-16 18:13:12 -07:00
bunnei ab102787fa Merge pull request #6083 from Morph1984/bsd-avoid-writebuffer
bsd: Avoid writing empty buffers
2021-03-16 11:59:05 -07:00
Morph 8441094ba3 bsd: Avoid writing empty buffers
Silences log spam on empty buffer writes
2021-03-16 12:50:44 -04:00
bunnei 0687a8370d Merge pull request #6069 from Morph1984/ngWord
system_archive: Update NgWord archive version
2021-03-15 15:44:04 -07:00
Morph df9899eed6 externals/libusb/CMakeLists: Add /utf-8 compile option for MSVC 2021-03-15 10:51:46 -04:00
Morph 824e53149d system_version: Update to 11.0.1 2021-03-14 08:47:36 -04:00
Morph 9761618a8d system_archive: Update NgWord archive version 2021-03-14 08:33:48 -04:00
bunnei d3a4a192fe Merge pull request #6054 from Morph1984/time-GetClockSnapshot
time: Assign the current time point to the ClockSnapshot
2021-03-13 23:15:54 -08:00
Rodrigo Locatti 2f30c10584 astc_decoder: Reimplement Layers
Reimplements the approach to decoding layers in the compute shader. Fixes multilayer astc decoding when using Vulkan.
2021-03-13 12:16:03 -05:00
ameerj c7553abe89 astc_decoder: Fix out of bounds memory access
resolves a crash with some anamolous textures found in Astral Chain.
2021-03-13 12:16:03 -05:00
ameerj 20eb368e14 renderer_vulkan: Accelerate ASTC decoding
Co-Authored-By: Rodrigo Locatti <reinuseslisp@airmail.cc>
2021-03-13 12:16:03 -05:00
ameerj f6566338eb host_shaders: Modify shader cmake integration to allow for larger shaders
using a raw string to encapsulate the entire shader code limits us to shaders of size less than 2KB. This change overcomes this limitation.
2021-03-13 12:16:03 -05:00
ameerj 2985e5e94c renderer_opengl: Accelerate ASTC texture decoding with a compute shader
ASTC texture decoding is currently handled by a CPU decoder for GPU's without native ASTC decoding support (most desktop GPUs). This is the cause for noticeable performance degradation in titles which use the format extensively.

This commit adds support to accelerate ASTC decoding using a compute shader on OpenGL for GPUs without native support.
2021-03-13 12:16:03 -05:00
bunnei 3b85ac2ac4 Merge pull request #6053 from Morph1984/time-CalculateSpanBetween
time: Fix CalculateSpanBetween implementation
2021-03-12 23:31:09 -08:00
bunnei 4735d18bb9 Merge pull request #6028 from bunnei/raster-cache
video_core: rasterizer_accelerated: Use a flat array instead of interval_map for cached pages.
2021-03-12 21:57:27 -08:00
bunnei a9d24b0df3 video_core: rasterizer_accelerated: Fix un/signed mismatch. 2021-03-12 21:52:49 -08:00
bunnei 5dae45b958 Merge pull request #5327 from AniLeo/master
qt: Set DISPLAY env var when not present
2021-03-12 12:10:28 -08:00
bunnei 827dcad26e Merge pull request #6040 from german77/toggleKeyboard
Enable toggle buttons for keyboard and mouse
2021-03-11 11:00:44 -08:00
zkitx 4439801c0f Fix casing on DeallocateAesKeySlot 2021-03-11 02:46:22 -05:00
zkitx ad653550eb Update SPL to fit N's service refactor (4.0.0+) which split into new services. 2021-03-11 02:36:48 -05:00
MerryMage 59173ff7a7 fiber: Double default stack size
Stack overflow occurs with some guest applications
2021-03-10 20:37:56 +00:00
Morph 87cfe5b1da time: Fix CalculateSpanBetween implementation
CalculateSpanBetween passes in the ClockSnapshots through 2 input buffers and not as raw arguments. Fix this by reading the 2 input buffers instead of popping raw arguments.

Partially fixes Super Smash Bros. Ultimate's Spirit Board
2021-03-10 11:42:59 -05:00
Morph 2490ffbbce time: Assign the current time point to the ClockSnapshot
Fixes the timer in Super Smash Bros Ultimate's Spirit Board.
2021-03-10 11:40:51 -05:00
Rodrigo Locatti daf5c5060b Merge pull request #5891 from ameerj/bgra-ogl
renderer_opengl: Use compute shaders to swizzle BGR textures on copy
2021-03-09 02:47:51 -03:00
bunnei d1a7b2eca7 Merge pull request #6021 from ReinUsesLisp/skip-cache-heuristic
buffer_cache: Heuristically decide to skip cache on uniform buffers
2021-03-08 17:48:55 -08:00
bunnei 9c4c9f1e7d Merge pull request #5990 from german77/mousePanningV2
InputCommon: Mouse fixes
2021-03-08 14:50:58 -08:00
bunnei 69ce5e41eb Merge pull request #6041 from bunnei/fiber-leaks
common: fiber: Use weak_ptr when yielding.
2021-03-08 13:51:37 -08:00
Morph 9d77ae39de Merge pull request #6047 from lioncash/dynarmic
external: Update dynarmic
2021-03-08 00:52:19 -05:00
Lioncash de21c9e330 external: Update dynarmic 2021-03-08 00:44:54 -05:00
bunnei 8f7eb194af common: Fiber: use a reference for YieldTo.
- Fixes another small leak.
2021-03-07 13:46:53 -08:00
Ani cd7abba1a9 qt: Set DISPLAY env var when not present
Fixes web browser opening (Help > Open Mods Page, Help > Open Quickstart 
Guide)
2021-03-07 15:56:22 +00:00
german77 41e94b7b99 Enable mouse toggle buttons 2021-03-06 13:27:02 -06:00
german 4bcc5bacff Add toggle button option for normal buttons 2021-03-06 07:36:41 -06:00
bunnei 68ffac250a common: fiber: Use weak_ptr when yielding.
- Avoids a memory leak, as taking a strong reference of the fiber here causes a circular reference.
- Supersedes #6006 with a more narrow fix.
2021-03-05 22:10:03 -08:00
german 1f228c51ca Enable button toggle for keyboard in the modifier button 2021-03-05 19:21:04 -06:00
bunnei 4cf5b860bd Merge pull request #6036 from bunnei/thread-leak
hle: kernel: KThread: Rework dummy threads & fix memory leak.
2021-03-05 17:15:35 -08:00
bunnei 47af34003b hle: kernel: KThread: Rework dummy threads & fix memory leak.
- Dummy threads are created on thread local storage for all host threads.
- Fixes a leak by removing creation of fibers, which are not applicable here.
2021-03-05 17:10:57 -08:00
LC 97415ad07a Merge pull request #6029 from Morph1984/compile-utf8
CMakeLists: Add /utf-8 compile option for MSVC
2021-03-05 20:09:37 -05:00
bunnei 7b29a8ce4e Merge pull request #6039 from yuzu-emu/revert-6006-fiber-unique-ptr
Revert "core: Switch to unique_ptr for usage of Common::Fiber."
2021-03-05 17:08:48 -08:00
bunnei a5ab85ac37 Revert "core: Switch to unique_ptr for usage of Common::Fiber." 2021-03-05 17:08:17 -08:00
bunnei 9d010be483 Merge pull request #6034 from Morph1984/mbedtls
externals: Update mbedtls to 2.16.9
2021-03-05 15:48:28 -08:00
bunnei 34a3ee1631 Merge pull request #6006 from bunnei/fiber-unique-ptr
core: Switch to unique_ptr for usage of Common::Fiber.
2021-03-04 23:59:06 -08:00
Morph 96c9e67b1b aes_util: Remove malformed mbedtls_cipher_finish function call 2021-03-05 02:05:05 -05:00
Morph 6faabd6d69 externals: Update mbedtls to 2.16.9
mbedtls 2.16 is the last version which has licensing for GPL 2.0. This updates mbedtls to our own fork of mbedtls 2.16
2021-03-05 02:05:05 -05:00
Morph e7038344aa CMakeLists: Add /utf-8 compile option for MSVC
Ensures that the source and execution character sets are in UTF-8
2021-03-05 01:46:56 -05:00
ameerj 5213f70230 texture_cache: Blacklist BGRA8 copies and views on OpenGL
In order to force the BGRA8 conversion on Nvidia using OpenGL, we need to forbid texture copies and views with other formats.

This commit also adds a boolean relating to this, as this needs to be done only for the OpenGL api, Vulkan must remain unchanged.
2021-03-04 14:14:49 -05:00
ameerj 0639244d85 renderer_opengl: Swizzle BGR textures on copy
OpenGL does not natively support BGR internal formats, which causes many BGR textures to render incorrectly, with Red and Blue channels swapped.

This commit aims to address this by swizzling the blue and red channels on texture copies when a BGR format is encountered.
2021-03-04 14:14:19 -05:00
bunnei b8b5891585 Merge pull request #5989 from ReinUsesLisp/cmdpool
vk_command_pool: Reduce the command pool size from 4096 to 4
2021-03-04 11:07:31 -08:00
bunnei 394475c4e3 Merge pull request #6004 from german77/udprandom
InputCommon: Use an unique client id for each udp socket instance
2021-03-03 15:45:32 -08:00
bunnei 50ee9c46ab video_core: rasterizer_accelerated: Fix delta check ordering. 2021-03-02 17:48:02 -08:00
bunnei 6ab839462c video_core: rasterizer_accelerated: Improve error handling & fix implicit conversion. 2021-03-02 17:44:02 -08:00
bunnei f8bfec3109 Merge pull request #5815 from comex/net-error-reform
Network error handling reform
2021-03-02 17:08:47 -08:00
bunnei 94da1e8a7e video_core: rasterizer_accelerated: Use a flat array instead of interval_map for cached pages.
- Uses a fixed 64MB for the cache instead of an ever growing map.
- Slightly faster by using atomics instead of a single mutex for access.
- Thanks for Rodrigo for the idea.
2021-03-02 16:57:53 -08:00
LC 4a45012f35 Merge pull request #6020 from bunnei/shutdown-crash-2
core: Shutdown: Move kernel cleanup to later in shutdown.
2021-03-02 09:28:28 -05:00
ReinUsesLisp 5ad62e7bfc buffer_cache: Heuristically decide to skip cache on uniform buffers
Some games benefit from skipping caches (Pokémon Sword), and others
don't (Animal Crossing: New Horizons). Add an heuristic to decide this
at runtime.

The cache hit ratio has to be ~98% or better to not skip the cache.
There are 16 frames of buffer.
2021-03-02 02:44:19 -03:00
bunnei 925671071c core: Shutdown: Move kernel cleanup to later in shutdown.
- Fixes a shutdown crash due to a race condition with GPU still accessing memory.
2021-03-01 21:42:06 -08:00
bunnei cd25817938 Merge pull request #6019 from Kelebek1/bcat
[Service::nifm] Fix bcat_backend's default initialisation
2021-03-01 19:27:06 -08:00
Kelebek1 c7a7e47615 Fix default bcat_backend init 2021-03-02 03:20:16 +00:00
german 9b3af0027b inputCommon: Use an unique client id for each socket instance 2021-03-01 09:19:33 -06:00
Morph ac8b1445ff Merge pull request #6016 from ameerj/remove-async-nvdec
gpu_thread: Remove Async NVDEC placeholders
2021-03-01 04:22:46 -05:00
ameerj 52e9d7fa49 gpu_thread: Remove Async NVDEC placeholders
This commit removes early placeholders for an implementation of async nvdec. With recent changes to the source code, the placeholders are no longer accurate, and can cause a nullptr dereference due to the nature of the cdma_pusher lifetime.
2021-02-28 22:03:00 -05:00
comex 2910aa77b2 [network] Error handling reform
`network.cpp` has several error paths which either:
- report "Unhandled host socket error=n" and return `SUCCESS`, or
- switch on a few possible errors, log them, and translate them to
  Errno; the same switch statement is copied and pasted in multiple
  places in the code

Convert these paths to use a helper function `GetAndLogLastError`, which
is roughly the equivalent of one of the switch statements, but:
- handling more cases (both ones that were already in `Errno`, and a few
  more I added), and
- using OS functions to convert the error to a string when logging, so
  it'll describe the error even if it's not one of the ones in the
  switch statement.
  - To handle this, refactor the logic in `GetLastErrorMsg` to expose a
    new function `NativeErrorToString` which takes the error number
    explicitly as an argument.  And improve the Windows version a bit.

Also, add a test which exercises two random error paths.
2021-02-28 17:25:31 -05:00
bunnei 9e9341f4b4 Merge pull request #6007 from bunnei/ldn-error
core: hle: ldn: Error out on call to Initialization.
2021-02-28 13:34:20 -08:00
Morph ee9ebeeb80 Merge pull request #5276 from german77/gestures
HID: Implement gestures
2021-02-27 22:18:41 -05:00
german e895ab7d6f Implements touch, pan, pinch and rotation gestures 2021-02-27 19:54:42 -06:00
german77 4738e14cb0 inputCommon: Mouse fixes 2021-02-27 17:53:10 -06:00
bunnei 55f556c53e Merge pull request #5984 from jbeich/gcc-freebsd
common,video-core: unbreak GCC 11 build on FreeBSD 13
2021-02-27 14:15:00 -07:00
bunnei ab65cb499d core: hle: ldn: Error out on call to Initialization.
- Since we do not emulate LDN, returning an error here makes more sense.
2021-02-27 11:59:29 -08:00
bunnei 51fb0a6f96 core: Switch to unique_ptr for usage of Common::Fiber.
- With using unique_ptr instead of shared_ptr, we have more explicit ownership of the context.
- Fixes a memory leak due to circular reference of the shared pointer.
2021-02-27 11:56:04 -08:00
bunnei 09f7c355c6 Merge pull request #5953 from bunnei/memory-refactor-1
Kernel Rework: Memory updates and refactoring (Part 1)
2021-02-27 12:48:35 -07:00
bunnei bfa1644464 Merge pull request #5944 from Morph1984/gc-vibrations
hid: Implement GameCube Controller Vibrations
2021-02-26 19:10:36 -07:00
bunnei 272bc4c3d6 Merge pull request #5997 from Kelebek1/Depth
[OpenGL] Implement glDepthRangeIndexeddNV
2021-02-26 15:06:55 -07:00
bunnei 1ba578c4aa Merge pull request #5977 from Morph1984/stub-acc
acc: Stub GetNintendoAccountUserResourceCacheForApplication
2021-02-24 17:46:15 -07:00
Kelebek1 d31dbb1bc1 Implement glDepthRangeIndexeddNV 2021-02-24 22:26:53 +00:00
ReinUsesLisp aae399c1a8 vk_command_pool: Reduce the command pool size from 4096 to 4
This allows drivers to reuse memory more easily and preallocate less.
The optimal number has been measured booting Pokémon Sword.
2021-02-23 19:08:24 -03:00
Jan Beich 1841ca4b9b video_core: add missing header after 468bd9c1b0
src/video_core/shader_notify.cpp: In member function 'void VideoCore::ShaderNotify::MarkShaderComplete()':
src/video_core/shader_notify.cpp:33:10: error: 'unique_lock' is not a member of 'std'
   33 |     std::unique_lock lock{mutex};
      |          ^~~~~~~~~~~
src/video_core/shader_notify.cpp:6:1: note: 'std::unique_lock' is defined in header '<mutex>'; did you forget to '#include <mutex>'?
    5 | #include "video_core/shader_notify.h"
  +++ |+#include <mutex>
    6 |
src/video_core/shader_notify.cpp: In member function 'void VideoCore::ShaderNotify::MarkSharderBuilding()':
src/video_core/shader_notify.cpp:38:10: error: 'unique_lock' is not a member of 'std'
   38 |     std::unique_lock lock{mutex};
      |          ^~~~~~~~~~~
src/video_core/shader_notify.cpp:38:10: note: 'std::unique_lock' is defined in header '<mutex>'; did you forget to '#include <mutex>'?
2021-02-23 00:04:36 +00:00
Jan Beich 71526ecfc7 common: add missing header after f3805376f7
In file included from src/video_core/dma_pusher.cpp:5:
src/./common/cityhash.h:69:47: error: 'size_t' has not been declared
   69 | [[nodiscard]] u64 CityHash64(const char* buf, size_t len);
      |                                               ^~~~~~
src/./common/cityhash.h:73:55: error: 'size_t' has not been declared
   73 | [[nodiscard]] u64 CityHash64WithSeed(const char* buf, size_t len, u64 seed);
      |                                                       ^~~~~~
src/./common/cityhash.h:77:56: error: 'size_t' has not been declared
   77 | [[nodiscard]] u64 CityHash64WithSeeds(const char* buf, size_t len, u64 seed0, u64 seed1);
      |                                                        ^~~~~~
src/./common/cityhash.h:80:47: error: 'size_t' has not been declared
   80 | [[nodiscard]] u128 CityHash128(const char* s, size_t len);
      |                                               ^~~~~~
src/./common/cityhash.h:84:55: error: 'size_t' has not been declared
   84 | [[nodiscard]] u128 CityHash128WithSeed(const char* s, size_t len, u128 seed);
      |                                                       ^~~~~~
2021-02-23 00:04:32 +00:00
LC ae876ed047 Merge pull request #5981 from lat9nq/ci-add-clang
ci: Add clang build scripts
2021-02-22 07:12:30 -05:00
lat9nq fb0b4c7e27 ci: Add clang build scripts
Adds scripts that instruct CI to build yuzu with the installed Clang
compiler on yuzuemu/build-environments:linux-fresh.

These scripts are based on the .ci/scripts/linux scripts, minus AppImage
building since that isn't necessary. Re-uses linux-fresh since that
container has Clang 12 installed.
2021-02-22 01:40:44 -05:00
bunnei 20245e660f Merge pull request #5936 from Kelebek1/Offsets
Offsets for TexelFetch and TextureGather in Vulkan
2021-02-21 21:23:45 -07:00
Morph ec19a85890 hid: Implement GameCube Controller Vibrations
Implements both SendVibrationGcErmCommand and GetActualVibrationGcErmCommand, and modifies GetVibrationDeviceInfo to account for additional controllers.
2021-02-21 10:32:59 -05:00
Morph 3de8e7a8f2 acc: Stub GetNintendoAccountUserResourceCacheForApplication
This command returns a Nintendo Account ID and writes 2 output buffers. The first output buffer is a NasUserBaseForApplication and the second output buffer is currently empty.

Used by:
- Pokken Tournament DX
- Super Smash Bros. Ultimate
- Super Nintendo Entertainment System - Nintendo Switch Online
- Mario Kart 8 Deluxe
2021-02-21 10:29:25 -05:00
bunnei 3d0394681c Merge pull request #5971 from ameerj/reslimit-dtor
kernel: Fix resource release exception on exit
2021-02-20 21:15:00 -08:00
ameerj 8e4c9c9852 kernel: Fix resource release exception on exit
After rewriting the resource limit, objects releasing reserved resources require a live kernel instance.
This commit fixes exceptions that occur due to the kernel being destroyed before some objects released their resources, allowing for a graceful exit.
2021-02-20 20:51:11 -05:00
Ameer J 2807a98168 Merge pull request #5965 from Morph1984/shader-count
gl_disk_shader_cache: Log total shader entries count on game load
2021-02-20 20:18:00 -05:00
bunnei 93e20867b0 hle: kernel: Migrate PageHeap/PageTable to KPageHeap/KPageTable. 2021-02-18 16:16:25 -08:00
bunnei b1e27890e8 hle: kernel: Migrate MemoryManager to KMemoryManager. 2021-02-18 16:16:25 -08:00
bunnei 93109c870e hle: kernel: Migrate PageLinkedList to KPageLinkedList. 2021-02-18 16:16:25 -08:00
bunnei 65e0178cc0 hle: kernel: Migrate to KMemoryBlock, KMemoryBlockManager, and others. 2021-02-18 16:16:25 -08:00
bunnei 9e520e8f12 hle: kernel: Migrate SlabHeap to KSlabHeap. 2021-02-18 16:16:25 -08:00
bunnei 1d162f28d1 hle: kernel: Migrate MemoryLayout to KMemoryLayout. 2021-02-18 16:16:25 -08:00
bunnei 7ed5dd0d62 hle: kernel: Migrate AddressSpaceInfo to KAddressSpaceInfo. 2021-02-18 16:16:25 -08:00
bunnei 701ef616b2 hle: kernel: memory_manager: Rename AllocateContinuous to AllocateContinuous. 2021-02-18 16:16:24 -08:00
bunnei f7a008d77f hle: kernel: KSystemControl does not belong in Memory namespace. 2021-02-18 16:16:24 -08:00
bunnei 6a19086001 hle: kernel: memory: PageHeap: Migrate to KPageBitmap class. 2021-02-18 16:16:24 -08:00
bunnei a02566136c hle: kernel: Add KPageBitmap class. 2021-02-18 16:16:24 -08:00
bunnei e7c33d1ad6 hle: kernel: system_control: Add function GenerateRandomU64. 2021-02-18 16:16:24 -08:00
bunnei c9235764c7 common: Add implementation of TinyMT (Mersenne Twister RNG). 2021-02-18 16:16:24 -08:00
bunnei 6da91da08e hle: kernel: Add KSpinLock implementation. 2021-02-18 16:16:24 -08:00
bunnei 24e1e17a8a core: memory: Add templated GetPointer methods. 2021-02-18 16:16:24 -08:00
bunnei b5b92fd1e5 common: alignment: Add DivideUp utility method. 2021-02-18 16:16:24 -08:00
bunnei 0d62f30b00 hle: kernel: Rename SharedMemory to KSharedMemory. 2021-02-18 16:16:12 -08:00
Kelebek1 9d8f793969 Review 1 2021-02-15 05:26:28 +00:00
Kelebek1 fb54c38631 Implement texture offset support for TexelFetch and TextureGather and add offsets for Tlds
Formatting
2021-02-15 00:36:37 +00:00
372 changed files with 9654 additions and 4701 deletions
+18
View File
@@ -0,0 +1,18 @@
#!/bin/bash -ex
# Exit on error, rather than continuing with the rest of the script.
set -e
cd /yuzu
ccache -s
mkdir build || true && cd build
cmake .. -DDISPLAY_VERSION=$1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/clang -DCMAKE_CXX_COMPILER=/usr/lib/ccache/clang++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DCMAKE_INSTALL_PREFIX="/usr"
make -j$(nproc)
ccache -s
ctest -VV -C Release
+8
View File
@@ -0,0 +1,8 @@
#!/bin/bash -ex
mkdir -p "ccache" || true
chmod a+x ./.ci/scripts/clang/docker.sh
# the UID for the container yuzu user is 1027
sudo chown -R 1027 ./
docker run -e ENABLE_COMPATIBILITY_REPORTING -e CCACHE_DIR=/yuzu/ccache -v $(pwd):/yuzu yuzuemu/build-environments:linux-fresh /bin/bash /yuzu/.ci/scripts/clang/docker.sh $1
sudo chown -R $UID ./
+20
View File
@@ -0,0 +1,20 @@
#!/bin/bash -ex
. .ci/scripts/common/pre-upload.sh
REV_NAME="yuzu-linux-${GITDATE}-${GITREV}"
ARCHIVE_NAME="${REV_NAME}.tar.xz"
COMPRESSION_FLAGS="-cJvf"
if [ "${RELEASE_NAME}" = "mainline" ]; then
DIR_NAME="${REV_NAME}"
else
DIR_NAME="${REV_NAME}_${RELEASE_NAME}"
fi
mkdir "$DIR_NAME"
cp build/bin/yuzu-cmd "$DIR_NAME"
cp build/bin/yuzu "$DIR_NAME"
. .ci/scripts/common/post-upload.sh
+1 -1
View File
@@ -8,7 +8,7 @@ steps:
displayName: 'Install vulkan-sdk'
- script: python -m pip install --upgrade pip conan
displayName: 'Install conan'
- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 16 2019" -A x64 --config Release -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} .. && cd ..
- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 16 2019" -A x64 -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} .. && cmake --install . --config Release && cd ..
displayName: 'Configure CMake'
- task: MSBuild@1
displayName: 'Build'
+4 -1
View File
@@ -12,6 +12,9 @@ jobs:
windows:
BuildSuffix: 'windows-mingw'
ScriptFolder: 'windows'
clang:
BuildSuffix: 'clang'
ScriptFolder: 'clang'
linux:
BuildSuffix: 'linux'
ScriptFolder: 'linux'
@@ -24,4 +27,4 @@ jobs:
parameters:
artifactSource: 'false'
cache: $(parameters.cache)
version: $(parameters.version)
version: $(parameters.version)
+1 -1
View File
@@ -27,7 +27,7 @@
url = https://github.com/ReinUsesLisp/sirit
[submodule "mbedtls"]
path = externals/mbedtls
url = https://github.com/DarkLordZach/mbedtls
url = https://github.com/yuzu-emu/mbedtls
[submodule "libzip"]
path = externals/libzip/libzip
url = https://github.com/nih-at/libzip.git
+38 -40
View File
@@ -11,6 +11,7 @@ project(yuzu)
# Set bundled sdl2/qt as dependent options.
# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON
option(ENABLE_SDL2 "Enable the SDL2 frontend" ON)
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON "ENABLE_SDL2;MSVC" OFF)
option(ENABLE_QT "Enable the Qt frontend" ON)
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
@@ -166,12 +167,12 @@ macro(yuzu_find_packages)
# Cmake Pkg Prefix Version Conan Pkg
"Catch2 2.13 catch2/2.13.0"
"fmt 7.1 fmt/7.1.2"
# can't use until https://github.com/bincrafters/community/issues/1173
#"libzip 1.5 libzip/1.5.2@bincrafters/stable"
"lz4 1.8 lz4/1.9.2"
"nlohmann_json 3.8 nlohmann_json/3.8.0"
"ZLIB 1.2 zlib/1.2.11"
"zstd 1.4 zstd/1.4.8"
# can't use opus until AVX check is fixed: https://github.com/yuzu-emu/yuzu/pull/4068
#"opus 1.3 opus/1.3.1"
)
foreach(PACKAGE ${REQUIRED_LIBS})
@@ -249,22 +250,44 @@ if(ENABLE_QT)
if (ENABLE_QT_TRANSLATION)
find_package(Qt5 REQUIRED COMPONENTS LinguistTools ${QT_PREFIX_HINT})
endif()
if (NOT Qt5_FOUND)
list(APPEND CONAN_REQUIRED_LIBS "qt/5.14.1@bincrafters/stable")
endif()
endif()
# find SDL2 exports a bunch of variables that are needed, so its easier to do this outside of the yuzu_find_package
if(ENABLE_SDL2)
if(EXISTS ${CMAKE_BINARY_DIR}/sdl2Config.cmake)
include(${CMAKE_BINARY_DIR}/sdl2Config.cmake)
list(APPEND CMAKE_MODULE_PATH "${CONAN_SDL2_ROOT_RELEASE}")
list(APPEND CMAKE_PREFIX_PATH "${CONAN_SDL2_ROOT_RELEASE}")
endif()
find_package(SDL2)
if (NOT SDL2_FOUND)
# otherwise add this to the list of libraries to install
list(APPEND CONAN_REQUIRED_LIBS "sdl2/2.0.14@bincrafters/stable")
if (ENABLE_SDL2)
if (YUZU_USE_BUNDLED_SDL2)
# Detect toolchain and platform
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1930) AND ARCHITECTURE_x86_64)
set(SDL2_VER "SDL2-2.0.14")
else()
message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.")
endif()
if (DEFINED SDL2_VER)
download_bundled_external("sdl2/" ${SDL2_VER} SDL2_PREFIX)
endif()
set(SDL2_FOUND YES)
set(SDL2_INCLUDE_DIR "${SDL2_PREFIX}/include" CACHE PATH "Path to SDL2 headers")
set(SDL2_LIBRARY "${SDL2_PREFIX}/lib/x64/SDL2.lib" CACHE PATH "Path to SDL2 library")
set(SDL2_DLL_DIR "${SDL2_PREFIX}/lib/x64/" CACHE PATH "Path to SDL2.dll")
add_library(SDL2 INTERFACE)
target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARY}")
target_include_directories(SDL2 INTERFACE "${SDL2_INCLUDE_DIR}")
else()
find_package(SDL2 REQUIRED)
# Some installations don't set SDL2_LIBRARIES
if("${SDL2_LIBRARIES}" STREQUAL "")
message(WARNING "SDL2_LIBRARIES wasn't set, manually setting to SDL2::SDL2")
set(SDL2_LIBRARIES "SDL2::SDL2")
endif()
include_directories(SYSTEM ${SDL2_INCLUDE_DIRS})
add_library(SDL2 INTERFACE)
target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARIES}")
endif()
else()
set(SDL2_FOUND NO)
endif()
# Install any missing dependencies with conan install
@@ -285,9 +308,6 @@ if (CONAN_REQUIRED_LIBS)
)
conan_check(VERSION 1.24.0 REQUIRED)
# Add the bincrafters remote
conan_add_remote(NAME bincrafters
URL https://api.bintray.com/conan/bincrafters/public-conan)
# Manually add iconv to fix a dep conflict between qt and sdl2
# We don't need to add it through find_package or anything since the other two can find it just fine
@@ -338,11 +358,6 @@ if (CONAN_REQUIRED_LIBS)
find_package(Qt5 REQUIRED COMPONENTS WebEngineCore WebEngineWidgets)
endif()
endif()
if(ENABLE_SDL2)
list(APPEND CMAKE_MODULE_PATH "${CONAN_SDL2_ROOT_RELEASE}")
list(APPEND CMAKE_PREFIX_PATH "${CONAN_SDL2_ROOT_RELEASE}")
find_package(SDL2 REQUIRED)
endif()
endif()
@@ -358,23 +373,6 @@ elseif (TARGET Boost::boost)
add_library(boost ALIAS Boost::boost)
endif()
if (TARGET sdl2::sdl2)
# imported from the conan generated sdl2Config.cmake
set_target_properties(sdl2::sdl2 PROPERTIES IMPORTED_GLOBAL TRUE)
add_library(SDL2 ALIAS sdl2::sdl2)
elseif(SDL2_FOUND)
# found through the system package manager
# Some installations don't set SDL2_LIBRARIES
if("${SDL2_LIBRARIES}" STREQUAL "")
message(WARNING "SDL2_LIBRARIES wasn't set, manually setting to SDL2::SDL2")
set(SDL2_LIBRARIES "SDL2::SDL2")
endif()
include_directories(SYSTEM ${SDL2_INCLUDE_DIRS})
add_library(SDL2 INTERFACE)
target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARIES}")
endif()
# Ensure libusb is properly configured (based on dolphin libusb include)
if(NOT APPLE)
include(FindPkgConfig)
+7 -3
View File
@@ -64,8 +64,8 @@ endif()
add_subdirectory(sirit)
# libzip
find_package(Libzip 1.5)
if (NOT LIBZIP_FOUND)
find_package(libzip 1.5)
if (NOT libzip_FOUND)
message(STATUS "libzip 1.5 or newer not found, falling back to externals")
add_subdirectory(libzip EXCLUDE_FROM_ALL)
endif()
@@ -97,4 +97,8 @@ if (ENABLE_WEB_SERVICE)
endif()
# Opus
add_subdirectory(opus)
find_package(opus 1.3)
if (NOT opus_FOUND)
message(STATUS "opus 1.3 or newer not found, falling back to externals")
add_subdirectory(opus EXCLUDE_FROM_ALL)
endif()
-72
View File
@@ -1,72 +0,0 @@
find_package(PkgConfig QUIET)
pkg_check_modules(PC_LIBZIP QUIET libzip)
find_path(LIBZIP_INCLUDE_DIR
NAMES zip.h
PATHS ${PC_LIBZIP_INCLUDE_DIRS}
"$ENV{LIB_DIR}/include"
"$ENV{INCLUDE}"
/usr/local/include
/usr/include
)
find_path(LIBZIP_INCLUDE_DIR_ZIPCONF
NAMES zipconf.h
HINTS ${PC_LIBZIP_INCLUDE_DIRS}
"$ENV{LIB_DIR}/include"
"$ENV{LIB_DIR}/lib/libzip/include"
"$ENV{LIB}/lib/libzip/include"
/usr/local/lib/libzip/include
/usr/lib/libzip/include
/usr/local/include
/usr/include
"$ENV{INCLUDE}"
)
find_library(LIBZIP_LIBRARY
NAMES zip
PATHS ${PC_LIBZIP_LIBRARY_DIRS}
"$ENV{LIB_DIR}/lib" "$ENV{LIB}" /usr/local/lib /usr/lib
)
if (LIBZIP_INCLUDE_DIR_ZIPCONF)
FILE(READ "${LIBZIP_INCLUDE_DIR_ZIPCONF}/zipconf.h" _LIBZIP_VERSION_CONTENTS)
if (_LIBZIP_VERSION_CONTENTS)
STRING(REGEX REPLACE ".*#define LIBZIP_VERSION \"([0-9.]+)\".*" "\\1" LIBZIP_VERSION "${_LIBZIP_VERSION_CONTENTS}")
endif()
unset(_LIBZIP_VERSION_CONTENTS)
endif()
set(LIBZIP_VERSION ${LIBZIP_VERSION} CACHE STRING "Version number of libzip")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Libzip
FOUND_VAR LIBZIP_FOUND
REQUIRED_VARS
LIBZIP_LIBRARY
LIBZIP_INCLUDE_DIR
LIBZIP_INCLUDE_DIR_ZIPCONF
LIBZIP_VERSION
VERSION_VAR LIBZIP_VERSION
)
if(LIBZIP_FOUND)
set(LIBZIP_LIBRARIES ${LIBZIP_LIBRARY})
set(LIBZIP_INCLUDE_DIRS ${LIBZIP_INCLUDE_DIR})
set(LIBZIP_DEFINITIONS ${PC_LIBZIP_CFLAGS_OTHER})
endif()
if(LIBZIP_FOUND AND NOT TARGET libzip::libzip)
add_library(libzip::libzip UNKNOWN IMPORTED)
set_target_properties(libzip::libzip PROPERTIES
IMPORTED_LOCATION "${LIBZIP_LIBRARY}"
INTERFACE_COMPILE_OPTIONS "${PC_LIBZIP_CFLAGS_OTHER}"
INTERFACE_INCLUDE_DIRECTORIES "${LIBZIP_INCLUDE_DIR}"
)
endif()
mark_as_advanced(
LIBZIP_INCLUDE_DIR
LIBZIP_INCLUDE_DIR_ZIPCONF
LIBZIP_LIBRARY
LIBZIP_VERSION
)
+72
View File
@@ -0,0 +1,72 @@
find_package(PkgConfig QUIET)
pkg_check_modules(PC_libzip QUIET libzip)
find_path(libzip_INCLUDE_DIR
NAMES zip.h
PATHS ${PC_libzip_INCLUDE_DIRS}
"$ENV{LIB_DIR}/include"
"$ENV{INCLUDE}"
/usr/local/include
/usr/include
)
find_path(libzip_INCLUDE_DIR_ZIPCONF
NAMES zipconf.h
HINTS ${PC_libzip_INCLUDE_DIRS}
"$ENV{LIB_DIR}/include"
"$ENV{LIB_DIR}/lib/libzip/include"
"$ENV{LIB}/lib/libzip/include"
/usr/local/lib/libzip/include
/usr/lib/libzip/include
/usr/local/include
/usr/include
"$ENV{INCLUDE}"
)
find_library(libzip_LIBRARY
NAMES zip
PATHS ${PC_libzip_LIBRARY_DIRS}
"$ENV{LIB_DIR}/lib" "$ENV{LIB}" /usr/local/lib /usr/lib
)
if (libzip_INCLUDE_DIR_ZIPCONF)
FILE(READ "${libzip_INCLUDE_DIR_ZIPCONF}/zipconf.h" _libzip_VERSION_CONTENTS)
if (_libzip_VERSION_CONTENTS)
STRING(REGEX REPLACE ".*#define LIBZIP_VERSION \"([0-9.]+)\".*" "\\1" libzip_VERSION "${_libzip_VERSION_CONTENTS}")
endif()
unset(_libzip_VERSION_CONTENTS)
endif()
set(libzip_VERSION ${libzip_VERSION} CACHE STRING "Version number of libzip")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(libzip
FOUND_VAR libzip_FOUND
REQUIRED_VARS
libzip_LIBRARY
libzip_INCLUDE_DIR
libzip_INCLUDE_DIR_ZIPCONF
libzip_VERSION
VERSION_VAR libzip_VERSION
)
if(libzip_FOUND)
set(libzip_LIBRARIES ${libzip_LIBRARY})
set(libzip_INCLUDE_DIRS ${libzip_INCLUDE_DIR})
set(libzip_DEFINITIONS ${PC_libzip_CFLAGS_OTHER})
endif()
if(libzip_FOUND AND NOT TARGET libzip::libzip)
add_library(libzip::libzip UNKNOWN IMPORTED)
set_target_properties(libzip::libzip PROPERTIES
IMPORTED_LOCATION "${libzip_LIBRARY}"
INTERFACE_COMPILE_OPTIONS "${PC_libzip_CFLAGS_OTHER}"
INTERFACE_INCLUDE_DIRECTORIES "${libzip_INCLUDE_DIR}"
)
endif()
mark_as_advanced(
libzip_INCLUDE_DIR
libzip_INCLUDE_DIR_ZIPCONF
libzip_LIBRARY
libzip_VERSION
)
+1 -1
View File
@@ -28,7 +28,7 @@ if(opus_FOUND)
endif()
if(opus_FOUND AND NOT TARGET Opus::Opus)
add_library(Opus::Opus UNKNOWN IMPORTED)
add_library(Opus::Opus UNKNOWN IMPORTED GLOBAL)
set_target_properties(Opus::Opus PROPERTIES
IMPORTED_LOCATION "${opus_LIBRARY}"
INTERFACE_COMPILE_OPTIONS "${PC_opus_CFLAGS_OTHER}"
+3
View File
@@ -5156,6 +5156,9 @@ GLAPI PFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv;
typedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDPROC)(GLuint index, GLdouble n, GLdouble f);
GLAPI PFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed;
#define glDepthRangeIndexed glad_glDepthRangeIndexed
typedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDDNVPROC)(GLuint index, GLdouble n, GLdouble f);
GLAPI PFNGLDEPTHRANGEINDEXEDDNVPROC glad_glDepthRangeIndexeddNV;
#define glDepthRangeIndexeddNV glad_glDepthRangeIndexeddNV
typedef void (APIENTRYP PFNGLGETFLOATI_VPROC)(GLenum target, GLuint index, GLfloat *data);
GLAPI PFNGLGETFLOATI_VPROC glad_glGetFloati_v;
#define glGetFloati_v glad_glGetFloati_v
+2
View File
@@ -1044,6 +1044,7 @@ PFNGLDEPTHMASKPROC glad_glDepthMask = NULL;
PFNGLDEPTHRANGEPROC glad_glDepthRange = NULL;
PFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv = NULL;
PFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed = NULL;
PFNGLDEPTHRANGEINDEXEDDNVPROC glad_glDepthRangeIndexeddNV = NULL;
PFNGLDEPTHRANGEFPROC glad_glDepthRangef = NULL;
PFNGLDETACHSHADERPROC glad_glDetachShader = NULL;
PFNGLDISABLEPROC glad_glDisable = NULL;
@@ -7971,6 +7972,7 @@ static void load_GL_NV_depth_buffer_float(GLADloadproc load) {
glad_glDepthRangedNV = (PFNGLDEPTHRANGEDNVPROC)load("glDepthRangedNV");
glad_glClearDepthdNV = (PFNGLCLEARDEPTHDNVPROC)load("glClearDepthdNV");
glad_glDepthBoundsdNV = (PFNGLDEPTHBOUNDSDNVPROC)load("glDepthBoundsdNV");
glad_glDepthRangeIndexeddNV = (PFNGLDEPTHRANGEINDEXEDDNVPROC)load("glDepthRangeIndexeddNV");
}
static void load_GL_NV_draw_texture(GLADloadproc load) {
if(!GLAD_GL_NV_draw_texture) return;
+5
View File
@@ -1,3 +1,8 @@
# Ensure libusb compiles with UTF-8 encoding on MSVC
if(MSVC)
add_compile_options(/utf-8)
endif()
add_library(usb STATIC EXCLUDE_FROM_ALL
libusb/libusb/core.c
libusb/libusb/core.c
+2
View File
@@ -252,3 +252,5 @@ PRIVATE
opus/silk/float
opus/src
)
add_library(Opus::Opus ALIAS opus)
+2
View File
@@ -27,6 +27,7 @@ if (MSVC)
# /Zo - Enhanced debug info for optimized builds
# /permissive- - Enables stricter C++ standards conformance checks
# /EHsc - C++-only exception handling semantics
# /utf-8 - Set source and execution character sets to UTF-8
# /volatile:iso - Use strict standards-compliant volatile semantics.
# /Zc:externConstexpr - Allow extern constexpr variables to have external linkage, like the standard mandates
# /Zc:inline - Let codegen omit inline functions in object files
@@ -38,6 +39,7 @@ if (MSVC)
/permissive-
/EHsc
/std:c++latest
/utf-8
/volatile:iso
/Zc:externConstexpr
/Zc:inline
+1 -1
View File
@@ -7,7 +7,7 @@
#include "audio_core/sink_details.h"
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/settings.h"
#include "common/settings.h"
namespace AudioCore {
+1 -1
View File
@@ -11,8 +11,8 @@
#include "audio_core/info_updater.h"
#include "audio_core/voice_context.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "core/memory.h"
#include "core/settings.h"
namespace {
[[nodiscard]] static constexpr s16 ClampToS16(s32 value) {
+1 -1
View File
@@ -11,7 +11,7 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/ring_buffer.h"
#include "core/settings.h"
#include "common/settings.h"
#ifdef _WIN32
#include <objbase.h>
+1 -1
View File
@@ -11,8 +11,8 @@
#include "audio_core/stream.h"
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "core/core_timing.h"
#include "core/settings.h"
namespace AudioCore {
+7
View File
@@ -97,6 +97,7 @@ add_custom_command(OUTPUT scm_rev.cpp
add_library(common STATIC
algorithm.h
alignment.h
assert.cpp
assert.h
atomic_ops.h
detached_tasks.cpp
@@ -109,6 +110,7 @@ add_library(common STATIC
cityhash.h
common_funcs.h
common_paths.h
common_sizes.h
common_types.h
concepts.h
div_ceil.h
@@ -150,6 +152,10 @@ add_library(common STATIC
scm_rev.cpp
scm_rev.h
scope_exit.h
settings.cpp
settings.h
settings_input.cpp
settings_input.h
spin_lock.cpp
spin_lock.h
stream.cpp
@@ -167,6 +173,7 @@ add_library(common STATIC
threadsafe_queue.h
time_zone.cpp
time_zone.h
tiny_mt.h
tree.h
uint128.h
uuid.cpp
+5
View File
@@ -42,6 +42,11 @@ requires std::is_integral_v<T>[[nodiscard]] constexpr bool IsAligned(T value, si
return (value & mask) == 0;
}
template <typename T, typename U>
requires std::is_integral_v<T>[[nodiscard]] constexpr T DivideUp(T x, U y) {
return (x + (y - 1)) / y;
}
template <typename T, size_t Align = 16>
class AlignmentAllocator {
public:
+14
View File
@@ -0,0 +1,14 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/assert.h"
#include "common/common_funcs.h"
#include "common/settings.h"
void assert_handle_failure() {
if (Settings::values.use_debug_asserts) {
Crash();
}
}
+8 -6
View File
@@ -4,10 +4,13 @@
#pragma once
#include <cstdlib>
#include "common/common_funcs.h"
#include "common/logging/log.h"
// Sometimes we want to try to continue even after hitting an assert.
// However touching this file yields a global recompilation as this header is included almost
// everywhere. So let's just move the handling of the failed assert to a single cpp file.
void assert_handle_failure();
// For asserts we'd like to keep all the junk executed when an assert happens away from the
// important code in the function. One way of doing this is to put all the relevant code inside a
// lambda and force the compiler to not inline it. Unfortunately, MSVC seems to have no syntax to
@@ -17,15 +20,14 @@
// enough for our purposes.
template <typename Fn>
#if defined(_MSC_VER)
[[msvc::noinline, noreturn]]
[[msvc::noinline]]
#elif defined(__GNUC__)
[[gnu::cold, gnu::noinline, noreturn]]
[[gnu::cold, gnu::noinline]]
#endif
static void
assert_noinline_call(const Fn& fn) {
fn();
Crash();
exit(1); // Keeps GCC's mouth shut about this actually returning
assert_handle_failure();
}
#define ASSERT(_a_) \
+1
View File
@@ -61,6 +61,7 @@
#pragma once
#include <cstddef>
#include "common/common_types.h"
namespace Common {
+5 -1
View File
@@ -52,9 +52,13 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
// Generic function to get last error message.
// Call directly after the command or use the error num.
// This function might change the error code.
// Defined in Misc.cpp.
// Defined in misc.cpp.
[[nodiscard]] std::string GetLastErrorMsg();
// Like GetLastErrorMsg(), but passing an explicit error code.
// Defined in misc.cpp.
[[nodiscard]] std::string NativeErrorToString(int e);
#define DECLARE_ENUM_FLAG_OPERATORS(type) \
[[nodiscard]] constexpr type operator|(type a, type b) noexcept { \
using T = std::underlying_type_t<type>; \
+43
View File
@@ -0,0 +1,43 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <limits>
#include "common/common_types.h"
namespace Common {
enum : u64 {
Size_1_KB = 0x400ULL,
Size_64_KB = 64ULL * Size_1_KB,
Size_128_KB = 128ULL * Size_1_KB,
Size_1_MB = 0x100000ULL,
Size_2_MB = 2ULL * Size_1_MB,
Size_4_MB = 4ULL * Size_1_MB,
Size_5_MB = 5ULL * Size_1_MB,
Size_14_MB = 14ULL * Size_1_MB,
Size_32_MB = 32ULL * Size_1_MB,
Size_33_MB = 33ULL * Size_1_MB,
Size_128_MB = 128ULL * Size_1_MB,
Size_448_MB = 448ULL * Size_1_MB,
Size_507_MB = 507ULL * Size_1_MB,
Size_562_MB = 562ULL * Size_1_MB,
Size_1554_MB = 1554ULL * Size_1_MB,
Size_2048_MB = 2048ULL * Size_1_MB,
Size_2193_MB = 2193ULL * Size_1_MB,
Size_3285_MB = 3285ULL * Size_1_MB,
Size_4916_MB = 4916ULL * Size_1_MB,
Size_1_GB = 0x40000000ULL,
Size_2_GB = 2ULL * Size_1_GB,
Size_4_GB = 4ULL * Size_1_GB,
Size_6_GB = 6ULL * Size_1_GB,
Size_8_GB = 8ULL * Size_1_GB,
Size_64_GB = 64ULL * Size_1_GB,
Size_512_GB = 512ULL * Size_1_GB,
Size_Invalid = std::numeric_limits<u64>::max(),
};
} // namespace Common
+14 -11
View File
@@ -11,7 +11,7 @@
namespace Common {
constexpr std::size_t default_stack_size = 256 * 1024;
constexpr std::size_t default_stack_size = 512 * 1024;
struct Fiber::FiberImpl {
FiberImpl() : stack{default_stack_size}, rewind_stack{default_stack_size} {}
@@ -116,16 +116,19 @@ void Fiber::Rewind() {
boost::context::detail::jump_fcontext(impl->rewind_context, this);
}
void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) {
ASSERT_MSG(from != nullptr, "Yielding fiber is null!");
ASSERT_MSG(to != nullptr, "Next fiber is null!");
to->impl->guard.lock();
to->impl->previous_fiber = from;
auto transfer = boost::context::detail::jump_fcontext(to->impl->context, to.get());
ASSERT(from->impl->previous_fiber != nullptr);
from->impl->previous_fiber->impl->context = transfer.fctx;
from->impl->previous_fiber->impl->guard.unlock();
from->impl->previous_fiber.reset();
void Fiber::YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to) {
to.impl->guard.lock();
to.impl->previous_fiber = weak_from.lock();
auto transfer = boost::context::detail::jump_fcontext(to.impl->context, &to);
// "from" might no longer be valid if the thread was killed
if (auto from = weak_from.lock()) {
ASSERT(from->impl->previous_fiber != nullptr);
from->impl->previous_fiber->impl->context = transfer.fctx;
from->impl->previous_fiber->impl->guard.unlock();
from->impl->previous_fiber.reset();
}
}
std::shared_ptr<Fiber> Fiber::ThreadToFiber() {
+1 -1
View File
@@ -41,7 +41,7 @@ public:
/// Yields control from Fiber 'from' to Fiber 'to'
/// Fiber 'from' must be the currently running fiber.
static void YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to);
static void YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to);
[[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber();
void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param);
+16 -12
View File
@@ -21,11 +21,11 @@
#include "common/logging/backend.h"
#include "common/logging/log.h"
#include "common/logging/text_formatter.h"
#include "common/settings.h"
#include "common/string_util.h"
#include "common/threadsafe_queue.h"
#include "core/settings.h"
namespace Log {
namespace Common::Log {
/**
* Static state as a singleton.
@@ -37,8 +37,11 @@ public:
return backend;
}
Impl(Impl const&) = delete;
const Impl& operator=(Impl const&) = delete;
Impl(const Impl&) = delete;
Impl& operator=(const Impl&) = delete;
Impl(Impl&&) = delete;
Impl& operator=(Impl&&) = delete;
void PushEntry(Class log_class, Level log_level, const char* filename, unsigned int line_num,
const char* function, std::string message) {
@@ -132,7 +135,7 @@ private:
std::mutex writing_mutex;
std::thread backend_thread;
std::vector<std::unique_ptr<Backend>> backends;
Common::MPSCQueue<Log::Entry> message_queue;
MPSCQueue<Entry> message_queue;
Filter filter;
std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()};
};
@@ -146,16 +149,16 @@ void ColorConsoleBackend::Write(const Entry& entry) {
}
FileBackend::FileBackend(const std::string& filename) : bytes_written(0) {
if (Common::FS::Exists(filename + ".old.txt")) {
Common::FS::Delete(filename + ".old.txt");
if (FS::Exists(filename + ".old.txt")) {
FS::Delete(filename + ".old.txt");
}
if (Common::FS::Exists(filename)) {
Common::FS::Rename(filename, filename + ".old.txt");
if (FS::Exists(filename)) {
FS::Rename(filename, filename + ".old.txt");
}
// _SH_DENYWR allows read only access to the file for other programs.
// It is #defined to 0 on other platforms
file = Common::FS::IOFile(filename, "w", _SH_DENYWR);
file = FS::IOFile(filename, "w", _SH_DENYWR);
}
void FileBackend::Write(const Entry& entry) {
@@ -182,7 +185,7 @@ void FileBackend::Write(const Entry& entry) {
void DebuggerBackend::Write(const Entry& entry) {
#ifdef _WIN32
::OutputDebugStringW(Common::UTF8ToUTF16W(FormatLogMessage(entry).append(1, '\n')).c_str());
::OutputDebugStringW(UTF8ToUTF16W(FormatLogMessage(entry).append(1, '\n')).c_str());
#endif
}
@@ -212,6 +215,7 @@ void DebuggerBackend::Write(const Entry& entry) {
SUB(Service, ARP) \
SUB(Service, BCAT) \
SUB(Service, BPC) \
SUB(Service, BGTC) \
SUB(Service, BTDRV) \
SUB(Service, BTM) \
SUB(Service, Capture) \
@@ -341,4 +345,4 @@ void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
instance.PushEntry(log_class, log_level, filename, line_num, function,
fmt::vformat(format, args));
}
} // namespace Log
} // namespace Common::Log
+2 -2
View File
@@ -11,7 +11,7 @@
#include "common/logging/filter.h"
#include "common/logging/log.h"
namespace Log {
namespace Common::Log {
class Filter;
@@ -135,4 +135,4 @@ const char* GetLevelName(Level log_level);
* never get the message
*/
void SetGlobalFilter(const Filter& filter);
} // namespace Log
} // namespace Common::Log
+2 -2
View File
@@ -7,7 +7,7 @@
#include "common/logging/filter.h"
#include "common/string_util.h"
namespace Log {
namespace Common::Log {
namespace {
template <typename It>
Level GetLevelByName(const It begin, const It end) {
@@ -103,4 +103,4 @@ bool Filter::IsDebug() const {
});
}
} // namespace Log
} // namespace Common::Log
+2 -2
View File
@@ -9,7 +9,7 @@
#include <string_view>
#include "common/logging/log.h"
namespace Log {
namespace Common::Log {
/**
* Implements a log message filter which allows different log classes to have different minimum
@@ -51,4 +51,4 @@ public:
private:
std::array<Level, static_cast<std::size_t>(Class::Count)> class_levels;
};
} // namespace Log
} // namespace Common::Log
+21 -14
View File
@@ -7,7 +7,7 @@
#include <fmt/format.h>
#include "common/common_types.h"
namespace Log {
namespace Common::Log {
// trims up to and including the last of ../, ..\, src/, src\ in a string
constexpr const char* TrimSourcePath(std::string_view source) {
@@ -66,6 +66,7 @@ enum class Class : ClassType {
Service_ARP, ///< The ARP service
Service_Audio, ///< The Audio (Audio control) service
Service_BCAT, ///< The BCAT service
Service_BGTC, ///< The BGTC (Background Task Controller) service
Service_BPC, ///< The BPC service
Service_BTDRV, ///< The Bluetooth driver service
Service_BTM, ///< The BTM service
@@ -147,28 +148,34 @@ void FmtLogMessage(Class log_class, Level log_level, const char* filename, unsig
fmt::make_format_args(args...));
}
} // namespace Log
} // namespace Common::Log
#ifdef _DEBUG
#define LOG_TRACE(log_class, ...) \
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Trace, \
::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__)
Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Trace, \
Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \
__VA_ARGS__)
#else
#define LOG_TRACE(log_class, fmt, ...) (void(0))
#endif
#define LOG_DEBUG(log_class, ...) \
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Debug, \
::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__)
Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Debug, \
Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \
__VA_ARGS__)
#define LOG_INFO(log_class, ...) \
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Info, \
::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__)
Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Info, \
Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \
__VA_ARGS__)
#define LOG_WARNING(log_class, ...) \
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Warning, \
::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__)
Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Warning, \
Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \
__VA_ARGS__)
#define LOG_ERROR(log_class, ...) \
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Error, \
::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__)
Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Error, \
Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \
__VA_ARGS__)
#define LOG_CRITICAL(log_class, ...) \
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Critical, \
::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__)
Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Critical, \
Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \
__VA_ARGS__)
+2 -2
View File
@@ -16,7 +16,7 @@
#include "common/logging/text_formatter.h"
#include "common/string_util.h"
namespace Log {
namespace Common::Log {
std::string FormatLogMessage(const Entry& entry) {
unsigned int time_seconds = static_cast<unsigned int>(entry.timestamp.count() / 1000000);
@@ -108,4 +108,4 @@ void PrintColoredMessage(const Entry& entry) {
#undef ESC
#endif
}
} // namespace Log
} // namespace Common::Log
+2 -2
View File
@@ -7,7 +7,7 @@
#include <cstddef>
#include <string>
namespace Log {
namespace Common::Log {
struct Entry;
@@ -17,4 +17,4 @@ std::string FormatLogMessage(const Entry& entry);
void PrintMessage(const Entry& entry);
/// Prints the same message as `PrintMessage`, but colored according to the severity level.
void PrintColoredMessage(const Entry& entry);
} // namespace Log
} // namespace Common::Log
+29 -15
View File
@@ -12,27 +12,41 @@
#include "common/common_funcs.h"
// Generic function to get last error message.
// Call directly after the command or use the error num.
// This function might change the error code.
std::string GetLastErrorMsg() {
static constexpr std::size_t buff_size = 255;
char err_str[buff_size];
std::string NativeErrorToString(int e) {
#ifdef _WIN32
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_str, buff_size, nullptr);
return std::string(err_str, buff_size);
#elif defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600))
LPSTR err_str;
DWORD res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPSTR>(&err_str), 1, nullptr);
if (!res) {
return "(FormatMessageA failed to format error)";
}
std::string ret(err_str);
LocalFree(err_str);
return ret;
#else
char err_str[255];
#if defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600))
// Thread safe (GNU-specific)
const char* str = strerror_r(errno, err_str, buff_size);
const char* str = strerror_r(e, err_str, sizeof(err_str));
return std::string(str);
#else
// Thread safe (XSI-compliant)
const int success = strerror_r(errno, err_str, buff_size);
if (success != 0) {
return {};
int second_err = strerror_r(e, err_str, sizeof(err_str));
if (second_err != 0) {
return "(strerror_r failed to format error)";
}
return std::string(err_str);
#endif // GLIBC etc.
#endif // _WIN32
}
std::string GetLastErrorMsg() {
#ifdef _WIN32
return NativeErrorToString(GetLastError());
#else
return NativeErrorToString(errno);
#endif
}
+2
View File
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
namespace Common {
/// Configure platform specific flags for Nvidia's driver
@@ -1,4 +1,4 @@
// Copyright 2014 Citra Emulator Project
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -7,10 +7,7 @@
#include "common/assert.h"
#include "common/file_util.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/service/hid/hid.h"
#include "core/settings.h"
#include "video_core/renderer_base.h"
#include "common/settings.h"
namespace Settings {
@@ -32,14 +29,6 @@ std::string GetTimeZoneString() {
return timezones[time_zone_index];
}
void Apply(Core::System& system) {
if (system.IsPoweredOn()) {
system.Renderer().RefreshBaseSettings();
}
Service::HID::ReloadInputDevices();
}
void LogSettings() {
const auto log_setting = [](std::string_view name, const auto& value) {
LOG_INFO(Config, "{}: {}", name, value);
@@ -1,4 +1,4 @@
// Copyright 2014 Citra Emulator Project
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -11,16 +11,13 @@
#include <optional>
#include <string>
#include <vector>
#include "common/common_types.h"
#include "input_common/settings.h"
namespace Core {
class System;
}
#include "common/common_types.h"
#include "common/settings_input.h"
namespace Settings {
enum class RendererBackend {
enum class RendererBackend : u32 {
OpenGL = 0,
Vulkan = 1,
};
@@ -31,7 +28,7 @@ enum class GPUAccuracy : u32 {
Extreme = 2,
};
enum class CPUAccuracy {
enum class CPUAccuracy : u32 {
Accurate = 0,
Unsafe = 1,
DebugMode = 2,
@@ -139,6 +136,7 @@ struct Values {
Setting<int> vulkan_device;
Setting<u16> resolution_factor{1};
Setting<int> fullscreen_mode;
Setting<int> aspect_ratio;
Setting<int> max_anisotropy;
Setting<bool> use_frame_limit;
@@ -222,6 +220,8 @@ struct Values {
bool quest_flag;
bool disable_macro_jit;
bool extended_logging;
bool use_debug_asserts;
bool use_auto_stub;
// Miscellaneous
std::string log_filter;
@@ -253,7 +253,6 @@ float Volume();
std::string GetTimeZoneString();
void Apply(Core::System& system);
void LogSettings();
// Restore the global state of all applicable settings in the Values struct
@@ -2,7 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "input_common/settings.h"
#include "common/settings_input.h"
namespace Settings {
namespace NativeButton {
@@ -6,6 +6,7 @@
#include <array>
#include <string>
#include "common/common_types.h"
namespace Settings {
+9 -1
View File
@@ -83,11 +83,15 @@ public:
return true;
}
T PopWait() {
void Wait() {
if (Empty()) {
std::unique_lock lock{cv_mutex};
cv.wait(lock, [this]() { return !Empty(); });
}
}
T PopWait() {
Wait();
T t;
Pop(t);
return t;
@@ -156,6 +160,10 @@ public:
return spsc_queue.Pop(t);
}
void Wait() {
spsc_queue.Wait();
}
T PopWait() {
return spsc_queue.PopWait();
}
+250
View File
@@ -0,0 +1,250 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include "common/alignment.h"
#include "common/common_types.h"
namespace Common {
// Implementation of TinyMT (mersenne twister RNG).
// Like Nintendo, we will use the sample parameters.
class TinyMT {
public:
static constexpr std::size_t NumStateWords = 4;
struct State {
std::array<u32, NumStateWords> data{};
};
private:
static constexpr u32 ParamMat1 = 0x8F7011EE;
static constexpr u32 ParamMat2 = 0xFC78FF1F;
static constexpr u32 ParamTmat = 0x3793FDFF;
static constexpr u32 ParamMult = 0x6C078965;
static constexpr u32 ParamPlus = 0x0019660D;
static constexpr u32 ParamXor = 0x5D588B65;
static constexpr u32 TopBitmask = 0x7FFFFFFF;
static constexpr int MinimumInitIterations = 8;
static constexpr int NumDiscardedInitOutputs = 8;
static constexpr u32 XorByShifted27(u32 value) {
return value ^ (value >> 27);
}
static constexpr u32 XorByShifted30(u32 value) {
return value ^ (value >> 30);
}
private:
State state{};
private:
// Internal API.
void FinalizeInitialization() {
const u32 state0 = this->state.data[0] & TopBitmask;
const u32 state1 = this->state.data[1];
const u32 state2 = this->state.data[2];
const u32 state3 = this->state.data[3];
if (state0 == 0 && state1 == 0 && state2 == 0 && state3 == 0) {
this->state.data[0] = 'T';
this->state.data[1] = 'I';
this->state.data[2] = 'N';
this->state.data[3] = 'Y';
}
for (int i = 0; i < NumDiscardedInitOutputs; i++) {
this->GenerateRandomU32();
}
}
u32 GenerateRandomU24() {
return (this->GenerateRandomU32() >> 8);
}
static void GenerateInitialValuePlus(TinyMT::State* state, int index, u32 value) {
u32& state0 = state->data[(index + 0) % NumStateWords];
u32& state1 = state->data[(index + 1) % NumStateWords];
u32& state2 = state->data[(index + 2) % NumStateWords];
u32& state3 = state->data[(index + 3) % NumStateWords];
const u32 x = XorByShifted27(state0 ^ state1 ^ state3) * ParamPlus;
const u32 y = x + index + value;
state0 = y;
state1 += x;
state2 += y;
}
static void GenerateInitialValueXor(TinyMT::State* state, int index) {
u32& state0 = state->data[(index + 0) % NumStateWords];
u32& state1 = state->data[(index + 1) % NumStateWords];
u32& state2 = state->data[(index + 2) % NumStateWords];
u32& state3 = state->data[(index + 3) % NumStateWords];
const u32 x = XorByShifted27(state0 + state1 + state3) * ParamXor;
const u32 y = x - index;
state0 = y;
state1 ^= x;
state2 ^= y;
}
public:
constexpr TinyMT() = default;
// Public API.
// Initialization.
void Initialize(u32 seed) {
this->state.data[0] = seed;
this->state.data[1] = ParamMat1;
this->state.data[2] = ParamMat2;
this->state.data[3] = ParamTmat;
for (int i = 1; i < MinimumInitIterations; i++) {
const u32 mixed = XorByShifted30(this->state.data[(i - 1) % NumStateWords]);
this->state.data[i % NumStateWords] ^= mixed * ParamMult + i;
}
this->FinalizeInitialization();
}
void Initialize(const u32* seed, int seed_count) {
this->state.data[0] = 0;
this->state.data[1] = ParamMat1;
this->state.data[2] = ParamMat2;
this->state.data[3] = ParamTmat;
{
const int num_init_iterations = std::max(seed_count + 1, MinimumInitIterations) - 1;
GenerateInitialValuePlus(&this->state, 0, seed_count);
for (int i = 0; i < num_init_iterations; i++) {
GenerateInitialValuePlus(&this->state, (i + 1) % NumStateWords,
(i < seed_count) ? seed[i] : 0);
}
for (int i = 0; i < static_cast<int>(NumStateWords); i++) {
GenerateInitialValueXor(&this->state,
(i + 1 + num_init_iterations) % NumStateWords);
}
}
this->FinalizeInitialization();
}
// State management.
void GetState(TinyMT::State& out) const {
out.data = this->state.data;
}
void SetState(const TinyMT::State& state_) {
this->state.data = state_.data;
}
// Random generation.
void GenerateRandomBytes(void* dst, std::size_t size) {
const uintptr_t start = reinterpret_cast<uintptr_t>(dst);
const uintptr_t end = start + size;
const uintptr_t aligned_start = Common::AlignUp(start, 4);
const uintptr_t aligned_end = Common::AlignDown(end, 4);
// Make sure we're aligned.
if (start < aligned_start) {
const u32 rnd = this->GenerateRandomU32();
std::memcpy(dst, &rnd, aligned_start - start);
}
// Write as many aligned u32s as we can.
{
u32* cur_dst = reinterpret_cast<u32*>(aligned_start);
u32* const end_dst = reinterpret_cast<u32*>(aligned_end);
while (cur_dst < end_dst) {
*(cur_dst++) = this->GenerateRandomU32();
}
}
// Handle any leftover unaligned data.
if (aligned_end < end) {
const u32 rnd = this->GenerateRandomU32();
std::memcpy(reinterpret_cast<void*>(aligned_end), &rnd, end - aligned_end);
}
}
u32 GenerateRandomU32() {
// Advance state.
const u32 x0 =
(this->state.data[0] & TopBitmask) ^ this->state.data[1] ^ this->state.data[2];
const u32 y0 = this->state.data[3];
const u32 x1 = x0 ^ (x0 << 1);
const u32 y1 = y0 ^ (y0 >> 1) ^ x1;
const u32 state0 = this->state.data[1];
u32 state1 = this->state.data[2];
u32 state2 = x1 ^ (y1 << 10);
const u32 state3 = y1;
if ((y1 & 1) != 0) {
state1 ^= ParamMat1;
state2 ^= ParamMat2;
}
this->state.data[0] = state0;
this->state.data[1] = state1;
this->state.data[2] = state2;
this->state.data[3] = state3;
// Temper.
const u32 t1 = state0 + (state2 >> 8);
u32 t0 = state3 ^ t1;
if ((t1 & 1) != 0) {
t0 ^= ParamTmat;
}
return t0;
}
u64 GenerateRandomU64() {
const u32 lo = this->GenerateRandomU32();
const u32 hi = this->GenerateRandomU32();
return (u64{hi} << 32) | u64{lo};
}
float GenerateRandomF32() {
// Floats have 24 bits of mantissa.
constexpr u32 MantissaBits = 24;
return static_cast<float>(GenerateRandomU24()) * (1.0f / (1U << MantissaBits));
}
double GenerateRandomF64() {
// Doubles have 53 bits of mantissa.
// The smart way to generate 53 bits of random would be to use 32 bits
// from the first rnd32() call, and then 21 from the second.
// Nintendo does not. They use (32 - 5) = 27 bits from the first rnd32()
// call, and (32 - 6) bits from the second. We'll do what they do, but
// There's not a clear reason why.
constexpr u32 MantissaBits = 53;
constexpr u32 Shift1st = (64 - MantissaBits) / 2;
constexpr u32 Shift2nd = (64 - MantissaBits) - Shift1st;
const u32 first = (this->GenerateRandomU32() >> Shift1st);
const u32 second = (this->GenerateRandomU32() >> Shift2nd);
return (1.0 * first * (u64{1} << (32 - Shift2nd)) + second) *
(1.0 / (u64{1} << MantissaBits));
}
};
} // namespace Common
+30 -22
View File
@@ -141,6 +141,9 @@ add_library(core STATIC
hardware_interrupt_manager.h
hle/ipc.h
hle/ipc_helpers.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
hle/kernel/client_port.cpp
hle/kernel/client_port.h
hle/kernel/client_session.cpp
@@ -156,6 +159,8 @@ add_library(core STATIC
hle/kernel/hle_ipc.h
hle/kernel/k_address_arbiter.cpp
hle/kernel/k_address_arbiter.h
hle/kernel/k_address_space_info.cpp
hle/kernel/k_address_space_info.h
hle/kernel/k_affinity_mask.h
hle/kernel/k_condition_variable.cpp
hle/kernel/k_condition_variable.h
@@ -164,6 +169,22 @@ add_library(core STATIC
hle/kernel/k_light_condition_variable.h
hle/kernel/k_light_lock.cpp
hle/kernel/k_light_lock.h
hle/kernel/k_memory_block.h
hle/kernel/k_memory_block_manager.cpp
hle/kernel/k_memory_block_manager.h
hle/kernel/k_memory_layout.cpp
hle/kernel/k_memory_layout.board.nintendo_nx.cpp
hle/kernel/k_memory_layout.h
hle/kernel/k_memory_manager.cpp
hle/kernel/k_memory_manager.h
hle/kernel/k_memory_region.h
hle/kernel/k_memory_region_type.h
hle/kernel/k_page_bitmap.h
hle/kernel/k_page_heap.cpp
hle/kernel/k_page_heap.h
hle/kernel/k_page_linked_list.h
hle/kernel/k_page_table.cpp
hle/kernel/k_page_table.h
hle/kernel/k_priority_queue.h
hle/kernel/k_readable_event.cpp
hle/kernel/k_readable_event.h
@@ -175,32 +196,23 @@ add_library(core STATIC
hle/kernel/k_scoped_lock.h
hle/kernel/k_scoped_resource_reservation.h
hle/kernel/k_scoped_scheduler_lock_and_sleep.h
hle/kernel/k_shared_memory.cpp
hle/kernel/k_shared_memory.h
hle/kernel/k_slab_heap.h
hle/kernel/k_spin_lock.cpp
hle/kernel/k_spin_lock.h
hle/kernel/k_synchronization_object.cpp
hle/kernel/k_synchronization_object.h
hle/kernel/k_system_control.h
hle/kernel/k_thread.cpp
hle/kernel/k_thread.h
hle/kernel/k_thread_queue.h
hle/kernel/k_trace.h
hle/kernel/k_writable_event.cpp
hle/kernel/k_writable_event.h
hle/kernel/kernel.cpp
hle/kernel/kernel.h
hle/kernel/memory/address_space_info.cpp
hle/kernel/memory/address_space_info.h
hle/kernel/memory/memory_block.h
hle/kernel/memory/memory_block_manager.cpp
hle/kernel/memory/memory_block_manager.h
hle/kernel/memory/memory_layout.h
hle/kernel/memory/memory_manager.cpp
hle/kernel/memory/memory_manager.h
hle/kernel/memory/memory_types.h
hle/kernel/memory/page_linked_list.h
hle/kernel/memory/page_heap.cpp
hle/kernel/memory/page_heap.h
hle/kernel/memory/page_table.cpp
hle/kernel/memory/page_table.h
hle/kernel/memory/slab_heap.h
hle/kernel/memory/system_control.cpp
hle/kernel/memory/system_control.h
hle/kernel/memory_types.h
hle/kernel/object.cpp
hle/kernel/object.h
hle/kernel/physical_core.cpp
@@ -218,8 +230,6 @@ add_library(core STATIC
hle/kernel/service_thread.h
hle/kernel/session.cpp
hle/kernel/session.h
hle/kernel/shared_memory.cpp
hle/kernel/shared_memory.h
hle/kernel/svc.cpp
hle/kernel/svc.h
hle/kernel/svc_common.h
@@ -611,8 +621,6 @@ add_library(core STATIC
perf_stats.h
reporter.cpp
reporter.h
settings.cpp
settings.h
telemetry_session.cpp
telemetry_session.h
tools/freezer.cpp
@@ -663,7 +671,7 @@ endif()
create_target_directory_groups(core)
target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls opus zip)
target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::Opus zip)
if (YUZU_ENABLE_BOXCAT)
target_compile_definitions(core PRIVATE -DYUZU_ENABLE_BOXCAT)
+18 -24
View File
@@ -10,6 +10,7 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/page_table.h"
#include "common/settings.h"
#include "core/arm/cpu_interrupt_handler.h"
#include "core/arm/dynarmic/arm_dynarmic_32.h"
#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
@@ -18,7 +19,6 @@
#include "core/core_timing.h"
#include "core/hle/kernel/svc.h"
#include "core/memory.h"
#include "core/settings.h"
namespace Core {
@@ -114,18 +114,17 @@ public:
static constexpr u64 minimum_run_cycles = 1000U;
};
std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable& page_table,
std::size_t address_space_bits) const {
std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* page_table) const {
Dynarmic::A32::UserConfig config;
config.callbacks = cb.get();
// TODO(bunnei): Implement page table for 32-bit
// config.page_table = &page_table.pointers;
config.coprocessors[15] = cp15;
config.define_unpredictable_behaviour = true;
static constexpr std::size_t PAGE_BITS = 12;
static constexpr std::size_t NUM_PAGE_TABLE_ENTRIES = 1 << (32 - PAGE_BITS);
config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>(
page_table.pointers.data());
if (page_table) {
config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>(
page_table->pointers.data());
}
config.absolute_offset_page_table = true;
config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
@@ -138,6 +137,10 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable&
// Timing
config.wall_clock_cntpct = uses_wall_clock;
// Code cache size
config.code_cache_size = 512 * 1024 * 1024;
config.far_code_offset = 256 * 1024 * 1024;
// Safe optimizations
if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {
if (!Settings::values.cpuopt_page_tables) {
@@ -201,7 +204,8 @@ ARM_Dynarmic_32::ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handle
: ARM_Interface{system, interrupt_handlers, uses_wall_clock},
cb(std::make_unique<DynarmicCallbacks32>(*this)),
cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index},
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)},
jit(MakeJit(nullptr)) {}
ARM_Dynarmic_32::~ARM_Dynarmic_32() = default;
@@ -256,9 +260,6 @@ void ARM_Dynarmic_32::ChangeProcessorID(std::size_t new_core_id) {
}
void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
if (!jit) {
return;
}
Dynarmic::A32::Context context;
jit->SaveContext(context);
ctx.cpu_registers = context.Regs();
@@ -268,9 +269,6 @@ void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
}
void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
if (!jit) {
return;
}
Dynarmic::A32::Context context;
context.Regs() = ctx.cpu_registers;
context.ExtRegs() = ctx.extension_registers;
@@ -284,35 +282,31 @@ void ARM_Dynarmic_32::PrepareReschedule() {
}
void ARM_Dynarmic_32::ClearInstructionCache() {
if (!jit) {
return;
}
jit->ClearCache();
}
void ARM_Dynarmic_32::InvalidateCacheRange(VAddr addr, std::size_t size) {
if (!jit) {
return;
}
jit->InvalidateCacheRange(static_cast<u32>(addr), size);
}
void ARM_Dynarmic_32::ClearExclusiveState() {
if (!jit) {
return;
}
jit->ClearExclusiveState();
}
void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table,
std::size_t new_address_space_size_in_bits) {
ThreadContext32 ctx{};
SaveContext(ctx);
auto key = std::make_pair(&page_table, new_address_space_size_in_bits);
auto iter = jit_cache.find(key);
if (iter != jit_cache.end()) {
jit = iter->second;
LoadContext(ctx);
return;
}
jit = MakeJit(page_table, new_address_space_size_in_bits);
jit = MakeJit(&page_table);
LoadContext(ctx);
jit_cache.emplace(key, jit);
}
+2 -3
View File
@@ -68,8 +68,7 @@ public:
std::size_t new_address_space_size_in_bits) override;
private:
std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable& page_table,
std::size_t address_space_bits) const;
std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const;
using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
using JitCacheType =
@@ -80,10 +79,10 @@ private:
std::unique_ptr<DynarmicCallbacks32> cb;
JitCacheType jit_cache;
std::shared_ptr<Dynarmic::A32::Jit> jit;
std::shared_ptr<DynarmicCP15> cp15;
std::size_t core_index;
DynarmicExclusiveMonitor& exclusive_monitor;
std::shared_ptr<Dynarmic::A32::Jit> jit;
};
} // namespace Core
+23 -26
View File
@@ -9,6 +9,7 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/page_table.h"
#include "common/settings.h"
#include "core/arm/cpu_interrupt_handler.h"
#include "core/arm/dynarmic/arm_dynarmic_64.h"
#include "core/arm/dynarmic/arm_exclusive_monitor.h"
@@ -19,7 +20,6 @@
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/svc.h"
#include "core/memory.h"
#include "core/settings.h"
namespace Core {
@@ -142,7 +142,7 @@ public:
static constexpr u64 minimum_run_cycles = 1000U;
};
std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable& page_table,
std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* page_table,
std::size_t address_space_bits) const {
Dynarmic::A64::UserConfig config;
@@ -150,13 +150,15 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
config.callbacks = cb.get();
// Memory
config.page_table = reinterpret_cast<void**>(page_table.pointers.data());
config.page_table_address_space_bits = address_space_bits;
config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
config.silently_mirror_page_table = false;
config.absolute_offset_page_table = true;
config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
config.only_detect_misalignment_via_page_table_on_page_boundary = true;
if (page_table) {
config.page_table = reinterpret_cast<void**>(page_table->pointers.data());
config.page_table_address_space_bits = address_space_bits;
config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
config.silently_mirror_page_table = false;
config.absolute_offset_page_table = true;
config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
config.only_detect_misalignment_via_page_table_on_page_boundary = true;
}
// Multi-process state
config.processor_id = core_index;
@@ -175,6 +177,10 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
// Timing
config.wall_clock_cntpct = uses_wall_clock;
// Code cache size
config.code_cache_size = 512 * 1024 * 1024;
config.far_code_offset = 256 * 1024 * 1024;
// Safe optimizations
if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {
if (!Settings::values.cpuopt_page_tables) {
@@ -237,7 +243,8 @@ ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handle
std::size_t core_index)
: ARM_Interface{system, interrupt_handlers, uses_wall_clock},
cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index},
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)},
jit(MakeJit(nullptr, 48)) {}
ARM_Dynarmic_64::~ARM_Dynarmic_64() = default;
@@ -294,9 +301,6 @@ void ARM_Dynarmic_64::ChangeProcessorID(std::size_t new_core_id) {
}
void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
if (!jit) {
return;
}
ctx.cpu_registers = jit->GetRegisters();
ctx.sp = jit->GetSP();
ctx.pc = jit->GetPC();
@@ -308,9 +312,6 @@ void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
}
void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) {
if (!jit) {
return;
}
jit->SetRegisters(ctx.cpu_registers);
jit->SetSP(ctx.sp);
jit->SetPC(ctx.pc);
@@ -326,35 +327,31 @@ void ARM_Dynarmic_64::PrepareReschedule() {
}
void ARM_Dynarmic_64::ClearInstructionCache() {
if (!jit) {
return;
}
jit->ClearCache();
}
void ARM_Dynarmic_64::InvalidateCacheRange(VAddr addr, std::size_t size) {
if (!jit) {
return;
}
jit->InvalidateCacheRange(addr, size);
}
void ARM_Dynarmic_64::ClearExclusiveState() {
if (!jit) {
return;
}
jit->ClearExclusiveState();
}
void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table,
std::size_t new_address_space_size_in_bits) {
ThreadContext64 ctx{};
SaveContext(ctx);
auto key = std::make_pair(&page_table, new_address_space_size_in_bits);
auto iter = jit_cache.find(key);
if (iter != jit_cache.end()) {
jit = iter->second;
LoadContext(ctx);
return;
}
jit = MakeJit(page_table, new_address_space_size_in_bits);
jit = MakeJit(&page_table, new_address_space_size_in_bits);
LoadContext(ctx);
jit_cache.emplace(key, jit);
}
+3 -2
View File
@@ -61,7 +61,7 @@ public:
std::size_t new_address_space_size_in_bits) override;
private:
std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable& page_table,
std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table,
std::size_t address_space_bits) const;
using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
@@ -71,10 +71,11 @@ private:
friend class DynarmicCallbacks64;
std::unique_ptr<DynarmicCallbacks64> cb;
JitCacheType jit_cache;
std::shared_ptr<Dynarmic::A64::Jit> jit;
std::size_t core_index;
DynarmicExclusiveMonitor& exclusive_monitor;
std::shared_ptr<Dynarmic::A64::Jit> jit;
};
} // namespace Core
+13 -12
View File
@@ -9,6 +9,7 @@
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/microprofile.h"
#include "common/settings.h"
#include "common/string_util.h"
#include "core/arm/exclusive_monitor.h"
#include "core/core.h"
@@ -36,6 +37,7 @@
#include "core/hle/service/apm/controller.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/glue/manager.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
#include "core/hle/service/time/time_manager.h"
@@ -45,7 +47,6 @@
#include "core/network/network.h"
#include "core/perf_stats.h"
#include "core/reporter.h"
#include "core/settings.h"
#include "core/telemetry_session.h"
#include "core/tools/freezer.h"
#include "video_core/renderer_base.h"
@@ -296,28 +297,20 @@ struct System::Impl {
exit_lock = false;
if (gpu_core) {
gpu_core->WaitIdle();
gpu_core->ShutDown();
}
// Shutdown emulation session
services.reset();
service_manager.reset();
cheat_engine.reset();
telemetry_session.reset();
// Close all CPU/threading state
cpu_manager.Shutdown();
// Shutdown kernel and core timing
time_manager.Shutdown();
core_timing.Shutdown();
kernel.Shutdown();
// Close app loader
app_loader.reset();
gpu_core.reset();
perf_stats.reset();
// Clear all applets
kernel.Shutdown();
applet_manager.ClearAll();
LOG_DEBUG(Core, "Shutdown OK");
@@ -782,4 +775,12 @@ void System::ExecuteProgram(std::size_t program_index) {
}
}
void System::ApplySettings() {
if (IsPoweredOn()) {
Renderer().RefreshBaseSettings();
}
Service::HID::ReloadInputDevices();
}
} // namespace Core
+3
View File
@@ -388,6 +388,9 @@ public:
*/
void ExecuteProgram(std::size_t program_index);
/// Applies any changes to settings to this core instance.
void ApplySettings();
private:
System();
+4 -4
View File
@@ -148,7 +148,7 @@ void CpuManager::MultiCoreRunSuspendThread() {
auto core = kernel.GetCurrentHostThreadID();
auto& scheduler = *kernel.CurrentScheduler();
Kernel::KThread* current_thread = scheduler.GetCurrentThread();
Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[core].host_context);
Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context);
ASSERT(scheduler.ContextSwitchPending());
ASSERT(core == kernel.GetCurrentHostThreadID());
scheduler.RescheduleCurrentCore();
@@ -245,7 +245,7 @@ void CpuManager::SingleCoreRunSuspendThread() {
auto core = kernel.GetCurrentHostThreadID();
auto& scheduler = *kernel.CurrentScheduler();
Kernel::KThread* current_thread = scheduler.GetCurrentThread();
Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[0].host_context);
Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[0].host_context);
ASSERT(scheduler.ContextSwitchPending());
ASSERT(core == kernel.GetCurrentHostThreadID());
scheduler.RescheduleCurrentCore();
@@ -271,7 +271,7 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
scheduler.Unload(scheduler.GetCurrentThread());
auto& next_scheduler = kernel.Scheduler(current_core);
Common::Fiber::YieldTo(current_thread->GetHostContext(), next_scheduler.ControlContext());
Common::Fiber::YieldTo(current_thread->GetHostContext(), *next_scheduler.ControlContext());
}
// May have changed scheduler
@@ -363,7 +363,7 @@ void CpuManager::RunThread(std::size_t core) {
auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
data.is_running = true;
Common::Fiber::YieldTo(data.host_context, current_thread->GetHostContext());
Common::Fiber::YieldTo(data.host_context, *current_thread->GetHostContext());
data.is_running = false;
data.is_paused = true;
data.exit_barrier->Wait();
-2
View File
@@ -105,8 +105,6 @@ void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* des
}
}
}
mbedtls_cipher_finish(context, nullptr, nullptr);
}
template <typename Key, std::size_t KeySize>
+1 -1
View File
@@ -22,6 +22,7 @@
#include "common/file_util.h"
#include "common/hex_util.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "common/string_util.h"
#include "core/crypto/aes_util.h"
#include "core/crypto/key_manager.h"
@@ -32,7 +33,6 @@
#include "core/file_sys/registered_cache.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h"
#include "core/settings.h"
namespace Core::Crypto {
namespace {
+8
View File
@@ -100,6 +100,14 @@ u64 NACP::GetDeviceSaveDataSize() const {
return raw.device_save_data_size;
}
u32 NACP::GetParentalControlFlag() const {
return raw.parental_control;
}
const std::array<u8, 0x20>& NACP::GetRatingAge() const {
return raw.rating_age;
}
std::vector<u8> NACP::GetRawBytes() const {
std::vector<u8> out(sizeof(RawNACP));
std::memcpy(out.data(), &raw, sizeof(RawNACP));
+2
View File
@@ -114,6 +114,8 @@ public:
std::vector<u8> GetRawBytes() const;
bool GetUserAccountSwitchLock() const;
u64 GetDeviceSaveDataSize() const;
u32 GetParentalControlFlag() const;
const std::array<u8, 0x20>& GetRatingAge() const;
private:
RawNACP raw{};
+1 -1
View File
@@ -10,6 +10,7 @@
#include "common/file_util.h"
#include "common/hex_util.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/file_sys/common_funcs.h"
@@ -25,7 +26,6 @@
#include "core/loader/loader.h"
#include "core/loader/nso.h"
#include "core/memory/cheat_engine.h"
#include "core/settings.h"
namespace FileSys {
namespace {
+2 -2
View File
@@ -14,7 +14,7 @@ namespace NgWord1Data {
constexpr std::size_t NUMBER_WORD_TXT_FILES = 0x10;
// Should this archive replacement mysteriously not work on a future game, consider updating.
constexpr std::array<u8, 4> VERSION_DAT{0x0, 0x0, 0x0, 0x19}; // 5.1.0 System Version
constexpr std::array<u8, 4> VERSION_DAT{0x0, 0x0, 0x0, 0x20}; // 11.0.1 System Version
constexpr std::array<u8, 30> WORD_TXT{
0xFE, 0xFF, 0x00, 0x5E, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x79, 0x00, 0x62, 0x00,
@@ -43,7 +43,7 @@ namespace NgWord2Data {
constexpr std::size_t NUMBER_AC_NX_FILES = 0x10;
// Should this archive replacement mysteriously not work on a future game, consider updating.
constexpr std::array<u8, 4> VERSION_DAT{0x0, 0x0, 0x0, 0x15}; // 5.1.0 System Version
constexpr std::array<u8, 4> VERSION_DAT{0x0, 0x0, 0x0, 0x1A}; // 11.0.1 System Version
constexpr std::array<u8, 0x2C> AC_NX_DATA{
0x1F, 0x8B, 0x08, 0x08, 0xD5, 0x2C, 0x09, 0x5C, 0x04, 0x00, 0x61, 0x63, 0x72, 0x61, 0x77,
@@ -14,15 +14,15 @@ namespace SystemVersionData {
constexpr u8 VERSION_MAJOR = 11;
constexpr u8 VERSION_MINOR = 0;
constexpr u8 VERSION_MICRO = 0;
constexpr u8 VERSION_MICRO = 1;
constexpr u8 REVISION_MAJOR = 5;
constexpr u8 REVISION_MAJOR = 1;
constexpr u8 REVISION_MINOR = 0;
constexpr char PLATFORM_STRING[] = "NX";
constexpr char VERSION_HASH[] = "34197eba8810e2edd5e9dfcfbde7b340882e856d";
constexpr char DISPLAY_VERSION[] = "11.0.0";
constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 11.0.0-5.0";
constexpr char VERSION_HASH[] = "69103fcb2004dace877094c2f8c29e6113be5dbf";
constexpr char DISPLAY_VERSION[] = "11.0.1";
constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 11.0.1-1.0";
} // namespace SystemVersionData
+1 -1
View File
@@ -2,9 +2,9 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/settings.h"
#include "core/frontend/applets/profile_select.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/settings.h"
namespace Core::Frontend {
+1 -1
View File
@@ -4,9 +4,9 @@
#include <cmath>
#include <mutex>
#include "common/settings.h"
#include "core/frontend/emu_window.h"
#include "core/frontend/input.h"
#include "core/settings.h"
namespace Core::Frontend {
+1 -1
View File
@@ -5,8 +5,8 @@
#include <cmath>
#include "common/assert.h"
#include "common/settings.h"
#include "core/frontend/framebuffer_layout.h"
#include "core/settings.h"
namespace Layout {
@@ -0,0 +1,20 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
// All architectures must define NumArchitectureDeviceRegions.
constexpr inline const auto NumArchitectureDeviceRegions = 3;
constexpr inline const auto KMemoryRegionType_Uart =
KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 0);
constexpr inline const auto KMemoryRegionType_InterruptCpuInterface =
KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 1)
.SetAttribute(KMemoryRegionAttr_NoUserMap);
constexpr inline const auto KMemoryRegionType_InterruptDistributor =
KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 2)
.SetAttribute(KMemoryRegionAttr_NoUserMap);
static_assert(KMemoryRegionType_Uart.GetValue() == (0x1D));
static_assert(KMemoryRegionType_InterruptCpuInterface.GetValue() ==
(0x2D | KMemoryRegionAttr_NoUserMap));
static_assert(KMemoryRegionType_InterruptDistributor.GetValue() ==
(0x4D | KMemoryRegionAttr_NoUserMap));
@@ -0,0 +1,52 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
// All architectures must define NumBoardDeviceRegions.
constexpr inline const auto NumBoardDeviceRegions = 6;
// UNUSED: .Derive(NumBoardDeviceRegions, 0);
constexpr inline const auto KMemoryRegionType_MemoryController =
KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 1)
.SetAttribute(KMemoryRegionAttr_NoUserMap);
constexpr inline const auto KMemoryRegionType_MemoryController1 =
KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 2)
.SetAttribute(KMemoryRegionAttr_NoUserMap);
constexpr inline const auto KMemoryRegionType_MemoryController0 =
KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 3)
.SetAttribute(KMemoryRegionAttr_NoUserMap);
constexpr inline const auto KMemoryRegionType_PowerManagementController =
KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 4).DeriveTransition();
constexpr inline const auto KMemoryRegionType_LegacyLpsDevices =
KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 5);
static_assert(KMemoryRegionType_MemoryController.GetValue() ==
(0x55 | KMemoryRegionAttr_NoUserMap));
static_assert(KMemoryRegionType_MemoryController1.GetValue() ==
(0x65 | KMemoryRegionAttr_NoUserMap));
static_assert(KMemoryRegionType_MemoryController0.GetValue() ==
(0x95 | KMemoryRegionAttr_NoUserMap));
static_assert(KMemoryRegionType_PowerManagementController.GetValue() == (0x1A5));
static_assert(KMemoryRegionType_LegacyLpsDevices.GetValue() == 0xC5);
constexpr inline const auto NumLegacyLpsDevices = 7;
constexpr inline const auto KMemoryRegionType_LegacyLpsExceptionVectors =
KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 0);
constexpr inline const auto KMemoryRegionType_LegacyLpsIram =
KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 1);
constexpr inline const auto KMemoryRegionType_LegacyLpsFlowController =
KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 2);
constexpr inline const auto KMemoryRegionType_LegacyLpsPrimaryICtlr =
KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 3);
constexpr inline const auto KMemoryRegionType_LegacyLpsSemaphore =
KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 4);
constexpr inline const auto KMemoryRegionType_LegacyLpsAtomics =
KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 5);
constexpr inline const auto KMemoryRegionType_LegacyLpsClkRst =
KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 6);
static_assert(KMemoryRegionType_LegacyLpsExceptionVectors.GetValue() == 0x3C5);
static_assert(KMemoryRegionType_LegacyLpsIram.GetValue() == 0x5C5);
static_assert(KMemoryRegionType_LegacyLpsFlowController.GetValue() == 0x6C5);
static_assert(KMemoryRegionType_LegacyLpsPrimaryICtlr.GetValue() == 0x9C5);
static_assert(KMemoryRegionType_LegacyLpsSemaphore.GetValue() == 0xAC5);
static_assert(KMemoryRegionType_LegacyLpsAtomics.GetValue() == 0xCC5);
static_assert(KMemoryRegionType_LegacyLpsClkRst.GetValue() == 0x11C5);
@@ -0,0 +1,164 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <random>
#include "common/common_sizes.h"
#include "core/hle/kernel/board/nintendo/nx/k_system_control.h"
#include "core/hle/kernel/board/nintendo/nx/secure_monitor.h"
#include "core/hle/kernel/k_trace.h"
namespace Kernel::Board::Nintendo::Nx {
namespace impl {
constexpr const std::size_t RequiredNonSecureSystemMemorySizeVi = 0x2238 * 4 * 1024;
constexpr const std::size_t RequiredNonSecureSystemMemorySizeNvservices = 0x710 * 4 * 1024;
constexpr const std::size_t RequiredNonSecureSystemMemorySizeMisc = 0x80 * 4 * 1024;
} // namespace impl
constexpr const std::size_t RequiredNonSecureSystemMemorySize =
impl::RequiredNonSecureSystemMemorySizeVi + impl::RequiredNonSecureSystemMemorySizeNvservices +
impl::RequiredNonSecureSystemMemorySizeMisc;
namespace {
u32 GetMemoryModeForInit() {
return 0x01;
}
u32 GetMemorySizeForInit() {
return 0;
}
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;
}
}
} // namespace
// Initialization.
size_t KSystemControl::Init::GetIntendedMemorySize() {
switch (GetMemorySizeForInit()) {
case Smc::MemorySize_4GB:
default: // All invalid modes should go to 4GB.
return Common::Size_4_GB;
case Smc::MemorySize_6GB:
return Common::Size_6_GB;
case Smc::MemorySize_8GB:
return Common::Size_8_GB;
}
}
PAddr KSystemControl::Init::GetKernelPhysicalBaseAddress(u64 base_address) {
return base_address;
}
bool KSystemControl::Init::ShouldIncreaseThreadResourceLimit() {
return true;
}
std::size_t KSystemControl::Init::GetApplicationPoolSize() {
// Get the base pool size.
const size_t base_pool_size = []() -> size_t {
switch (GetMemoryArrangeForInit()) {
case Smc::MemoryArrangement_4GB:
default:
return Common::Size_3285_MB;
case Smc::MemoryArrangement_4GBForAppletDev:
return Common::Size_2048_MB;
case Smc::MemoryArrangement_4GBForSystemDev:
return Common::Size_3285_MB;
case Smc::MemoryArrangement_6GB:
return Common::Size_4916_MB;
case Smc::MemoryArrangement_6GBForAppletDev:
return Common::Size_3285_MB;
case Smc::MemoryArrangement_8GB:
return Common::Size_4916_MB;
}
}();
// Return (possibly) adjusted size.
return base_pool_size;
}
size_t KSystemControl::Init::GetAppletPoolSize() {
// Get the base pool size.
const size_t base_pool_size = []() -> size_t {
switch (GetMemoryArrangeForInit()) {
case Smc::MemoryArrangement_4GB:
default:
return Common::Size_507_MB;
case Smc::MemoryArrangement_4GBForAppletDev:
return Common::Size_1554_MB;
case Smc::MemoryArrangement_4GBForSystemDev:
return Common::Size_448_MB;
case Smc::MemoryArrangement_6GB:
return Common::Size_562_MB;
case Smc::MemoryArrangement_6GBForAppletDev:
return Common::Size_2193_MB;
case Smc::MemoryArrangement_8GB:
return Common::Size_2193_MB;
}
}();
// Return (possibly) adjusted size.
constexpr size_t ExtraSystemMemoryForAtmosphere = Common::Size_33_MB;
return base_pool_size - ExtraSystemMemoryForAtmosphere - KTraceBufferSize;
}
size_t KSystemControl::Init::GetMinimumNonSecureSystemPoolSize() {
// Verify that our minimum is at least as large as Nintendo's.
constexpr size_t MinimumSize = RequiredNonSecureSystemMemorySize;
static_assert(MinimumSize >= 0x29C8000);
return MinimumSize;
}
namespace {
template <typename F>
u64 GenerateUniformRange(u64 min, u64 max, F f) {
// Handle the case where the difference is too large to represent.
if (max == std::numeric_limits<u64>::max() && min == std::numeric_limits<u64>::min()) {
return f();
}
// Iterate until we get a value in range.
const u64 range_size = ((max + 1) - min);
const u64 effective_max = (std::numeric_limits<u64>::max() / range_size) * range_size;
while (true) {
if (const u64 rnd = f(); rnd < effective_max) {
return min + (rnd % range_size);
}
}
}
} // Anonymous namespace
u64 KSystemControl::GenerateRandomU64() {
static std::random_device device;
static std::mt19937 gen(device());
static std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
return distribution(gen);
}
u64 KSystemControl::GenerateRandomRange(u64 min, u64 max) {
return GenerateUniformRange(min, max, GenerateRandomU64);
}
} // namespace Kernel::Board::Nintendo::Nx
@@ -0,0 +1,28 @@
// Copyright 2021 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::Board::Nintendo::Nx {
class KSystemControl {
public:
class Init {
public:
// Initialization.
static std::size_t GetIntendedMemorySize();
static PAddr GetKernelPhysicalBaseAddress(u64 base_address);
static bool ShouldIncreaseThreadResourceLimit();
static std::size_t GetApplicationPoolSize();
static std::size_t GetAppletPoolSize();
static std::size_t GetMinimumNonSecureSystemPoolSize();
};
static u64 GenerateRandomRange(u64 min, u64 max);
static u64 GenerateRandomU64();
};
} // namespace Kernel::Board::Nintendo::Nx
@@ -0,0 +1,26 @@
// Copyright 2021 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::Board::Nintendo::Nx::Smc {
enum MemorySize {
MemorySize_4GB = 0,
MemorySize_6GB = 1,
MemorySize_8GB = 2,
};
enum MemoryArrangement {
MemoryArrangement_4GB = 0,
MemoryArrangement_4GBForAppletDev = 1,
MemoryArrangement_4GBForSystemDev = 2,
MemoryArrangement_6GB = 3,
MemoryArrangement_6GBForAppletDev = 4,
MemoryArrangement_8GB = 5,
};
} // namespace Kernel::Board::Nintendo::Nx::Smc
@@ -0,0 +1,106 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <array>
#include "common/assert.h"
#include "common/common_sizes.h"
#include "core/hle/kernel/k_address_space_info.h"
namespace Kernel {
namespace {
// clang-format off
constexpr std::array<KAddressSpaceInfo, 13> AddressSpaceInfos{{
{ .bit_width = 32, .address = Common::Size_2_MB , .size = Common::Size_1_GB - Common::Size_2_MB , .type = KAddressSpaceInfo::Type::MapSmall, },
{ .bit_width = 32, .address = Common::Size_1_GB , .size = Common::Size_4_GB - Common::Size_1_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
{ .bit_width = 32, .address = Common::Size_Invalid, .size = Common::Size_1_GB , .type = KAddressSpaceInfo::Type::Alias, },
{ .bit_width = 32, .address = Common::Size_Invalid, .size = Common::Size_1_GB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 36, .address = Common::Size_128_MB , .size = Common::Size_2_GB - Common::Size_128_MB, .type = KAddressSpaceInfo::Type::MapSmall, },
{ .bit_width = 36, .address = Common::Size_2_GB , .size = Common::Size_64_GB - Common::Size_2_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
{ .bit_width = 36, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 36, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Alias, },
{ .bit_width = 39, .address = Common::Size_128_MB , .size = Common::Size_512_GB - Common::Size_128_MB, .type = KAddressSpaceInfo::Type::Map39Bit, },
{ .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_64_GB , .type = KAddressSpaceInfo::Type::MapSmall },
{ .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_64_GB , .type = KAddressSpaceInfo::Type::Alias, },
{ .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_2_GB , .type = KAddressSpaceInfo::Type::Stack, },
}};
// clang-format on
constexpr bool IsAllowedIndexForAddress(std::size_t index) {
return index < AddressSpaceInfos.size() &&
AddressSpaceInfos[index].address != Common::Size_Invalid;
}
using IndexArray =
std::array<std::size_t, static_cast<std::size_t>(KAddressSpaceInfo::Type::Count)>;
constexpr IndexArray AddressSpaceIndices32Bit{
0, 1, 0, 2, 0, 3,
};
constexpr IndexArray AddressSpaceIndices36Bit{
4, 5, 4, 6, 4, 7,
};
constexpr IndexArray AddressSpaceIndices39Bit{
9, 8, 8, 10, 12, 11,
};
constexpr bool IsAllowed32BitType(KAddressSpaceInfo::Type type) {
return type < KAddressSpaceInfo::Type::Count && type != KAddressSpaceInfo::Type::Map39Bit &&
type != KAddressSpaceInfo::Type::Stack;
}
constexpr bool IsAllowed36BitType(KAddressSpaceInfo::Type type) {
return type < KAddressSpaceInfo::Type::Count && type != KAddressSpaceInfo::Type::Map39Bit &&
type != KAddressSpaceInfo::Type::Stack;
}
constexpr bool IsAllowed39BitType(KAddressSpaceInfo::Type type) {
return type < KAddressSpaceInfo::Type::Count && type != KAddressSpaceInfo::Type::MapLarge;
}
} // namespace
u64 KAddressSpaceInfo::GetAddressSpaceStart(std::size_t width, Type type) {
const std::size_t index{static_cast<std::size_t>(type)};
switch (width) {
case 32:
ASSERT(IsAllowed32BitType(type));
ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices32Bit[index]));
return AddressSpaceInfos[AddressSpaceIndices32Bit[index]].address;
case 36:
ASSERT(IsAllowed36BitType(type));
ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices36Bit[index]));
return AddressSpaceInfos[AddressSpaceIndices36Bit[index]].address;
case 39:
ASSERT(IsAllowed39BitType(type));
ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices39Bit[index]));
return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].address;
}
UNREACHABLE();
return 0;
}
std::size_t KAddressSpaceInfo::GetAddressSpaceSize(std::size_t width, Type type) {
const std::size_t index{static_cast<std::size_t>(type)};
switch (width) {
case 32:
ASSERT(IsAllowed32BitType(type));
return AddressSpaceInfos[AddressSpaceIndices32Bit[index]].size;
case 36:
ASSERT(IsAllowed36BitType(type));
return AddressSpaceInfos[AddressSpaceIndices36Bit[index]].size;
case 39:
ASSERT(IsAllowed39BitType(type));
return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].size;
}
UNREACHABLE();
return 0;
}
} // namespace Kernel
@@ -2,20 +2,17 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
// This file references various implementation details from Atmosphere, an open-source firmware for
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
#pragma once
#include "common/common_types.h"
namespace Kernel::Memory {
namespace Kernel {
struct AddressSpaceInfo final {
struct KAddressSpaceInfo final {
enum class Type : u32 {
Is32Bit = 0,
Small64Bit = 1,
Large64Bit = 2,
MapSmall = 0,
MapLarge = 1,
Map39Bit = 2,
Heap = 3,
Stack = 4,
Alias = 5,
@@ -31,4 +28,4 @@ struct AddressSpaceInfo final {
const Type type{};
};
} // namespace Kernel::Memory
} // namespace Kernel
@@ -2,20 +2,17 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
// This file references various implementation details from Atmosphere, an open-source firmware for
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
#pragma once
#include "common/alignment.h"
#include "common/assert.h"
#include "common/common_types.h"
#include "core/hle/kernel/memory/memory_types.h"
#include "core/hle/kernel/memory_types.h"
#include "core/hle/kernel/svc_types.h"
namespace Kernel::Memory {
namespace Kernel {
enum class MemoryState : u32 {
enum class KMemoryState : u32 {
None = 0,
Mask = 0xFF,
All = ~None,
@@ -97,31 +94,31 @@ enum class MemoryState : u32 {
FlagReferenceCounted | FlagCanDebug,
CodeOut = static_cast<u32>(Svc::MemoryState::CodeOut) | FlagMapped | FlagReferenceCounted,
};
DECLARE_ENUM_FLAG_OPERATORS(MemoryState);
DECLARE_ENUM_FLAG_OPERATORS(KMemoryState);
static_assert(static_cast<u32>(MemoryState::Free) == 0x00000000);
static_assert(static_cast<u32>(MemoryState::Io) == 0x00002001);
static_assert(static_cast<u32>(MemoryState::Static) == 0x00042002);
static_assert(static_cast<u32>(MemoryState::Code) == 0x00DC7E03);
static_assert(static_cast<u32>(MemoryState::CodeData) == 0x03FEBD04);
static_assert(static_cast<u32>(MemoryState::Normal) == 0x037EBD05);
static_assert(static_cast<u32>(MemoryState::Shared) == 0x00402006);
static_assert(static_cast<u32>(MemoryState::AliasCode) == 0x00DD7E08);
static_assert(static_cast<u32>(MemoryState::AliasCodeData) == 0x03FFBD09);
static_assert(static_cast<u32>(MemoryState::Ipc) == 0x005C3C0A);
static_assert(static_cast<u32>(MemoryState::Stack) == 0x005C3C0B);
static_assert(static_cast<u32>(MemoryState::ThreadLocal) == 0x0040200C);
static_assert(static_cast<u32>(MemoryState::Transferred) == 0x015C3C0D);
static_assert(static_cast<u32>(MemoryState::SharedTransferred) == 0x005C380E);
static_assert(static_cast<u32>(MemoryState::SharedCode) == 0x0040380F);
static_assert(static_cast<u32>(MemoryState::Inaccessible) == 0x00000010);
static_assert(static_cast<u32>(MemoryState::NonSecureIpc) == 0x005C3811);
static_assert(static_cast<u32>(MemoryState::NonDeviceIpc) == 0x004C2812);
static_assert(static_cast<u32>(MemoryState::Kernel) == 0x00002013);
static_assert(static_cast<u32>(MemoryState::GeneratedCode) == 0x00402214);
static_assert(static_cast<u32>(MemoryState::CodeOut) == 0x00402015);
static_assert(static_cast<u32>(KMemoryState::Free) == 0x00000000);
static_assert(static_cast<u32>(KMemoryState::Io) == 0x00002001);
static_assert(static_cast<u32>(KMemoryState::Static) == 0x00042002);
static_assert(static_cast<u32>(KMemoryState::Code) == 0x00DC7E03);
static_assert(static_cast<u32>(KMemoryState::CodeData) == 0x03FEBD04);
static_assert(static_cast<u32>(KMemoryState::Normal) == 0x037EBD05);
static_assert(static_cast<u32>(KMemoryState::Shared) == 0x00402006);
static_assert(static_cast<u32>(KMemoryState::AliasCode) == 0x00DD7E08);
static_assert(static_cast<u32>(KMemoryState::AliasCodeData) == 0x03FFBD09);
static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x005C3C0A);
static_assert(static_cast<u32>(KMemoryState::Stack) == 0x005C3C0B);
static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0040200C);
static_assert(static_cast<u32>(KMemoryState::Transferred) == 0x015C3C0D);
static_assert(static_cast<u32>(KMemoryState::SharedTransferred) == 0x005C380E);
static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0040380F);
static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010);
static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x005C3811);
static_assert(static_cast<u32>(KMemoryState::NonDeviceIpc) == 0x004C2812);
static_assert(static_cast<u32>(KMemoryState::Kernel) == 0x00002013);
static_assert(static_cast<u32>(KMemoryState::GeneratedCode) == 0x00402214);
static_assert(static_cast<u32>(KMemoryState::CodeOut) == 0x00402015);
enum class MemoryPermission : u8 {
enum class KMemoryPermission : u8 {
None = 0,
Mask = static_cast<u8>(~None),
@@ -135,9 +132,9 @@ enum class MemoryPermission : u8 {
UserMask = static_cast<u8>(Svc::MemoryPermission::Read | Svc::MemoryPermission::Write |
Svc::MemoryPermission::Execute),
};
DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission);
DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission);
enum class MemoryAttribute : u8 {
enum class KMemoryAttribute : u8 {
None = 0x00,
Mask = 0x7F,
All = Mask,
@@ -152,18 +149,18 @@ enum class MemoryAttribute : u8 {
LockedAndIpcLocked = Locked | IpcLocked,
DeviceSharedAndUncached = DeviceShared | Uncached
};
DECLARE_ENUM_FLAG_OPERATORS(MemoryAttribute);
DECLARE_ENUM_FLAG_OPERATORS(KMemoryAttribute);
static_assert((static_cast<u8>(MemoryAttribute::Mask) &
static_cast<u8>(MemoryAttribute::DontCareMask)) == 0);
static_assert((static_cast<u8>(KMemoryAttribute::Mask) &
static_cast<u8>(KMemoryAttribute::DontCareMask)) == 0);
struct MemoryInfo {
struct KMemoryInfo {
VAddr addr{};
std::size_t size{};
MemoryState state{};
MemoryPermission perm{};
MemoryAttribute attribute{};
MemoryPermission original_perm{};
KMemoryState state{};
KMemoryPermission perm{};
KMemoryAttribute attribute{};
KMemoryPermission original_perm{};
u16 ipc_lock_count{};
u16 device_use_count{};
@@ -171,9 +168,9 @@ struct MemoryInfo {
return {
addr,
size,
static_cast<Svc::MemoryState>(state & MemoryState::Mask),
static_cast<Svc::MemoryAttribute>(attribute & MemoryAttribute::Mask),
static_cast<Svc::MemoryPermission>(perm & MemoryPermission::UserMask),
static_cast<Svc::MemoryState>(state & KMemoryState::Mask),
static_cast<Svc::MemoryAttribute>(attribute & KMemoryAttribute::Mask),
static_cast<Svc::MemoryPermission>(perm & KMemoryPermission::UserMask),
ipc_lock_count,
device_use_count,
};
@@ -196,21 +193,21 @@ struct MemoryInfo {
}
};
class MemoryBlock final {
friend class MemoryBlockManager;
class KMemoryBlock final {
friend class KMemoryBlockManager;
private:
VAddr addr{};
std::size_t num_pages{};
MemoryState state{MemoryState::None};
KMemoryState state{KMemoryState::None};
u16 ipc_lock_count{};
u16 device_use_count{};
MemoryPermission perm{MemoryPermission::None};
MemoryPermission original_perm{MemoryPermission::None};
MemoryAttribute attribute{MemoryAttribute::None};
KMemoryPermission perm{KMemoryPermission::None};
KMemoryPermission original_perm{KMemoryPermission::None};
KMemoryAttribute attribute{KMemoryAttribute::None};
public:
static constexpr int Compare(const MemoryBlock& lhs, const MemoryBlock& rhs) {
static constexpr int Compare(const KMemoryBlock& lhs, const KMemoryBlock& rhs) {
if (lhs.GetAddress() < rhs.GetAddress()) {
return -1;
} else if (lhs.GetAddress() <= rhs.GetLastAddress()) {
@@ -221,9 +218,9 @@ public:
}
public:
constexpr MemoryBlock() = default;
constexpr MemoryBlock(VAddr addr_, std::size_t num_pages_, MemoryState state_,
MemoryPermission perm_, MemoryAttribute attribute_)
constexpr KMemoryBlock() = default;
constexpr KMemoryBlock(VAddr addr_, std::size_t num_pages_, KMemoryState state_,
KMemoryPermission perm_, KMemoryAttribute attribute_)
: addr{addr_}, num_pages(num_pages_), state{state_}, perm{perm_}, attribute{attribute_} {}
constexpr VAddr GetAddress() const {
@@ -246,40 +243,40 @@ public:
return GetEndAddress() - 1;
}
constexpr MemoryInfo GetMemoryInfo() const {
constexpr KMemoryInfo GetMemoryInfo() const {
return {
GetAddress(), GetSize(), state, perm,
attribute, original_perm, ipc_lock_count, device_use_count,
};
}
void ShareToDevice(MemoryPermission /*new_perm*/) {
ASSERT((attribute & MemoryAttribute::DeviceShared) == MemoryAttribute::DeviceShared ||
void ShareToDevice(KMemoryPermission /*new_perm*/) {
ASSERT((attribute & KMemoryAttribute::DeviceShared) == KMemoryAttribute::DeviceShared ||
device_use_count == 0);
attribute |= MemoryAttribute::DeviceShared;
attribute |= KMemoryAttribute::DeviceShared;
const u16 new_use_count{++device_use_count};
ASSERT(new_use_count > 0);
}
void UnshareToDevice(MemoryPermission /*new_perm*/) {
ASSERT((attribute & MemoryAttribute::DeviceShared) == MemoryAttribute::DeviceShared);
void UnshareToDevice(KMemoryPermission /*new_perm*/) {
ASSERT((attribute & KMemoryAttribute::DeviceShared) == KMemoryAttribute::DeviceShared);
const u16 prev_use_count{device_use_count--};
ASSERT(prev_use_count > 0);
if (prev_use_count == 1) {
attribute &= ~MemoryAttribute::DeviceShared;
attribute &= ~KMemoryAttribute::DeviceShared;
}
}
private:
constexpr bool HasProperties(MemoryState s, MemoryPermission p, MemoryAttribute a) const {
constexpr MemoryAttribute AttributeIgnoreMask{MemoryAttribute::DontCareMask |
MemoryAttribute::IpcLocked |
MemoryAttribute::DeviceShared};
constexpr bool HasProperties(KMemoryState s, KMemoryPermission p, KMemoryAttribute a) const {
constexpr KMemoryAttribute AttributeIgnoreMask{KMemoryAttribute::DontCareMask |
KMemoryAttribute::IpcLocked |
KMemoryAttribute::DeviceShared};
return state == s && perm == p &&
(attribute | AttributeIgnoreMask) == (a | AttributeIgnoreMask);
}
constexpr bool HasSameProperties(const MemoryBlock& rhs) const {
constexpr bool HasSameProperties(const KMemoryBlock& rhs) const {
return state == rhs.state && perm == rhs.perm && original_perm == rhs.original_perm &&
attribute == rhs.attribute && ipc_lock_count == rhs.ipc_lock_count &&
device_use_count == rhs.device_use_count;
@@ -296,25 +293,25 @@ private:
num_pages += count;
}
constexpr void Update(MemoryState new_state, MemoryPermission new_perm,
MemoryAttribute new_attribute) {
ASSERT(original_perm == MemoryPermission::None);
ASSERT((attribute & MemoryAttribute::IpcLocked) == MemoryAttribute::None);
constexpr void Update(KMemoryState new_state, KMemoryPermission new_perm,
KMemoryAttribute new_attribute) {
ASSERT(original_perm == KMemoryPermission::None);
ASSERT((attribute & KMemoryAttribute::IpcLocked) == KMemoryAttribute::None);
state = new_state;
perm = new_perm;
attribute = static_cast<MemoryAttribute>(
attribute = static_cast<KMemoryAttribute>(
new_attribute |
(attribute & (MemoryAttribute::IpcLocked | MemoryAttribute::DeviceShared)));
(attribute & (KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared)));
}
constexpr MemoryBlock Split(VAddr split_addr) {
constexpr KMemoryBlock Split(VAddr split_addr) {
ASSERT(GetAddress() < split_addr);
ASSERT(Contains(split_addr));
ASSERT(Common::IsAligned(split_addr, PageSize));
MemoryBlock block;
KMemoryBlock block;
block.addr = addr;
block.num_pages = (split_addr - GetAddress()) / PageSize;
block.state = state;
@@ -330,6 +327,6 @@ private:
return block;
}
};
static_assert(std::is_trivially_destructible<MemoryBlock>::value);
static_assert(std::is_trivially_destructible<KMemoryBlock>::value);
} // namespace Kernel::Memory
} // namespace Kernel
@@ -2,19 +2,19 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/hle/kernel/memory/memory_block_manager.h"
#include "core/hle/kernel/memory/memory_types.h"
#include "core/hle/kernel/k_memory_block_manager.h"
#include "core/hle/kernel/memory_types.h"
namespace Kernel::Memory {
namespace Kernel {
MemoryBlockManager::MemoryBlockManager(VAddr start_addr, VAddr end_addr)
KMemoryBlockManager::KMemoryBlockManager(VAddr start_addr, VAddr end_addr)
: start_addr{start_addr}, end_addr{end_addr} {
const u64 num_pages{(end_addr - start_addr) / PageSize};
memory_block_tree.emplace_back(start_addr, num_pages, MemoryState::Free, MemoryPermission::None,
MemoryAttribute::None);
memory_block_tree.emplace_back(start_addr, num_pages, KMemoryState::Free,
KMemoryPermission::None, KMemoryAttribute::None);
}
MemoryBlockManager::iterator MemoryBlockManager::FindIterator(VAddr addr) {
KMemoryBlockManager::iterator KMemoryBlockManager::FindIterator(VAddr addr) {
auto node{memory_block_tree.begin()};
while (node != end()) {
const VAddr end_addr{node->GetNumPages() * PageSize + node->GetAddress()};
@@ -26,9 +26,9 @@ MemoryBlockManager::iterator MemoryBlockManager::FindIterator(VAddr addr) {
return end();
}
VAddr MemoryBlockManager::FindFreeArea(VAddr region_start, std::size_t region_num_pages,
std::size_t num_pages, std::size_t align, std::size_t offset,
std::size_t guard_pages) {
VAddr KMemoryBlockManager::FindFreeArea(VAddr region_start, std::size_t region_num_pages,
std::size_t num_pages, std::size_t align,
std::size_t offset, std::size_t guard_pages) {
if (num_pages == 0) {
return {};
}
@@ -41,7 +41,7 @@ VAddr MemoryBlockManager::FindFreeArea(VAddr region_start, std::size_t region_nu
break;
}
if (info.state != MemoryState::Free) {
if (info.state != KMemoryState::Free) {
continue;
}
@@ -63,17 +63,17 @@ VAddr MemoryBlockManager::FindFreeArea(VAddr region_start, std::size_t region_nu
return {};
}
void MemoryBlockManager::Update(VAddr addr, std::size_t num_pages, MemoryState prev_state,
MemoryPermission prev_perm, MemoryAttribute prev_attribute,
MemoryState state, MemoryPermission perm,
MemoryAttribute attribute) {
void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState prev_state,
KMemoryPermission prev_perm, KMemoryAttribute prev_attribute,
KMemoryState state, KMemoryPermission perm,
KMemoryAttribute attribute) {
const VAddr end_addr{addr + num_pages * PageSize};
iterator node{memory_block_tree.begin()};
prev_attribute |= MemoryAttribute::IpcAndDeviceMapped;
prev_attribute |= KMemoryAttribute::IpcAndDeviceMapped;
while (node != memory_block_tree.end()) {
MemoryBlock* block{&(*node)};
KMemoryBlock* block{&(*node)};
iterator next_node{std::next(node)};
const VAddr cur_addr{block->GetAddress()};
const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr};
@@ -106,13 +106,13 @@ void MemoryBlockManager::Update(VAddr addr, std::size_t num_pages, MemoryState p
}
}
void MemoryBlockManager::Update(VAddr addr, std::size_t num_pages, MemoryState state,
MemoryPermission perm, MemoryAttribute attribute) {
void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState state,
KMemoryPermission perm, KMemoryAttribute attribute) {
const VAddr end_addr{addr + num_pages * PageSize};
iterator node{memory_block_tree.begin()};
while (node != memory_block_tree.end()) {
MemoryBlock* block{&(*node)};
KMemoryBlock* block{&(*node)};
iterator next_node{std::next(node)};
const VAddr cur_addr{block->GetAddress()};
const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr};
@@ -141,13 +141,13 @@ void MemoryBlockManager::Update(VAddr addr, std::size_t num_pages, MemoryState s
}
}
void MemoryBlockManager::UpdateLock(VAddr addr, std::size_t num_pages, LockFunc&& lock_func,
MemoryPermission perm) {
void KMemoryBlockManager::UpdateLock(VAddr addr, std::size_t num_pages, LockFunc&& lock_func,
KMemoryPermission perm) {
const VAddr end_addr{addr + num_pages * PageSize};
iterator node{memory_block_tree.begin()};
while (node != memory_block_tree.end()) {
MemoryBlock* block{&(*node)};
KMemoryBlock* block{&(*node)};
iterator next_node{std::next(node)};
const VAddr cur_addr{block->GetAddress()};
const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr};
@@ -176,9 +176,9 @@ void MemoryBlockManager::UpdateLock(VAddr addr, std::size_t num_pages, LockFunc&
}
}
void MemoryBlockManager::IterateForRange(VAddr start, VAddr end, IterateFunc&& func) {
void KMemoryBlockManager::IterateForRange(VAddr start, VAddr end, IterateFunc&& func) {
const_iterator it{FindIterator(start)};
MemoryInfo info{};
KMemoryInfo info{};
do {
info = it->GetMemoryInfo();
func(info);
@@ -186,8 +186,8 @@ void MemoryBlockManager::IterateForRange(VAddr start, VAddr end, IterateFunc&& f
} while (info.addr + info.size - 1 < end - 1 && it != cend());
}
void MemoryBlockManager::MergeAdjacent(iterator it, iterator& next_it) {
MemoryBlock* block{&(*it)};
void KMemoryBlockManager::MergeAdjacent(iterator it, iterator& next_it) {
KMemoryBlock* block{&(*it)};
auto EraseIt = [&](const iterator it_to_erase) {
if (next_it == it_to_erase) {
@@ -197,7 +197,7 @@ void MemoryBlockManager::MergeAdjacent(iterator it, iterator& next_it) {
};
if (it != memory_block_tree.begin()) {
MemoryBlock* prev{&(*std::prev(it))};
KMemoryBlock* prev{&(*std::prev(it))};
if (block->HasSameProperties(*prev)) {
const iterator prev_it{std::prev(it)};
@@ -211,7 +211,7 @@ void MemoryBlockManager::MergeAdjacent(iterator it, iterator& next_it) {
}
if (it != cend()) {
const MemoryBlock* const next{&(*std::next(it))};
const KMemoryBlock* const next{&(*std::next(it))};
if (block->HasSameProperties(*next)) {
block->Add(next->GetNumPages());
@@ -220,4 +220,4 @@ void MemoryBlockManager::MergeAdjacent(iterator it, iterator& next_it) {
}
}
} // namespace Kernel::Memory
} // namespace Kernel
@@ -8,18 +8,18 @@
#include <list>
#include "common/common_types.h"
#include "core/hle/kernel/memory/memory_block.h"
#include "core/hle/kernel/k_memory_block.h"
namespace Kernel::Memory {
namespace Kernel {
class MemoryBlockManager final {
class KMemoryBlockManager final {
public:
using MemoryBlockTree = std::list<MemoryBlock>;
using MemoryBlockTree = std::list<KMemoryBlock>;
using iterator = MemoryBlockTree::iterator;
using const_iterator = MemoryBlockTree::const_iterator;
public:
MemoryBlockManager(VAddr start_addr, VAddr end_addr);
KMemoryBlockManager(VAddr start_addr, VAddr end_addr);
iterator end() {
return memory_block_tree.end();
@@ -36,21 +36,22 @@ public:
VAddr FindFreeArea(VAddr region_start, std::size_t region_num_pages, std::size_t num_pages,
std::size_t align, std::size_t offset, std::size_t guard_pages);
void Update(VAddr addr, std::size_t num_pages, MemoryState prev_state,
MemoryPermission prev_perm, MemoryAttribute prev_attribute, MemoryState state,
MemoryPermission perm, MemoryAttribute attribute);
void Update(VAddr addr, std::size_t num_pages, KMemoryState prev_state,
KMemoryPermission prev_perm, KMemoryAttribute prev_attribute, KMemoryState state,
KMemoryPermission perm, KMemoryAttribute attribute);
void Update(VAddr addr, std::size_t num_pages, MemoryState state,
MemoryPermission perm = MemoryPermission::None,
MemoryAttribute attribute = MemoryAttribute::None);
void Update(VAddr addr, std::size_t num_pages, KMemoryState state,
KMemoryPermission perm = KMemoryPermission::None,
KMemoryAttribute attribute = KMemoryAttribute::None);
using LockFunc = std::function<void(iterator, MemoryPermission)>;
void UpdateLock(VAddr addr, std::size_t num_pages, LockFunc&& lock_func, MemoryPermission perm);
using LockFunc = std::function<void(iterator, KMemoryPermission)>;
void UpdateLock(VAddr addr, std::size_t num_pages, LockFunc&& lock_func,
KMemoryPermission perm);
using IterateFunc = std::function<void(const MemoryInfo&)>;
using IterateFunc = std::function<void(const KMemoryInfo&)>;
void IterateForRange(VAddr start, VAddr end, IterateFunc&& func);
MemoryBlock& FindBlock(VAddr addr) {
KMemoryBlock& FindBlock(VAddr addr) {
return *FindIterator(addr);
}
@@ -63,4 +64,4 @@ private:
MemoryBlockTree memory_block_tree;
};
} // namespace Kernel::Memory
} // namespace Kernel
@@ -0,0 +1,199 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/alignment.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/kernel/k_system_control.h"
#include "core/hle/kernel/k_trace.h"
namespace Kernel {
namespace {
constexpr size_t CarveoutAlignment = 0x20000;
constexpr size_t CarveoutSizeMax = (512ULL * 1024 * 1024) - CarveoutAlignment;
bool SetupPowerManagementControllerMemoryRegion(KMemoryLayout& memory_layout) {
// Above firmware 2.0.0, the PMC is not mappable.
return memory_layout.GetPhysicalMemoryRegionTree().Insert(
0x7000E000, 0x400, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap) &&
memory_layout.GetPhysicalMemoryRegionTree().Insert(
0x7000E400, 0xC00,
KMemoryRegionType_PowerManagementController | KMemoryRegionAttr_NoUserMap);
}
void InsertPoolPartitionRegionIntoBothTrees(KMemoryLayout& memory_layout, size_t start, size_t size,
KMemoryRegionType phys_type,
KMemoryRegionType virt_type, u32& cur_attr) {
const u32 attr = cur_attr++;
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(start, size,
static_cast<u32>(phys_type), attr));
const KMemoryRegion* phys = memory_layout.GetPhysicalMemoryRegionTree().FindByTypeAndAttribute(
static_cast<u32>(phys_type), attr);
ASSERT(phys != nullptr);
ASSERT(phys->GetEndAddress() != 0);
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(phys->GetPairAddress(), size,
static_cast<u32>(virt_type), attr));
}
} // namespace
namespace Init {
void SetupDevicePhysicalMemoryRegions(KMemoryLayout& memory_layout) {
ASSERT(SetupPowerManagementControllerMemoryRegion(memory_layout));
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
0x70019000, 0x1000, KMemoryRegionType_MemoryController | KMemoryRegionAttr_NoUserMap));
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
0x7001C000, 0x1000, KMemoryRegionType_MemoryController0 | KMemoryRegionAttr_NoUserMap));
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
0x7001D000, 0x1000, KMemoryRegionType_MemoryController1 | KMemoryRegionAttr_NoUserMap));
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
0x50040000, 0x1000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap));
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
0x50041000, 0x1000,
KMemoryRegionType_InterruptDistributor | KMemoryRegionAttr_ShouldKernelMap));
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
0x50042000, 0x1000,
KMemoryRegionType_InterruptCpuInterface | KMemoryRegionAttr_ShouldKernelMap));
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
0x50043000, 0x1D000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap));
// Map IRAM unconditionally, to support debug-logging-to-iram build config.
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
0x40000000, 0x40000, KMemoryRegionType_LegacyLpsIram | KMemoryRegionAttr_ShouldKernelMap));
// Above firmware 2.0.0, prevent mapping the bpmp exception vectors or the ipatch region.
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
0x6000F000, 0x1000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap));
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
0x6001DC00, 0x400, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap));
}
void SetupDramPhysicalMemoryRegions(KMemoryLayout& memory_layout) {
const size_t intended_memory_size = KSystemControl::Init::GetIntendedMemorySize();
const PAddr physical_memory_base_address =
KSystemControl::Init::GetKernelPhysicalBaseAddress(DramPhysicalAddress);
// Insert blocks into the tree.
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
physical_memory_base_address, intended_memory_size, KMemoryRegionType_Dram));
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
physical_memory_base_address, ReservedEarlyDramSize, KMemoryRegionType_DramReservedEarly));
// Insert the KTrace block at the end of Dram, if KTrace is enabled.
static_assert(!IsKTraceEnabled || KTraceBufferSize > 0);
if constexpr (IsKTraceEnabled) {
const PAddr ktrace_buffer_phys_addr =
physical_memory_base_address + intended_memory_size - KTraceBufferSize;
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
ktrace_buffer_phys_addr, KTraceBufferSize, KMemoryRegionType_KernelTraceBuffer));
}
}
void SetupPoolPartitionMemoryRegions(KMemoryLayout& memory_layout) {
// Start by identifying the extents of the DRAM memory region.
const auto dram_extents = memory_layout.GetMainMemoryPhysicalExtents();
ASSERT(dram_extents.GetEndAddress() != 0);
// Determine the end of the pool region.
const u64 pool_end = dram_extents.GetEndAddress() - KTraceBufferSize;
// Find the start of the kernel DRAM region.
const KMemoryRegion* kernel_dram_region =
memory_layout.GetPhysicalMemoryRegionTree().FindFirstDerived(
KMemoryRegionType_DramKernelBase);
ASSERT(kernel_dram_region != nullptr);
const u64 kernel_dram_start = kernel_dram_region->GetAddress();
ASSERT(Common::IsAligned(kernel_dram_start, CarveoutAlignment));
// Find the start of the pool partitions region.
const KMemoryRegion* pool_partitions_region =
memory_layout.GetPhysicalMemoryRegionTree().FindByTypeAndAttribute(
KMemoryRegionType_DramPoolPartition, 0);
ASSERT(pool_partitions_region != nullptr);
const u64 pool_partitions_start = pool_partitions_region->GetAddress();
// Setup the pool partition layouts.
// On 5.0.0+, setup modern 4-pool-partition layout.
// Get Application and Applet pool sizes.
const size_t application_pool_size = KSystemControl::Init::GetApplicationPoolSize();
const size_t applet_pool_size = KSystemControl::Init::GetAppletPoolSize();
const size_t unsafe_system_pool_min_size =
KSystemControl::Init::GetMinimumNonSecureSystemPoolSize();
// Decide on starting addresses for our pools.
const u64 application_pool_start = pool_end - application_pool_size;
const u64 applet_pool_start = application_pool_start - applet_pool_size;
const u64 unsafe_system_pool_start = std::min(
kernel_dram_start + CarveoutSizeMax,
Common::AlignDown(applet_pool_start - unsafe_system_pool_min_size, CarveoutAlignment));
const size_t unsafe_system_pool_size = applet_pool_start - unsafe_system_pool_start;
// We want to arrange application pool depending on where the middle of dram is.
const u64 dram_midpoint = (dram_extents.GetAddress() + dram_extents.GetEndAddress()) / 2;
u32 cur_pool_attr = 0;
size_t total_overhead_size = 0;
if (dram_extents.GetEndAddress() <= dram_midpoint || dram_midpoint <= application_pool_start) {
InsertPoolPartitionRegionIntoBothTrees(
memory_layout, application_pool_start, application_pool_size,
KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool,
cur_pool_attr);
total_overhead_size +=
KMemoryManager::CalculateManagementOverheadSize(application_pool_size);
} else {
const size_t first_application_pool_size = dram_midpoint - application_pool_start;
const size_t second_application_pool_size =
application_pool_start + application_pool_size - dram_midpoint;
InsertPoolPartitionRegionIntoBothTrees(
memory_layout, application_pool_start, first_application_pool_size,
KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool,
cur_pool_attr);
InsertPoolPartitionRegionIntoBothTrees(
memory_layout, dram_midpoint, second_application_pool_size,
KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool,
cur_pool_attr);
total_overhead_size +=
KMemoryManager::CalculateManagementOverheadSize(first_application_pool_size);
total_overhead_size +=
KMemoryManager::CalculateManagementOverheadSize(second_application_pool_size);
}
// Insert the applet pool.
InsertPoolPartitionRegionIntoBothTrees(memory_layout, applet_pool_start, applet_pool_size,
KMemoryRegionType_DramAppletPool,
KMemoryRegionType_VirtualDramAppletPool, cur_pool_attr);
total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(applet_pool_size);
// Insert the nonsecure system pool.
InsertPoolPartitionRegionIntoBothTrees(
memory_layout, unsafe_system_pool_start, unsafe_system_pool_size,
KMemoryRegionType_DramSystemNonSecurePool, KMemoryRegionType_VirtualDramSystemNonSecurePool,
cur_pool_attr);
total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(unsafe_system_pool_size);
// Insert the pool management region.
total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(
(unsafe_system_pool_start - pool_partitions_start) - total_overhead_size);
const u64 pool_management_start = unsafe_system_pool_start - total_overhead_size;
const size_t pool_management_size = total_overhead_size;
u32 pool_management_attr = 0;
InsertPoolPartitionRegionIntoBothTrees(
memory_layout, pool_management_start, pool_management_size,
KMemoryRegionType_DramPoolManagement, KMemoryRegionType_VirtualDramPoolManagement,
pool_management_attr);
// Insert the system pool.
const u64 system_pool_size = pool_management_start - pool_partitions_start;
InsertPoolPartitionRegionIntoBothTrees(memory_layout, pool_partitions_start, system_pool_size,
KMemoryRegionType_DramSystemPool,
KMemoryRegionType_VirtualDramSystemPool, cur_pool_attr);
}
} // namespace Init
} // namespace Kernel
+166
View File
@@ -0,0 +1,166 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <array>
#include "common/alignment.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_system_control.h"
namespace Kernel {
namespace {
template <typename... Args>
KMemoryRegion* AllocateRegion(KMemoryRegionAllocator& memory_region_allocator, Args&&... args) {
return memory_region_allocator.Allocate(std::forward<Args>(args)...);
}
} // namespace
KMemoryRegionTree::KMemoryRegionTree(KMemoryRegionAllocator& memory_region_allocator_)
: memory_region_allocator{memory_region_allocator_} {}
void KMemoryRegionTree::InsertDirectly(u64 address, u64 last_address, u32 attr, u32 type_id) {
this->insert(*AllocateRegion(memory_region_allocator, address, last_address, attr, type_id));
}
bool KMemoryRegionTree::Insert(u64 address, size_t size, u32 type_id, u32 new_attr, u32 old_attr) {
// Locate the memory region that contains the address.
KMemoryRegion* found = this->FindModifiable(address);
// We require that the old attr is correct.
if (found->GetAttributes() != old_attr) {
return false;
}
// We further require that the region can be split from the old region.
const u64 inserted_region_end = address + size;
const u64 inserted_region_last = inserted_region_end - 1;
if (found->GetLastAddress() < inserted_region_last) {
return false;
}
// Further, we require that the type id is a valid transformation.
if (!found->CanDerive(type_id)) {
return false;
}
// Cache information from the region before we remove it.
const u64 old_address = found->GetAddress();
const u64 old_last = found->GetLastAddress();
const u64 old_pair = found->GetPairAddress();
const u32 old_type = found->GetType();
// Erase the existing region from the tree.
this->erase(this->iterator_to(*found));
// Insert the new region into the tree.
if (old_address == address) {
// Reuse the old object for the new region, if we can.
found->Reset(address, inserted_region_last, old_pair, new_attr, type_id);
this->insert(*found);
} else {
// If we can't re-use, adjust the old region.
found->Reset(old_address, address - 1, old_pair, old_attr, old_type);
this->insert(*found);
// Insert a new region for the split.
const u64 new_pair = (old_pair != std::numeric_limits<u64>::max())
? old_pair + (address - old_address)
: old_pair;
this->insert(*AllocateRegion(memory_region_allocator, address, inserted_region_last,
new_pair, new_attr, type_id));
}
// If we need to insert a region after the region, do so.
if (old_last != inserted_region_last) {
const u64 after_pair = (old_pair != std::numeric_limits<u64>::max())
? old_pair + (inserted_region_end - old_address)
: old_pair;
this->insert(*AllocateRegion(memory_region_allocator, inserted_region_end, old_last,
after_pair, old_attr, old_type));
}
return true;
}
VAddr KMemoryRegionTree::GetRandomAlignedRegion(size_t size, size_t alignment, u32 type_id) {
// We want to find the total extents of the type id.
const auto extents = this->GetDerivedRegionExtents(static_cast<KMemoryRegionType>(type_id));
// Ensure that our alignment is correct.
ASSERT(Common::IsAligned(extents.GetAddress(), alignment));
const u64 first_address = extents.GetAddress();
const u64 last_address = extents.GetLastAddress();
const u64 first_index = first_address / alignment;
const u64 last_index = last_address / alignment;
while (true) {
const u64 candidate =
KSystemControl::GenerateRandomRange(first_index, last_index) * alignment;
// Ensure that the candidate doesn't overflow with the size.
if (!(candidate < candidate + size)) {
continue;
}
const u64 candidate_last = candidate + size - 1;
// Ensure that the candidate fits within the region.
if (candidate_last > last_address) {
continue;
}
// Locate the candidate region, and ensure it fits and has the correct type id.
if (const auto& candidate_region = *this->Find(candidate);
!(candidate_last <= candidate_region.GetLastAddress() &&
candidate_region.GetType() == type_id)) {
continue;
}
return candidate;
}
}
KMemoryLayout::KMemoryLayout()
: virtual_tree{memory_region_allocator}, physical_tree{memory_region_allocator},
virtual_linear_tree{memory_region_allocator}, physical_linear_tree{memory_region_allocator} {}
void KMemoryLayout::InitializeLinearMemoryRegionTrees(PAddr aligned_linear_phys_start,
VAddr linear_virtual_start) {
// Set static differences.
linear_phys_to_virt_diff = linear_virtual_start - aligned_linear_phys_start;
linear_virt_to_phys_diff = aligned_linear_phys_start - linear_virtual_start;
// Initialize linear trees.
for (auto& region : GetPhysicalMemoryRegionTree()) {
if (region.HasTypeAttribute(KMemoryRegionAttr_LinearMapped)) {
GetPhysicalLinearMemoryRegionTree().InsertDirectly(
region.GetAddress(), region.GetLastAddress(), region.GetAttributes(),
region.GetType());
}
}
for (auto& region : GetVirtualMemoryRegionTree()) {
if (region.IsDerivedFrom(KMemoryRegionType_Dram)) {
GetVirtualLinearMemoryRegionTree().InsertDirectly(
region.GetAddress(), region.GetLastAddress(), region.GetAttributes(),
region.GetType());
}
}
}
size_t KMemoryLayout::GetResourceRegionSizeForInit() {
// Calculate resource region size based on whether we allow extra threads.
const bool use_extra_resources = KSystemControl::Init::ShouldIncreaseThreadResourceLimit();
size_t resource_region_size =
KernelResourceSize + (use_extra_resources ? KernelSlabHeapAdditionalSize : 0);
return resource_region_size;
}
} // namespace Kernel
+399
View File
@@ -0,0 +1,399 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <utility>
#include "common/alignment.h"
#include "common/common_sizes.h"
#include "common/common_types.h"
#include "core/device_memory.h"
#include "core/hle/kernel/k_memory_region.h"
#include "core/hle/kernel/k_memory_region_type.h"
#include "core/hle/kernel/memory_types.h"
namespace Kernel {
constexpr std::size_t L1BlockSize = Common::Size_1_GB;
constexpr std::size_t L2BlockSize = Common::Size_2_MB;
constexpr std::size_t GetMaximumOverheadSize(std::size_t size) {
return (Common::DivideUp(size, L1BlockSize) + Common::DivideUp(size, L2BlockSize)) * PageSize;
}
constexpr std::size_t MainMemorySize = Common::Size_4_GB;
constexpr std::size_t MainMemorySizeMax = Common::Size_8_GB;
constexpr std::size_t ReservedEarlyDramSize = 0x60000;
constexpr std::size_t DramPhysicalAddress = 0x80000000;
constexpr std::size_t KernelAslrAlignment = Common::Size_2_MB;
constexpr std::size_t KernelVirtualAddressSpaceWidth = 1ULL << 39;
constexpr std::size_t KernelPhysicalAddressSpaceWidth = 1ULL << 48;
constexpr std::size_t KernelVirtualAddressSpaceBase = 0ULL - KernelVirtualAddressSpaceWidth;
constexpr std::size_t KernelVirtualAddressSpaceEnd =
KernelVirtualAddressSpaceBase + (KernelVirtualAddressSpaceWidth - KernelAslrAlignment);
constexpr std::size_t KernelVirtualAddressSpaceLast = KernelVirtualAddressSpaceEnd - 1ULL;
constexpr std::size_t KernelVirtualAddressSpaceSize =
KernelVirtualAddressSpaceEnd - KernelVirtualAddressSpaceBase;
constexpr std::size_t KernelVirtualAddressCodeBase = KernelVirtualAddressSpaceBase;
constexpr std::size_t KernelVirtualAddressCodeSize = 0x62000;
constexpr std::size_t KernelVirtualAddressCodeEnd =
KernelVirtualAddressCodeBase + KernelVirtualAddressCodeSize;
constexpr std::size_t KernelPhysicalAddressSpaceBase = 0ULL;
constexpr std::size_t KernelPhysicalAddressSpaceEnd =
KernelPhysicalAddressSpaceBase + KernelPhysicalAddressSpaceWidth;
constexpr std::size_t KernelPhysicalAddressSpaceLast = KernelPhysicalAddressSpaceEnd - 1ULL;
constexpr std::size_t KernelPhysicalAddressSpaceSize =
KernelPhysicalAddressSpaceEnd - KernelPhysicalAddressSpaceBase;
constexpr std::size_t KernelPhysicalAddressCodeBase = DramPhysicalAddress + ReservedEarlyDramSize;
constexpr std::size_t KernelPageTableHeapSize = GetMaximumOverheadSize(MainMemorySizeMax);
constexpr std::size_t KernelInitialPageHeapSize = Common::Size_128_KB;
constexpr std::size_t KernelSlabHeapDataSize = Common::Size_5_MB;
constexpr std::size_t KernelSlabHeapGapsSize = Common::Size_2_MB - Common::Size_64_KB;
constexpr std::size_t KernelSlabHeapSize = KernelSlabHeapDataSize + KernelSlabHeapGapsSize;
// NOTE: This is calculated from KThread slab counts, assuming KThread size <= 0x860.
constexpr std::size_t KernelSlabHeapAdditionalSize = 0x68000ULL;
constexpr std::size_t KernelResourceSize =
KernelPageTableHeapSize + KernelInitialPageHeapSize + KernelSlabHeapSize;
constexpr bool IsKernelAddressKey(VAddr key) {
return KernelVirtualAddressSpaceBase <= key && key <= KernelVirtualAddressSpaceLast;
}
constexpr bool IsKernelAddress(VAddr address) {
return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd;
}
class KMemoryLayout final {
public:
KMemoryLayout();
KMemoryRegionTree& GetVirtualMemoryRegionTree() {
return virtual_tree;
}
const KMemoryRegionTree& GetVirtualMemoryRegionTree() const {
return virtual_tree;
}
KMemoryRegionTree& GetPhysicalMemoryRegionTree() {
return physical_tree;
}
const KMemoryRegionTree& GetPhysicalMemoryRegionTree() const {
return physical_tree;
}
KMemoryRegionTree& GetVirtualLinearMemoryRegionTree() {
return virtual_linear_tree;
}
const KMemoryRegionTree& GetVirtualLinearMemoryRegionTree() const {
return virtual_linear_tree;
}
KMemoryRegionTree& GetPhysicalLinearMemoryRegionTree() {
return physical_linear_tree;
}
const KMemoryRegionTree& GetPhysicalLinearMemoryRegionTree() const {
return physical_linear_tree;
}
VAddr GetLinearVirtualAddress(PAddr address) const {
return address + linear_phys_to_virt_diff;
}
PAddr GetLinearPhysicalAddress(VAddr address) const {
return address + linear_virt_to_phys_diff;
}
const KMemoryRegion* FindVirtual(VAddr address) const {
return Find(address, GetVirtualMemoryRegionTree());
}
const KMemoryRegion* FindPhysical(PAddr address) const {
return Find(address, GetPhysicalMemoryRegionTree());
}
const KMemoryRegion* FindVirtualLinear(VAddr address) const {
return Find(address, GetVirtualLinearMemoryRegionTree());
}
const KMemoryRegion* FindPhysicalLinear(PAddr address) const {
return Find(address, GetPhysicalLinearMemoryRegionTree());
}
VAddr GetMainStackTopAddress(s32 core_id) const {
return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscMainStack);
}
VAddr GetIdleStackTopAddress(s32 core_id) const {
return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscIdleStack);
}
VAddr GetExceptionStackTopAddress(s32 core_id) const {
return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscExceptionStack);
}
VAddr GetSlabRegionAddress() const {
return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelSlab))
.GetAddress();
}
const KMemoryRegion& GetDeviceRegion(KMemoryRegionType type) const {
return Dereference(GetPhysicalMemoryRegionTree().FindFirstDerived(type));
}
PAddr GetDevicePhysicalAddress(KMemoryRegionType type) const {
return GetDeviceRegion(type).GetAddress();
}
VAddr GetDeviceVirtualAddress(KMemoryRegionType type) const {
return GetDeviceRegion(type).GetPairAddress();
}
const KMemoryRegion& GetPoolManagementRegion() const {
return Dereference(
GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_VirtualDramPoolManagement));
}
const KMemoryRegion& GetPageTableHeapRegion() const {
return Dereference(
GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_VirtualDramKernelPtHeap));
}
const KMemoryRegion& GetKernelStackRegion() const {
return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelStack));
}
const KMemoryRegion& GetTempRegion() const {
return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelTemp));
}
const KMemoryRegion& GetKernelTraceBufferRegion() const {
return Dereference(GetVirtualLinearMemoryRegionTree().FindByType(
KMemoryRegionType_VirtualDramKernelTraceBuffer));
}
const KMemoryRegion& GetVirtualLinearRegion(VAddr address) const {
return Dereference(FindVirtualLinear(address));
}
const KMemoryRegion* GetPhysicalKernelTraceBufferRegion() const {
return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_KernelTraceBuffer);
}
const KMemoryRegion* GetPhysicalOnMemoryBootImageRegion() const {
return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_OnMemoryBootImage);
}
const KMemoryRegion* GetPhysicalDTBRegion() const {
return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_DTB);
}
bool IsHeapPhysicalAddress(const KMemoryRegion*& region, PAddr address) const {
return IsTypedAddress(region, address, GetPhysicalLinearMemoryRegionTree(),
KMemoryRegionType_DramUserPool);
}
bool IsHeapVirtualAddress(const KMemoryRegion*& region, VAddr address) const {
return IsTypedAddress(region, address, GetVirtualLinearMemoryRegionTree(),
KMemoryRegionType_VirtualDramUserPool);
}
bool IsHeapPhysicalAddress(const KMemoryRegion*& region, PAddr address, size_t size) const {
return IsTypedAddress(region, address, size, GetPhysicalLinearMemoryRegionTree(),
KMemoryRegionType_DramUserPool);
}
bool IsHeapVirtualAddress(const KMemoryRegion*& region, VAddr address, size_t size) const {
return IsTypedAddress(region, address, size, GetVirtualLinearMemoryRegionTree(),
KMemoryRegionType_VirtualDramUserPool);
}
bool IsLinearMappedPhysicalAddress(const KMemoryRegion*& region, PAddr address) const {
return IsTypedAddress(region, address, GetPhysicalLinearMemoryRegionTree(),
static_cast<KMemoryRegionType>(KMemoryRegionAttr_LinearMapped));
}
bool IsLinearMappedPhysicalAddress(const KMemoryRegion*& region, PAddr address,
size_t size) const {
return IsTypedAddress(region, address, size, GetPhysicalLinearMemoryRegionTree(),
static_cast<KMemoryRegionType>(KMemoryRegionAttr_LinearMapped));
}
std::pair<size_t, size_t> GetTotalAndKernelMemorySizes() const {
size_t total_size = 0, kernel_size = 0;
for (const auto& region : GetPhysicalMemoryRegionTree()) {
if (region.IsDerivedFrom(KMemoryRegionType_Dram)) {
total_size += region.GetSize();
if (!region.IsDerivedFrom(KMemoryRegionType_DramUserPool)) {
kernel_size += region.GetSize();
}
}
}
return std::make_pair(total_size, kernel_size);
}
void InitializeLinearMemoryRegionTrees(PAddr aligned_linear_phys_start,
VAddr linear_virtual_start);
static size_t GetResourceRegionSizeForInit();
auto GetKernelRegionExtents() const {
return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_Kernel);
}
auto GetKernelCodeRegionExtents() const {
return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelCode);
}
auto GetKernelStackRegionExtents() const {
return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelStack);
}
auto GetKernelMiscRegionExtents() const {
return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelMisc);
}
auto GetKernelSlabRegionExtents() const {
return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelSlab);
}
auto GetLinearRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionAttr_LinearMapped);
}
auto GetLinearRegionVirtualExtents() const {
const auto physical = GetLinearRegionPhysicalExtents();
return KMemoryRegion(GetLinearVirtualAddress(physical.GetAddress()),
GetLinearVirtualAddress(physical.GetLastAddress()), 0,
KMemoryRegionType_None);
}
auto GetMainMemoryPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_Dram);
}
auto GetCarveoutRegionExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionAttr_CarveoutProtected);
}
auto GetKernelRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramKernelBase);
}
auto GetKernelCodeRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramKernelCode);
}
auto GetKernelSlabRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramKernelSlab);
}
auto GetKernelPageTableHeapRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramKernelPtHeap);
}
auto GetKernelInitPageTableRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramKernelInitPt);
}
auto GetKernelPoolManagementRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramPoolManagement);
}
auto GetKernelPoolPartitionRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramPoolPartition);
}
auto GetKernelSystemPoolRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramSystemPool);
}
auto GetKernelSystemNonSecurePoolRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramSystemNonSecurePool);
}
auto GetKernelAppletPoolRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramAppletPool);
}
auto GetKernelApplicationPoolRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramApplicationPool);
}
auto GetKernelTraceBufferRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_KernelTraceBuffer);
}
private:
template <typename AddressType>
static bool IsTypedAddress(const KMemoryRegion*& region, AddressType address,
const KMemoryRegionTree& tree, KMemoryRegionType type) {
// Check if the cached region already contains the address.
if (region != nullptr && region->Contains(address)) {
return true;
}
// Find the containing region, and update the cache.
if (const KMemoryRegion* found = tree.Find(address);
found != nullptr && found->IsDerivedFrom(type)) {
region = found;
return true;
} else {
return false;
}
}
template <typename AddressType>
static bool IsTypedAddress(const KMemoryRegion*& region, AddressType address, size_t size,
const KMemoryRegionTree& tree, KMemoryRegionType type) {
// Get the end of the checked region.
const u64 last_address = address + size - 1;
// Walk the tree to verify the region is correct.
const KMemoryRegion* cur =
(region != nullptr && region->Contains(address)) ? region : tree.Find(address);
while (cur != nullptr && cur->IsDerivedFrom(type)) {
if (last_address <= cur->GetLastAddress()) {
region = cur;
return true;
}
cur = cur->GetNext();
}
return false;
}
template <typename AddressType>
static const KMemoryRegion* Find(AddressType address, const KMemoryRegionTree& tree) {
return tree.Find(address);
}
static KMemoryRegion& Dereference(KMemoryRegion* region) {
ASSERT(region != nullptr);
return *region;
}
static const KMemoryRegion& Dereference(const KMemoryRegion* region) {
ASSERT(region != nullptr);
return *region;
}
VAddr GetStackTopAddress(s32 core_id, KMemoryRegionType type) const {
const auto& region = Dereference(
GetVirtualMemoryRegionTree().FindByTypeAndAttribute(type, static_cast<u32>(core_id)));
ASSERT(region.GetEndAddress() != 0);
return region.GetEndAddress();
}
private:
u64 linear_phys_to_virt_diff{};
u64 linear_virt_to_phys_diff{};
KMemoryRegionAllocator memory_region_allocator;
KMemoryRegionTree virtual_tree;
KMemoryRegionTree physical_tree;
KMemoryRegionTree virtual_linear_tree;
KMemoryRegionTree physical_linear_tree;
};
namespace Init {
// These should be generic, regardless of board.
void SetupPoolPartitionMemoryRegions(KMemoryLayout& memory_layout);
// These may be implemented in a board-specific manner.
void SetupDevicePhysicalMemoryRegions(KMemoryLayout& memory_layout);
void SetupDramPhysicalMemoryRegions(KMemoryLayout& memory_layout);
} // namespace Init
} // namespace Kernel
@@ -8,20 +8,20 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "common/scope_exit.h"
#include "core/hle/kernel/memory/memory_manager.h"
#include "core/hle/kernel/memory/page_linked_list.h"
#include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/kernel/k_page_linked_list.h"
#include "core/hle/kernel/svc_results.h"
namespace Kernel::Memory {
namespace Kernel {
std::size_t MemoryManager::Impl::Initialize(Pool new_pool, u64 start_address, u64 end_address) {
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{PageHeap::CalculateMetadataOverheadSize(size)};
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));
@@ -41,29 +41,30 @@ std::size_t MemoryManager::Impl::Initialize(Pool new_pool, u64 start_address, u6
return total_metadata_size;
}
void MemoryManager::InitializeManager(Pool pool, u64 start_address, u64 end_address) {
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);
}
VAddr MemoryManager::AllocateContinuous(std::size_t num_pages, std::size_t align_pages, Pool pool,
Direction dir) {
VAddr KMemoryManager::AllocateAndOpenContinuous(std::size_t num_pages, std::size_t align_pages,
u32 option) {
// Early return if we're allocating no pages
if (num_pages == 0) {
return {};
}
// 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]};
// Choose a heap based on our page size request
const s32 heap_index{PageHeap::GetAlignedBlockIndex(num_pages, align_pages)};
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)};
VAddr allocated_block{chosen_manager.AllocateBlock(heap_index, false)};
// If we failed to allocate, quit now
if (!allocated_block) {
@@ -71,7 +72,7 @@ VAddr MemoryManager::AllocateContinuous(std::size_t num_pages, std::size_t align
}
// If we allocated more than we need, free some
const auto allocated_pages{PageHeap::GetBlockNumPages(heap_index)};
const auto allocated_pages{KPageHeap::GetBlockNumPages(heap_index)};
if (allocated_pages > num_pages) {
chosen_manager.Free(allocated_block + num_pages * PageSize, allocated_pages - num_pages);
}
@@ -79,8 +80,8 @@ VAddr MemoryManager::AllocateContinuous(std::size_t num_pages, std::size_t align
return allocated_block;
}
ResultCode MemoryManager::Allocate(PageLinkedList& page_list, std::size_t num_pages, Pool pool,
Direction dir) {
ResultCode KMemoryManager::Allocate(KPageLinkedList& page_list, std::size_t num_pages, Pool pool,
Direction dir) {
ASSERT(page_list.GetNumPages() == 0);
// Early return if we're allocating no pages
@@ -93,7 +94,7 @@ ResultCode MemoryManager::Allocate(PageLinkedList& page_list, std::size_t num_pa
std::lock_guard lock{pool_locks[pool_index]};
// Choose a heap based on our page size request
const s32 heap_index{PageHeap::GetBlockIndex(num_pages)};
const s32 heap_index{KPageHeap::GetBlockIndex(num_pages)};
if (heap_index < 0) {
return ResultOutOfMemory;
}
@@ -112,11 +113,11 @@ ResultCode MemoryManager::Allocate(PageLinkedList& page_list, std::size_t num_pa
// 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{PageHeap::GetBlockNumPages(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)};
VAddr allocated_block{chosen_manager.AllocateBlock(index, false)};
if (!allocated_block) {
break;
}
@@ -148,8 +149,8 @@ ResultCode MemoryManager::Allocate(PageLinkedList& page_list, std::size_t num_pa
return RESULT_SUCCESS;
}
ResultCode MemoryManager::Free(PageLinkedList& page_list, std::size_t num_pages, Pool pool,
Direction dir) {
ResultCode KMemoryManager::Free(KPageLinkedList& page_list, std::size_t num_pages, Pool pool,
Direction dir) {
// Early return if we're freeing no pages
if (!num_pages) {
return RESULT_SUCCESS;
@@ -172,4 +173,16 @@ ResultCode MemoryManager::Free(PageLinkedList& page_list, std::size_t num_pages,
return RESULT_SUCCESS;
}
} // namespace Kernel::Memory
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 =
(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);
return manager_meta_size + page_heap_size;
}
} // namespace Kernel
+137
View File
@@ -0,0 +1,137 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <mutex>
#include <tuple>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hle/kernel/k_page_heap.h"
#include "core/hle/result.h"
namespace Kernel {
class KPageLinkedList;
class KMemoryManager final : NonCopyable {
public:
enum class Pool : u32 {
Application = 0,
Applet = 1,
System = 2,
SystemNonSecure = 3,
Count,
Shift = 4,
Mask = (0xF << Shift),
// Aliases.
Unsafe = Application,
Secure = System,
};
enum class Direction : u32 {
FromFront = 0,
FromBack = 1,
Shift = 0,
Mask = (0xF << Shift),
};
KMemoryManager() = default;
constexpr std::size_t GetSize(Pool pool) const {
return managers[static_cast<std::size_t>(pool)].GetSize();
}
void InitializeManager(Pool pool, u64 start_address, u64 end_address);
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 = Direction::FromFront);
ResultCode Free(KPageLinkedList& page_list, std::size_t num_pages, Pool pool,
Direction dir = Direction::FromFront);
static constexpr std::size_t MaxManagerCount = 10;
public:
static std::size_t CalculateManagementOverheadSize(std::size_t region_size) {
return Impl::CalculateManagementOverheadSize(region_size);
}
static constexpr u32 EncodeOption(Pool pool, Direction dir) {
return (static_cast<u32>(pool) << static_cast<u32>(Pool::Shift)) |
(static_cast<u32>(dir) << static_cast<u32>(Direction::Shift));
}
static constexpr Pool GetPool(u32 option) {
return static_cast<Pool>((static_cast<u32>(option) & static_cast<u32>(Pool::Mask)) >>
static_cast<u32>(Pool::Shift));
}
static constexpr Direction GetDirection(u32 option) {
return static_cast<Direction>(
(static_cast<u32>(option) & static_cast<u32>(Direction::Mask)) >>
static_cast<u32>(Direction::Shift));
}
static constexpr std::tuple<Pool, Direction> DecodeOption(u32 option) {
return std::make_tuple(GetPool(option), GetDirection(option));
}
private:
class Impl final : NonCopyable {
private:
using RefCount = u16;
private:
KPageHeap heap;
Pool pool{};
public:
static std::size_t CalculateManagementOverheadSize(std::size_t region_size);
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;
std::size_t Initialize(Pool new_pool, u64 start_address, u64 end_address);
VAddr AllocateBlock(s32 index, bool random) {
return heap.AllocateBlock(index, random);
}
void Free(VAddr addr, std::size_t num_pages) {
heap.Free(addr, num_pages);
}
constexpr std::size_t GetSize() const {
return heap.GetSize();
}
constexpr VAddr GetAddress() const {
return heap.GetAddress();
}
constexpr VAddr GetEndAddress() const {
return heap.GetEndAddress();
}
};
private:
std::array<std::mutex, static_cast<std::size_t>(Pool::Count)> pool_locks;
std::array<Impl, MaxManagerCount> managers;
};
} // namespace Kernel
+350
View File
@@ -0,0 +1,350 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/assert.h"
#include "common/common_types.h"
#include "common/intrusive_red_black_tree.h"
#include "core/hle/kernel/k_memory_region_type.h"
namespace Kernel {
class KMemoryRegionAllocator;
class KMemoryRegion final : public Common::IntrusiveRedBlackTreeBaseNode<KMemoryRegion>,
NonCopyable {
friend class KMemoryRegionTree;
public:
constexpr KMemoryRegion() = default;
constexpr KMemoryRegion(u64 address_, u64 last_address_)
: address{address_}, last_address{last_address_} {}
constexpr KMemoryRegion(u64 address_, u64 last_address_, u64 pair_address_, u32 attributes_,
u32 type_id_)
: address(address_), last_address(last_address_), pair_address(pair_address_),
attributes(attributes_), type_id(type_id_) {}
constexpr KMemoryRegion(u64 address_, u64 last_address_, u32 attributes_, u32 type_id_)
: KMemoryRegion(address_, last_address_, std::numeric_limits<u64>::max(), attributes_,
type_id_) {}
static constexpr int Compare(const KMemoryRegion& lhs, const KMemoryRegion& rhs) {
if (lhs.GetAddress() < rhs.GetAddress()) {
return -1;
} else if (lhs.GetAddress() <= rhs.GetLastAddress()) {
return 0;
} else {
return 1;
}
}
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;
}
constexpr u64 GetPairAddress() const {
return pair_address;
}
constexpr u64 GetLastAddress() const {
return last_address;
}
constexpr u64 GetEndAddress() const {
return this->GetLastAddress() + 1;
}
constexpr size_t GetSize() const {
return this->GetEndAddress() - this->GetAddress();
}
constexpr u32 GetAttributes() const {
return attributes;
}
constexpr u32 GetType() const {
return type_id;
}
constexpr void SetType(u32 type) {
ASSERT(this->CanDerive(type));
type_id = type;
}
constexpr bool Contains(u64 address) const {
ASSERT(this->GetEndAddress() != 0);
return this->GetAddress() <= address && address <= this->GetLastAddress();
}
constexpr bool IsDerivedFrom(u32 type) const {
return (this->GetType() | type) == this->GetType();
}
constexpr bool HasTypeAttribute(u32 attr) const {
return (this->GetType() | attr) == this->GetType();
}
constexpr bool CanDerive(u32 type) const {
return (this->GetType() | type) == type;
}
constexpr void SetPairAddress(u64 a) {
pair_address = a;
}
constexpr void SetTypeAttribute(u32 attr) {
type_id |= attr;
}
private:
u64 address{};
u64 last_address{};
u64 pair_address{};
u32 attributes{};
u32 type_id{};
};
class KMemoryRegionTree final : NonCopyable {
public:
struct DerivedRegionExtents {
const KMemoryRegion* first_region{};
const KMemoryRegion* last_region{};
constexpr DerivedRegionExtents() = default;
constexpr u64 GetAddress() const {
return this->first_region->GetAddress();
}
constexpr u64 GetLastAddress() const {
return this->last_region->GetLastAddress();
}
constexpr u64 GetEndAddress() const {
return this->GetLastAddress() + 1;
}
constexpr size_t GetSize() const {
return this->GetEndAddress() - this->GetAddress();
}
};
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_);
public:
KMemoryRegion* FindModifiable(u64 address) {
if (auto it = this->find(KMemoryRegion(address, address, 0, 0)); it != this->end()) {
return std::addressof(*it);
} else {
return nullptr;
}
}
const KMemoryRegion* Find(u64 address) const {
if (auto it = this->find(KMemoryRegion(address, address, 0, 0)); it != this->cend()) {
return std::addressof(*it);
} else {
return nullptr;
}
}
const KMemoryRegion* FindByType(KMemoryRegionType type_id) const {
for (auto it = this->cbegin(); it != this->cend(); ++it) {
if (it->GetType() == static_cast<u32>(type_id)) {
return std::addressof(*it);
}
}
return nullptr;
}
const KMemoryRegion* FindByTypeAndAttribute(u32 type_id, u32 attr) const {
for (auto it = this->cbegin(); it != this->cend(); ++it) {
if (it->GetType() == type_id && it->GetAttributes() == attr) {
return std::addressof(*it);
}
}
return nullptr;
}
const KMemoryRegion* FindFirstDerived(KMemoryRegionType type_id) const {
for (auto it = this->cbegin(); it != this->cend(); it++) {
if (it->IsDerivedFrom(type_id)) {
return std::addressof(*it);
}
}
return nullptr;
}
const KMemoryRegion* FindLastDerived(KMemoryRegionType type_id) const {
const KMemoryRegion* region = nullptr;
for (auto it = this->begin(); it != this->end(); it++) {
if (it->IsDerivedFrom(type_id)) {
region = std::addressof(*it);
}
}
return region;
}
DerivedRegionExtents GetDerivedRegionExtents(KMemoryRegionType type_id) const {
DerivedRegionExtents extents;
ASSERT(extents.first_region == nullptr);
ASSERT(extents.last_region == nullptr);
for (auto it = this->cbegin(); it != this->cend(); it++) {
if (it->IsDerivedFrom(type_id)) {
if (extents.first_region == nullptr) {
extents.first_region = std::addressof(*it);
}
extents.last_region = std::addressof(*it);
}
}
ASSERT(extents.first_region != nullptr);
ASSERT(extents.last_region != nullptr);
return extents;
}
DerivedRegionExtents GetDerivedRegionExtents(u32 type_id) const {
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);
VAddr GetRandomAlignedRegion(size_t size, size_t alignment, u32 type_id);
VAddr GetRandomAlignedRegionWithGuard(size_t size, size_t alignment, u32 type_id,
size_t guard_size) {
return this->GetRandomAlignedRegion(size + 2 * guard_size, alignment, type_id) + guard_size;
}
public:
// Iterator accessors.
iterator begin() {
return m_tree.begin();
}
const_iterator begin() const {
return m_tree.begin();
}
iterator end() {
return m_tree.end();
}
const_iterator end() const {
return m_tree.end();
}
const_iterator cbegin() const {
return this->begin();
}
const_iterator cend() const {
return this->end();
}
iterator iterator_to(reference ref) {
return m_tree.iterator_to(ref);
}
const_iterator iterator_to(const_reference ref) const {
return m_tree.iterator_to(ref);
}
// Content management.
bool empty() const {
return m_tree.empty();
}
reference back() {
return m_tree.back();
}
const_reference back() const {
return m_tree.back();
}
reference front() {
return m_tree.front();
}
const_reference front() const {
return m_tree.front();
}
iterator insert(reference ref) {
return m_tree.insert(ref);
}
iterator erase(iterator it) {
return m_tree.erase(it);
}
iterator find(const_reference ref) const {
return m_tree.find(ref);
}
iterator nfind(const_reference ref) const {
return m_tree.nfind(ref);
}
};
class KMemoryRegionAllocator final : NonCopyable {
public:
static constexpr size_t MaxMemoryRegions = 200;
constexpr KMemoryRegionAllocator() = default;
template <typename... Args>
KMemoryRegion* Allocate(Args&&... args) {
// Ensure we stay within the bounds of our heap.
ASSERT(this->num_regions < MaxMemoryRegions);
// Create the new region.
KMemoryRegion* region = std::addressof(this->region_heap[this->num_regions++]);
new (region) KMemoryRegion(std::forward<Args>(args)...);
return region;
}
private:
std::array<KMemoryRegion, MaxMemoryRegions> region_heap{};
size_t num_regions{};
};
} // namespace Kernel
+338
View File
@@ -0,0 +1,338 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/bit_util.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#define ARCH_ARM64
#define BOARD_NINTENDO_NX
namespace Kernel {
enum KMemoryRegionType : u32 {
KMemoryRegionAttr_CarveoutProtected = 0x04000000,
KMemoryRegionAttr_DidKernelMap = 0x08000000,
KMemoryRegionAttr_ShouldKernelMap = 0x10000000,
KMemoryRegionAttr_UserReadOnly = 0x20000000,
KMemoryRegionAttr_NoUserMap = 0x40000000,
KMemoryRegionAttr_LinearMapped = 0x80000000,
};
DECLARE_ENUM_FLAG_OPERATORS(KMemoryRegionType);
namespace impl {
constexpr size_t BitsForDeriveSparse(size_t n) {
return n + 1;
}
constexpr size_t BitsForDeriveDense(size_t n) {
size_t low = 0, high = 1;
for (size_t i = 0; i < n - 1; ++i) {
if ((++low) == high) {
++high;
low = 0;
}
}
return high + 1;
}
class KMemoryRegionTypeValue {
public:
using ValueType = std::underlying_type_t<KMemoryRegionType>;
constexpr KMemoryRegionTypeValue() = default;
constexpr operator KMemoryRegionType() const {
return static_cast<KMemoryRegionType>(m_value);
}
constexpr ValueType GetValue() const {
return m_value;
}
constexpr const KMemoryRegionTypeValue& Finalize() {
m_finalized = true;
return *this;
}
constexpr const KMemoryRegionTypeValue& SetSparseOnly() {
m_sparse_only = true;
return *this;
}
constexpr const KMemoryRegionTypeValue& SetDenseOnly() {
m_dense_only = true;
return *this;
}
constexpr KMemoryRegionTypeValue& SetAttribute(u32 attr) {
m_value |= attr;
return *this;
}
constexpr KMemoryRegionTypeValue DeriveInitial(
size_t i, size_t next = Common::BitSize<ValueType>()) const {
KMemoryRegionTypeValue new_type = *this;
new_type.m_value = (ValueType{1} << i);
new_type.m_next_bit = next;
return new_type;
}
constexpr KMemoryRegionTypeValue DeriveAttribute(u32 attr) const {
KMemoryRegionTypeValue new_type = *this;
new_type.m_value |= attr;
return new_type;
}
constexpr KMemoryRegionTypeValue DeriveTransition(size_t ofs = 0, size_t adv = 1) const {
KMemoryRegionTypeValue new_type = *this;
new_type.m_value |= (ValueType{1} << (m_next_bit + ofs));
new_type.m_next_bit += adv;
return new_type;
}
constexpr KMemoryRegionTypeValue DeriveSparse(size_t ofs, size_t n, size_t i) const {
KMemoryRegionTypeValue new_type = *this;
new_type.m_value |= (ValueType{1} << (m_next_bit + ofs));
new_type.m_value |= (ValueType{1} << (m_next_bit + ofs + 1 + i));
new_type.m_next_bit += ofs + n + 1;
return new_type;
}
constexpr KMemoryRegionTypeValue Derive(size_t n, size_t i) const {
size_t low = 0, high = 1;
for (size_t j = 0; j < i; ++j) {
if ((++low) == high) {
++high;
low = 0;
}
}
KMemoryRegionTypeValue new_type = *this;
new_type.m_value |= (ValueType{1} << (m_next_bit + low));
new_type.m_value |= (ValueType{1} << (m_next_bit + high));
new_type.m_next_bit += BitsForDeriveDense(n);
return new_type;
}
constexpr KMemoryRegionTypeValue Advance(size_t n) const {
KMemoryRegionTypeValue new_type = *this;
new_type.m_next_bit += n;
return new_type;
}
constexpr bool IsAncestorOf(ValueType v) const {
return (m_value | v) == v;
}
private:
constexpr KMemoryRegionTypeValue(ValueType v) : m_value(v) {}
private:
ValueType m_value{};
size_t m_next_bit{};
bool m_finalized{};
bool m_sparse_only{};
bool m_dense_only{};
};
} // namespace impl
constexpr auto KMemoryRegionType_None = impl::KMemoryRegionTypeValue();
constexpr auto KMemoryRegionType_Kernel = KMemoryRegionType_None.DeriveInitial(0, 2);
constexpr auto KMemoryRegionType_Dram = KMemoryRegionType_None.DeriveInitial(1, 2);
static_assert(KMemoryRegionType_Kernel.GetValue() == 0x1);
static_assert(KMemoryRegionType_Dram.GetValue() == 0x2);
constexpr auto KMemoryRegionType_DramKernelBase =
KMemoryRegionType_Dram.DeriveSparse(0, 3, 0)
.SetAttribute(KMemoryRegionAttr_NoUserMap)
.SetAttribute(KMemoryRegionAttr_CarveoutProtected);
constexpr auto KMemoryRegionType_DramReservedBase = KMemoryRegionType_Dram.DeriveSparse(0, 3, 1);
constexpr auto KMemoryRegionType_DramHeapBase =
KMemoryRegionType_Dram.DeriveSparse(0, 3, 2).SetAttribute(KMemoryRegionAttr_LinearMapped);
static_assert(KMemoryRegionType_DramKernelBase.GetValue() ==
(0xE | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap));
static_assert(KMemoryRegionType_DramReservedBase.GetValue() == (0x16));
static_assert(KMemoryRegionType_DramHeapBase.GetValue() == (0x26 | KMemoryRegionAttr_LinearMapped));
constexpr auto KMemoryRegionType_DramKernelCode =
KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 0);
constexpr auto KMemoryRegionType_DramKernelSlab =
KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 1);
constexpr auto KMemoryRegionType_DramKernelPtHeap =
KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 2).SetAttribute(
KMemoryRegionAttr_LinearMapped);
constexpr auto KMemoryRegionType_DramKernelInitPt =
KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 3).SetAttribute(
KMemoryRegionAttr_LinearMapped);
static_assert(KMemoryRegionType_DramKernelCode.GetValue() ==
(0xCE | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap));
static_assert(KMemoryRegionType_DramKernelSlab.GetValue() ==
(0x14E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap));
static_assert(KMemoryRegionType_DramKernelPtHeap.GetValue() ==
(0x24E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap |
KMemoryRegionAttr_LinearMapped));
static_assert(KMemoryRegionType_DramKernelInitPt.GetValue() ==
(0x44E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap |
KMemoryRegionAttr_LinearMapped));
constexpr auto KMemoryRegionType_DramReservedEarly =
KMemoryRegionType_DramReservedBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap);
static_assert(KMemoryRegionType_DramReservedEarly.GetValue() ==
(0x16 | KMemoryRegionAttr_NoUserMap));
constexpr auto KMemoryRegionType_KernelTraceBuffer =
KMemoryRegionType_DramReservedBase.DeriveSparse(0, 3, 0)
.SetAttribute(KMemoryRegionAttr_LinearMapped)
.SetAttribute(KMemoryRegionAttr_UserReadOnly);
constexpr auto KMemoryRegionType_OnMemoryBootImage =
KMemoryRegionType_DramReservedBase.DeriveSparse(0, 3, 1);
constexpr auto KMemoryRegionType_DTB = KMemoryRegionType_DramReservedBase.DeriveSparse(0, 3, 2);
static_assert(KMemoryRegionType_KernelTraceBuffer.GetValue() ==
(0xD6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_UserReadOnly));
static_assert(KMemoryRegionType_OnMemoryBootImage.GetValue() == 0x156);
static_assert(KMemoryRegionType_DTB.GetValue() == 0x256);
constexpr auto KMemoryRegionType_DramPoolPartition =
KMemoryRegionType_DramHeapBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap);
static_assert(KMemoryRegionType_DramPoolPartition.GetValue() ==
(0x26 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
constexpr auto KMemoryRegionType_DramPoolManagement =
KMemoryRegionType_DramPoolPartition.DeriveTransition(0, 2).DeriveTransition().SetAttribute(
KMemoryRegionAttr_CarveoutProtected);
constexpr auto KMemoryRegionType_DramUserPool =
KMemoryRegionType_DramPoolPartition.DeriveTransition(1, 2).DeriveTransition();
static_assert(KMemoryRegionType_DramPoolManagement.GetValue() ==
(0x166 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap |
KMemoryRegionAttr_CarveoutProtected));
static_assert(KMemoryRegionType_DramUserPool.GetValue() ==
(0x1A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
constexpr auto KMemoryRegionType_DramApplicationPool = KMemoryRegionType_DramUserPool.Derive(4, 0);
constexpr auto KMemoryRegionType_DramAppletPool = KMemoryRegionType_DramUserPool.Derive(4, 1);
constexpr auto KMemoryRegionType_DramSystemNonSecurePool =
KMemoryRegionType_DramUserPool.Derive(4, 2);
constexpr auto KMemoryRegionType_DramSystemPool =
KMemoryRegionType_DramUserPool.Derive(4, 3).SetAttribute(KMemoryRegionAttr_CarveoutProtected);
static_assert(KMemoryRegionType_DramApplicationPool.GetValue() ==
(0x7A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
static_assert(KMemoryRegionType_DramAppletPool.GetValue() ==
(0xBA6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
static_assert(KMemoryRegionType_DramSystemNonSecurePool.GetValue() ==
(0xDA6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
static_assert(KMemoryRegionType_DramSystemPool.GetValue() ==
(0x13A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap |
KMemoryRegionAttr_CarveoutProtected));
constexpr auto KMemoryRegionType_VirtualDramHeapBase = KMemoryRegionType_Dram.DeriveSparse(1, 3, 0);
constexpr auto KMemoryRegionType_VirtualDramKernelPtHeap =
KMemoryRegionType_Dram.DeriveSparse(1, 3, 1);
constexpr auto KMemoryRegionType_VirtualDramKernelTraceBuffer =
KMemoryRegionType_Dram.DeriveSparse(1, 3, 2);
static_assert(KMemoryRegionType_VirtualDramHeapBase.GetValue() == 0x1A);
static_assert(KMemoryRegionType_VirtualDramKernelPtHeap.GetValue() == 0x2A);
static_assert(KMemoryRegionType_VirtualDramKernelTraceBuffer.GetValue() == 0x4A);
constexpr auto KMemoryRegionType_VirtualDramKernelInitPt =
KMemoryRegionType_VirtualDramHeapBase.Derive(3, 0);
constexpr auto KMemoryRegionType_VirtualDramPoolManagement =
KMemoryRegionType_VirtualDramHeapBase.Derive(3, 1);
constexpr auto KMemoryRegionType_VirtualDramUserPool =
KMemoryRegionType_VirtualDramHeapBase.Derive(3, 2);
static_assert(KMemoryRegionType_VirtualDramKernelInitPt.GetValue() == 0x19A);
static_assert(KMemoryRegionType_VirtualDramPoolManagement.GetValue() == 0x29A);
static_assert(KMemoryRegionType_VirtualDramUserPool.GetValue() == 0x31A);
// NOTE: For unknown reason, the pools are derived out-of-order here. It's worth eventually trying
// to understand why Nintendo made this choice.
// UNUSED: .Derive(6, 0);
// UNUSED: .Derive(6, 1);
constexpr auto KMemoryRegionType_VirtualDramAppletPool =
KMemoryRegionType_VirtualDramUserPool.Derive(6, 2);
constexpr auto KMemoryRegionType_VirtualDramApplicationPool =
KMemoryRegionType_VirtualDramUserPool.Derive(6, 3);
constexpr auto KMemoryRegionType_VirtualDramSystemNonSecurePool =
KMemoryRegionType_VirtualDramUserPool.Derive(6, 4);
constexpr auto KMemoryRegionType_VirtualDramSystemPool =
KMemoryRegionType_VirtualDramUserPool.Derive(6, 5);
static_assert(KMemoryRegionType_VirtualDramAppletPool.GetValue() == 0x1B1A);
static_assert(KMemoryRegionType_VirtualDramApplicationPool.GetValue() == 0x271A);
static_assert(KMemoryRegionType_VirtualDramSystemNonSecurePool.GetValue() == 0x2B1A);
static_assert(KMemoryRegionType_VirtualDramSystemPool.GetValue() == 0x331A);
constexpr auto KMemoryRegionType_ArchDeviceBase =
KMemoryRegionType_Kernel.DeriveTransition(0, 1).SetSparseOnly();
constexpr auto KMemoryRegionType_BoardDeviceBase =
KMemoryRegionType_Kernel.DeriveTransition(0, 2).SetDenseOnly();
static_assert(KMemoryRegionType_ArchDeviceBase.GetValue() == 0x5);
static_assert(KMemoryRegionType_BoardDeviceBase.GetValue() == 0x5);
#if defined(ARCH_ARM64)
#include "core/hle/kernel/arch/arm64/k_memory_region_device_types.inc"
#elif defined(ARCH_ARM)
#error "Unimplemented"
#else
// Default to no architecture devices.
constexpr auto NumArchitectureDeviceRegions = 0;
#endif
static_assert(NumArchitectureDeviceRegions >= 0);
#if defined(BOARD_NINTENDO_NX)
#include "core/hle/kernel/board/nintendo/nx/k_memory_region_device_types.inc"
#else
// Default to no board devices.
constexpr auto NumBoardDeviceRegions = 0;
#endif
static_assert(NumBoardDeviceRegions >= 0);
constexpr auto KMemoryRegionType_KernelCode = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 0);
constexpr auto KMemoryRegionType_KernelStack = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 1);
constexpr auto KMemoryRegionType_KernelMisc = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 2);
constexpr auto KMemoryRegionType_KernelSlab = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 3);
static_assert(KMemoryRegionType_KernelCode.GetValue() == 0x19);
static_assert(KMemoryRegionType_KernelStack.GetValue() == 0x29);
static_assert(KMemoryRegionType_KernelMisc.GetValue() == 0x49);
static_assert(KMemoryRegionType_KernelSlab.GetValue() == 0x89);
constexpr auto KMemoryRegionType_KernelMiscDerivedBase =
KMemoryRegionType_KernelMisc.DeriveTransition();
static_assert(KMemoryRegionType_KernelMiscDerivedBase.GetValue() == 0x149);
// UNUSED: .Derive(7, 0);
constexpr auto KMemoryRegionType_KernelMiscMainStack =
KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 1);
constexpr auto KMemoryRegionType_KernelMiscMappedDevice =
KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 2);
constexpr auto KMemoryRegionType_KernelMiscExceptionStack =
KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 3);
constexpr auto KMemoryRegionType_KernelMiscUnknownDebug =
KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 4);
// UNUSED: .Derive(7, 5);
constexpr auto KMemoryRegionType_KernelMiscIdleStack =
KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 6);
static_assert(KMemoryRegionType_KernelMiscMainStack.GetValue() == 0xB49);
static_assert(KMemoryRegionType_KernelMiscMappedDevice.GetValue() == 0xD49);
static_assert(KMemoryRegionType_KernelMiscExceptionStack.GetValue() == 0x1349);
static_assert(KMemoryRegionType_KernelMiscUnknownDebug.GetValue() == 0x1549);
static_assert(KMemoryRegionType_KernelMiscIdleStack.GetValue() == 0x2349);
constexpr auto KMemoryRegionType_KernelTemp = KMemoryRegionType_Kernel.Advance(2).Derive(2, 0);
static_assert(KMemoryRegionType_KernelTemp.GetValue() == 0x31);
constexpr KMemoryRegionType GetTypeForVirtualLinearMapping(u32 type_id) {
if (KMemoryRegionType_KernelTraceBuffer.IsAncestorOf(type_id)) {
return KMemoryRegionType_VirtualDramKernelTraceBuffer;
} else if (KMemoryRegionType_DramKernelPtHeap.IsAncestorOf(type_id)) {
return KMemoryRegionType_VirtualDramKernelPtHeap;
} else {
return KMemoryRegionType_Dram;
}
}
} // namespace Kernel
+279
View File
@@ -0,0 +1,279 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <bit>
#include "common/alignment.h"
#include "common/assert.h"
#include "common/bit_util.h"
#include "common/common_types.h"
#include "common/tiny_mt.h"
#include "core/hle/kernel/k_system_control.h"
namespace Kernel {
class KPageBitmap {
private:
class RandomBitGenerator {
private:
Common::TinyMT rng{};
u32 entropy{};
u32 bits_available{};
private:
void RefreshEntropy() {
entropy = rng.GenerateRandomU32();
bits_available = static_cast<u32>(Common::BitSize<decltype(entropy)>());
}
bool GenerateRandomBit() {
if (bits_available == 0) {
this->RefreshEntropy();
}
const bool rnd_bit = (entropy & 1) != 0;
entropy >>= 1;
--bits_available;
return rnd_bit;
}
public:
RandomBitGenerator() {
rng.Initialize(static_cast<u32>(KSystemControl::GenerateRandomU64()));
}
std::size_t SelectRandomBit(u64 bitmap) {
u64 selected = 0;
u64 cur_num_bits = Common::BitSize<decltype(bitmap)>() / 2;
u64 cur_mask = (1ULL << cur_num_bits) - 1;
while (cur_num_bits) {
const u64 low = (bitmap >> 0) & cur_mask;
const u64 high = (bitmap >> cur_num_bits) & cur_mask;
bool choose_low;
if (high == 0) {
// If only low val is set, choose low.
choose_low = true;
} else if (low == 0) {
// If only high val is set, choose high.
choose_low = false;
} else {
// If both are set, choose random.
choose_low = this->GenerateRandomBit();
}
// If we chose low, proceed with low.
if (choose_low) {
bitmap = low;
selected += 0;
} else {
bitmap = high;
selected += cur_num_bits;
}
// Proceed.
cur_num_bits /= 2;
cur_mask >>= cur_num_bits;
}
return selected;
}
};
public:
static constexpr std::size_t MaxDepth = 4;
private:
std::array<u64*, MaxDepth> bit_storages{};
RandomBitGenerator rng{};
std::size_t num_bits{};
std::size_t used_depths{};
public:
KPageBitmap() = default;
constexpr std::size_t GetNumBits() const {
return num_bits;
}
constexpr s32 GetHighestDepthIndex() const {
return static_cast<s32>(used_depths) - 1;
}
u64* Initialize(u64* storage, std::size_t size) {
// Initially, everything is un-set.
num_bits = 0;
// Calculate the needed bitmap depth.
used_depths = static_cast<std::size_t>(GetRequiredDepth(size));
ASSERT(used_depths <= MaxDepth);
// Set the bitmap pointers.
for (s32 depth = this->GetHighestDepthIndex(); depth >= 0; depth--) {
bit_storages[depth] = storage;
size = Common::AlignUp(size, Common::BitSize<u64>()) / Common::BitSize<u64>();
storage += size;
}
return storage;
}
s64 FindFreeBlock(bool random) {
uintptr_t offset = 0;
s32 depth = 0;
if (random) {
do {
const u64 v = bit_storages[depth][offset];
if (v == 0) {
// If depth is bigger than zero, then a previous level indicated a block was
// free.
ASSERT(depth == 0);
return -1;
}
offset = offset * Common::BitSize<u64>() + rng.SelectRandomBit(v);
++depth;
} while (depth < static_cast<s32>(used_depths));
} else {
do {
const u64 v = bit_storages[depth][offset];
if (v == 0) {
// If depth is bigger than zero, then a previous level indicated a block was
// free.
ASSERT(depth == 0);
return -1;
}
offset = offset * Common::BitSize<u64>() + std::countr_zero(v);
++depth;
} while (depth < static_cast<s32>(used_depths));
}
return static_cast<s64>(offset);
}
void SetBit(std::size_t offset) {
this->SetBit(this->GetHighestDepthIndex(), offset);
num_bits++;
}
void ClearBit(std::size_t offset) {
this->ClearBit(this->GetHighestDepthIndex(), offset);
num_bits--;
}
bool ClearRange(std::size_t offset, std::size_t count) {
s32 depth = this->GetHighestDepthIndex();
u64* bits = bit_storages[depth];
std::size_t bit_ind = offset / Common::BitSize<u64>();
if (count < Common::BitSize<u64>()) {
const std::size_t shift = offset % Common::BitSize<u64>();
ASSERT(shift + count <= Common::BitSize<u64>());
// Check that all the bits are set.
const u64 mask = ((u64(1) << count) - 1) << shift;
u64 v = bits[bit_ind];
if ((v & mask) != mask) {
return false;
}
// Clear the bits.
v &= ~mask;
bits[bit_ind] = v;
if (v == 0) {
this->ClearBit(depth - 1, bit_ind);
}
} else {
ASSERT(offset % Common::BitSize<u64>() == 0);
ASSERT(count % Common::BitSize<u64>() == 0);
// Check that all the bits are set.
std::size_t remaining = count;
std::size_t i = 0;
do {
if (bits[bit_ind + i++] != ~u64(0)) {
return false;
}
remaining -= Common::BitSize<u64>();
} while (remaining > 0);
// Clear the bits.
remaining = count;
i = 0;
do {
bits[bit_ind + i] = 0;
this->ClearBit(depth - 1, bit_ind + i);
i++;
remaining -= Common::BitSize<u64>();
} while (remaining > 0);
}
num_bits -= count;
return true;
}
private:
void SetBit(s32 depth, std::size_t offset) {
while (depth >= 0) {
std::size_t ind = offset / Common::BitSize<u64>();
std::size_t which = offset % Common::BitSize<u64>();
const u64 mask = u64(1) << which;
u64* bit = std::addressof(bit_storages[depth][ind]);
u64 v = *bit;
ASSERT((v & mask) == 0);
*bit = v | mask;
if (v) {
break;
}
offset = ind;
depth--;
}
}
void ClearBit(s32 depth, std::size_t offset) {
while (depth >= 0) {
std::size_t ind = offset / Common::BitSize<u64>();
std::size_t which = offset % Common::BitSize<u64>();
const u64 mask = u64(1) << which;
u64* bit = std::addressof(bit_storages[depth][ind]);
u64 v = *bit;
ASSERT((v & mask) != 0);
v &= ~mask;
*bit = v;
if (v) {
break;
}
offset = ind;
depth--;
}
}
private:
static constexpr s32 GetRequiredDepth(std::size_t region_size) {
s32 depth = 0;
while (true) {
region_size /= Common::BitSize<u64>();
depth++;
if (region_size == 0) {
return depth;
}
}
}
public:
static constexpr std::size_t CalculateManagementOverheadSize(std::size_t region_size) {
std::size_t overhead_bits = 0;
for (s32 depth = GetRequiredDepth(region_size) - 1; depth >= 0; depth--) {
region_size =
Common::AlignUp(region_size, Common::BitSize<u64>()) / Common::BitSize<u64>();
overhead_bits += region_size;
}
return overhead_bits * sizeof(u64);
}
};
} // namespace Kernel
@@ -2,16 +2,13 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
// This file references various implementation details from Atmosphere, an open-source firmware for
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
#include "core/core.h"
#include "core/hle/kernel/memory/page_heap.h"
#include "core/hle/kernel/k_page_heap.h"
#include "core/memory.h"
namespace Kernel::Memory {
namespace Kernel {
void PageHeap::Initialize(VAddr address, std::size_t size, std::size_t metadata_size) {
void KPageHeap::Initialize(VAddr address, std::size_t size, std::size_t metadata_size) {
// Check our assumptions
ASSERT(Common::IsAligned((address), PageSize));
ASSERT(Common::IsAligned(size, PageSize));
@@ -32,11 +29,11 @@ void PageHeap::Initialize(VAddr address, std::size_t size, std::size_t metadata_
}
}
VAddr PageHeap::AllocateBlock(s32 index) {
VAddr KPageHeap::AllocateBlock(s32 index, bool random) {
const std::size_t needed_size{blocks[index].GetSize()};
for (s32 i{index}; i < static_cast<s32>(MemoryBlockPageShifts.size()); i++) {
if (const VAddr addr{blocks[i].PopBlock()}; addr) {
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);
@@ -48,13 +45,13 @@ VAddr PageHeap::AllocateBlock(s32 index) {
return 0;
}
void PageHeap::FreeBlock(VAddr block, s32 index) {
void KPageHeap::FreeBlock(VAddr block, s32 index) {
do {
block = blocks[index++].PushBlock(block);
} while (block != 0);
}
void PageHeap::Free(VAddr addr, std::size_t num_pages) {
void KPageHeap::Free(VAddr addr, std::size_t num_pages) {
// Freeing no pages is a no-op
if (num_pages == 0) {
return;
@@ -104,16 +101,16 @@ void PageHeap::Free(VAddr addr, std::size_t num_pages) {
}
}
std::size_t PageHeap::CalculateMetadataOverheadSize(std::size_t region_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};
overhead_size += PageHeap::Block::CalculateMetadataOverheadSize(
overhead_size += KPageHeap::Block::CalculateManagementOverheadSize(
region_size, cur_block_shift, next_block_shift);
}
return Common::AlignUp(overhead_size, PageSize);
}
} // namespace Kernel::Memory
} // namespace Kernel
+193
View File
@@ -0,0 +1,193 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <bit>
#include <vector>
#include "common/alignment.h"
#include "common/assert.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 {
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) {
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) {
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 std::size_t GetBlockNumPages(std::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{};
public:
Block() = default;
constexpr std::size_t GetShift() const {
return block_shift;
}
constexpr std::size_t GetNextShift() const {
return next_block_shift;
}
constexpr std::size_t GetSize() const {
return static_cast<std::size_t>(1) << GetShift();
}
constexpr std::size_t GetNumPages() const {
return GetSize() / PageSize;
}
constexpr std::size_t GetNumFreeBlocks() const {
return bitmap.GetNumBits();
}
constexpr std::size_t GetNumFreePages() const {
return GetNumFreeBlocks() * 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;
// 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);
heap_address = addr;
end_offset = (end - addr) / (1ULL << block_shift);
return bitmap.Initialize(bit_storage, end_offset);
}
VAddr PushBlock(VAddr address) {
// Set the bit for the free block
std::size_t offset{(address - heap_address) >> GetShift()};
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())};
offset = Common::AlignDown(offset, diff);
if (bitmap.ClearRange(offset, diff)) {
return heap_address + (offset << GetShift());
}
}
// We couldn't coalesce, or we're already as big as possible
return 0;
}
VAddr PopBlock(bool random) {
// Find a free block
const s64 soffset{bitmap.FindFreeBlock(random)};
if (soffset < 0) {
return 0;
}
const auto offset{static_cast<std::size_t>(soffset)};
// Update our tracking and return it
bitmap.ClearBit(offset);
return heap_address + (offset << 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};
return KPageBitmap::CalculateManagementOverheadSize(
(align * 2 + Common::AlignUp(region_size, align)) / cur_block_size);
}
};
public:
KPageHeap() = default;
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 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);
private:
constexpr std::size_t GetNumFreePages() const {
std::size_t num_free{};
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;
};
} // namespace Kernel
@@ -8,12 +8,12 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "core/hle/kernel/memory/memory_types.h"
#include "core/hle/kernel/memory_types.h"
#include "core/hle/result.h"
namespace Kernel::Memory {
namespace Kernel {
class PageLinkedList final {
class KPageLinkedList final {
public:
class Node final {
public:
@@ -33,8 +33,8 @@ public:
};
public:
PageLinkedList() = default;
PageLinkedList(u64 address, u64 num_pages) {
KPageLinkedList() = default;
KPageLinkedList(u64 address, u64 num_pages) {
ASSERT(AddBlock(address, num_pages).IsSuccess());
}
@@ -54,7 +54,7 @@ public:
return num_pages;
}
bool IsEqual(PageLinkedList& other) const {
bool IsEqual(KPageLinkedList& other) const {
auto this_node = nodes.begin();
auto other_node = other.nodes.begin();
while (this_node != nodes.end() && other_node != other.nodes.end()) {
@@ -89,4 +89,4 @@ private:
std::list<Node> nodes;
};
} // namespace Kernel::Memory
} // namespace Kernel
File diff suppressed because it is too large Load Diff
@@ -10,27 +10,27 @@
#include "common/common_types.h"
#include "common/page_table.h"
#include "core/file_sys/program_metadata.h"
#include "core/hle/kernel/memory/memory_block.h"
#include "core/hle/kernel/memory/memory_manager.h"
#include "core/hle/kernel/k_memory_block.h"
#include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/result.h"
namespace Core {
class System;
}
namespace Kernel::Memory {
namespace Kernel {
class MemoryBlockManager;
class KMemoryBlockManager;
class PageTable final : NonCopyable {
class KPageTable final : NonCopyable {
public:
explicit PageTable(Core::System& system);
explicit KPageTable(Core::System& system);
ResultCode InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr,
VAddr code_addr, std::size_t code_size,
Memory::MemoryManager::Pool pool);
ResultCode MapProcessCode(VAddr addr, std::size_t pages_count, MemoryState state,
MemoryPermission perm);
KMemoryManager::Pool pool);
ResultCode MapProcessCode(VAddr addr, std::size_t pages_count, KMemoryState state,
KMemoryPermission perm);
ResultCode MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
ResultCode UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
ResultCode MapPhysicalMemory(VAddr addr, std::size_t size);
@@ -38,20 +38,20 @@ public:
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 MapPages(VAddr addr, PageLinkedList& page_linked_list, MemoryState state,
MemoryPermission perm);
ResultCode SetCodeMemoryPermission(VAddr addr, std::size_t size, MemoryPermission perm);
MemoryInfo QueryInfo(VAddr addr);
ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, MemoryPermission perm);
ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state,
KMemoryPermission perm);
ResultCode SetCodeMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm);
KMemoryInfo QueryInfo(VAddr addr);
ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm);
ResultCode ResetTransferMemory(VAddr addr, std::size_t size);
ResultCode SetMemoryAttribute(VAddr addr, std::size_t size, MemoryAttribute mask,
MemoryAttribute value);
ResultCode SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryAttribute mask,
KMemoryAttribute value);
ResultCode SetHeapCapacity(std::size_t new_heap_capacity);
ResultVal<VAddr> SetHeapSize(std::size_t size);
ResultVal<VAddr> AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align,
bool is_map_only, VAddr region_start,
std::size_t region_num_pages, MemoryState state,
MemoryPermission perm, PAddr map_addr = 0);
std::size_t region_num_pages, KMemoryState state,
KMemoryPermission perm, PAddr map_addr = 0);
ResultCode LockForDeviceAddressSpace(VAddr addr, std::size_t size);
ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size);
@@ -72,47 +72,49 @@ private:
ChangePermissionsAndRefresh,
};
static constexpr MemoryAttribute DefaultMemoryIgnoreAttr =
MemoryAttribute::DontCareMask | MemoryAttribute::IpcLocked | MemoryAttribute::DeviceShared;
static constexpr KMemoryAttribute DefaultMemoryIgnoreAttr = KMemoryAttribute::DontCareMask |
KMemoryAttribute::IpcLocked |
KMemoryAttribute::DeviceShared;
ResultCode InitializeMemoryLayout(VAddr start, VAddr end);
ResultCode MapPages(VAddr addr, const PageLinkedList& page_linked_list, MemoryPermission perm);
void MapPhysicalMemory(PageLinkedList& page_linked_list, VAddr start, VAddr end);
ResultCode MapPages(VAddr addr, const KPageLinkedList& page_linked_list,
KMemoryPermission perm);
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, PageLinkedList& page_linked_list);
MemoryInfo QueryInfoImpl(VAddr addr);
void AddRegionToPages(VAddr start, std::size_t num_pages, KPageLinkedList& page_linked_list);
KMemoryInfo QueryInfoImpl(VAddr addr);
VAddr AllocateVirtualMemory(VAddr start, std::size_t region_num_pages, u64 needed_num_pages,
std::size_t align);
ResultCode Operate(VAddr addr, std::size_t num_pages, const PageLinkedList& page_group,
ResultCode Operate(VAddr addr, std::size_t num_pages, const KPageLinkedList& page_group,
OperationType operation);
ResultCode Operate(VAddr addr, std::size_t num_pages, MemoryPermission perm,
ResultCode Operate(VAddr addr, std::size_t num_pages, KMemoryPermission perm,
OperationType operation, PAddr map_addr = 0);
constexpr VAddr GetRegionAddress(MemoryState state) const;
constexpr std::size_t GetRegionSize(MemoryState state) const;
constexpr bool CanContain(VAddr addr, std::size_t size, MemoryState state) const;
constexpr VAddr GetRegionAddress(KMemoryState state) const;
constexpr std::size_t GetRegionSize(KMemoryState state) const;
constexpr bool CanContain(VAddr addr, std::size_t size, KMemoryState state) const;
constexpr ResultCode CheckMemoryState(const MemoryInfo& info, MemoryState state_mask,
MemoryState state, MemoryPermission perm_mask,
MemoryPermission perm, MemoryAttribute attr_mask,
MemoryAttribute attr) const;
ResultCode CheckMemoryState(MemoryState* out_state, MemoryPermission* out_perm,
MemoryAttribute* out_attr, VAddr addr, std::size_t size,
MemoryState state_mask, MemoryState state,
MemoryPermission perm_mask, MemoryPermission perm,
MemoryAttribute attr_mask, MemoryAttribute attr,
MemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr);
ResultCode CheckMemoryState(VAddr addr, std::size_t size, MemoryState state_mask,
MemoryState state, MemoryPermission perm_mask,
MemoryPermission perm, MemoryAttribute attr_mask,
MemoryAttribute attr,
MemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) {
constexpr ResultCode CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask,
KMemoryState state, KMemoryPermission perm_mask,
KMemoryPermission perm, KMemoryAttribute attr_mask,
KMemoryAttribute attr) const;
ResultCode CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
KMemoryAttribute* out_attr, VAddr addr, std::size_t size,
KMemoryState state_mask, KMemoryState state,
KMemoryPermission perm_mask, KMemoryPermission perm,
KMemoryAttribute attr_mask, KMemoryAttribute attr,
KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr);
ResultCode CheckMemoryState(VAddr addr, std::size_t size, KMemoryState state_mask,
KMemoryState state, KMemoryPermission perm_mask,
KMemoryPermission perm, KMemoryAttribute attr_mask,
KMemoryAttribute attr,
KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) {
return CheckMemoryState(nullptr, nullptr, nullptr, addr, size, state_mask, state, perm_mask,
perm, attr_mask, attr, ignore_attr);
}
std::recursive_mutex page_table_lock;
std::unique_ptr<MemoryBlockManager> block_manager;
std::unique_ptr<KMemoryBlockManager> block_manager;
public:
constexpr VAddr GetAddressSpaceStart() const {
@@ -212,7 +214,7 @@ public:
return !IsOutsideASLRRegion(address, size);
}
constexpr PAddr GetPhysicalAddr(VAddr addr) {
return page_table_impl.backing_addr[addr >> Memory::PageBits] + addr;
return page_table_impl.backing_addr[addr >> PageBits] + addr;
}
private:
@@ -267,11 +269,11 @@ private:
bool is_kernel{};
bool is_aslr_enabled{};
MemoryManager::Pool memory_pool{MemoryManager::Pool::Application};
KMemoryManager::Pool memory_pool{KMemoryManager::Pool::Application};
Common::PageTable page_table_impl;
Core::System& system;
};
} // namespace Kernel::Memory
} // namespace Kernel
+4 -9
View File
@@ -2,21 +2,16 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
// This file references various implementation details from Atmosphere, an open-source firmware for
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
#include "common/assert.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/svc_results.h"
namespace Kernel {
constexpr s64 DefaultTimeout = 10000000000; // 10 seconds
KResourceLimit::KResourceLimit(KernelCore& kernel, Core::System& system)
: Object{kernel}, lock{kernel}, cond_var{kernel}, kernel{kernel}, system(system) {}
KResourceLimit::KResourceLimit(KernelCore& kernel, const Core::Timing::CoreTiming& core_timing_)
: Object{kernel}, lock{kernel}, cond_var{kernel}, core_timing(core_timing_) {}
KResourceLimit::~KResourceLimit() = default;
s64 KResourceLimit::GetLimitValue(LimitableResource which) const {
@@ -83,7 +78,7 @@ ResultCode KResourceLimit::SetLimitValue(LimitableResource which, s64 value) {
}
bool KResourceLimit::Reserve(LimitableResource which, s64 value) {
return Reserve(which, value, system.CoreTiming().GetGlobalTimeNs().count() + DefaultTimeout);
return Reserve(which, value, core_timing.GetGlobalTimeNs().count() + DefaultTimeout);
}
bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) {
@@ -114,7 +109,7 @@ bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) {
}
if (current_hints[index] + value <= limit_values[index] &&
(timeout < 0 || system.CoreTiming().GetGlobalTimeNs().count() < timeout)) {
(timeout < 0 || core_timing.GetGlobalTimeNs().count() < timeout)) {
waiter_count++;
cond_var.Wait(&lock, timeout);
waiter_count--;
+4 -8
View File
@@ -2,9 +2,6 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
// This file references various implementation details from Atmosphere, an open-source firmware for
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
#pragma once
#include <array>
@@ -15,8 +12,8 @@
union ResultCode;
namespace Core {
class System;
namespace Core::Timing {
class CoreTiming;
}
namespace Kernel {
@@ -37,7 +34,7 @@ constexpr bool IsValidResourceType(LimitableResource type) {
class KResourceLimit final : public Object {
public:
explicit KResourceLimit(KernelCore& kernel, Core::System& system);
explicit KResourceLimit(KernelCore& kernel, const Core::Timing::CoreTiming& core_timing_);
~KResourceLimit();
s64 GetLimitValue(LimitableResource which) const;
@@ -75,7 +72,6 @@ private:
mutable KLightLock lock;
s32 waiter_count{};
KLightConditionVariable cond_var;
KernelCore& kernel;
Core::System& system;
const Core::Timing::CoreTiming& core_timing;
};
} // namespace Kernel
+17 -22
View File
@@ -62,7 +62,7 @@ void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedul
}
u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) {
std::scoped_lock lock{guard};
KScopedSpinLock lk{guard};
if (KThread* prev_highest_thread = state.highest_priority_thread;
prev_highest_thread != highest_thread) {
if (prev_highest_thread != nullptr) {
@@ -637,11 +637,11 @@ void KScheduler::RescheduleCurrentCore() {
if (phys_core.IsInterrupted()) {
phys_core.ClearInterrupt();
}
guard.lock();
guard.Lock();
if (state.needs_scheduling.load()) {
Schedule();
} else {
guard.unlock();
guard.Unlock();
}
}
@@ -669,7 +669,7 @@ void KScheduler::Unload(KThread* thread) {
} else {
prev_thread = nullptr;
}
thread->context_guard.unlock();
thread->context_guard.Unlock();
}
}
@@ -713,7 +713,7 @@ void KScheduler::ScheduleImpl() {
// If we're not actually switching thread, there's nothing to do.
if (next_thread == current_thread.load()) {
guard.unlock();
guard.Unlock();
return;
}
@@ -732,9 +732,9 @@ void KScheduler::ScheduleImpl() {
} else {
old_context = &idle_thread->GetHostContext();
}
guard.unlock();
guard.Unlock();
Common::Fiber::YieldTo(*old_context, switch_fiber);
Common::Fiber::YieldTo(*old_context, *switch_fiber);
/// When a thread wakes up, the scheduler may have changed to other in another core.
auto& next_scheduler = *system.Kernel().CurrentScheduler();
next_scheduler.SwitchContextStep2();
@@ -748,34 +748,29 @@ void KScheduler::OnSwitch(void* this_scheduler) {
void KScheduler::SwitchToCurrent() {
while (true) {
{
std::scoped_lock lock{guard};
KScopedSpinLock lk{guard};
current_thread.store(state.highest_priority_thread);
state.needs_scheduling.store(false);
}
const auto is_switch_pending = [this] {
std::scoped_lock lock{guard};
KScopedSpinLock lk{guard};
return state.needs_scheduling.load();
};
do {
auto next_thread = current_thread.load();
if (next_thread != nullptr) {
next_thread->context_guard.lock();
next_thread->context_guard.Lock();
if (next_thread->GetRawState() != ThreadState::Runnable) {
next_thread->context_guard.unlock();
next_thread->context_guard.Unlock();
break;
}
if (next_thread->GetActiveCore() != core_id) {
next_thread->context_guard.unlock();
next_thread->context_guard.Unlock();
break;
}
}
std::shared_ptr<Common::Fiber>* next_context;
if (next_thread != nullptr) {
next_context = &next_thread->GetHostContext();
} else {
next_context = &idle_thread->GetHostContext();
}
Common::Fiber::YieldTo(switch_fiber, *next_context);
auto thread = next_thread ? next_thread : idle_thread;
Common::Fiber::YieldTo(switch_fiber, *thread->GetHostContext());
} while (!is_switch_pending());
}
}
@@ -800,9 +795,9 @@ void KScheduler::Initialize() {
std::string name = "Idle Thread Id:" + std::to_string(core_id);
std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc();
void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
auto thread_res = KThread::Create(system, ThreadType::Main, name, 0,
KThread::IdleThreadPriority, 0, static_cast<u32>(core_id), 0,
nullptr, std::move(init_func), init_func_parameter);
auto thread_res = KThread::CreateThread(
system, ThreadType::Main, name, 0, KThread::IdleThreadPriority, 0,
static_cast<u32>(core_id), 0, nullptr, std::move(init_func), init_func_parameter);
idle_thread = thread_res.Unwrap().get();
}
+4 -7
View File
@@ -2,19 +2,16 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
// This file references various implementation details from Atmosphere, an open-source firmware for
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
#pragma once
#include <atomic>
#include "common/common_types.h"
#include "common/spin_lock.h"
#include "core/hle/kernel/global_scheduler_context.h"
#include "core/hle/kernel/k_priority_queue.h"
#include "core/hle/kernel/k_scheduler_lock.h"
#include "core/hle/kernel/k_scoped_lock.h"
#include "core/hle/kernel/k_spin_lock.h"
namespace Common {
class Fiber;
@@ -195,12 +192,12 @@ private:
u64 last_context_switch_time{};
const s32 core_id;
Common::SpinLock guard{};
KSpinLock guard{};
};
class KScopedSchedulerLock : KScopedLock<GlobalSchedulerContext::LockType> {
class [[nodiscard]] KScopedSchedulerLock : KScopedLock<GlobalSchedulerContext::LockType> {
public:
explicit KScopedSchedulerLock(KernelCore& kernel);
explicit KScopedSchedulerLock(KernelCore & kernel);
~KScopedSchedulerLock();
};
+4 -7
View File
@@ -2,14 +2,11 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
// This file references various implementation details from Atmosphere, an open-source firmware for
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
#pragma once
#include "common/assert.h"
#include "common/spin_lock.h"
#include "core/hardware_properties.h"
#include "core/hle/kernel/k_spin_lock.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h"
@@ -34,7 +31,7 @@ public:
} else {
// Otherwise, we want to disable scheduling and acquire the spinlock.
SchedulerType::DisableScheduling(kernel);
spin_lock.lock();
spin_lock.Lock();
// For debug, ensure that our state is valid.
ASSERT(lock_count == 0);
@@ -58,7 +55,7 @@ public:
// Note that we no longer hold the lock, and unlock the spinlock.
owner_thread = nullptr;
spin_lock.unlock();
spin_lock.Unlock();
// Enable scheduling, and perform a rescheduling operation.
SchedulerType::EnableScheduling(kernel, cores_needing_scheduling);
@@ -67,7 +64,7 @@ public:
private:
KernelCore& kernel;
Common::SpinLock spin_lock{};
KAlignedSpinLock spin_lock{};
s32 lock_count{};
KThread* owner_thread{};
};
+8 -5
View File
@@ -20,19 +20,22 @@ concept KLockable = !std::is_reference_v<T> && requires(T & t) {
};
template <typename T>
requires KLockable<T> class KScopedLock {
requires KLockable<T> class [[nodiscard]] KScopedLock {
public:
explicit KScopedLock(T* l) : lock_ptr(l) {
explicit KScopedLock(T * l) : lock_ptr(l) {
this->lock_ptr->Lock();
}
explicit KScopedLock(T& l) : KScopedLock(std::addressof(l)) { /* ... */
}
explicit KScopedLock(T & l) : KScopedLock(std::addressof(l)) {}
~KScopedLock() {
this->lock_ptr->Unlock();
}
KScopedLock(const KScopedLock&) = delete;
KScopedLock(KScopedLock&&) = delete;
KScopedLock& operator=(const KScopedLock&) = delete;
KScopedLock(KScopedLock &&) = delete;
KScopedLock& operator=(KScopedLock&&) = delete;
private:
T* lock_ptr;
@@ -15,9 +15,9 @@
namespace Kernel {
class KScopedSchedulerLockAndSleep {
class [[nodiscard]] KScopedSchedulerLockAndSleep {
public:
explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, KThread* t, s64 timeout)
explicit KScopedSchedulerLockAndSleep(KernelCore & kernel, KThread * t, s64 timeout)
: kernel(kernel), thread(t), timeout_tick(timeout) {
// Lock the scheduler.
kernel.GlobalSchedulerContext().scheduler_lock.Lock();
@@ -4,33 +4,32 @@
#include "common/assert.h"
#include "core/core.h"
#include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/k_scoped_resource_reservation.h"
#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/memory/page_table.h"
#include "core/hle/kernel/shared_memory.h"
namespace Kernel {
SharedMemory::SharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory)
KSharedMemory::KSharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory)
: Object{kernel}, device_memory{device_memory} {}
SharedMemory::~SharedMemory() {
KSharedMemory::~KSharedMemory() {
kernel.GetSystemResourceLimit()->Release(LimitableResource::PhysicalMemory, size);
}
std::shared_ptr<SharedMemory> SharedMemory::Create(
std::shared_ptr<KSharedMemory> KSharedMemory::Create(
KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process,
Memory::PageLinkedList&& page_list, Memory::MemoryPermission owner_permission,
Memory::MemoryPermission user_permission, PAddr physical_address, std::size_t size,
std::string name) {
KPageLinkedList&& page_list, KMemoryPermission owner_permission,
KMemoryPermission user_permission, PAddr physical_address, std::size_t size, std::string name) {
const auto resource_limit = kernel.GetSystemResourceLimit();
KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory,
size);
ASSERT(memory_reservation.Succeeded());
std::shared_ptr<SharedMemory> shared_memory{
std::make_shared<SharedMemory>(kernel, device_memory)};
std::shared_ptr<KSharedMemory> shared_memory{
std::make_shared<KSharedMemory>(kernel, device_memory)};
shared_memory->owner_process = owner_process;
shared_memory->page_list = std::move(page_list);
@@ -44,22 +43,22 @@ std::shared_ptr<SharedMemory> SharedMemory::Create(
return shared_memory;
}
ResultCode SharedMemory::Map(Process& target_process, VAddr address, std::size_t size,
Memory::MemoryPermission permissions) {
const u64 page_count{(size + Memory::PageSize - 1) / Memory::PageSize};
ResultCode KSharedMemory::Map(Process& target_process, VAddr address, std::size_t size,
KMemoryPermission permissions) {
const u64 page_count{(size + PageSize - 1) / PageSize};
if (page_list.GetNumPages() != page_count) {
UNIMPLEMENTED_MSG("Page count does not match");
}
const Memory::MemoryPermission expected =
const KMemoryPermission expected =
&target_process == owner_process ? owner_permission : user_permission;
if (permissions != expected) {
UNIMPLEMENTED_MSG("Permission does not match");
}
return target_process.PageTable().MapPages(address, page_list, Memory::MemoryState::Shared,
return target_process.PageTable().MapPages(address, page_list, KMemoryState::Shared,
permissions);
}
@@ -9,8 +9,8 @@
#include "common/common_types.h"
#include "core/device_memory.h"
#include "core/hle/kernel/memory/memory_block.h"
#include "core/hle/kernel/memory/page_linked_list.h"
#include "core/hle/kernel/k_memory_block.h"
#include "core/hle/kernel/k_page_linked_list.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/process.h"
#include "core/hle/result.h"
@@ -19,15 +19,15 @@ namespace Kernel {
class KernelCore;
class SharedMemory final : public Object {
class KSharedMemory final : public Object {
public:
explicit SharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory);
~SharedMemory() override;
explicit KSharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory);
~KSharedMemory() override;
static std::shared_ptr<SharedMemory> Create(
static std::shared_ptr<KSharedMemory> Create(
KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process,
Memory::PageLinkedList&& page_list, Memory::MemoryPermission owner_permission,
Memory::MemoryPermission user_permission, PAddr physical_address, std::size_t size,
KPageLinkedList&& page_list, KMemoryPermission owner_permission,
KMemoryPermission user_permission, PAddr physical_address, std::size_t size,
std::string name);
std::string GetTypeName() const override {
@@ -51,7 +51,7 @@ public:
* @param permissions Memory block map permissions (specified by SVC field)
*/
ResultCode Map(Process& target_process, VAddr address, std::size_t size,
Memory::MemoryPermission permissions);
KMemoryPermission permissions);
/**
* Gets a pointer to the shared memory block
@@ -76,9 +76,9 @@ public:
private:
Core::DeviceMemory& device_memory;
Process* owner_process{};
Memory::PageLinkedList page_list;
Memory::MemoryPermission owner_permission{};
Memory::MemoryPermission user_permission{};
KPageLinkedList page_list;
KMemoryPermission owner_permission{};
KMemoryPermission user_permission{};
PAddr physical_address{};
std::size_t size{};
std::string name;
@@ -2,9 +2,6 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
// This file references various implementation details from Atmosphere, an open-source firmware for
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
#pragma once
#include <atomic>
@@ -12,17 +9,17 @@
#include "common/assert.h"
#include "common/common_types.h"
namespace Kernel::Memory {
namespace Kernel {
namespace impl {
class SlabHeapImpl final : NonCopyable {
class KSlabHeapImpl final : NonCopyable {
public:
struct Node {
Node* next{};
};
constexpr SlabHeapImpl() = default;
constexpr KSlabHeapImpl() = default;
void Initialize(std::size_t size) {
ASSERT(head == nullptr);
@@ -65,9 +62,9 @@ private:
} // namespace impl
class SlabHeapBase : NonCopyable {
class KSlabHeapBase : NonCopyable {
public:
constexpr SlabHeapBase() = default;
constexpr KSlabHeapBase() = default;
constexpr bool Contains(uintptr_t addr) const {
return start <= addr && addr < end;
@@ -126,7 +123,7 @@ public:
}
private:
using Impl = impl::SlabHeapImpl;
using Impl = impl::KSlabHeapImpl;
Impl impl;
uintptr_t peak{};
@@ -135,9 +132,9 @@ private:
};
template <typename T>
class SlabHeap final : public SlabHeapBase {
class KSlabHeap final : public KSlabHeapBase {
public:
constexpr SlabHeap() : SlabHeapBase() {}
constexpr KSlabHeap() : KSlabHeapBase() {}
void Initialize(void* memory, std::size_t memory_size) {
InitializeImpl(sizeof(T), memory, memory_size);
@@ -160,4 +157,4 @@ public:
}
};
} // namespace Kernel::Memory
} // namespace Kernel
+54
View File
@@ -0,0 +1,54 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/hle/kernel/k_spin_lock.h"
#if _MSC_VER
#include <intrin.h>
#if _M_AMD64
#define __x86_64__ 1
#endif
#if _M_ARM64
#define __aarch64__ 1
#endif
#else
#if __x86_64__
#include <xmmintrin.h>
#endif
#endif
namespace {
void ThreadPause() {
#if __x86_64__
_mm_pause();
#elif __aarch64__ && _MSC_VER
__yield();
#elif __aarch64__
asm("yield");
#endif
}
} // namespace
namespace Kernel {
void KSpinLock::Lock() {
while (lck.test_and_set(std::memory_order_acquire)) {
ThreadPause();
}
}
void KSpinLock::Unlock() {
lck.clear(std::memory_order_release);
}
bool KSpinLock::TryLock() {
if (lck.test_and_set(std::memory_order_acquire)) {
return false;
}
return true;
}
} // namespace Kernel
+39
View File
@@ -0,0 +1,39 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <atomic>
#include "core/hle/kernel/k_scoped_lock.h"
namespace Kernel {
class KSpinLock {
public:
KSpinLock() = default;
KSpinLock(const KSpinLock&) = delete;
KSpinLock& operator=(const KSpinLock&) = delete;
KSpinLock(KSpinLock&&) = delete;
KSpinLock& operator=(KSpinLock&&) = delete;
void Lock();
void Unlock();
[[nodiscard]] bool TryLock();
private:
std::atomic_flag lck = ATOMIC_FLAG_INIT;
};
// TODO(bunnei): Alias for now, in case we want to implement these accurately in the future.
using KAlignedSpinLock = KSpinLock;
using KNotAlignedSpinLock = KSpinLock;
using KScopedSpinLock = KScopedLock<KSpinLock>;
using KScopedAlignedSpinLock = KScopedLock<KAlignedSpinLock>;
using KScopedNotAlignedSpinLock = KScopedLock<KNotAlignedSpinLock>;
} // namespace Kernel
+23
View File
@@ -0,0 +1,23 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/common_types.h"
#define BOARD_NINTENDO_NX
#ifdef BOARD_NINTENDO_NX
#include "core/hle/kernel/board/nintendo/nx/k_system_control.h"
namespace Kernel {
using Kernel::Board::Nintendo::Nx::KSystemControl;
} // namespace Kernel
#else
#error "Unknown board for KSystemControl"
#endif

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